Mounting a file system image inside an unshared namespace

loop-devicemountnamespaceunshare

I'm using unshare to perform things like bind mounts local to a certain process without requiring root access, e.g.:

unshare -mr bash mount --bind a b

(Yes, this seems kinda dumb; in my actual use case; unshare is running a bash script that performs the bind mount. I didn't do that here so that it's a smaller example.)

However, if I try a loop mount, it fails:

ryan@DevPC-LX ~/stuff/util-linux master $ unshare -mr mount -o loop x.img a
mount: no permission to look at /dev/loop<N>

:/

I've tried using mknod to create a fake loop device (requires privileges not available to non-root), manually running losetup (still requires root privileges), and a bunch of other stuff that doesn't work.

Of course, I could just do chown myuser /dev/loop*, but that seems like it could become a major security issue.

In addition, guestmount is too slow for my use case, and fuseext2 has a warning about possible data loss in write mode (and it's also too slow).

Is there any way to do…this? At all?

Best Answer

In order to run unshare, you have to have root capabilities to create a separate mount space.

I tried this that seems to do what you want (I think):

Ishtar:> mkdir -p /tmp/unshare/home
Ishtar:> cd /tmp/unshare
Ishtar:/tmp/unshare> sudo unshare -m /bin/bash
Ishtar:/tmp/unshare# mount --rbind /home/packages /tmp/unshare/home
Ishtar:/tmp/unshare# tty
/dev/pts/4
Ishtar:/tmp/unshare# # ls home
BUILD@      RPMS@     build/           linux@    sources/           tmp/
BUILDROOT@  SOURCES@  buildroot/       logs/     specs/
OSbuild/    SPECS@    config-scripts/  perlsrc/  srpms/
OTHER/      SRPMS@    debug@           rpms/     sysvinit-288.spec

So the above process has '/home/packages mounted @ /tmp/unshare/home.

In another tty-window, with any user, I can try to see: what is in /tmp/unshare/home:

Ishtar:/> tty
/dev/pts/5
Ishtar:/> ll /tmp/unshare/home
total 0
Ishtar:/> cd tmp/unshare
Ishtar:/tmp/unshare> sudo
Ishtar:/tmp/unshare# ls home
Ishtar:/tmp/unshare# ll home
total 0
# create file in original "bound" dir from 1st usr above:
Ishtar:/tmp/unshare# touch /home/packages/PACKAGES.DIR 
Ishtar:/tmp/unshare# ll home  #home still empty
total 0
Ishtar:/> tty
/dev/pts/5
# now on other user again
Ishtar:/tmp/unshare# tty
/dev/pts/4
Ishtar:/tmp/unshare# ls home
BUILD@        RPMS@     buildroot/       perlsrc/  sysvinit-288.spec
BUILDROOT@    SOURCES@  config-scripts/  rpms/     tmp/
OSbuild/      SPECS@    debug@           sources/
OTHER/        SRPMS@    linux@           specs/
PACKAGES.DIR  build/    logs/            srpms/
#^^^ see PACKAGES.DIR appear (as created in original dir by another
# user

Once you have your "private dir mounted for user in "pts/4" you can change to the UID you want to run under for the program:

Ishtar:/tmp/unshare# su astara
Ishtar:/tmp/unshare> whoami
astara
Ishtar:/tmp/unshare> ls home/PACK*
home/PACKAGES.DIR

Note mount is still there for the unpriv'd user.

To be save, I'd put the 'su to other user' in a script file followed by a 'unmount /tmp/unshare/home', (since when su OTHERUSER exits, it will become root again, and unmount the file in the private space,). Then you can exit.

Does this come close to what you want? -- You have to use 'root' to setup your child env, but then run the child -- and only it has access to the mount created in the new mount namespace.

(update) BTW -- just noticed unshare has a --map-root-user that to specifically allow using either root or caps to setup options in the new namespace. The manpage says (about this switch):

....This makes it possible to  conveniently
gain  capabilities needed to manage various aspects of the newly
created namespaces (such as configuring interfaces in  the  net-
work  namespace  or mounting filesystems in the mount namespace)
even when run unprivileged.

This could allow you to manage your loop dev w/o being root (or so says the manpage). Likely CAP_SYS_ADMIN is the cap needed for doing this.

Related Question