linux 有没有什么措施防御 fork 炸弹?

linux 有没有什么措施防御 fork 炸弹?
#include <unistd.h>
int main(int argc, char* argv[]) {
  while(1)
  {
    fork();
  } 
}

我在我的 Linux 上运行这个程序,终端上没有任何输出,操作系统似乎死机了。Linux 对这种可能耗尽内存的程序有什么保护措施吗?

答案1

这被称为叉子炸弹

linux对这种可能耗尽内存的程序有什么保护措施吗?

并非如此。每次 fork 都会生成一个新进程,具有自己的虚拟地址空间和内存使用量。因此,每个副本都相对较小。最终,您将用尽系统上的所有物理+交换内存,并且内存不足 (OOM) 终止程序将开始终止单个进程。但 fork 炸弹仍将以同样快的速度(如果不是更快的话)创建进程。

防止这种情况发生的一种方法是限制用户进程的数量,使用ulimit -u(假设您正在使用 Bash;其他 shell 会有等效项)。

答案2

是的,尽管您的系统可能未默认启用此功能。setrlimit系统调用定义系统限制——包括每个用户的进程数。

让我们首先在内核 API 中查看它(因为您提到了“linux”):您可以使用 setrlimit 的手册页,它将告诉您执行类似以下操作

#include <sys/resource.h>
...

struct rlimit  r;

rnew.r_cur = 40;
rnew.r_max = 50;
setrlimit(RLIMIT_NPROC,&r);

这会将每个用户的最大进程数(RLIMIT_NPROC)设置为 40(软限制)和 50(硬限制)。

现在,从 shell 中,如果您使用 bash,则可以使用ulimit内置命令:

ulimit -u
29089

您可以通过将其作为参数传递来设置限制:

ulimit -u 100

ulimit --help将显示您可以设置的其他几个限制(您可能感兴趣的一个限制是用户使用的最大文件描述符数量)。

答案3

这取决于您想在用户级别还是系统级别使用它。在用户级别ulimit(或其他 shell 的相应命令)将是最简单的解决方案。

然而,在系统层面,有一些机制可以防止恶意用户(或只是不使用 ulimit)停止系统。Linux cgroups 机制可以限制每个组的资源。您可以(通过pam_systemd机制)强制用户会话处于特定组中。这还有其他好处,例如 CPU 调度程序。

答案4

由于这里最新的答案已有 3 年多了,我想指出,较新的内核(自 4.3 以来)已明确支持通过新的“PID 子系统”防止 fork 炸弹。(见https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=49b786ea146f69c371df18e81ce0a2d5839f865chttps://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=917d8e2d10f40e28aa9e0d824b2e5b8197d79fc2

相关内容