]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
mountpoint-util: add helper that checks if MS_NOSYMFOLLOW is supported
authorLennart Poettering <lennart@poettering.net>
Mon, 6 Mar 2023 21:49:30 +0000 (22:49 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 9 Mar 2023 15:14:29 +0000 (16:14 +0100)
src/basic/mountpoint-util.c
src/basic/mountpoint-util.h
src/test/test-mountpoint-util.c

index bc74fbef8f7cd840b84bd3ca802d420ae7cba0d0..b60cf78b5ac036b12d03aee2640b15de390e027e 100644 (file)
@@ -3,6 +3,9 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <sys/mount.h>
+#if WANT_LINUX_FS_H
+#include <linux/fs.h>
+#endif
 
 #include "alloc-util.h"
 #include "chase-symlinks.h"
@@ -10,6 +13,8 @@
 #include "fileio.h"
 #include "filesystems.h"
 #include "fs-util.h"
+#include "missing_fs.h"
+#include "missing_mount.h"
 #include "missing_stat.h"
 #include "missing_syscall.h"
 #include "mkdir.h"
@@ -602,3 +607,60 @@ int mount_propagation_flag_from_string(const char *name, unsigned long *ret) {
 bool mount_propagation_flag_is_valid(unsigned long flag) {
         return IN_SET(flag, 0, MS_SHARED, MS_PRIVATE, MS_SLAVE);
 }
+
+unsigned long ms_nosymfollow_supported(void) {
+        _cleanup_close_ int fsfd = -EBADF, mntfd = -EBADF;
+        static int cache = -1;
+
+        /* Returns MS_NOSYMFOLLOW if it is supported, zero otherwise. */
+
+        if (cache >= 0)
+                return cache ? MS_NOSYMFOLLOW : 0;
+
+        /* Checks if MS_NOSYMFOLLOW is supported (which was added in 5.10). We use the new mount API's
+         * mount_setattr() call for that, which was added in 5.12, which is close enough. */
+
+        fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC);
+        if (fsfd < 0) {
+                if (ERRNO_IS_NOT_SUPPORTED(errno))
+                        goto not_supported;
+
+                log_debug_errno(errno, "Failed to open superblock context for tmpfs: %m");
+                return 0;
+        }
+
+        if (fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) {
+                if (ERRNO_IS_NOT_SUPPORTED(errno))
+                        goto not_supported;
+
+                log_debug_errno(errno, "Failed to create tmpfs superblock: %m");
+                return 0;
+        }
+
+        mntfd = fsmount(fsfd, FSMOUNT_CLOEXEC, 0);
+        if (mntfd < 0) {
+                if (ERRNO_IS_NOT_SUPPORTED(errno))
+                        goto not_supported;
+
+                log_debug_errno(errno, "Failed to turn superblock fd into mount fd: %m");
+                return 0;
+        }
+
+        if (mount_setattr(mntfd, "", AT_EMPTY_PATH|AT_RECURSIVE,
+                          &(struct mount_attr) {
+                                  .attr_set = MOUNT_ATTR_NOSYMFOLLOW,
+                          }, sizeof(struct mount_attr)) < 0) {
+                if (ERRNO_IS_NOT_SUPPORTED(errno))
+                        goto not_supported;
+
+                log_debug_errno(errno, "Failed to set MOUNT_ATTR_NOSYMFOLLOW mount attribute: %m");
+                return 0;
+        }
+
+        cache = true;
+        return MS_NOSYMFOLLOW;
+
+not_supported:
+        cache = false;
+        return 0;
+}
index 19709195e84e346b23f903a839fd5d27a452002c..f8529030849067846165fcbc270992de26c0178e 100644 (file)
@@ -58,3 +58,5 @@ int mount_nofollow(const char *source, const char *target, const char *filesyste
 const char *mount_propagation_flag_to_string(unsigned long flags);
 int mount_propagation_flag_from_string(const char *name, unsigned long *ret);
 bool mount_propagation_flag_is_valid(unsigned long flag);
+
+unsigned long ms_nosymfollow_supported(void);
index ea47c3a5b3ae1bafd9d1a34250fe604b6c4f7b53..5df853a1d97e4592dd23219eb4aface18a34eda4 100644 (file)
@@ -321,6 +321,10 @@ TEST(fd_is_mount_point) {
         assert_se(fd_is_mount_point(fd, "", 0) == -EINVAL);
 }
 
+TEST(ms_nosymfollow_supported) {
+        log_info("MS_NOSYMFOLLOW supported: %s", yes_no(ms_nosymfollow_supported()));
+}
+
 static int intro(void) {
         /* let's move into our own mount namespace with all propagation from the host turned off, so
          * that /proc/self/mountinfo is static and constant for the whole time our test runs. */