October 22, 2024
Chicago 12, Melborne City, USA
C#

Failed to mount /proc after clone with CLONE_NEWUSER


I’m trying to mount /proc and /dev after pivot_root, but it’s failed if the child process is create with CLONE_NEWUSER. Refer to the following section for the code.

After removed CLONE_NEWUSER when clone, everthing works.

#define _GNU_SOURCE
#include <err.h>
#include <limits.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>

static int
pivot_root(const char *new_root, const char *put_old)
{
    return syscall(SYS_pivot_root, new_root, put_old);
}

#define STACK_SIZE (1024 * 1024)

static int              /* Startup function for cloned child */
child(void *arg)
{
    char        **args = arg;
    char        *new_root = args[0];

    /* Ensure that 'new_root' and its parent mount don't have
       shared propagation (which would cause pivot_root() to
       return an error), and prevent propagation of mount
       events to the initial mount namespace. */

    if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) == -1)
        err(EXIT_FAILURE, "mount-MS_PRIVATE");

    /* Ensure that 'new_root' is a mount point. */

    if (mount(new_root, new_root, NULL, MS_BIND, NULL) == -1)
        err(EXIT_FAILURE, "mount-MS_BIND");


    /* And pivot the root filesystem. */

    if (pivot_root(new_root, new_root) == -1)
        err(EXIT_FAILURE, "pivot_root");

    /* Switch the current working directory to "/". */

    if (chdir("/") == -1)
        err(EXIT_FAILURE, "chdir");

    /* Unmount old root and remove mount point. */
    if (mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL) == -1)
        err(EXIT_FAILURE, "mount-MS_PRIVATE");

    if (umount2("/", MNT_DETACH) == -1)
        perror("umount2");

    
    if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NODEV | MS_NOEXEC, NULL) == -1)
        err(EXIT_FAILURE, "mount-proc");

    if (mount("tmpfs", "/dev", "tmpfs", MS_STRICTATIME | MS_NOSUID, NULL) == -1)
        err(EXIT_FAILURE, "mount-proc");


    /* Execute the command specified in argv[1]... */

    execv(args[1], &args[1]);
    err(EXIT_FAILURE, "execv");
}

int
main(int argc, char *argv[])
{
    char *stack;

    /* Create a child process in a new mount namespace. */
    stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
                 MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
    if (stack == MAP_FAILED)
        err(EXIT_FAILURE, "mmap");

    if (clone(child, stack + STACK_SIZE,
              CLONE_NEWNS | 
                          CLONE_NEWPID |
                          CLONE_NEWNET | 
                          CLONE_NEWUSER | 
                          SIGCHLD, &argv[1]) == -1)
        err(EXIT_FAILURE, "clone");

    /* Parent falls through to here; wait for child. */

    if (wait(NULL) == -1)
        err(EXIT_FAILURE, "wait");

    exit(EXIT_SUCCESS);
}

Here’s the example without CLONE_NEWUSER:

sudo ./pivot_root_demo /opt/chariot/containers/busybox/rootfs /bin/ls /proc
1                  consoles           dynamic_debug      ioports            kpagecgroup        meminfo            pagetypeinfo       softirqs           timer_list         zoneinfo
acpi               cpuinfo            execdomains        irq                kpagecount         misc               partitions         stat               tty
bootconfig         crypto             fb                 kallsyms           kpageflags         modules            pressure           swaps              uptime
buddyinfo          devices            filesystems        kcore              latency_stats      mounts             schedstat          sys                version
bus                diskstats          fs                 key-users          loadavg            mtd                scsi               sysrq-trigger      version_signature
cgroups            dma                interrupts         keys               locks              mtrr               self               sysvipc            vmallocinfo
cmdline            driver             iomem              kmsg               mdstat             net                slabinfo           thread-self        vmstat

But when I add CLONE_NEWUSER when during clone, I’ll get the following error:

sudo ./pivot_root_demo /opt/chariot/containers/busybox/rootfs /bin/ls /proc
pivot_root_demo: mount-proc: Operation not permitted



You need to sign in to view this answers

Leave feedback about this

  • Quality
  • Price
  • Service

PROS

+
Add Field

CONS

+
Add Field
Choose Image
Choose Video