Lucene search

HistoryFeb 27, 2009 - 12:00 a.m.

Linux Kernel克隆进程CLONE_PARENT本地拒绝服务漏洞


0.0004 Low




CVE(CAN) ID: CVE-2009-0028

Linux Kernel是开放源码操作系统Linux所使用的内核。

Linux Kernel的clone()系统调用允许调用程序在其子进程退出的时候说明所接收到的信号类型。如果结合CLONE_PARENT利用的话,就会导致新的子进程与调用程序共享相同的父进程,这就允许向调用程序的父进程发送任意信号。


Linux kernel 2.6.x



<a href=“” target=“_blank”></a>

                                                Programs affected: Linux kernel up to at least 2.6.28.
Fixed: Fix sent upsteam. See credits below.
Severity: Send signals to processes you shouldn't be able to.

There are various interesting ways signals can be sent using the Linux kernel API. There are certainly more options that just boring kill(SIG, pid)! Examples include:

    * Use of the fcntl() flags F_SETOWN and the lesser known F_SETSIG
    * Use of prctl(PR_SET_PDEATHSIG, ...)
    * Use of clone(..., SIG, ...)

It is this final example that features in this advisory. The clone() system call permits the caller to indicate what signal it receives when its child exits; the traditional SIGCHLD or perhaps something more exotic. Normally this would not be a problem but there's the nice trick of combining this with CLONE_PARENT. CLONE_PARENT causes the new child to share the same parent as the caller, thus enabling this arbitrary signal to be sent to the caller's parent.

There is limited mischief that can be caused using this. The most likely is a DoS by killing some daemon process. This can be achieved if said daemon process launches untrusted user processes as direct children. There will be a problem if the user processes are the result of an execve() after fork() and setuid(). Without the execve(), the process will be marked as not &quot;dumpable&quot;, so debug attach via ptrace() will not be permitted.

In some rare and bizarre cases, the ability to send a specific signal to a process at a specific time may be abused to make it misbehave. Certainly an area for further research.

Here is a sample piece of code which shows a root-owned process being killed by a non root-owned process.

#include &lt;sched.h&gt;
#include &lt;signal.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;

static int the_child(void* arg) {

int main(int argc, const char* argv[]) {
  int ret = fork();
  if (ret &lt; 0)
  else if (ret &gt; 0)
    for (;;);
    int status;
    char* stack = malloc(4096);
    int flags = SIGKILL | CLONE_PARENT;
    int child = clone(the_child, stack + 4096, flags, NULL);

Patch sent upstream (see credits below) was:

--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1184,7 +1184,9 @@ static struct task_struct *copy_process(
       p-&gt;parent_exec_id = p-&gt;self_exec_id;

       /* ok, now we should be set up.. */
-       p-&gt;exit_signal = (clone_flags &amp; CLONE_THREAD) ? -1 : (clone_flags &amp; CSIGNAL);
+       p-&gt;exit_signal = (clone_flags &amp; CLONE_THREAD) ? -1 :
+                        (clone_flags &amp; CLONE_PARENT) ? current-&gt;group_leader-&gt;exit_signal :
+                        (clone_flags &amp; CSIGNAL);
       p-&gt;pdeath_signal = 0;
       p-&gt;exit_state = 0;


    * Oleg Nesterov and Don Howard for working out a suitable fix and creating the above patch.
    * Eugene Teo for co-ordinating.

CESA-2009-002 - rev 1
Chris Evans
[email protected]