我有一个 cpp 进程,它分叉并创建另一个子进程。该子进程可以启动其他子进程。我想在父进程死亡或崩溃时终止整个子进程树。有没有办法通过使用 prctl 或其他东西来实现这一点?
我想过使用 prctl(PR_SET_PDEATHSIG, SIGKILL)
但它似乎只能杀死直接子进程,而不能杀死完整的进程树。还有一点 - 当我使用
setpgid(0, 0)
进行 fork 时,我会将子进程的 pgrp 重置为其自己的 PID。这样做是为了让父级可以使用
kill(-pid, SIGKILL)
终止进程树。但是我的武器库中缺少崩溃的家长案例。
一种可能的技术是父母使用
ptrace
追踪孩子并使用
PTRACE_O_EXITKILL
指定标志
PTRACE_SETOPTIONS
。如果跟踪器因任何原因终止,此标志告诉内核杀死被跟踪者。为了确保被跟踪者的任何后代也将被杀死,我认为您还必须指定
PTRACE_O_TRACECLONE
、
PTRACE_O_TRACEEXEC
、
PTRACE_O_TRACEFORK
和
PTRACE_O_TRACEVFORK
,以便任何子进程也将自动被跟踪同一个示踪剂。但是,我假设当进程
PTRACE_O_TRACEEXEC
是 setuid 或 setgid 可执行文件或从
exec
调用获取任何功能时,
exec
将被忽略,因此该技术不能完全保证没有后代进程可以“逃逸”。使用
PID 命名空间似乎可以提供更强大的解决方案;请参阅此处对此功能的介绍以及文档此处。简而言之,如果您使用 CLONE_NEWPID
创建一个新的子进程,该子进程将成为全新 PID 命名空间的初始进程。该初始进程创建的任何进程都属于新的命名空间,并且当初始进程终止(出于任何原因)时,内核会杀死命名空间中的所有其他进程。请注意,为了使用
CAP_SYS_ADMIN
标志,需要
CLONE_NEWPID
功能。这意味着您可能需要创建一个带有
CAP_SYS_ADMIN
文件系统功能位集的专用二进制文件,其唯一目的是创建新 PID 命名空间的初始进程,然后退出;同时,如果不再需要,子进程应该立即放弃此功能。