*/
#include "mountP.h"
+#include "fileutils.h"
#include "strutils.h"
#include "namespace.h"
#include "match.h"
cxt->ns_orig.fd = -1;
cxt->ns_tgt.fd = -1;
cxt->ns_cur = &cxt->ns_orig;
+ cxt->fd_target = -1;
cxt->map_linux = mnt_get_builtin_optmap(MNT_LINUX_MAP);
cxt->map_userspace = mnt_get_builtin_optmap(MNT_USERSPACE_MAP);
cxt->map_userspace = mnt_get_builtin_optmap(MNT_USERSPACE_MAP);
mnt_context_reset_status(cxt);
+ mnt_context_close_target_fd(cxt);
mnt_context_deinit_hooksets(cxt);
if (cxt->table_fltrcb)
return cxt->restricted;
}
+int mnt_context_target_fd_required(struct libmnt_context *cxt)
+{
+ return mnt_context_is_restricted(cxt);
+}
+
+int mnt_context_reopen_target_fd(struct libmnt_context *cxt)
+{
+ assert(cxt);
+
+ if (!mnt_context_target_fd_required(cxt))
+ return 0;
+ mnt_context_close_target_fd(cxt);
+ if (mnt_context_get_target_fd(cxt) < 0)
+ return -errno;
+ return 0;
+}
+
+int mnt_context_get_target_fd(struct libmnt_context *cxt)
+{
+ assert(cxt);
+
+ if (cxt->fd_target < 0) {
+ const char *target = mnt_fs_get_target(cxt->fs);
+
+ if (target)
+ cxt->fd_target = ul_open_no_symlinks(target,
+ O_PATH | O_CLOEXEC, 0);
+ }
+ return cxt->fd_target;
+}
+
+void mnt_context_close_target_fd(struct libmnt_context *cxt)
+{
+ assert(cxt);
+
+ if (cxt->fd_target >= 0)
+ close(cxt->fd_target);
+ cxt->fd_target = -1;
+}
+
/**
* mnt_context_force_unrestricted:
* @cxt: mount context
if (rc == 0)
rc = mnt_context_call_hooks(cxt, MNT_STAGE_PREP_TARGET);
+ if (rc == 0
+ && mnt_context_target_fd_required(cxt)
+ && mnt_context_get_target_fd(cxt) < 0) {
+ DBG_OBJ(CXT, cxt, ul_debug("failed to pin target"));
+ rc = -errno;
+ }
+
if (!mnt_context_switch_ns(cxt, ns_old))
return -MNT_ERR_NAMESPACE;
if (mnt_context_is_beneath(cxt))
flags |= MOVE_MOUNT_BENEATH;
- rc = move_mount(api->fd_tree, "", AT_FDCWD, target, flags);
+ /* fd_target is open in restricted mode (see prepare_target()) */
+ if (mnt_context_target_fd_required(cxt)) {
+ int fd = mnt_context_get_target_fd(cxt);
+
+ if (fd < 0)
+ return -errno;
+ flags |= MOVE_MOUNT_T_EMPTY_PATH;
+ rc = move_mount(api->fd_tree, "", fd, "", flags);
+ } else
+ rc = move_mount(api->fd_tree, "", AT_FDCWD, target, flags);
+
hookset_set_syscall_status(cxt, "move_mount", rc == 0);
if (rc == 0) {
mnt_fs_mark_moved(cxt->fs);
else
mnt_fs_mark_attached(cxt->fs);
+
+ /* re-open to point to the mounted filesystem root */
+ rc = mnt_context_reopen_target_fd(cxt);
}
return rc == 0 ? 0 : -errno;
else
mnt_fs_mark_attached(cxt->fs);
+ /* re-open to point to the mounted filesystem root */
+ rc = mnt_context_reopen_target_fd(cxt);
+
cxt->syscall_status = 0;
return rc;
}
unsigned int has_selinux_opt : 1; /* temporary for broken fsconfig() syscall */
unsigned int force_clone : 1; /* OPEN_TREE_CLONE */
+ int fd_target; /* pinned target fd (RESOLVE_NO_SYMLINKS) */
+
struct list_head hooksets_datas; /* global hooksets data */
struct list_head hooksets_hooks; /* global hooksets data */
};
extern void mnt_cache_enable_noprobe(struct libmnt_cache *cache, int enable);
+extern int mnt_context_target_fd_required(struct libmnt_context *cxt);
+extern int mnt_context_get_target_fd(struct libmnt_context *cxt);
+extern void mnt_context_close_target_fd(struct libmnt_context *cxt);
+extern int mnt_context_reopen_target_fd(struct libmnt_context *cxt);
+
extern int mnt_context_umount_setopt(struct libmnt_context *cxt, int c, char *arg);
extern int mnt_context_mount_setopt(struct libmnt_context *cxt, int c, char *arg);