Skip to contentSkip to conversation

unshare -m and mount propagation

DISCUSSION Yuriy M. Kaminskiy 2 participants 7 messages Mar 18, 2016 – Apr 18, 2016 Util-Linux package

lore
Share & tools
lore
#0 lore raw

1. User-ns, mount-ns and mount propagation.

When you create mount-ns in user-ns (or both at once), kernel automatically breaks mount propagation from guest to host (in other words, forcibly downgrade "shared" mounts to "slave"), due to obvious security consideration (if your mount in user-ns guest will propagate back to host, it will be disaster).

E.g. try
unshare -r -m --prop unchanged findmnt -no TARGET,PROPAGATION|head -1
or
unshare -r unshare --prop unchanged findmnt -no TARGET,PROPAGATION|head -1
(both will show "/ private,slave", even though unshare(1) have not tried to change propagation flags).

Note that once propagation is broken, you cannot go back. E.g.
unshare -r -m --propagation shared -- findmnt -no TARGET,PROPAGATION|head -1
or (basically same)
unshare -r -m --propagation unchanged sh -c 'mount --make-rshared /;
findmnt -no TARGET,PROPAGATION|head -1'
will results in "/ shared,slave"; that is, propagation from guest to host is disabled, but propagation within guest is enabled.

2. Long-lived mount-ns and dangers of --propagation private (default in recent util-linux).

--propagation private breaks unmount propagation from "host" to "guest", so if you mount e.g. removable media in host, unshare mount namespace and spawn long-lived process, then umount your media in host namespace, it still remains mounted in guest namespace, and keep device busy:

  mount /media/cdrom
  unshare -rm --prop private sleep inf &
  pid=$!
  eject /media/cdrom # oops, still locked
  grep /media/cdrom /proc/self/mounts
  (empty)
  sudo nsenter -t $pid -m grep /media/cdrom /proc/self/mounts
  # ... as it is still mounted there

If device locks mounted media (e.g. cdrom), this can be confusing to user ("why eject does not work? I umounted it, fuser/lsof shows nothing???").

If device does not lock mounted media, and user forcibly ejects media (e.g. cardreader or usb drive), this can result in data loss (filesystem is not properly umounted, there can be unsynced data in cache).

--propagation slave does not have this problem (when host unmount /cdrom, it is also unmounted in guest):

mount /media/cdrom
unshare -rm --prop slave sleep inf &
pid=$!
umount /media/cdrom # or eject /media/cdrom
sudo nsenter -t $pid -m grep /media/cdrom /proc/self/mounts
(empty)

Also, once you (completely) broke propagation by --propagation private [as implied by default in current util-linux], you cannot go back. E.g.

  unshare -rm sh -c 'findmnt -no TARGET,PROPAGATION|head -1;
  mount --make-rslave /;
  findmnt -no TARGET,PROPAGATION|head -1'

/ private
/ private

I think this issue should be at least documented. And, maybe, default --propagation should be changed to slave.

=====================================================================

P.S. I'd like to note that this thing has some abuse potential. Above scenarios suggest *accidental* case when `unshare -rm --prop private \
sleep inf &` can trigger data loss. But someone can *intentionally* try to choose moment when it triggers most disruption to other users (and root) work. This also affects fs/devices they cannot access (and thus cannot normally block by chdir or opening file; besides, chdir or open file is visible in lsof/fuser, stray sleep-in-namespace is not).

(Of course, this possible abuse is *not* a util-linux problem [and cannot be solved within util-linux]; this is a *kernel* problem)

P.P.S. as I dig into user-ns, I'm more and more happy our debian overlords disabled unprivileged userns by default. And lately I feel they should've disabled it completely :-| It's a way too prone to abuse.

maintainer
#1 lore raw
Quoted 2 lines · Yuriy M. Kaminskiy

I think this issue should be at least documented. And, maybe, default --propagation should be changed to slave.

The reason why we use 'private' is that it's the kernel default for years and it's what has been expected by users for long time before we introduced --propagation and any unshare(1) default.

The current --propagation default unifies things and makes unshare(1) portable to distributions where root fs is mounted as 'shared' (e.g. systemd distros) and all this in backwardly compatible way for users who have no clue about --propagation.

