]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sysupdate: don't get confused by sysext on /usr/ 36617/head
authorLennart Poettering <lennart@poettering.net>
Wed, 5 Mar 2025 13:23:17 +0000 (14:23 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 6 Mar 2025 09:27:55 +0000 (10:27 +0100)
Fixes: #24562
src/sysupdate/sysupdate-resource.c

index 2f7a0880924a860ecf627b67e47a19faa49430d2..842722c68259379dbd597170fd1e8c9f877b4524 100644 (file)
@@ -20,6 +20,7 @@
 #include "hexdecoct.h"
 #include "import-util.h"
 #include "macro.h"
+#include "missing_magic.h"
 #include "process-util.h"
 #include "sort-util.h"
 #include "string-table.h"
@@ -552,6 +553,47 @@ Instance* resource_find_instance(Resource *rr, const char *version) {
         return *found;
 }
 
+static int get_sysext_overlay_block(const char *p, dev_t *ret) {
+        int r;
+
+        assert(p);
+        assert(ret);
+
+        /* Tries to read the backing device information systemd-sysext puts in the virtual file
+         * /usr/.systemd-sysext/backing */
+
+        _cleanup_free_ char *j = path_join(p, ".systemd-sysext");
+        if (!j)
+                return log_oom_debug();
+
+        _cleanup_close_ int fd = open(j, O_RDONLY|O_DIRECTORY);
+        if (fd < 0)
+                return log_debug_errno(errno, "Failed to open '%s': %m", j);
+
+        r = fd_is_fs_type(fd, OVERLAYFS_SUPER_MAGIC);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to determine backing file system of '%s': %m", j);
+        if (r == 0)
+                return log_debug_errno(SYNTHETIC_ERRNO(ENOTTY), "Backing file system of '%s' is not an overlayfs.", j);
+
+        _cleanup_free_ char *buf = NULL;
+        r = read_one_line_file_at(fd, "backing", &buf);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to read contents of '%s/backing': %m", j);
+
+        r = parse_devnum(buf, ret);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to parse contents of '%s/backing': %m", j);
+
+        if (major(*ret) == 0) { /* not a block device? */
+                *ret = 0;
+                return 0;
+        }
+
+        (void) block_get_originating(*ret, ret);
+        return 1;
+}
+
 int resource_resolve_path(
                 Resource *rr,
                 const char *root,
@@ -571,8 +613,6 @@ int resource_resolve_path(
                                        path_relative_to_to_string(rr->path_relative_to));
 
         if (rr->path_auto) {
-                struct stat orig_root_stats;
-
                 /* NB: If the root mount has been replaced by some form of volatile file system (overlayfs),
                  * the original root block device node is symlinked in /run/systemd/volatile-root. Let's
                  * follow that link here. If that doesn't exist, we check the backing device of "/usr". We
@@ -596,12 +636,18 @@ int resource_resolve_path(
                         return log_error_errno(SYNTHETIC_ERRNO(EPERM),
                                                "Block device is not allowed when using --root= mode.");
 
-                r = stat("/run/systemd/volatile-root", &orig_root_stats);
+                struct stat orig_root_stats;
+                r = RET_NERRNO(stat("/run/systemd/volatile-root", &orig_root_stats));
                 if (r < 0) {
-                        if (errno == ENOENT) /* volatile-root not found */
-                                r = get_block_device_harder("/usr/", &d);
-                        else
+                        if (r != -ENOENT)
                                 return log_error_errno(r, "Failed to stat /run/systemd/volatile-root: %m");
+
+                        /* volatile-root not found */
+                        r = get_block_device_harder("/usr/", &d);
+                        if (r == 0) /* Not backed by a block device? Let's see if this is a sysext overlayfs instance */
+                                r = get_sysext_overlay_block("/usr/", &d);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to determine block device of file system: %m");
                 } else if (!S_ISBLK(orig_root_stats.st_mode)) /* symlink was present but not block device */
                         return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "/run/systemd/volatile-root is not linked to a block device.");
                 else /* symlink was present and a block device */
@@ -643,7 +689,9 @@ int resource_resolve_path(
                 if (real_fd < 0)
                         return log_error_errno(real_fd, "Failed to convert O_PATH file descriptor for %s to regular file descriptor: %m", rr->path);
 
-                r = get_block_device_harder_fd(fd, &d);
+                r = get_block_device_harder_fd(real_fd, &d);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to determine block device of file system: %m");
 
         } else if (RESOURCE_IS_FILESYSTEM(rr->type)) {
                 _cleanup_free_ char *resolved = NULL, *relative_to = NULL;
@@ -682,9 +730,6 @@ int resource_resolve_path(
         } else
                 return 0; /* Otherwise assume there's nothing to resolve */
 
-        if (r < 0)
-                return log_error_errno(r, "Failed to determine block device of file system: %m");
-
         r = block_get_whole_disk(d, &d);
         if (r < 0)
                 return log_error_errno(r, "Failed to find whole disk device for partition backing file system: %m");