![当没有 root 权限且超出 nproc 限制时如何终止进程?](https://linux22.com/image/107929/%E5%BD%93%E6%B2%A1%E6%9C%89%20root%20%E6%9D%83%E9%99%90%E4%B8%94%E8%B6%85%E5%87%BA%20nproc%20%E9%99%90%E5%88%B6%E6%97%B6%E5%A6%82%E4%BD%95%E7%BB%88%E6%AD%A2%E8%BF%9B%E7%A8%8B%EF%BC%9F.png)
所以,用户已经超出了她的nproc
限制。因此,SSH 和 都su
无法以目标用户身份登录。然而,用户没有可访问的外壳。没有root权限怎么解决这个问题?
谢谢
答案1
当我看到 nproc 和“ulimit”标签时,我将为此 ulimit 机制添加 2 点:
我希望您的系统管理员将软限制设置为比硬限制低一点,正是为了避免您遇到的情况。这样,您就可以增加软值以su
从另一个帐户启动并使用它来进行杀戮。
另外,请记住 ulimit 是由 PAM ( grep -r pam_limits.so /etc/pam.d/
) 设置的,因此如果您有不使用此 PAM 模块的身份验证方法/程序,您可以避免此 ulimit 并生成终止。
CAP_KILL
除了这两个需要在问题出现之前采取行动的解决方案之外,如果没有正确的访问权限(相同的用户、root、setuid 或capability ),确实无法向现有程序发送信号。
答案2
如果您有其他用户的凭据,并且目标用户的凭据可用于以某种方式更改文件系统,您可以编译以下程序,设置 s 位并使用其他用户的凭据来执行它。
注意:可执行文件必须由目标用户拥有,以便能够seteuid
访问目标用户的uid
.
该程序的第一个参数是目标用户的uid
.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <errno.h>
int main(int argc, char**argv) {
if(seteuid(atoi(argv[1])) != 0) {
printf("seteuid failed... %d", errno);
}
if(kill(-1, SIGTERM) != 0) {
printf("kill failed...%d", errno);
}
return 0;
}
答案3
如您所知,如果nproc
已达到,内核将不允许任何其他进程使用该用户的凭据运行。这意味着没有通过 SSH 的远程会话,没有su
或sudo
,甚至没有程序 setuid 到他们的帐户。
这样你就只能使用 root 或用户(如果他们碰巧仍有可工作的交互式会话)。由于你排除了 root,所以你必须希望你的用户仍在运行 shell。如果是这样,他们的 shell 中应该有足够的内置功能来终止一些有问题的进程。你需要利用 shell 内置函数来迭代/proc
。
例如,如果我想杀死所有bash
shell,我可以这样做,它只使用 Bash shell 内置命令:
pushd /proc && for pid in *; do
test "$pid" = "self" && continue # skip /proc/self
test -d "$pid" || continue # skip if not a directory
test -O "$pid" || continue # skip if we don't own it
read cmd < "${pid}/cmdline"
case "$cmd" in
*bash*) kill -9 $pid ;; # or whatever you want to do to it
esac
done && popd
这确实存在一些限制,因此它并不是万无一失的,但在大多数情况下应该很有用。
如果有一个很多处理运行时,
*
循环顶部的扩展可能会导致字符串超出最大命令长度。如果遇到这种情况,您可以使用1*
、2*
、{1..3}*
或类似的东西通过多次运行来减少通配符扩展。/proc/${pid}/cmdline
包含一个以 NULL 分隔的列表,实际命令只是其中一项。我不知道有什么方法可以仅使用 Bash 内置函数来干净地解析这样的字符串。由于字符串通常以 NULL 结尾,因此read
只会获取第一项,它可能是也可能不是命令名称。另一种方法是迭代/proc/${pid}/stat
or/proc/${pid}/status
。