linuxmountumount

unshare system call doesn't work


The following simple C++ program attempts to unshare the mount space, mount a USB storage device (located on /dev/sdd), waits for input, and then umounts that device.

#include <iostream>
#include <stdio.h>
#include <exception>
#include <algorithm>
#include <vector>
#include <limits> 
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
    unshare(CLONE_NEWNS);

    pid_t pid = fork();

    if (0 == pid)
    {
        char * mount_args[] = {"/bin/mount", "--make-rprivate", "/dev/sdd", "/mnt", "-o,ro", "-o,noexec", NULL};

        if (0 > execv("/bin/mount", mount_args))
        {
            perror("execv: ");
            exit(1);
        }
        //this line will never be reached.
        return 0;
    }
    else if (0 < pid)
    {
        //parent process!
        int status = -1;
        wait(&status);

        if (0 == status)
        {
            std::cout << "press ENTER to continue....";
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

            char * umount_args[] = {"/bin/umount", "/mnt", NULL};
            if (0 > execv("/bin/umount", umount_args))
            {
                perror("execv: ");
                exit(1);
            }
        }
        return status;
    }
    else
    {
        //fork error!
        perror("fork!\n");
        exit(1);
    }
    return 0;
}

However, when I run it (after compiling with -fpermissive) the mount is visible from every other process on the system.

My goal , of my mounts being invisible to other user-space processes, is clearly not achieved.

What am I doing wrong?

Edit: this code doesn't work on Ubuntu 16.04 (kernel version 4.4). It does work on Ubuntu 14.04 (kernel version 4.2) - might this have something to do with it?


Solution

  • Turns out the OS default mount option has changed in Ubuntu 16. In order to make unshare(2) work, you need to add the following line to your code (prior to the unshare):

    mount("none", "/", NULL, MS_PRIVATE | MS_REC, NULL);