When I call the Linux system function unshare(CLONE_NEWNS), it returns 0 indicating success. But, it doesn't seem to work as I was expecting. Specifically when I then add a new mount such as a tmpfs one, it is globally visible. Therefore it is in fact not a private mount namespace as expected.
Here is an example program that demonstrates the issue. Compile this up and run it in one terminal. Then open another terminal and check if the path written by the example program is visible. It shouldn't be but is. It is behaving as though the unshare call did nothing. What I was expecting was that from that moment on, any subsequent mounts performed by this program will not be visible to other processes.
/* Run this program as root. As mount and unshare requires higher privileges. */
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <stdlib.h>
#include <stdio.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
int main(int argc, char *argv[])
{
// Create a temporary directory at /tmp/unshare
mkdir("/tmp/unshare", S_IRWXG);
if (unshare(CLONE_NEWNS) == -1)
errExit("unshare");
if (mount("none", "/tmp/unshare", "tmpfs", 0, "mode=0700") == -1)
errExit("unshare");
FILE* fp = fopen("/tmp/unshare/test", "w");
fprintf(fp, "This file should not be seen by other processes right?\n");
fclose(fp);
// Pause
printf("Now open another shell. As the root user, verify the file /tmp/unshare/test is not seen\n.Press enter end finish\n");
char c = getchar();
if (umount("/tmp/unshare") == -1)
errExit("umount");
}
I should point out that the mount manpage suggests this should work. Specifically section labeled "Per-process namespaces".
i.e.
A process can obtain a private mount namespace if ...
it calls unshare(2) with the CLONE_NEWNS flag, which
causes the caller's mount namespace to obtain a private copy of the
namespace that it was previously sharing with other processes, so that
future mounts and unmounts by the caller are invisible to other pro‐
cesses (except child processes that the caller subsequently creates)
and vice versa.
If you use the unshare terminal command, it works. But that also forks another process. But the man page suggests there is no need to fork or clone when using the unshare system call. What am I doing wrong here?
After running strace I found the answer.
\> strace unmount -m true
...
unshare(CLONE_NEWNS) = 0
mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL) = 0
execve("/home/matt/.nvm/versions/node/v6.9.1/bin/true", ["true"], [/* 29 vars */]) = -1 ENOENT (No such file or directory)
...
Note the mount following the unshare. This mount call would appear to recursively mark all subsequent changes to mounts as private. And looking at this sandbox code: https://github.com/swetland/mkbox The author is doing just that also.
So here is the working version.
/* Run this program as root. As mount and unshare requires higher privileges. */
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <stdlib.h>
#include <stdio.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
int main(int argc, char *argv[])
{
// Create a temporary directory at /tmp/unshare
mkdir("/tmp/unshare", S_IRWXG);
if (unshare(CLONE_NEWNS | CLONE_FS | CLONE_THREAD) == -1)
errExit("unshare");
/* ensure that changes to our mount namespace do not "leak" to
* outside namespaces (what mount --make-rprivate / does)
*/
if (mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL) == -1)
errExit("mount1");
if (mount("none", "/tmp/unshare", "tmpfs", 0, NULL) == -1)
errExit("mount2");
// if (mount("none", "/tmp/unshare", NULL, MS_PRIVATE, NULL) == -1)
// errExit("mount2");
FILE* fp = fopen("/tmp/unshare/test", "w");
fprintf(fp, "This file should not be seen\n");
fclose(fp);
// Pause
printf("Now open another shell. As the root user, verify the file /tmp/unshare/test is not seen\n.Press enter end finish\n");
char c = getchar();
if (umount("/tmp/unshare") == -1)
errExit("umount");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With