From 2a684833d723e29af0ba772b3e6917492c69e023 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 3 Jun 2024 12:33:01 +0200 Subject: [PATCH] libmount: fix tree FD usage in subdir hook * Initialize the tree file descriptor in the hook_subdir.c module if it has not been initialized yet. (hook_mount.c does not open the tree if the mount. helper will be executed.) * Move the function to open the tree to context.c to make it more generic and usable in more places. Reported-by: Linus Heckemann Signed-off-by: Karel Zak --- libmount/src/context.c | 41 ++++++++++++++++++++++++++++++++++++ libmount/src/hook_mount.c | 43 +++----------------------------------- libmount/src/hook_subdir.c | 31 ++++++++++++++++----------- libmount/src/mountP.h | 3 +++ 4 files changed, 66 insertions(+), 52 deletions(-) diff --git a/libmount/src/context.c b/libmount/src/context.c index 332e456e6..c91b0148e 100644 --- a/libmount/src/context.c +++ b/libmount/src/context.c @@ -44,6 +44,8 @@ #include #include +#include "mount-api-utils.h" + /** * mnt_new_context: * @@ -1791,6 +1793,45 @@ int mnt_context_set_mountdata(struct libmnt_context *cxt, void *data) return 0; } +#ifdef USE_LIBMOUNT_MOUNTFD_SUPPORT +int mnt_context_open_tree(struct libmnt_context *cxt, const char *path, unsigned long mflg) +{ + unsigned long oflg = OPEN_TREE_CLOEXEC; + int rc = 0, fd = -1; + + if (mflg == (unsigned long) -1) { + rc = mnt_optlist_get_flags(cxt->optlist, &mflg, cxt->map_linux, 0); + if (rc) + return rc; + } + if (!path) { + path = mnt_fs_get_target(cxt->fs); + if (!path) + return -EINVAL; + } + + /* Classic -oremount,bind,ro is not bind operation, it's just + * VFS flags update only */ + if ((mflg & MS_BIND) && !(mflg & MS_REMOUNT)) { + oflg |= OPEN_TREE_CLONE; + + if (mnt_optlist_is_rbind(cxt->optlist)) + oflg |= AT_RECURSIVE; + } + + if (cxt->force_clone) + oflg |= OPEN_TREE_CLONE; + + DBG(CXT, ul_debugobj(cxt, "open_tree(path=%s%s%s)", path, + oflg & OPEN_TREE_CLONE ? " clone" : "", + oflg & AT_RECURSIVE ? " recursive" : "")); + fd = open_tree(AT_FDCWD, path, oflg); + mnt_context_syscall_save_status(cxt, "open_tree", fd >= 0); + + return fd; +} +#endif + /* * Translates LABEL/UUID/path to mountable path */ diff --git a/libmount/src/hook_mount.c b/libmount/src/hook_mount.c index 6b7caff85..cd57bdbcb 100644 --- a/libmount/src/hook_mount.c +++ b/libmount/src/hook_mount.c @@ -255,43 +255,6 @@ static int open_fs_configuration_context(struct libmnt_context *cxt, return api->fd_fs; } -static int open_mount_tree(struct libmnt_context *cxt, const char *path, unsigned long mflg) -{ - unsigned long oflg = OPEN_TREE_CLOEXEC; - int rc = 0, fd = -1; - - if (mflg == (unsigned long) -1) { - rc = mnt_optlist_get_flags(cxt->optlist, &mflg, cxt->map_linux, 0); - if (rc) - return rc; - } - if (!path) { - path = mnt_fs_get_target(cxt->fs); - if (!path) - return -EINVAL; - } - - /* Classic -oremount,bind,ro is not bind operation, it's just - * VFS flags update only */ - if ((mflg & MS_BIND) && !(mflg & MS_REMOUNT)) { - oflg |= OPEN_TREE_CLONE; - - if (mnt_optlist_is_rbind(cxt->optlist)) - oflg |= AT_RECURSIVE; - } - - if (cxt->force_clone) - oflg |= OPEN_TREE_CLONE; - - DBG(HOOK, ul_debug("open_tree(path=%s%s%s)", path, - oflg & OPEN_TREE_CLONE ? " clone" : "", - oflg & AT_RECURSIVE ? " recursive" : "")); - fd = open_tree(AT_FDCWD, path, oflg); - hookset_set_syscall_status(cxt, "open_tree", fd >= 0); - - return fd; -} - static int hook_create_mount(struct libmnt_context *cxt, const struct libmnt_hookset *hs, void *data __attribute__((__unused__))) @@ -419,7 +382,7 @@ static int set_vfsflags(struct libmnt_context *cxt, /* fallback only; necessary when init_sysapi() during preparation * cannot open the tree -- for example when we call /sbin/mount. */ if (api->fd_tree < 0 && mnt_fs_get_target(cxt->fs)) { - rc = api->fd_tree = open_mount_tree(cxt, NULL, (unsigned long) -1); + rc = api->fd_tree = mnt_context_open_tree(cxt, NULL, (unsigned long) -1); if (rc < 0) return rc; rc = 0; @@ -497,7 +460,7 @@ static int hook_set_propagation(struct libmnt_context *cxt, /* fallback only; necessary when init_sysapi() during preparation * cannot open the tree -- for example when we call /sbin/mount. */ if (api->fd_tree < 0 && mnt_fs_get_target(cxt->fs)) { - rc = api->fd_tree = open_mount_tree(cxt, NULL, (unsigned long) -1); + rc = api->fd_tree = mnt_context_open_tree(cxt, NULL, (unsigned long) -1); if (rc < 0) goto done; rc = 0; @@ -634,7 +597,7 @@ static int init_sysapi(struct libmnt_context *cxt, return -ENOMEM; if (path) { - api->fd_tree = open_mount_tree(cxt, path, flags); + api->fd_tree = mnt_context_open_tree(cxt, path, flags); if (api->fd_tree < 0) goto fail; diff --git a/libmount/src/hook_subdir.c b/libmount/src/hook_subdir.c index 65674aa9e..99c30e173 100644 --- a/libmount/src/hook_subdir.c +++ b/libmount/src/hook_subdir.c @@ -165,17 +165,29 @@ static int tmptgt_cleanup(struct hookset_data *hsd) static int do_mount_subdir( struct libmnt_context *cxt, struct hookset_data *hsd, - const char *root, - const char *target) + const char *root) { int rc = 0; const char *subdir = hsd->subdir; + const char *target; #ifdef USE_LIBMOUNT_MOUNTFD_SUPPORT - struct libmnt_sysapi *api; + struct libmnt_sysapi *api = mnt_context_get_sysapi(cxt); + + /* fallback only; necessary when hook_mount.c during preparation + * cannot open the tree -- for example when we call /sbin/mount. */ + if (api && api->fd_tree < 0) { + api->fd_tree = mnt_context_open_tree(cxt, NULL, (unsigned long) -1); + if (api->fd_tree < 0) + return api->fd_tree; + } +#endif + /* reset to the original mountpoint */ + mnt_fs_set_target(cxt->fs, hsd->org_target); + target = mnt_fs_get_target(cxt->fs); - api = mnt_context_get_sysapi(cxt); - if (api) { +#ifdef USE_LIBMOUNT_MOUNTFD_SUPPORT + if (api && api->fd_tree >= 0) { /* FD based way - unfortunately, it's impossible to open * sub-directory on not-yet attached mount. It means * hook_mount.c attaches FS to temporary directory, and we @@ -186,7 +198,7 @@ static int do_mount_subdir( */ int fd; - DBG(HOOK, ul_debug("attach subdir %s", subdir)); + DBG(HOOK, ul_debug("attach subdir '%s'", subdir)); fd = open_tree(api->fd_tree, subdir, OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE); mnt_context_syscall_save_status(cxt, "open_tree", fd >= 0); @@ -255,13 +267,8 @@ static int hook_mount_post( if (!hsd || !hsd->subdir) return 0; - /* reset to the original mountpoint */ - mnt_fs_set_target(cxt->fs, hsd->org_target); - /* bind subdir to the real target, umount temporary target */ - rc = do_mount_subdir(cxt, hsd, - MNT_PATH_TMPTGT, - mnt_fs_get_target(cxt->fs)); + rc = do_mount_subdir(cxt, hsd, MNT_PATH_TMPTGT); if (rc) return rc; diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h index d3232bf1c..b855a90b3 100644 --- a/libmount/src/mountP.h +++ b/libmount/src/mountP.h @@ -679,6 +679,9 @@ static inline struct libmnt_sysapi *mnt_context_get_sysapi(struct libmnt_context { return mnt_context_get_hookset_data(cxt, &hookset_mount); } + +int mnt_context_open_tree(struct libmnt_context *cxt, const char *path, unsigned long mflg); + #endif #endif /* _LIBMOUNT_PRIVATE_H */ -- 2.47.2