This sequence of commands works:
unshare --fork --pid --mount umount /proc mount -t proc proc /proc umount /dev/pts mount -t devpts devpts /dev/pts
However, the corresponding C program does not work as expected (it seems it does not unmount the previous /proc, and also it provides EBUSY trying to unmount the devpts):
unshare(CLONE_NEWPID | CLONE_NEWNS ); int pid = fork(); if (pid != 0) { int status; waitpid(-1, &status, 0); return status; } printf("My pid: %in", getpid()); // It prints 1 as expected umount("/proc"); // Returns 0 system("mount"); // Should print error on mtab, but it prints the previous mounted filesystems mount("proc", "/proc", "proc", MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL)); // Returns 0 umount("/dev/pts"); // Returns -1 errno = 0 (??) mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL) ); // Returns -1 errno = EBUSY
I omitted here error checking for readability
I think that unshare or unmount does not work as expect: even if it returns zero, it seems that does not unmount /proc (if I try to exec a system("mount")
after that, it prints the mounted filesystems).
Advertisement
Answer
I found the problem checking the source code of unshare command. The /proc
must be unmounted with MS_PRIVATE | MS_REC
and mounted without them, this is essentially to ensure that the the mount has effect only in the current (the new) namespace. The second problem is it is not possible to umount /dev/pts
without producing an effect on global namespace (this is caused by the internal routine of devpts driver). To have a private /dev/pts the only way is to mount it with the dedicated -o newinstance
option. Finally /dev/ptmx
should also be bind-remounted.
Therefore, this is the C working code as expected:
unshare(CLONE_NEWPID | CLONE_NEWNS ); int pid = fork(); if (pid != 0) { int status; waitpid(-1, &status, 0); return status; } printf("New PID after unshare is %i", getpid()); if (mount("none", "/proc", NULL, MS_PRIVATE|MS_REC, NULL)) { printf("Cannot umount proc! errno=%i", errno); exit(1); } if (mount("proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL)) { printf("Cannot mount proc! errno=%i", errno); exit(1); } if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL | MS_NOSUID | MS_NOEXEC, "newinstance") ) { printf("Cannot mount pts! errno=%i", errno); exit(1); } if (mount("/dev/pts/ptmx", "/dev/ptmx", NULL, MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_BIND, NULL) ) { printf("Cannot mount ptmx! errno=%i", errno); exit(1); }