So, I don't think we want to change any default to corrupt scripts where is no explicitly specified --propagation.

Karel

Signature · 2 lines
 Karel Zak  <[email protected]>
 http://karelzak.blogspot.com
#2 lore raw
Quoted 8 lines · Karel Zak
Quoted 2 lines · Yuriy M. Kaminskiy

I think this issue should be at least documented. And, maybe, default --propagation should be changed to slave.

The reason why we use 'private' is that it's the kernel default for years and it's what has been expected by users for long time before we introduced --propagation and any unshare(1) default.

Quoted 7 lines

The current --propagation default unifies things and makes unshare(1) portable to distributions where root fs is mounted as 'shared' (e.g. systemd distros) and all this in backwardly compatible way for users who have no clue about --propagation.

So, I don't think we want to change any default to corrupt scripts where is no explicitly specified --propagation.

By you already broke scripts that expected old a-la '--propagation unchanged' behavior.
E.g. one my script did
unshare -m sh -c 'mount --make-rslave /; ...'
Now I must check for util-linux version and either use --propagation option, or mount --make-rslave (you cannot revert back from private to slave).
(And as I said, 'private' breaks umount propagation and thus very bad for long-running namespaces).

maintainer
#3 lore raw
Quoted 15 lines · Yuriy M. Kaminskiy
Quoted 13 lines · Karel Zak
Quoted 2 lines · Yuriy M. Kaminskiy

I think this issue should be at least documented. And, maybe, default --propagation should be changed to slave.

The reason why we use 'private' is that it's the kernel default for years and it's what has been expected by users for long time before we introduced --propagation and any unshare(1) default.

The current --propagation default unifies things and makes unshare(1) portable to distributions where root fs is mounted as 'shared' (e.g. systemd distros) and all this in backwardly compatible way for users who have no clue about --propagation.

Quoted 5 lines
Quoted 2 lines

So, I don't think we want to change any default to corrupt scripts where is no explicitly specified --propagation.

By you already broke scripts that expected old a-la '--propagation unchanged' behavior.

Only if your system uses something else that kernel default 'private' and you depend on this non-default setting. (IMHO relatively small groups of users)

The old "--propagation unchanged" makes unshare useless on some mainstream distros where default is 'shared'.

Anyway, we will not change any default now.

Karel

Signature · 2 lines
 Karel Zak  <[email protected]>
 http://karelzak.blogspot.com
#4 lore raw
Quoted 7 lines · Karel Zak
Quoted 6 lines · Yuriy M. Kaminskiy
Quoted 4 lines · Karel Zak
Quoted 2 lines · Yuriy M. Kaminskiy

I think this issue should be at least documented. And, maybe, default --propagation should be changed to slave.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

The reason why we use 'private' is that it's the kernel default for years and it's what has been expected by users for long time before we introduced --propagation and any unshare(1) default.

The current --propagation default unifies things and makes unshare(1) portable to distributions where root fs is mounted as 'shared' (e.g. systemd distros) and all this in backwardly compatible way for users

Opposite. It does not change anything for older systems, but breaks things for new systems.

Quoted 1 line
Quoted 1 line
Quoted 1 line

who have no clue about --propagation.

And it is *especially* harmful for users that are not aware about --propagation. As private (new 2.27+ default) break umount propagation, and results in nasty surprises (up to data loss).

Quoted 9 lines
Quoted 5 lines
Quoted 2 lines

So, I don't think we want to change any default to corrupt scripts where is no explicitly specified --propagation.

By you already broke scripts that expected old a-la '--propagation unchanged' behavior.

Only if your system uses something else that kernel default 'private' and you depend on this non-default setting. (IMHO relatively small groups of users)

All systemd systems use shared. Which is not "small group of users".

Quoted 2 lines

The old "--propagation unchanged" makes unshare useless on some mainstream distros where default is 'shared'.

No, it is not. --propagation does not do *anything* that cannot be done without it. On pre-2.27 util-linux,

  unshare -m sh -c 'mount --make-rprivate /; ...'

does exactly same as unshare -m [--propagation=private] ... in 2.27+.

Reverse is not true! With 2.27 you *must* use new [backward-incompatible] options to revert to sane behavior [which is *slave*, not *private*].

Quoted 1 line

