]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core/namespace: unify logic of mounting /proc and /sys
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 11 Oct 2023 05:57:54 +0000 (14:57 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 26 Oct 2023 10:06:27 +0000 (19:06 +0900)
No functional change, just refactoring.

src/core/namespace.c

index cae082c655c8d807d69aea2a481fbfd8bdd722c1..9202fbc1b73f6cb36ad8221c5e3297a49a120ab7 100644 (file)
@@ -1160,37 +1160,64 @@ static int mount_bind_sysfs(const MountEntry *m) {
         return mount_nofollow_verbose(LOG_DEBUG, "/sys", mount_entry_path(m), NULL, MS_BIND|MS_REC, NULL);
 }
 
-static int mount_private_sysfs(const MountEntry *m) {
-        const char *entry_path = mount_entry_path(ASSERT_PTR(m));
+static int mount_private_apivfs(
+                const char *fstype,
+                const char *entry_path,
+                const char *bind_source,
+                const char *opts) {
+
         int r, n;
 
-        (void) mkdir_p_label(entry_path, 0755);
+        assert(fstype);
+        assert(entry_path);
+        assert(bind_source);
 
-        n = umount_recursive(entry_path, 0);
+        (void) mkdir_p_label(entry_path, 0755);
+        n = umount_recursive(entry_path, /* flags = */ 0);
 
-        r = mount_nofollow_verbose(LOG_DEBUG, "sysfs", entry_path, "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL);
+        r = mount_nofollow_verbose(LOG_DEBUG, fstype, entry_path, fstype, MS_NOSUID|MS_NOEXEC|MS_NODEV, opts);
+        if (r == -EINVAL && opts)
+                /* If this failed with EINVAL then this likely means the textual hidepid= stuff for procfs is
+                 * not supported by the kernel, and thus the per-instance hidepid= neither, which means we
+                 * really don't want to use it, since it would affect our host's /proc mount. Hence let's
+                 * gracefully fallback to a classic, unrestricted version. */
+                r = mount_nofollow_verbose(LOG_DEBUG, fstype, entry_path, fstype, MS_NOSUID|MS_NOEXEC|MS_NODEV, /* opts = */ NULL);
         if (ERRNO_IS_NEG_PRIVILEGE(r)) {
-                /* When we do not have enough privileges to mount sysfs, fall back to use existing /sys. */
+                /* When we do not have enough privileges to mount a new instance, fall back to use an
+                 * existing mount. */
 
                 if (n > 0)
-                        /* /sys or some of sub-mounts are umounted in the above. Refuse incomplete tree.
+                        /* The mount or some of sub-mounts are umounted in the above. Refuse incomplete tree.
                          * Propagate the original error code returned by mount() in the above. */
                         return r;
 
-                return mount_bind_sysfs(m);
+                r = path_is_mount_point(entry_path, /* root = */ NULL, /* flags = */ 0);
+                if (r < 0)
+                        return log_debug_errno(r, "Unable to determine whether '%s' is already mounted: %m", entry_path);
+                if (r > 0)
+                        return 0; /* Use the current mount as is. */
+
+                /* We lack permissions to mount a new instance, and it is not already mounted. But we can
+                 * access the host's, so as a final fallback bind-mount it to the destination, as most likely
+                 * we are inside a user manager in an unprivileged user namespace. */
+                return mount_nofollow_verbose(LOG_DEBUG, bind_source, entry_path, /* fstype = */ NULL, MS_BIND|MS_REC, /* opts = */ NULL);
 
         } else if (r < 0)
                 return r;
 
-        /* We mounted a new instance now. Let's bind mount the children over now. */
-        (void) bind_mount_submounts("/sys", entry_path);
+        /* We mounted a new instance now. Let's bind mount the children over now. This matters for nspawn
+         * where a bunch of files are overmounted, in particular the boot id. */
+        (void) bind_mount_submounts(bind_source, entry_path);
         return 0;
 }
 
+static int mount_private_sysfs(const MountEntry *m) {
+        assert(m);
+        return mount_private_apivfs("sysfs", mount_entry_path(m), "/sys", /* opts = */ NULL);
+}
+
 static int mount_procfs(const MountEntry *m, const NamespaceParameters *p) {
         _cleanup_free_ char *opts = NULL;
-        const char *entry_path;
-        int r, n;
 
         assert(m);
         assert(p);
@@ -1226,49 +1253,11 @@ static int mount_procfs(const MountEntry *m, const NamespaceParameters *p) {
                                 return -ENOMEM;
         }
 
-        entry_path = mount_entry_path(m);
-        (void) mkdir_p_label(entry_path, 0755);
-
         /* Mount a new instance, so that we get the one that matches our user namespace, if we are running in
          * one. i.e we don't reuse existing mounts here under any condition, we want a new instance owned by
          * our user namespace and with our hidepid= settings applied. Hence, let's get rid of everything
          * mounted on /proc/ first. */
-
-        n = umount_recursive(entry_path, 0);
-
-        r = mount_nofollow_verbose(LOG_DEBUG, "proc", entry_path, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, opts);
-        if (r == -EINVAL && opts)
-                /* If this failed with EINVAL then this likely means the textual hidepid= stuff is
-                 * not supported by the kernel, and thus the per-instance hidepid= neither, which
-                 * means we really don't want to use it, since it would affect our host's /proc
-                 * mount. Hence let's gracefully fallback to a classic, unrestricted version. */
-                r = mount_nofollow_verbose(LOG_DEBUG, "proc", entry_path, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL);
-        if (ERRNO_IS_NEG_PRIVILEGE(r)) {
-                /* When we do not have enough privileges to mount /proc, fall back to use existing /proc. */
-
-                if (n > 0)
-                        /* /proc or some of sub-mounts are umounted in the above. Refuse incomplete tree.
-                         * Propagate the original error code returned by mount() in the above. */
-                        return r;
-
-                r = path_is_mount_point(entry_path, NULL, 0);
-                if (r < 0)
-                        return log_debug_errno(r, "Unable to determine whether /proc is already mounted: %m");
-                if (r > 0)
-                        return 0;
-
-                /* We lack permissions to mount a new instance of /proc, and it is not already mounted. But
-                 * we can access the host's, so as a final fallback bind-mount it to the destination, as most
-                 * likely we are inside a user manager in an unprivileged user namespace. */
-                return mount_nofollow_verbose(LOG_DEBUG, "/proc", entry_path, NULL, MS_BIND|MS_REC, NULL);
-
-        } else if (r < 0)
-                return r;
-
-        /* We mounted a new instance now. Let's bind mount the children over now. This matters for nspawn
-         * where a bunch of files are overmounted, in particular the boot id */
-        (void) bind_mount_submounts("/proc", entry_path);
-        return 0;
+        return mount_private_apivfs("proc", mount_entry_path(m), "/proc", opts);
 }
 
 static int mount_tmpfs(const MountEntry *m) {