···1+From 22b91501d30a65d25ecf48ce5169ec70848117b8 Mon Sep 17 00:00:00 2001
2+From: Karel Zak <kzak@redhat.com>
3+Date: Wed, 9 Apr 2025 12:15:57 +0200
4+Subject: [PATCH] libmount: (subdir) restrict for real mounts only
5+6+It's now possible to use, for example, for bind operations, but it
7+does not make sense as you can specify the target with the
8+subdirectory.
9+10+Signed-off-by: Karel Zak <kzak@redhat.com>
11+(cherry picked from commit 437a271f7108f689d350f1b3d837490d3d283c3c)
12+---
13+ libmount/src/hook_subdir.c | 21 ++++++++++++++++-----
14+ sys-utils/mount.8.adoc | 6 ++++--
15+ 2 files changed, 20 insertions(+), 7 deletions(-)
16+17+diff --git a/libmount/src/hook_subdir.c b/libmount/src/hook_subdir.c
18+index 1e5d79958..7cbb2c88d 100644
19+--- a/libmount/src/hook_subdir.c
20++++ b/libmount/src/hook_subdir.c
21+@@ -313,6 +313,7 @@ static int is_subdir_required(struct libmnt_context *cxt, int *rc, char **subdir
22+ struct libmnt_optlist *ol;
23+ struct libmnt_opt *opt;
24+ const char *dir = NULL;
25++ unsigned long flags = 0;
26+27+ assert(cxt);
28+ assert(rc);
29+@@ -328,16 +329,26 @@ static int is_subdir_required(struct libmnt_context *cxt, int *rc, char **subdir
30+ return 0;
31+32+ dir = mnt_opt_get_value(opt);
33+-
34+ if (!dir || !*dir) {
35+ DBG(HOOK, ul_debug("failed to parse X-mount.subdir '%s'", dir));
36+ *rc = -MNT_ERR_MOUNTOPT;
37+- } else {
38+- *subdir = strdup(dir);
39+- if (!*subdir)
40+- *rc = -ENOMEM;
41++ return 0;
42++ }
43++
44++ *rc = mnt_optlist_get_flags(ol, &flags, cxt->map_linux, 0);
45++ if (*rc)
46++ return 0;
47++
48++ if (flags & MS_REMOUNT || flags & MS_BIND || flags & MS_MOVE
49++ || mnt_context_propagation_only(cxt)) {
50++ DBG(HOOK, ul_debug("ignore subdir= (bind/move/remount/..)"));
51++ return 0;
52+ }
53+54++ *subdir = strdup(dir);
55++ if (!*subdir)
56++ *rc = -ENOMEM;
57++
58+ return *rc == 0;
59+ }
60+61+diff --git a/sys-utils/mount.8.adoc b/sys-utils/mount.8.adoc
62+index 6a17cd5eb..d9ce31fd4 100644
63+--- a/sys-utils/mount.8.adoc
64++++ b/sys-utils/mount.8.adoc
65+@@ -763,8 +763,10 @@ Note that *mount*(8) still sanitizes and canonicalizes the source and target pat
66+ *X-mount.noloop*::
67+ Do not create and mount a loop device, even if the source of the mount is a regular file.
68+69+-*X-mount.subdir=*__directory__::
70+-Allow mounting sub-directory from a filesystem instead of the root directory. For now, this feature is implemented by temporary filesystem root directory mount in unshared namespace and then bind the sub-directory to the final mount point and umount the root of the filesystem. The sub-directory mount shows up atomically for the rest of the system although it is implemented by multiple *mount*(2) syscalls.
71++**X-mount.subdir=**_directory_::
72++Allow mounting a subdirectory of a filesystem instead of the root directory. This is effective only when a new instance of a filesystem is attached to the system. The option is silently ignored for operations like remount, bind mount, or move.
73+++
74++For now, this feature is implemented by a temporary filesystem root-directory mount in an unshared namespace and then binding the sub-directory to the final mount point and unmounting the root of the filesystem. The sub-directory mount shows up atomically for the rest of the system although it is implemented by multiple *mount*(2) syscalls.
75+ +
76+ Note that this feature will not work in session with an unshared private mount namespace (after *unshare --mount*) on old kernels or with *mount*(8) without support for file-descriptors-based mount kernel API. In this case, you need *unshare --mount --propagation shared*.
77+ +
78+--
79+2.49.0
80+