Skip to content

Commit df7342b

Browse files
committed
mount: Don't allow copying MNT_UNBINDABLE|MNT_LOCKED mounts
Jonathan Calmels from NVIDIA reported that he's able to bypass the mount visibility security check in place in the Linux kernel by using a combination of the unbindable property along with the private mount propagation option to allow a unprivileged user to see a path which was purposefully hidden by the root user. Reproducer: # Hide a path to all users using a tmpfs root@castiana:~# mount -t tmpfs tmpfs /sys/devices/ root@castiana:~# # As an unprivileged user, unshare user namespace and mount namespace stgraber@castiana:~$ unshare -U -m -r # Confirm the path is still not accessible root@castiana:~# ls /sys/devices/ # Make /sys recursively unbindable and private root@castiana:~# mount --make-runbindable /sys root@castiana:~# mount --make-private /sys # Recursively bind-mount the rest of /sys over to /mnnt root@castiana:~# mount --rbind /sys/ /mnt # Access our hidden /sys/device as an unprivileged user root@castiana:~# ls /mnt/devices/ breakpoint cpu cstate_core cstate_pkg i915 intel_pt isa kprobe LNXSYSTM:00 msr pci0000:00 platform pnp0 power software system tracepoint uncore_arb uncore_cbox_0 uncore_cbox_1 uprobe virtual Solve this by teaching copy_tree to fail if a mount turns out to be both unbindable and locked. Cc: stable@vger.kernel.org Fixes: 5ff9d8a ("vfs: Lock in place mounts from more privileged users") Reported-by: Jonathan Calmels <jcalmels@nvidia.com> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
1 parent 25d202e commit df7342b

File tree

1 file changed

+8
-2
lines changed

1 file changed

+8
-2
lines changed

fs/namespace.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,8 +1734,14 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
17341734
for (s = r; s; s = next_mnt(s, r)) {
17351735
if (!(flag & CL_COPY_UNBINDABLE) &&
17361736
IS_MNT_UNBINDABLE(s)) {
1737-
s = skip_mnt_tree(s);
1738-
continue;
1737+
if (s->mnt.mnt_flags & MNT_LOCKED) {
1738+
/* Both unbindable and locked. */
1739+
q = ERR_PTR(-EPERM);
1740+
goto out;
1741+
} else {
1742+
s = skip_mnt_tree(s);
1743+
continue;
1744+
}
17391745
}
17401746
if (!(flag & CL_COPY_MNT_NS_FILE) &&
17411747
is_mnt_ns_file(s->mnt.mnt_root)) {

0 commit comments

Comments
 (0)