Jeremy Hua
Jeremy Hua

Reputation: 41

Why I couldn't use mount --bind /proc/<pid>/ns/mnt to another file in ubuntu?

Recently, I am learning about linux namespaces. I hope even if the process ends, I could still attach the namespace that process is in. Someone told I could use mount --bind /proc/<pid>/ns/pid ./pid to keep this file open. So I tried it. When I mount uts, user, ipc, pid, net... They are all okay..

root@ubuntu:/home/jiashenh/workspace# touch uts
root@ubuntu:/home/jiashenh/workspace# mount --bind /proc/171/ns/uts ./uts

But when it comes to mnt.... I used it in the same way ...

root@ubuntu:/home/jiashenh/workspace# touch mnt    
root@ubuntu:/home/jiashenh/workspace# mount --bind /proc/171/ns/mnt ./mnt
mount: wrong fs type, bad option, bad superblock on /proc/171/ns/mnt,
       missing codepage or helper program, or other error

       In some cases useful info is found in syslog - try
       dmesg | tail or so

It failed.....So could anyone told me how to fix it? .

Upvotes: 3

Views: 2986

Answers (1)

gavv
gavv

Reputation: 4883

Bind mount for /proc/<pid>/ns/mnt really doesn't work if called within the same mount namespace.

However, bind mount for ns/mnt works if:

  • mount() is called from a process with another mount namespace, and
  • mount() is called from a process where the ns/mnt being mounted is visible.

Both requirements are met if mount() is called from a process forked before unshare() call that created ns/mnt entry being mounted.

(Note that after unshare() call, previously visible ns/mnt entries are no more visible and become broken symlinks).

Here is a test:

#define _GNU_SOURCE
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/mount.h>

int main(int argc, char** argv) {
    int fd = open("/tmp/mnt.ns", O_CREAT | O_RDWR);
    close(fd);
    if (argc > 1) {
        if (fork() == 0) {
            sleep(1);
        } else {
            unshare(CLONE_NEWNS);
            wait(NULL);
            return 0;
        }
    }
    char src[PATH_MAX] = {};
    snprintf(src, sizeof(src), "/proc/%u/ns/mnt", (unsigned)getppid());
    if (mount(src, "/tmp/mnt.ns", NULL, MS_BIND, NULL) != 0) {
        printf("mount failed: %s\n", strerror(errno));
        return 1;
    }
    else {
        printf("mount ok\n");
    }
    return 0;
}

This test fails without fork() and unshare():

$ sudo ./a.out  
mount failed: Invalid argument

But works if it calls fork() and unshare() before mount() (note the x arg):

$ sudo ./a.out x
mount ok

See this commit for unshare tool and also this patch.

Unfortunately, this behaviour specific to ns/mnt is not documented in namespaces(7).

Upvotes: 3

Related Questions