From: Lennart Poettering Date: Wed, 5 Mar 2025 13:23:17 +0000 (+0100) Subject: sysupdate: don't get confused by sysext on /usr/ X-Git-Tag: v258-rc1~1164^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F36617%2Fhead;p=thirdparty%2Fsystemd.git sysupdate: don't get confused by sysext on /usr/ Fixes: #24562 --- diff --git a/src/sysupdate/sysupdate-resource.c b/src/sysupdate/sysupdate-resource.c index 2f7a0880924..842722c6825 100644 --- a/src/sysupdate/sysupdate-resource.c +++ b/src/sysupdate/sysupdate-resource.c @@ -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");