From: Lennart Poettering Date: Tue, 19 Jan 2021 18:57:13 +0000 (+0100) Subject: sysext: split version validation logic into function of its own X-Git-Tag: v248-rc1~285^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9901835d80adc6358a7092d3cb3bbd7689d63caa;p=thirdparty%2Fsystemd.git sysext: split version validation logic into function of its own Just some simple refactoring to simplify the logic. --- diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index 17b8dcd2fcc..e54f1845f82 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -399,6 +399,71 @@ static int strverscmpp(char *const* a, char *const* b) { return strverscmp(*a, *b); } +static int validate_version( + const char *root, + const char *name, + const char *host_os_release_id, + const char *host_os_release_version_id, + const char *host_os_release_sysext_level) { + + _cleanup_free_ char *extension_release_id = NULL, *extension_release_version_id = NULL, *extension_release_sysext_level = NULL; + int r; + + assert(root); + assert(name); + + /* Insist that extension images do not overwrite the underlying OS release file (it's fine if + * they place one in /etc/os-release, i.e. where things don't matter, as they aren't + * merged.) */ + r = chase_symlinks("/usr/lib/os-release", root, CHASE_PREFIX_ROOT, NULL, NULL); + if (r < 0) { + if (r != -ENOENT) + return log_error_errno(r, "Failed to determine whether /usr/lib/os-release exists in the extension image: %m"); + } else + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Extension image contains /usr/lib/os-release file, which is not allowed (it may carry /etc/os-release), refusing."); + + /* Now that we can look into the extension image, let's see if the OS version is compatible */ + r = parse_extension_release( + root, + name, + "ID", &extension_release_id, + "VERSION_ID", &extension_release_version_id, + "SYSEXT_LEVEL", &extension_release_sysext_level, + NULL); + if (r == -ENOENT) { + log_notice_errno(r, "Extension '%s' carries no extension-release data, ignoring extension.", name); + return 0; + } + if (r < 0) + return log_error_errno(r, "Failed to acquire 'os-release' data of extension '%s': %m", name); + + if (!streq_ptr(host_os_release_id, extension_release_id)) { + log_notice("Extension '%s' is for OS '%s', but running on '%s', ignoring extension.", + name, strna(extension_release_id), strna(host_os_release_id)); + return 0; + } + + /* If the extension has a sysext API level declared, then it must match the host API + * level. Otherwise, compare OS version as a whole */ + if (extension_release_sysext_level) { + if (!streq_ptr(host_os_release_sysext_level, extension_release_sysext_level)) { + log_notice("Extension '%s' is for sysext API level '%s', but running on sysext API level '%s', ignoring extension.", + name, extension_release_sysext_level, strna(host_os_release_sysext_level)); + return 0; + } + } else { + if (!streq_ptr(host_os_release_version_id, extension_release_version_id)) { + log_notice("Extension '%s' is for OS version '%s', but running on OS version '%s', ignoring extension.", + name, extension_release_version_id, strna(host_os_release_version_id)); + return 0; + } + } + + log_debug("Version info of extension '%s' matches host.", name); + return 1; +} + static int merge_subprocess(Hashmap *images, const char *workspace) { _cleanup_free_ char *host_os_release_id = NULL, *host_os_release_version_id = NULL, *host_os_release_sysext_level = NULL, *buf = NULL; @@ -440,8 +505,7 @@ static int merge_subprocess(Hashmap *images, const char *workspace) { /* Let's now mount all images */ HASHMAP_FOREACH(img, images) { - _cleanup_free_ char *p = NULL, - *extension_release_id = NULL, *extension_release_version_id = NULL, *extension_release_sysext_level = NULL; + _cleanup_free_ char *p = NULL; p = path_join(workspace, "extensions", img->name); if (!p) @@ -523,57 +587,17 @@ static int merge_subprocess(Hashmap *images, const char *workspace) { assert_not_reached("Unsupported image type"); } - /* Insist that extension images do not overwrite the underlying OS release file (it's fine if - * they place one in /etc/os-release, i.e. where things don't matter, as they aren't - * merged.) */ - r = chase_symlinks("/usr/lib/os-release", p, CHASE_PREFIX_ROOT, NULL, NULL); - if (r < 0) { - if (r != -ENOENT) - return log_error_errno(r, "Failed to determine whether /usr/lib/os-release exists in the extension image: %m"); - } else - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Extension image contains /usr/lib/os-release file, which is not allowed (it may carry /etc/os-release), refusing."); - - /* Now that we can look into the extension image, let's see if the OS version is compatible */ - r = parse_extension_release( + r = validate_version( p, img->name, - "ID", &extension_release_id, - "VERSION_ID", &extension_release_version_id, - "SYSEXT_LEVEL", &extension_release_sysext_level, - NULL); - if (r == -ENOENT) { - log_notice_errno(r, "Extension '%s' carries no extension-release data, ignoring extension.", img->name); + host_os_release_id, + host_os_release_version_id, + host_os_release_sysext_level); + if (r < 0) + return r; + if (r == 0) { n_ignored++; continue; - } else if (r < 0) - return log_error_errno(r, "Failed to acquire 'os-release' data of extension '%s': %m", img->name); - else { - if (!streq_ptr(host_os_release_id, extension_release_id)) { - log_notice("Extension '%s' is for OS '%s', but running on '%s', ignoring extension.", - img->name, strna(extension_release_id), strna(host_os_release_id)); - n_ignored++; - continue; - } - - /* If the extension has a sysext API level declared, then it must match the host API level. Otherwise, compare OS version as a whole */ - if (extension_release_sysext_level) { - if (!streq_ptr(host_os_release_sysext_level, extension_release_sysext_level)) { - log_notice("Extension '%s' is for sysext API level '%s', but running on sysext API level '%s', ignoring extension.", - img->name, extension_release_sysext_level, strna(host_os_release_sysext_level)); - n_ignored++; - continue; - } - } else { - if (!streq_ptr(host_os_release_version_id, extension_release_version_id)) { - log_notice("Extension '%s' is for OS version '%s', but running on OS version '%s', ignoring extension.", - img->name, extension_release_version_id, strna(host_os_release_version_id)); - n_ignored++; - continue; - } - } - - log_debug("Version info of extension '%s' matches host.", img->name); } /* Noice! This one is an extension we want. */