最近我一直在挖掘有关 GNU/Linux 进程的信息,并且遇到了臭名昭著的 fork 炸弹:
:(){ : | :& }; :
理论上,它应该无限复制自己,直到系统耗尽资源......
但是,我尝试过在命令行界面和一个桂薄荷发行版,它似乎对系统影响不大。是的,创建了大量进程,过了一会儿我在控制台消息中读到,例如:
bash:fork:资源暂时不可用
bash:fork:重试:没有子进程
但一段时间后,所有进程都会被终止,一切都会恢复正常。我读过极限值设置每个用户的最大进程量,但我似乎无法将其提高太多。
针对叉子炸弹的系统保护措施有哪些?为什么它不自我复制,直到一切都冻结或至少滞后很多?有没有办法真正用叉子炸弹让系统崩溃?
答案1
您可能有一个使用 systemd 的 Linux 发行版。
Systemd为每个用户创建一个cgroup,一个用户的所有进程都属于同一个cgroup。
Cgroups 是一种 Linux 机制,用于设置系统资源限制,例如最大进程数、CPU 周期、RAM 使用情况等。这是一个与ulimit
(使用getrlimit()
系统调用)不同的、更现代的资源限制层。
如果运行systemctl status user-<uid>.slice
(代表用户的cgroup),可以看到当前和最大数量任务该 cgroup 中允许的(进程和线程)。
$ systemctl status user-$UID.slice ● user-22001.slice - UID 22001 的用户切片 已加载:已加载 插入:/usr/lib/systemd/system/user-.slice.d └─10-defaults.conf 活跃:自东部夏令时间 2018-09-10 星期一 17:36:35 起活跃; 1 周 3 天前 任务:17(限制:10267) 内存:616.7M
默认情况下,systemd 允许每个用户执行的最大任务数是“系统范围最大任务数”的 33% ( sysctl kernel.threads-max
);这通常相当于约 10,000 个任务。如果您想更改此限制:
在 systemd v239 及更高版本中,用户默认设置是通过最大任务数=在:
/usr/lib/systemd/system/user-.slice.d/10-defaults.conf
要调整特定用户的限制(将立即应用并存储在 /etc/systemd/system.control 中),请运行:
systemctl [--runtime] set-property user-<uid>.slice TasksMax=<value>
此处也可以使用覆盖设备设置的常用机制(例如
systemctl edit
),但需要重新启动。例如,如果您想更改以下限制每一个用户,您可以创建/etc/systemd/system/user-.slice.d/15-limits.conf
.在 systemd v238 及更早版本中,用户默认设置是通过用户任务最大=在
/etc/systemd/logind.conf
。更改该值通常需要重新启动。
有关此的更多信息:
答案2
无论如何,这不会再使现代 Linux 系统崩溃。
它会创建大量进程,但当进程空闲时并不会真正消耗那么多 CPU。现在,在用完 RAM 之前,您已经用完了进程表中的插槽。
如果您没有像 Hkoof 指出的那样限制 cgroup,则以下更改仍然会导致系统崩溃:
:(){ : | :& : | :& }; :
答案3
早在 90 年代,我就无意中向自己释放了其中一个。我无意中在包含 fork() 命令的 C 源文件上设置了执行位。当我双击它时,csh 尝试运行它,而不是像我想要的那样在编辑器中打开它。
即使如此,它也没有使系统崩溃。 Unix 足够强大,您的帐户和/或操作系统将有进程限制。相反,它会变得非常缓慢,任何需要启动进程的事情都可能会失败。
幕后发生的事情是进程表填满了试图创建新进程的进程。如果其中一个进程终止(由于进程表已满而导致分叉错误,或者由于绝望的操作员试图恢复系统的正常状态),其他进程之一将愉快地分叉一个新进程来填充虚空。
“叉子炸弹”基本上是一个无意的进程自我修复系统,其任务是保持进程表满。阻止它的唯一方法就是以某种方式一次性杀死他们。