mirror of
https://github.com/systemd/systemd.git
synced 2025-03-28 02:50:16 +03:00
tree-wide: tweaks to mount point inode creation (#36308)
Some love for make_mount_point_inode_from_xyz() and ports PID 1 over to it for mount units. Alternative to #36290
This commit is contained in:
commit
5dbc4f37c5
@ -460,6 +460,18 @@ this directory become inaccessible. To see those over-mounted files,
|
||||
please manually mount the underlying file system to a secondary
|
||||
location.
|
||||
|
||||
-- 1edabb4eda2a49c19bc0206f24b43889
|
||||
Subject: Mount point path contains symlinks
|
||||
Defined-By: systemd
|
||||
Support: %SUPPORT_URL%
|
||||
|
||||
The path @WHERE@ is specified as a mount point path (second field in /etc/fstab
|
||||
or Where= field in systemd unit file) and is not canonical, i.e. contains one
|
||||
or more symlinks as path elements. This is generally not supported and such
|
||||
mount attempts are refused, because the mount table information exposed by the
|
||||
kernel and the requested path would deviate once established. Please
|
||||
canonicalize paths before requesting a mount to be established.
|
||||
|
||||
-- 24d8d4452573402496068381a6312df2
|
||||
Subject: A virtual machine or container has been started
|
||||
Defined-By: systemd
|
||||
|
@ -340,6 +340,24 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--canonicalize=</option></term>
|
||||
|
||||
<listitem>
|
||||
<para>Controls whether the specified path shall be canonicalized on the client side before
|
||||
requesting the operation or not. Takes a boolean parameter, defaults to true. Note that for
|
||||
non-local operation (i.e. when <option>--machine=</option> or --<option>--host=</option> are used)
|
||||
canonicalization is implicitly turned off.</para>
|
||||
|
||||
<para>Canonicalization of path entails resolving of symlinks, <literal>..</literal> path elements
|
||||
and <varname>LABEL=</varname>/<varname>UUID=</varname> style device node expansion. If
|
||||
canonicalization is disabled and the path contains a symlink element, <literal>..</literal>, or a
|
||||
<varname>LABEL=</varname>/<varname>UUID=</varname>/… expansion the operation will fail.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="user-system-options.xml" xpointer="user" />
|
||||
<xi:include href="user-system-options.xml" xpointer="system" />
|
||||
<xi:include href="user-system-options.xml" xpointer="host" />
|
||||
|
@ -556,7 +556,7 @@ static void automount_enter_waiting(Automount *a) {
|
||||
|
||||
set_clear(a->tokens);
|
||||
|
||||
r = unit_fail_if_noncanonical(UNIT(a), a->where);
|
||||
r = unit_fail_if_noncanonical_mount_path(UNIT(a), a->where);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -8,11 +8,13 @@
|
||||
#include "sd-messages.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "chase.h"
|
||||
#include "dbus-mount.h"
|
||||
#include "dbus-unit.h"
|
||||
#include "device.h"
|
||||
#include "exec-credential.h"
|
||||
#include "exit-status.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "fstab-util.h"
|
||||
@ -1183,22 +1185,32 @@ static int mount_set_mount_command(Mount *m, ExecCommand *c, const MountParamete
|
||||
}
|
||||
|
||||
static void mount_enter_mounting(Mount *m) {
|
||||
MountParameters *p;
|
||||
bool source_is_dir = true;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = unit_fail_if_noncanonical(UNIT(m), m->where);
|
||||
if (r < 0)
|
||||
/* Validate that the path we are overmounting does not contain any symlinks, because if it does, we
|
||||
* couldn't support that reasonably: the mounts in /proc/self/mountinfo would not be recognizable to
|
||||
* us anymore. */
|
||||
fd = chase_and_open_parent(m->where, /* root= */ NULL, CHASE_PROHIBIT_SYMLINKS|CHASE_MKDIR_0755, &fn);
|
||||
if (fd == -EREMCHG) {
|
||||
r = unit_log_noncanonical_mount_path(UNIT(m), m->where);
|
||||
goto fail;
|
||||
}
|
||||
if (fd < 0) {
|
||||
log_unit_error_errno(UNIT(m), fd, "Failed to resolve parent of mount point '%s': %m", m->where);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
p = get_mount_parameters_fragment(m);
|
||||
MountParameters *p = get_mount_parameters_fragment(m);
|
||||
if (!p) {
|
||||
r = log_unit_warning_errno(UNIT(m), SYNTHETIC_ERRNO(ENOENT), "No mount parameters to operate on.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bool source_is_dir = true;
|
||||
if (mount_is_bind(p)) {
|
||||
r = is_dir(p->what, /* follow = */ true);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
@ -1207,10 +1219,11 @@ static void mount_enter_mounting(Mount *m) {
|
||||
source_is_dir = false;
|
||||
}
|
||||
|
||||
if (source_is_dir)
|
||||
r = mkdir_p_label(m->where, m->directory_mode);
|
||||
else
|
||||
r = touch_file(m->where, /* parents = */ true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
|
||||
r = make_mount_point_inode_from_mode(
|
||||
fd,
|
||||
fn,
|
||||
source_is_dir ? S_IFDIR : S_IFREG,
|
||||
m->directory_mode);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
log_unit_warning_errno(UNIT(m), r, "Failed to create mount point '%s', ignoring: %m", m->where);
|
||||
|
||||
|
@ -5125,14 +5125,28 @@ void unit_warn_if_dir_nonempty(Unit *u, const char* where) {
|
||||
"WHERE=%s", where);
|
||||
}
|
||||
|
||||
int unit_fail_if_noncanonical(Unit *u, const char* where) {
|
||||
_cleanup_free_ char *canonical_where = NULL;
|
||||
int unit_log_noncanonical_mount_path(Unit *u, const char *where) {
|
||||
assert(u);
|
||||
assert(where);
|
||||
|
||||
/* No need to mention "." or "..", they would already have been rejected by unit_name_from_path() */
|
||||
log_unit_struct(u, LOG_ERR,
|
||||
"MESSAGE_ID=" SD_MESSAGE_NON_CANONICAL_MOUNT_STR,
|
||||
LOG_UNIT_INVOCATION_ID(u),
|
||||
LOG_UNIT_MESSAGE(u, "Mount path %s is not canonical (contains a symlink).", where),
|
||||
"WHERE=%s", where);
|
||||
|
||||
return -ELOOP;
|
||||
}
|
||||
|
||||
int unit_fail_if_noncanonical_mount_path(Unit *u, const char* where) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(where);
|
||||
|
||||
r = chase(where, NULL, CHASE_NONEXISTENT, &canonical_where, NULL);
|
||||
_cleanup_free_ char *canonical_where = NULL;
|
||||
r = chase(where, /* root= */ NULL, CHASE_NONEXISTENT, &canonical_where, /* ret_fd= */ NULL);
|
||||
if (r < 0) {
|
||||
log_unit_debug_errno(u, r, "Failed to check %s for symlinks, ignoring: %m", where);
|
||||
return 0;
|
||||
@ -5142,14 +5156,7 @@ int unit_fail_if_noncanonical(Unit *u, const char* where) {
|
||||
if (path_equal(where, canonical_where))
|
||||
return 0;
|
||||
|
||||
/* No need to mention "." or "..", they would already have been rejected by unit_name_from_path() */
|
||||
log_unit_struct(u, LOG_ERR,
|
||||
"MESSAGE_ID=" SD_MESSAGE_OVERMOUNTING_STR,
|
||||
LOG_UNIT_INVOCATION_ID(u),
|
||||
LOG_UNIT_MESSAGE(u, "Mount path %s is not canonical (contains a symlink).", where),
|
||||
"WHERE=%s", where);
|
||||
|
||||
return -ELOOP;
|
||||
return unit_log_noncanonical_mount_path(u, where);
|
||||
}
|
||||
|
||||
bool unit_is_pristine(Unit *u) {
|
||||
|
@ -974,7 +974,8 @@ static inline PidRef* unit_main_pid(Unit *u) {
|
||||
}
|
||||
|
||||
void unit_warn_if_dir_nonempty(Unit *u, const char* where);
|
||||
int unit_fail_if_noncanonical(Unit *u, const char* where);
|
||||
int unit_log_noncanonical_mount_path(Unit *u, const char *where);
|
||||
int unit_fail_if_noncanonical_mount_path(Unit *u, const char* where);
|
||||
|
||||
int unit_test_start_limit(Unit *u);
|
||||
|
||||
|
@ -230,11 +230,11 @@ int machine_get_addresses(Machine *machine, struct local_address **ret_addresses
|
||||
/* except_fds = */ NULL,
|
||||
/* n_except_fds = */ 0,
|
||||
FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL,
|
||||
/* pidns_fd = */ -1,
|
||||
/* mntns_fd = */ -1,
|
||||
/* pidns_fd = */ -EBADF,
|
||||
/* mntns_fd = */ -EBADF,
|
||||
netns_fd,
|
||||
/* userns_fd = */ -1,
|
||||
/* root_fd = */ -1,
|
||||
/* userns_fd = */ -EBADF,
|
||||
/* root_fd = */ -EBADF,
|
||||
&child);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to fork(): %m");
|
||||
@ -347,8 +347,8 @@ int machine_get_os_release(Machine *machine, char ***ret_os_release) {
|
||||
FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL,
|
||||
pidns_fd,
|
||||
mntns_fd,
|
||||
/* netns_fd = */ -1,
|
||||
/* userns_fd = */ -1,
|
||||
/* netns_fd = */ -EBADF,
|
||||
/* userns_fd = */ -EBADF,
|
||||
root_fd,
|
||||
&child);
|
||||
if (r < 0)
|
||||
|
@ -75,6 +75,7 @@ static bool arg_fsck = true;
|
||||
static bool arg_aggressive_gc = false;
|
||||
static bool arg_tmpfs = false;
|
||||
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
|
||||
static bool arg_canonicalize = true;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_mount_what, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_mount_where, freep);
|
||||
@ -90,14 +91,14 @@ static int parse_where(const char *input, char **ret_where) {
|
||||
assert(input);
|
||||
assert(ret_where);
|
||||
|
||||
if (arg_transport == BUS_TRANSPORT_LOCAL) {
|
||||
r = chase(input, NULL, CHASE_NONEXISTENT, ret_where, NULL);
|
||||
if (arg_transport == BUS_TRANSPORT_LOCAL && arg_canonicalize) {
|
||||
r = chase(input, /* root= */ NULL, CHASE_NONEXISTENT, ret_where, /* ret_fd= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to make path %s absolute: %m", input);
|
||||
} else {
|
||||
if (!path_is_absolute(input))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Path must be absolute when operating remotely: %s",
|
||||
"Path must be absolute when operating remotely or when canonicalization is turned off: %s",
|
||||
input);
|
||||
|
||||
r = path_simplify_alloc(input, ret_where);
|
||||
@ -119,8 +120,9 @@ static int help(void) {
|
||||
printf("systemd-mount [OPTIONS...] WHAT [WHERE]\n"
|
||||
"systemd-mount [OPTIONS...] --tmpfs [NAME] WHERE\n"
|
||||
"systemd-mount [OPTIONS...] --list\n"
|
||||
"%s [OPTIONS...] %sWHAT|WHERE...\n\n"
|
||||
"%sEstablish a mount or auto-mount point transiently.%s\n\n"
|
||||
"%1$s [OPTIONS...] %7$sWHAT|WHERE...\n"
|
||||
"\n%5$sEstablish a mount or auto-mount point transiently.%6$s\n"
|
||||
"\n%3$sOptions:%4$s\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --no-block Do not wait until operation finished\n"
|
||||
@ -149,12 +151,16 @@ static int help(void) {
|
||||
" -u --umount Unmount mount points\n"
|
||||
" -G --collect Unload unit after it stopped, even when failed\n"
|
||||
" -T --tmpfs Create a new tmpfs on the mount point\n"
|
||||
"\nSee the %s for details.\n",
|
||||
" --canonicalize=BOOL Controls whether to canonicalize path before\n"
|
||||
" operation\n"
|
||||
"\nSee the %2$s for details.\n",
|
||||
program_invocation_short_name,
|
||||
streq(program_invocation_short_name, "systemd-umount") ? "" : "--umount ",
|
||||
link,
|
||||
ansi_underline(),
|
||||
ansi_normal(),
|
||||
ansi_highlight(),
|
||||
ansi_normal(),
|
||||
link);
|
||||
streq(program_invocation_short_name, "systemd-umount") ? "" : "--umount ");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -181,6 +187,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_BIND_DEVICE,
|
||||
ARG_LIST,
|
||||
ARG_JSON,
|
||||
ARG_CANONICALIZE,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@ -213,6 +220,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "collect", no_argument, NULL, 'G' },
|
||||
{ "tmpfs", no_argument, NULL, 'T' },
|
||||
{ "json", required_argument, NULL, ARG_JSON },
|
||||
{ "canonicalize", required_argument, NULL, ARG_CANONICALIZE },
|
||||
{},
|
||||
};
|
||||
|
||||
@ -374,6 +382,13 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
break;
|
||||
|
||||
case ARG_CANONICALIZE:
|
||||
r = parse_boolean_argument("--canonicalize=", optarg, &arg_canonicalize);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
@ -441,21 +456,21 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (!arg_mount_what)
|
||||
return log_oom();
|
||||
|
||||
} else if (arg_transport == BUS_TRANSPORT_LOCAL) {
|
||||
} else if (arg_transport == BUS_TRANSPORT_LOCAL && arg_canonicalize) {
|
||||
_cleanup_free_ char *u = NULL;
|
||||
|
||||
u = fstab_node_to_udev_node(argv[optind]);
|
||||
if (!u)
|
||||
return log_oom();
|
||||
|
||||
r = chase(u, NULL, 0, &arg_mount_what, NULL);
|
||||
r = chase(u, /* root= */ NULL, /* flags= */ 0, &arg_mount_what, /* ret_fd= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to make path %s absolute: %m", u);
|
||||
|
||||
} else {
|
||||
if (!path_is_absolute(argv[optind]))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Path must be absolute when operating remotely: %s",
|
||||
"Path must be absolute when operating remotely or when canonicalization is turned off: %s",
|
||||
argv[optind]);
|
||||
|
||||
r = path_simplify_alloc(argv[optind], &arg_mount_what);
|
||||
@ -1044,9 +1059,13 @@ static int action_umount(
|
||||
int argc,
|
||||
char **argv) {
|
||||
|
||||
int r, r2 = 0;
|
||||
int r, ret = 0;
|
||||
|
||||
if (arg_transport != BUS_TRANSPORT_LOCAL) {
|
||||
assert(bus);
|
||||
assert(argv);
|
||||
assert(argc > optind);
|
||||
|
||||
if (arg_transport != BUS_TRANSPORT_LOCAL || !arg_canonicalize) {
|
||||
for (int i = optind; i < argc; i++) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
@ -1054,46 +1073,52 @@ static int action_umount(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = stop_mounts(bus, p);
|
||||
if (r < 0)
|
||||
r2 = r;
|
||||
RET_GATHER(ret, stop_mounts(bus, p));
|
||||
}
|
||||
return r2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = optind; i < argc; i++) {
|
||||
_cleanup_free_ char *u = NULL, *p = NULL;
|
||||
struct stat st;
|
||||
|
||||
u = fstab_node_to_udev_node(argv[i]);
|
||||
if (!u)
|
||||
return log_oom();
|
||||
|
||||
r = chase(u, NULL, 0, &p, NULL);
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
r = chase(u, /* root= */ NULL, 0, &p, &fd);
|
||||
if (r < 0) {
|
||||
r2 = log_error_errno(r, "Failed to make path %s absolute: %m", argv[i]);
|
||||
RET_GATHER(ret, log_error_errno(r, "Failed to make path %s absolute: %m", u));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stat(p, &st) < 0)
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) < 0)
|
||||
return log_error_errno(errno, "Can't stat %s (from %s): %m", p, argv[i]);
|
||||
|
||||
if (S_ISBLK(st.st_mode))
|
||||
r = umount_by_device_node(bus, p);
|
||||
else if (S_ISREG(st.st_mode))
|
||||
r = umount_loop(bus, p);
|
||||
else if (S_ISDIR(st.st_mode))
|
||||
r = stop_mounts(bus, p);
|
||||
r = is_mount_point_at(fd, /* filename= */ NULL, /* flags= */ 0);
|
||||
fd = safe_close(fd); /* before continuing make sure the dir is not keeping anything busy */
|
||||
if (r > 0)
|
||||
RET_GATHER(ret, stop_mounts(bus, p));
|
||||
else {
|
||||
log_error("Invalid file type: %s (from %s)", p, argv[i]);
|
||||
r = -EINVAL;
|
||||
}
|
||||
/* This can realistically fail on pre-5.8 kernels that do not tell us via statx() if
|
||||
* something is a mount point, hence handle this gracefully, and go by type as we did
|
||||
* in pre-v258 times. */
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to determine if '%s' is a mount point, ignoring: %m", u);
|
||||
|
||||
if (r < 0)
|
||||
r2 = r;
|
||||
if (S_ISBLK(st.st_mode))
|
||||
RET_GATHER(ret, umount_by_device_node(bus, p));
|
||||
else if (S_ISREG(st.st_mode))
|
||||
RET_GATHER(ret, umount_loop(bus, p));
|
||||
else if (S_ISDIR(st.st_mode))
|
||||
RET_GATHER(ret, stop_mounts(bus, p));
|
||||
else
|
||||
RET_GATHER(ret, log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid file type: %s (from %s)", p, argv[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return r2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acquire_mount_type(sd_device *d) {
|
||||
|
@ -958,10 +958,7 @@ static int mount_in_namespace_legacy(
|
||||
|
||||
/* Second, we mount the source file or directory to a directory inside of our MS_SLAVE playground. */
|
||||
mount_tmp = strjoina(mount_slave, "/mount");
|
||||
if (flags & MOUNT_IN_NAMESPACE_IS_IMAGE)
|
||||
r = mkdir_p(mount_tmp, 0700);
|
||||
else
|
||||
r = make_mount_point_inode_from_stat(chased_src_st, mount_tmp, 0700);
|
||||
r = make_mount_point_inode_from_mode(AT_FDCWD, mount_tmp, (flags & MOUNT_IN_NAMESPACE_IS_IMAGE) ? S_IFDIR : chased_src_st->st_mode, 0700);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to create temporary mount point %s: %m", mount_tmp);
|
||||
goto finish;
|
||||
@ -1038,8 +1035,18 @@ static int mount_in_namespace_legacy(
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = namespace_fork("(sd-bindmnt)", "(sd-bindmnt-inner)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM,
|
||||
pidns_fd, mntns_fd, -1, -1, root_fd, &child);
|
||||
r = namespace_fork(
|
||||
"(sd-bindmnt)",
|
||||
"(sd-bindmnt-inner)",
|
||||
/* except_fds= */ NULL,
|
||||
/* n_except_fds= */ 0,
|
||||
FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM,
|
||||
pidns_fd,
|
||||
mntns_fd,
|
||||
/* netns_fd= */ -EBADF,
|
||||
/* userns_fd= */ -EBADF,
|
||||
root_fd,
|
||||
&child);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (r == 0) {
|
||||
@ -1047,12 +1054,15 @@ static int mount_in_namespace_legacy(
|
||||
|
||||
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
|
||||
|
||||
if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY) {
|
||||
if (!(flags & MOUNT_IN_NAMESPACE_IS_IMAGE)) {
|
||||
(void) mkdir_parents(dest, 0755);
|
||||
(void) make_mount_point_inode_from_stat(chased_src_st, dest, 0700);
|
||||
} else
|
||||
(void) mkdir_p(dest, 0755);
|
||||
_cleanup_close_ int dest_fd = -EBADF;
|
||||
_cleanup_free_ char *dest_fn = NULL;
|
||||
r = chase(dest, /* root= */ NULL, CHASE_PARENT|CHASE_EXTRACT_FILENAME|((flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY) ? CHASE_MKDIR_0755 : 0), &dest_fn, &dest_fd);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to pin parent directory of mount '%s', ignoring: %m", dest);
|
||||
else if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY) {
|
||||
r = make_mount_point_inode_from_mode(dest_fd, dest_fn, (flags & MOUNT_IN_NAMESPACE_IS_IMAGE) ? S_IFDIR : chased_src_st->st_mode, 0700);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to make mount point inode of mount '%s', ignoring: %m", dest);
|
||||
}
|
||||
|
||||
/* Fifth, move the mount to the right place inside */
|
||||
@ -1066,7 +1076,7 @@ static int mount_in_namespace_legacy(
|
||||
if (!mount_inside)
|
||||
report_errno_and_exit(errno_pipe_fd[1], log_oom_debug());
|
||||
|
||||
r = mount_nofollow_verbose(LOG_DEBUG, mount_inside, dest, NULL, MS_MOVE, NULL);
|
||||
r = mount_nofollow_verbose(LOG_DEBUG, mount_inside, dest_fd >= 0 ? FORMAT_PROC_FD_PATH(dest_fd) : dest, /* fstype= */ NULL, MS_MOVE, /* options= */ NULL);
|
||||
if (r < 0)
|
||||
report_errno_and_exit(errno_pipe_fd[1], r);
|
||||
|
||||
@ -1237,8 +1247,14 @@ static int mount_in_namespace(
|
||||
if (r == 0) {
|
||||
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
|
||||
|
||||
_cleanup_close_ int dest_fd = -EBADF;
|
||||
_cleanup_free_ char *dest_fn = NULL;
|
||||
r = chase(dest, /* root= */ NULL, CHASE_PARENT|CHASE_EXTRACT_FILENAME|((flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY) ? CHASE_MKDIR_0755 : 0), &dest_fn, &dest_fd);
|
||||
if (r < 0)
|
||||
report_errno_and_exit(errno_pipe_fd[1], r);
|
||||
|
||||
if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY)
|
||||
(void) mkdir_parents(dest, 0755);
|
||||
(void) make_mount_point_inode_from_mode(dest_fd, dest_fn, img ? S_IFDIR : st.st_mode, 0700);
|
||||
|
||||
if (img) {
|
||||
DissectImageFlags f =
|
||||
@ -1258,12 +1274,8 @@ static int mount_in_namespace(
|
||||
/* uid_range= */ UID_INVALID,
|
||||
/* userns_fd= */ -EBADF,
|
||||
f);
|
||||
} else {
|
||||
if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY)
|
||||
(void) make_mount_point_inode_from_stat(&st, dest, 0700);
|
||||
|
||||
} else
|
||||
r = mount_exchange_graceful(new_mount_fd, dest, /* mount_beneath= */ true);
|
||||
}
|
||||
|
||||
report_errno_and_exit(errno_pipe_fd[1], r);
|
||||
}
|
||||
@ -1688,17 +1700,17 @@ int bind_mount_submounts(
|
||||
return ret;
|
||||
}
|
||||
|
||||
int make_mount_point_inode_from_stat(const struct stat *st, const char *dest, mode_t mode) {
|
||||
assert(st);
|
||||
int make_mount_point_inode_from_mode(int dir_fd, const char *dest, mode_t source_mode, mode_t target_mode) {
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
assert(dest);
|
||||
|
||||
if (S_ISDIR(st->st_mode))
|
||||
return mkdir_label(dest, mode);
|
||||
if (S_ISDIR(source_mode))
|
||||
return mkdirat_label(dir_fd, dest, target_mode & 07777);
|
||||
else
|
||||
return RET_NERRNO(mknod(dest, S_IFREG|(mode & ~0111), 0));
|
||||
return RET_NERRNO(mknodat(dir_fd, dest, S_IFREG|(target_mode & 07666), 0)); /* Mask off X bit */
|
||||
}
|
||||
|
||||
int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t mode) {
|
||||
int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t access_mode) {
|
||||
struct stat st;
|
||||
|
||||
assert(source);
|
||||
@ -1707,7 +1719,7 @@ int make_mount_point_inode_from_path(const char *source, const char *dest, mode_
|
||||
if (stat(source, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
return make_mount_point_inode_from_stat(&st, dest, mode);
|
||||
return make_mount_point_inode_from_mode(AT_FDCWD, dest, st.st_mode, access_mode);
|
||||
}
|
||||
|
||||
int trigger_automount_at(int dir_fd, const char *path) {
|
||||
|
@ -178,8 +178,8 @@ int bind_mount_submounts(
|
||||
const char *source,
|
||||
const char *target);
|
||||
|
||||
/* Creates a mount point (not parents) based on the source path or stat - ie, a file or a directory */
|
||||
int make_mount_point_inode_from_stat(const struct stat *st, const char *dest, mode_t mode);
|
||||
/* Creates a mount point (without any parents) based on the source path or mode - i.e., a file or a directory */
|
||||
int make_mount_point_inode_from_mode(int dir_fd, const char *dest, mode_t source_mode, mode_t target_mode);
|
||||
int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t mode);
|
||||
|
||||
int trigger_automount_at(int dir_fd, const char *path);
|
||||
|
@ -297,22 +297,28 @@ static int move_submounts(const char *src, const char *dst) {
|
||||
|
||||
assert_se(suffix = path_startswith(m->path, src));
|
||||
|
||||
if (fstat(m->mount_fd, &st) < 0)
|
||||
return log_error_errno(errno, "Failed to stat %s: %m", m->path);
|
||||
|
||||
t = path_join(dst, suffix);
|
||||
if (!t)
|
||||
return log_oom();
|
||||
|
||||
if (fstat(m->mount_fd, &st) < 0)
|
||||
return log_error_errno(errno, "Failed to stat %s: %m", m->path);
|
||||
|
||||
r = mkdir_parents(t, 0755);
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
r = chase(t, /* root= */ NULL, CHASE_PARENT|CHASE_EXTRACT_FILENAME|CHASE_PROHIBIT_SYMLINKS|CHASE_MKDIR_0755, &fn, &fd);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create parent directories of %s: %m", t);
|
||||
return log_error_errno(r, "Failed to create and pin parent directory of %s: %m", t);
|
||||
|
||||
r = make_mount_point_inode_from_stat(&st, t, 0755);
|
||||
r = make_mount_point_inode_from_mode(fd, fn, st.st_mode, 0755);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
return log_error_errno(r, "Failed to create mountpoint %s: %m", t);
|
||||
|
||||
r = mount_follow_verbose(LOG_ERR, m->path, t, NULL, MS_BIND|MS_REC, NULL);
|
||||
_cleanup_close_ int child_fd = openat(fd, fn, O_PATH|O_CLOEXEC);
|
||||
if (child_fd < 0)
|
||||
return log_error_errno(errno, "Failed to pin mountpoint %s: %m", t);
|
||||
|
||||
r = mount_follow_verbose(LOG_ERR, m->path, FORMAT_PROC_FD_PATH(child_fd), /* fstype= */ NULL, MS_BIND|MS_REC, /* options= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -190,6 +190,8 @@ _SD_BEGIN_DECLARATIONS;
|
||||
|
||||
#define SD_MESSAGE_OVERMOUNTING SD_ID128_MAKE(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7)
|
||||
#define SD_MESSAGE_OVERMOUNTING_STR SD_ID128_MAKE_STR(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7)
|
||||
#define SD_MESSAGE_NON_CANONICAL_MOUNT SD_ID128_MAKE(1e,da,bb,4e,da,2a,49,c1,9b,c0,20,6f,24,b4,38,89)
|
||||
#define SD_MESSAGE_NON_CANONICAL_MOUNT_STR SD_ID128_MAKE_STR(1e,da,bb,4e,da,2a,49,c1,9b,c0,20,6f,24,b4,38,89)
|
||||
|
||||
#define SD_MESSAGE_UNIT_OOMD_KILL SD_ID128_MAKE(d9,89,61,1b,15,e4,4c,9d,bf,31,e3,c8,12,56,e4,ed)
|
||||
#define SD_MESSAGE_UNIT_OOMD_KILL_STR SD_ID128_MAKE_STR(d9,89,61,1b,15,e4,4c,9d,bf,31,e3,c8,12,56,e4,ed)
|
||||
|
@ -266,9 +266,9 @@ TEST(make_mount_point_inode) {
|
||||
assert_se(rmdir(dst_dir) == 0);
|
||||
|
||||
assert_se(stat(src_file, &st) == 0);
|
||||
assert_se(make_mount_point_inode_from_stat(&st, dst_file, 0755) >= 0);
|
||||
assert_se(make_mount_point_inode_from_mode(AT_FDCWD, dst_file, st.st_mode, 0755) >= 0);
|
||||
assert_se(stat(src_dir, &st) == 0);
|
||||
assert_se(make_mount_point_inode_from_stat(&st, dst_dir, 0755) >= 0);
|
||||
assert_se(make_mount_point_inode_from_mode(AT_FDCWD, dst_dir, st.st_mode, 0755) >= 0);
|
||||
|
||||
assert_se(stat(dst_dir, &st) == 0);
|
||||
assert_se(S_ISDIR(st.st_mode));
|
||||
|
@ -39,3 +39,21 @@ systemd-mount --type=overlay --options="lowerdir=/etc,upperdir=$WORK_DIR/upper,w
|
||||
touch "$WORK_DIR/overlay/foo"
|
||||
test -e "$WORK_DIR/upper/foo"
|
||||
systemd-umount "$WORK_DIR/overlay"
|
||||
|
||||
# Validate that we cannot mount through a symlink or ..
|
||||
mkdir "$WORK_DIR"/flurb
|
||||
ln -s flurb "$WORK_DIR"/knarb
|
||||
systemd-mount --canonicalize=no --tmpfs "$WORK_DIR"/flurb/shlum
|
||||
systemd-umount "$WORK_DIR/"/flurb/shlum
|
||||
(! systemd-mount --canonicalize=no --tmpfs "$WORK_DIR"/knarb/shlum)
|
||||
systemd-mount --canonicalize=yes --tmpfs "$WORK_DIR"/knarb/shlum
|
||||
systemd-umount "$WORK_DIR/"/flurb/shlum
|
||||
(! systemd-mount --canonicalize=no --tmpfs "$WORK_DIR"/flurb/../flurb/shlum)
|
||||
systemd-mount --canonicalize=yes --tmpfs "$WORK_DIR"/flurb/../flurb/shlum
|
||||
systemd-umount "$WORK_DIR/"/flurb/shlum
|
||||
|
||||
# Validate that we can correctly create dir and reg files inodes if needed
|
||||
systemd-mount --tmpfs "$WORK_DIR"/flurb/shlum/some/more/dirs
|
||||
systemd-umount "$WORK_DIR/"/flurb/shlum/some/more/dirs
|
||||
systemd-mount /bin/ls "$WORK_DIR"/flurb/shlum/some/more/dirs/file -o bind
|
||||
systemd-umount "$WORK_DIR/"/flurb/shlum/some/more/dirs/file
|
||||
|
Loading…
x
Reference in New Issue
Block a user