1
0
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:
Luca Boccassi 2025-02-19 22:09:52 +00:00 committed by GitHub
commit 5dbc4f37c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 212 additions and 98 deletions

View File

@ -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

View File

@ -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" />

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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)

View File

@ -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) {

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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));

View File

@ -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