0

I ran

unshare -mfp sh -c 'mount -tproc none /proc ; ls /proc'

As expected, that printed a /proc with only directories for PID 1 and PID 3, and exited, leaving me back in my old prompt in the root namespace.

Then I did

ls /proc

and I got back a listing without any PID directories. I was expecting my usual /proc full of processes. I had to mount proc again to fix things.

Why is this happening? How do I fix things so the /proc I mounted inside the PID namespace stays local to it?

I tried passing --mount-private to mount, but it didn't seem to have any effect.

I'm on Amazon Linux 2016.03 which comes with util-linux 2.23.2.

  • I was intrigued by your problem and I have spent some time investigating the same effect on Ubuntu. I found that the command gave write failed /proc/self/gid_map: Operation not permitted unless I gave root privileges; when I did this it behaved as you describe, and all users lost PID and mount access: only rebooting allowed me to recover. My reading of the manual concurs with yours, so I conclude that either we are both misunderstanding, or the implementation is completely wrong. In either case, I can't see a way to a solution, other than to try some of the coding examples. – AFH May 3 '16 at 12:42
  • I found this article and this series helpful. – AFH May 3 '16 at 12:44
0

Either unshare(1) is broken or I am stupid.

I modified the code in http://crosbymichael.com/creating-containers-part-1.html so it would actually work for me. Had to umount /proc lazily with umount2, and include linux/sched.h instead of sched.h.

To compile do gcc foo.c -ofoo.

You will note that after running, e.g ./foo ls /proc, /proc on the host system won't be wiped out.

//
// This compiles and works on Amazon Linux 2016.03 (kernel 4.4.5-15.26.amzn1.x86_64)
//

#include <stdio.h>
#include <stdlib.h>
// was <sched.h>, but wouldn't compile on Amazon Linux
#include <linux/sched.h>
// for umount2()
#include <sys/mount.h>
#include <sys/wait.h>
#include <errno.h>

#define STACKSIZE (1024*1024)
static char child_stack[STACKSIZE];

struct clone_args {
        char **argv;
};

static int child_exec(void *stuff) {
        struct clone_args *args = (struct clone_args *)stuff;

        // the fprintf()s crash. Not sure why.

        // changed from umount(), lazy umount succeeds
        if (umount2("/proc", MNT_DETACH) != 0) {
                fprintf(stderr, "failed to unmount /proc: %s\n", strerror(errno));
                exit(-1);
        }

        if (mount("proc", "/proc", "proc", 0, "") != 0) {
                fprintf(stderr, "failed to mount /proc: %s\n", strerror(errno));
                exit(-1);
        }

        if (execvp(args->argv[0], args->argv) != 0) {
                fprintf(stderr, "failed to execvp arguments: %s\n", strerror(errno));
                exit(-1);
        }

        // unreachable
        exit(EXIT_FAILURE);
}

int main(int argc, char **argv) {
        struct clone_args args;
        args.argv = &argv[1];

        int clone_flags = CLONE_NEWPID | CLONE_NEWNS | SIGCHLD;
        pid_t pid = clone(child_exec, child_stack + STACKSIZE, clone_flags, &args);

        if (pid < 0) {
                fprintf(stderr, "clone failed: %s\n", strerror(errno));
                exit(EXIT_FAILURE);
        }

        if (waitpid(pid, NULL, 0) == -1) {
                fprintf(stderr, "failed to wait pid %d\n", pid);
                exit(EXIT_FAILURE);
        }

        exit(EXIT_SUCCESS);
}

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.