Anyway, we will not change any default now.

maintainer
#5 lore raw
Quoted 16 lines · Yuriy M. Kaminskiy
Quoted 7 lines · Karel Zak
Quoted 6 lines · Yuriy M. Kaminskiy
Quoted 4 lines · Karel Zak
Quoted 2 lines · Yuriy M. Kaminskiy

I think this issue should be at least documented. And, maybe, default --propagation should be changed to slave.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

The reason why we use 'private' is that it's the kernel default for years and it's what has been expected by users for long time before we introduced --propagation and any unshare(1) default.

The current --propagation default unifies things and makes unshare(1) portable to distributions where root fs is mounted as 'shared' (e.g. systemd distros) and all this in backwardly compatible way for users

Quoted 8 lines

Opposite. It does not change anything for older systems, but breaks things for new systems.

Quoted 1 line
Quoted 1 line
Quoted 1 line

who have no clue about --propagation.

And it is *especially* harmful for users that are not aware about --propagation. As private (new 2.27+ default) break umount propagation, and results in nasty surprises (up to data loss).

Well, you see only umount propagation...

The problem is that the original implementation (try emulate by "--propagation unchanged") makes "unshare --mount" useless at all on systems with shared root fs.

The very old (since year 2009) and very common use-case is:

 # unshare --mount
 # mount /dev/foo /mnt

and user expects that /mnt will be visible *only* in the session (namespace). This is the way how many users use unshare for years.

Unfortunately, after systemd installation it does not work anymore and /mnt is visible everywhere. For users it's regression and it has been reported many many times.

You can blame systemd, but the problem is that unshare(1) was not robust enough. So we have forced unshare to use "private" by default to keep the *original behavior* independently on root fs propagation flag.

Karel

Signature · 2 lines
 Karel Zak  <[email protected]>
 http://karelzak.blogspot.com
#6 lore raw
Quoted 20 lines · Karel Zak
Quoted 19 lines · Yuriy M. Kaminskiy
Quoted 7 lines · Karel Zak
Quoted 6 lines · Yuriy M. Kaminskiy
Quoted 4 lines · Karel Zak
Quoted 2 lines · Yuriy M. Kaminskiy

I think this issue should be at least documented. And, maybe, default --propagation should be changed to slave.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

The reason why we use 'private' is that it's the kernel default for years and it's what has been expected by users for long time before we introduced --propagation and any unshare(1) default.

The current --propagation default unifies things and makes unshare(1) portable to distributions where root fs is mounted as 'shared' (e.g. systemd distros) and all this in backwardly compatible way for users

Opposite. It does not change anything for older systems, but breaks things for new systems.

Quoted 7 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line

who have no clue about --propagation.

And it is *especially* harmful for users that are not aware about --propagation. As private (new 2.27+ default) break umount propagation, and results in nasty surprises (up to data loss).

Well, you see only umount propagation...

Because *breaking* it causes real problems?

Quoted 7 lines

The problem is that the original implementation (try emulate by "--propagation unchanged") makes "unshare --mount" useless at all on systems with shared root fs.

The very old (since year 2009) and very common use-case is:

  # unshare --mount
     mount --make-rslave / # or --make-rprivate or whatever
Quoted 1 line
  # mount /dev/foo /mnt

And? I've posted how this could be solved *without* changing anything in unshare.

Quoted 11 lines

and user expects that /mnt will be visible *only* in the session (namespace). This is the way how many users use unshare for years.

Unfortunately, after systemd installation it does not work anymore and /mnt is visible everywhere. For users it's regression and it has been reported many many times.

You can blame systemd, but the problem is that unshare(1) was not robust enough. So we have forced unshare to use "private" by default to keep the *original behavior* independently on root fs propagation flag.

You can have same effect with *slave* as default, with exception that host->guest mount/unmount propagation still works.
When kernel have to get rid of shared propagation (in userns), it downgrades shared mounts to *slave*, not to *private*.
When systemd itself downgrades shared propagation (for running service in new mount namespace; Protect*/Private*/etc), it also downgrades *shared* propagation to *slave*, not to *private*.

P.S. For sure, *any* of propagation variants have some or other drawbacks and corner cases; however, without special care about removable media (and alike), *private* has higher chance to beat you in a nasty way.