···11+From 22b91501d30a65d25ecf48ce5169ec70848117b8 Mon Sep 17 00:00:00 2001
22+From: Karel Zak <kzak@redhat.com>
33+Date: Wed, 9 Apr 2025 12:15:57 +0200
44+Subject: [PATCH] libmount: (subdir) restrict for real mounts only
55+66+It's now possible to use, for example, for bind operations, but it
77+does not make sense as you can specify the target with the
88+subdirectory.
99+1010+Signed-off-by: Karel Zak <kzak@redhat.com>
1111+(cherry picked from commit 437a271f7108f689d350f1b3d837490d3d283c3c)
1212+---
1313+ libmount/src/hook_subdir.c | 21 ++++++++++++++++-----
1414+ sys-utils/mount.8.adoc | 6 ++++--
1515+ 2 files changed, 20 insertions(+), 7 deletions(-)
1616+1717+diff --git a/libmount/src/hook_subdir.c b/libmount/src/hook_subdir.c
1818+index 1e5d79958..7cbb2c88d 100644
1919+--- a/libmount/src/hook_subdir.c
2020++++ b/libmount/src/hook_subdir.c
2121+@@ -313,6 +313,7 @@ static int is_subdir_required(struct libmnt_context *cxt, int *rc, char **subdir
2222+ struct libmnt_optlist *ol;
2323+ struct libmnt_opt *opt;
2424+ const char *dir = NULL;
2525++ unsigned long flags = 0;
2626+2727+ assert(cxt);
2828+ assert(rc);
2929+@@ -328,16 +329,26 @@ static int is_subdir_required(struct libmnt_context *cxt, int *rc, char **subdir
3030+ return 0;
3131+3232+ dir = mnt_opt_get_value(opt);
3333+-
3434+ if (!dir || !*dir) {
3535+ DBG(HOOK, ul_debug("failed to parse X-mount.subdir '%s'", dir));
3636+ *rc = -MNT_ERR_MOUNTOPT;
3737+- } else {
3838+- *subdir = strdup(dir);
3939+- if (!*subdir)
4040+- *rc = -ENOMEM;
4141++ return 0;
4242++ }
4343++
4444++ *rc = mnt_optlist_get_flags(ol, &flags, cxt->map_linux, 0);
4545++ if (*rc)
4646++ return 0;
4747++
4848++ if (flags & MS_REMOUNT || flags & MS_BIND || flags & MS_MOVE
4949++ || mnt_context_propagation_only(cxt)) {
5050++ DBG(HOOK, ul_debug("ignore subdir= (bind/move/remount/..)"));
5151++ return 0;
5252+ }
5353+5454++ *subdir = strdup(dir);
5555++ if (!*subdir)
5656++ *rc = -ENOMEM;
5757++
5858+ return *rc == 0;
5959+ }
6060+6161+diff --git a/sys-utils/mount.8.adoc b/sys-utils/mount.8.adoc
6262+index 6a17cd5eb..d9ce31fd4 100644
6363+--- a/sys-utils/mount.8.adoc
6464++++ b/sys-utils/mount.8.adoc
6565+@@ -763,8 +763,10 @@ Note that *mount*(8) still sanitizes and canonicalizes the source and target pat
6666+ *X-mount.noloop*::
6767+ Do not create and mount a loop device, even if the source of the mount is a regular file.
6868+6969+-*X-mount.subdir=*__directory__::
7070+-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.
7171++**X-mount.subdir=**_directory_::
7272++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.
7373+++
7474++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.
7575+ +
7676+ 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*.
7777+ +
7878+--
7979+2.49.0
8080+