From: Lennart Poettering Date: Tue, 22 Sep 2020 13:16:15 +0000 (+0200) Subject: mount-util: add helpers for mount() without following symlinks X-Git-Tag: v247-rc1~183^2~6 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=28126409b20bca9aa6ff18dff594e58aa79caba9;p=thirdparty%2Fsystemd.git mount-util: add helpers for mount() without following symlinks --- diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c index 53fb46e7bca..76308a8b065 100644 --- a/src/shared/mount-util.c +++ b/src/shared/mount-util.c @@ -19,10 +19,60 @@ #include "parse-util.h" #include "path-util.h" #include "set.h" +#include "stat-util.h" #include "stdio-util.h" #include "string-util.h" #include "strv.h" +int mount_fd(const char *source, + int target_fd, + const char *filesystemtype, + unsigned long mountflags, + const void *data) { + + char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + + xsprintf(path, "/proc/self/fd/%i", target_fd); + if (mount(source, path, filesystemtype, mountflags, data) < 0) { + if (errno != ENOENT) + return -errno; + + /* ENOENT can mean two things: either that the source is missing, or that /proc/ isn't + * mounted. Check for the latter to generate better error messages. */ + if (proc_mounted() == 0) + return -ENOSYS; + + return -ENOENT; + } + + return 0; +} + +int mount_nofollow( + const char *source, + const char *target, + const char *filesystemtype, + unsigned long mountflags, + const void *data) { + + _cleanup_close_ int fd = -1; + + /* In almost all cases we want to manipulate the mount table without following symlinks, hence + * mount_nofollow() is usually the way to go. The only exceptions are environments where /proc/ is + * not available yet, since we need /proc/self/fd/ for this logic to work. i.e. during the early + * initialization of namespacing/container stuff where /proc is not yet mounted (and maybe even the + * fs to mount) we can only use traditional mount() directly. + * + * Note that this disables following only for the final component of the target, i.e symlinks within + * the path of the target are honoured, as are symlinks in the source path everywhere. */ + + fd = open(target, O_PATH|O_CLOEXEC|O_NOFOLLOW); + if (fd < 0) + return -errno; + + return mount_fd(source, fd, filesystemtype, mountflags, data); +} + int umount_recursive(const char *prefix, int flags) { int n = 0, r; bool again; diff --git a/src/shared/mount-util.h b/src/shared/mount-util.h index 8fb597e7c03..3c74ad44876 100644 --- a/src/shared/mount-util.h +++ b/src/shared/mount-util.h @@ -32,6 +32,9 @@ #define TMPFS_LIMITS_ROOTFS TMPFS_LIMITS_VAR #define TMPFS_LIMITS_VOLATILE_STATE TMPFS_LIMITS_VAR +int mount_fd(const char *source, int target_fd, const char *filesystemtype, unsigned long mountflags, const void *data); +int mount_nofollow(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data); + int repeat_unmount(const char *path, int flags); int umount_recursive(const char *target, int flags); int bind_remount_recursive(const char *prefix, unsigned long new_flags, unsigned long flags_mask, char **deny_list);