]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
confext: add dissect tool support for confext images
authorMaanya Goenka <maanyagoenka@microsoft.com>
Thu, 13 Jul 2023 22:07:49 +0000 (22:07 +0000)
committerMaanya Goenka <maanyagoenka@microsoft.com>
Fri, 14 Jul 2023 16:59:34 +0000 (16:59 +0000)
Allow image wide systemd tool support for confext images by adding dissect
tool support for these images

src/basic/os-util.h
src/dissect/dissect.c
src/portable/portable.c
src/shared/dissect-image.c
src/shared/dissect-image.h
src/sysext/sysext.c
src/test/test-image-policy.c

index 480f71e614c769eb1506c4b37a62327c3960842a..11afc4c6cab141ef89747a6d04cc6913d73f6ed2 100644 (file)
@@ -19,6 +19,7 @@ const char* image_class_to_string(ImageClass cl) _const_;
 ImageClass image_class_from_string(const char *s) _pure_;
 
 /* The *_extension_release flavours will look for /usr/lib/extension-release/extension-release.NAME
+ * for sysext images and for /etc/extension-release.d/extension-release.NAME for confext images
  * in accordance with the OS extension specification, rather than for /usr/lib/ or /etc/os-release. */
 
 bool image_name_is_valid(const char *s) _pure_;
index 893fa4f03402e87df4311c81ae6d0aed144bada0..4b830bf2a66da357270409bf2318ae8dbee09b69 100644 (file)
@@ -782,22 +782,24 @@ static void strv_pair_print(char **l, const char *prefix) {
                         printf("%*s %s=%s\n", (int) strlen(prefix), "", *p, *q);
 }
 
-static int get_sysext_scopes(DissectedImage *m, char ***ret_scopes) {
+static int get_extension_scopes(DissectedImage *m, char ***ret_scopes) {
         _cleanup_strv_free_ char **l = NULL;
         const char *e;
 
         assert(m);
         assert(ret_scopes);
 
-        /* If there's no extension-release file its not a system extension. Otherwise the SYSEXT_SCOPE field
-         * indicates which scope it is for — and it defaults to "system" + "portable" if unset. */
-
+        /* If there's no extension-release file its not a system extension. Otherwise the SYSEXT_SCOPE
+         * field for sysext images and the CONFEXT_SCOPE field for confext images indicates which scope
+         * it is for — and it defaults to "system" + "portable" if unset. */
         if (!m->extension_release) {
                 *ret_scopes = NULL;
                 return 0;
         }
 
         e = strv_env_pairs_get(m->extension_release, "SYSEXT_SCOPE");
+        if (!e)
+                e = strv_env_pairs_get(m->extension_release, "CONFEXT_SCOPE");
         if (e)
                 l = strv_split(e, WHITESPACE);
         else
@@ -858,7 +860,7 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
         else if (r < 0)
                 return log_error_errno(r, "Failed to acquire image metadata: %m");
         else if (arg_json_format_flags & JSON_FORMAT_OFF) {
-                _cleanup_strv_free_ char **sysext_scopes = NULL;
+                _cleanup_strv_free_ char **extension_scopes = NULL;
 
                 if (!sd_id128_is_null(m->image_uuid))
                         printf("Image UUID: %s\n", SD_ID128_TO_UUID_STRING(m->image_uuid));
@@ -896,21 +898,22 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
                 printf("            %s initrd\n",
                        COLOR_MARK_BOOL(!strv_isempty(m->initrd_release)));
 
-                r = get_sysext_scopes(m, &sysext_scopes);
+                r = get_extension_scopes(m, &extension_scopes);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to parse SYSEXT_SCOPE: %m");
+                        return log_error_errno(r, "Failed to parse scope: %m");
 
-                printf("            %s extension for system\n",
-                       COLOR_MARK_BOOL(strv_contains(sysext_scopes, "system")));
-                printf("            %s extension for initrd\n",
-                       COLOR_MARK_BOOL(strv_contains(sysext_scopes, "initrd")));
-                printf("            %s extension for portable service\n",
-                       COLOR_MARK_BOOL(strv_contains(sysext_scopes, "portable")));
+                const char *string_class = image_class_to_string(m->image_class);
+                printf("            %s %s extension for system\n",
+                        COLOR_MARK_BOOL(strv_contains(extension_scopes, "system")), string_class);
+                printf("            %s %s extension for initrd\n",
+                        COLOR_MARK_BOOL(strv_contains(extension_scopes, "initrd")), string_class);
+                printf("            %s %s extension for portable service\n",
+                        COLOR_MARK_BOOL(strv_contains(extension_scopes, "portable")), string_class);
 
                 putc('\n', stdout);
         } else {
                 _cleanup_(json_variant_unrefp) JsonVariant *mi = NULL, *osr = NULL, *irdr = NULL, *exr = NULL;
-                _cleanup_strv_free_ char **sysext_scopes = NULL;
+                _cleanup_strv_free_ char **extension_scopes = NULL;
 
                 if (!strv_isempty(m->machine_info)) {
                         r = strv_pair_to_json(m->machine_info, &mi);
@@ -936,9 +939,9 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
                                 return log_oom();
                 }
 
-                r = get_sysext_scopes(m, &sysext_scopes);
+                r = get_extension_scopes(m, &extension_scopes);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to parse SYSEXT_SCOPE: %m");
+                        return log_error_errno(r, "Failed to parse scope: %m");
 
                 r = json_build(&v, JSON_BUILD_OBJECT(
                                                JSON_BUILD_PAIR("name", JSON_BUILD_STRING(bn)),
@@ -955,9 +958,10 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
                                                JSON_BUILD_PAIR_CONDITION(m->has_init_system >= 0, "useBootableContainer", JSON_BUILD_BOOLEAN(m->has_init_system)),
                                                JSON_BUILD_PAIR("useInitrd", JSON_BUILD_BOOLEAN(!strv_isempty(m->initrd_release))),
                                                JSON_BUILD_PAIR("usePortableService", JSON_BUILD_BOOLEAN(strv_env_pairs_get(m->os_release, "PORTABLE_MATCHES"))),
-                                               JSON_BUILD_PAIR("useSystemExtension", JSON_BUILD_BOOLEAN(strv_contains(sysext_scopes, "system"))),
-                                               JSON_BUILD_PAIR("useInitRDExtension", JSON_BUILD_BOOLEAN(strv_contains(sysext_scopes, "initrd"))),
-                                               JSON_BUILD_PAIR("usePortableExtension", JSON_BUILD_BOOLEAN(strv_contains(sysext_scopes, "portable")))));
+                                               JSON_BUILD_PAIR("ExtensionType", JSON_BUILD_STRING(image_class_to_string(m->image_class))),
+                                               JSON_BUILD_PAIR("useSystemExtension", JSON_BUILD_BOOLEAN(strv_contains(extension_scopes, "system"))),
+                                               JSON_BUILD_PAIR("useInitRDExtension", JSON_BUILD_BOOLEAN(strv_contains(extension_scopes, "initrd"))),
+                                               JSON_BUILD_PAIR("usePortableExtension", JSON_BUILD_BOOLEAN(strv_contains(extension_scopes, "portable")))));
                 if (r < 0)
                         return log_oom();
         }
index 52b8a5ba83141b54047f6bd6fc791cf511e22f2a..5891547b90ec967ac08ee4dabef18771f49ebb4f 100644 (file)
@@ -420,7 +420,7 @@ static int portable_extract_by_path(
                         seq[0] = safe_close(seq[0]);
 
                         if (path_is_extension)
-                                flags |= DISSECT_IMAGE_VALIDATE_OS_EXT | (relax_extension_release_check ? DISSECT_IMAGE_RELAX_SYSEXT_CHECK : 0);
+                                flags |= DISSECT_IMAGE_VALIDATE_OS_EXT | (relax_extension_release_check ? DISSECT_IMAGE_RELAX_EXTENSION_CHECK : 0);
                         else
                                 flags |= DISSECT_IMAGE_VALIDATE_OS;
 
index 44e77f932825004f99b8284c73be463af233cf0e..6334c0cd22e86b89159e50c78b7d7f61bc5c7d6b 100644 (file)
@@ -2102,7 +2102,9 @@ int dissected_image_mount(
                                 if (r < 0)
                                         return r;
                                 if (r == 0) {
-                                        r = path_is_extension_tree(IMAGE_SYSEXT, where, m->image_name, FLAGS_SET(flags, DISSECT_IMAGE_RELAX_SYSEXT_CHECK));
+                                        r = path_is_extension_tree(IMAGE_SYSEXT, where, m->image_name, FLAGS_SET(flags, DISSECT_IMAGE_RELAX_EXTENSION_CHECK));
+                                        if (r == 0)
+                                                r = path_is_extension_tree(IMAGE_CONFEXT, where, m->image_name, FLAGS_SET(flags, DISSECT_IMAGE_RELAX_EXTENSION_CHECK));
                                         if (r < 0)
                                                 return r;
                                         if (r > 0)
@@ -3295,10 +3297,12 @@ int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_
         int fds[2 * _META_MAX], r, v;
         int has_init_system = -1;
         ssize_t n;
+        ImageClass image_class = IMAGE_SYSEXT;
 
         BLOCK_SIGNALS(SIGCHLD);
 
         assert(m);
+        assert(image_class);
 
         for (; n_meta_initialized < _META_MAX; n_meta_initialized ++) {
                 if (!paths[n_meta_initialized]) {
@@ -3352,7 +3356,7 @@ int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_
 
                         switch (k) {
 
-                        case META_EXTENSION_RELEASE:
+                        case META_EXTENSION_RELEASE: {
                                 /* As per the os-release spec, if the image is an extension it will have a file
                                  * named after the image name in extension-release.d/ - we use the image name
                                  * and try to resolve it with the extension-release helpers, as sometimes
@@ -3362,10 +3366,23 @@ int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_
                                  * we allow a fallback that matches on the first extension-release
                                  * file found in the directory, if one named after the image cannot
                                  * be found first. */
+                                ImageClass class = IMAGE_SYSEXT;
                                 r = open_extension_release(t, IMAGE_SYSEXT, m->image_name, /* relax_extension_release_check= */ false, NULL, &fd);
+                                if (r == -ENOENT) {
+                                        r = open_extension_release(t, IMAGE_CONFEXT, m->image_name, /* relax_extension_release_check= */ false, NULL, &fd);
+                                        if (r >= 0)
+                                                class = IMAGE_CONFEXT;
+                                }
                                 if (r < 0)
-                                        fd = r; /* Propagate the error. */
+                                        fd = r;
+                                else {
+                                        r = loop_write(fds[2*k+1], &class, sizeof(class), false);
+                                        if (r < 0)
+                                                goto inner_fail; /* Propagate the error to the parent */
+                                }
+
                                 break;
+                        }
 
                         case META_HAS_INIT_SYSTEM: {
                                 bool found = false;
@@ -3487,12 +3504,23 @@ int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_
 
                         break;
 
-                case META_EXTENSION_RELEASE:
-                        r = load_env_file_pairs(f, "extension-release", &extension_release);
-                        if (r < 0)
-                                log_debug_errno(r, "Failed to read extension release file of image: %m");
+                case META_EXTENSION_RELEASE: {
+                        ImageClass cl = IMAGE_SYSEXT;
+                        size_t nr;
+
+                        errno = 0;
+                        nr = fread(&cl, 1, sizeof(cl), f);
+                        if (nr != sizeof(cl))
+                                log_debug_errno(errno_or_else(EIO), "Failed to read class of extension image: %m");
+                        else {
+                                image_class = cl;
+                                r = load_env_file_pairs(f, "extension-release", &extension_release);
+                                if (r < 0)
+                                        log_debug_errno(r, "Failed to read extension release file of image: %m");
+                        }
 
                         break;
+                }
 
                 case META_HAS_INIT_SYSTEM: {
                         bool b = false;
@@ -3532,6 +3560,7 @@ int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_
         strv_free_and_replace(m->initrd_release, initrd_release);
         strv_free_and_replace(m->extension_release, extension_release);
         m->has_init_system = has_init_system;
+        m->image_class = image_class;
 
 finish:
         for (unsigned k = 0; k < n_meta_initialized; k++)
@@ -3820,7 +3849,7 @@ int verity_dissect_and_mount(
                 return log_debug_errno(r, "Failed to load root hash: %m");
 
         dissect_image_flags = (verity.data_path ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0) |
-                (relax_extension_release_check ? DISSECT_IMAGE_RELAX_SYSEXT_CHECK : 0) |
+                (relax_extension_release_check ? DISSECT_IMAGE_RELAX_EXTENSION_CHECK : 0) |
                 DISSECT_IMAGE_ADD_PARTITION_DEVICES |
                 DISSECT_IMAGE_PIN_PARTITION_DEVICES;
 
@@ -3889,10 +3918,16 @@ int verity_dissect_and_mount(
          * then a simple match on the ID will be performed. */
         if (required_host_os_release_id) {
                 _cleanup_strv_free_ char **extension_release = NULL;
+                ImageClass class = IMAGE_SYSEXT;
 
                 assert(!isempty(required_host_os_release_id));
 
                 r = load_extension_release_pairs(dest, IMAGE_SYSEXT, dissected_image->image_name, relax_extension_release_check, &extension_release);
+                if (r == -ENOENT) {
+                        r = load_extension_release_pairs(dest, IMAGE_CONFEXT, dissected_image->image_name, relax_extension_release_check, &extension_release);
+                        if (r >= 0)
+                                class = IMAGE_CONFEXT;
+                }
                 if (r < 0)
                         return log_debug_errno(r, "Failed to parse image %s extension-release metadata: %m", dissected_image->image_name);
 
@@ -3903,7 +3938,7 @@ int verity_dissect_and_mount(
                                 required_host_os_release_sysext_level,
                                 required_sysext_scope,
                                 extension_release,
-                                IMAGE_SYSEXT);
+                                class);
                 if (r == 0)
                         return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "Image %s extension-release metadata does not match the root's", dissected_image->image_name);
                 if (r < 0)
index 184e6151ed386635692673064b92fad5dddc2b7c..508085fd1a75ad42daa92f060eb4a02562efde33 100644 (file)
@@ -10,6 +10,7 @@
 #include "list.h"
 #include "loop-util.h"
 #include "macro.h"
+#include "os-util.h"
 
 typedef struct DissectedImage DissectedImage;
 typedef struct DissectedPartition DissectedPartition;
@@ -78,7 +79,7 @@ typedef enum DissectImageFlags {
         DISSECT_IMAGE_MOUNT_IDMAPPED           = 1 << 19, /* Mount mounts with kernel 5.12-style userns ID mapping, if file system type doesn't support uid=/gid= */
         DISSECT_IMAGE_ADD_PARTITION_DEVICES    = 1 << 20, /* Create partition devices via BLKPG_ADD_PARTITION */
         DISSECT_IMAGE_PIN_PARTITION_DEVICES    = 1 << 21, /* Open dissected partitions and decrypted partitions and pin them by fd */
-        DISSECT_IMAGE_RELAX_SYSEXT_CHECK       = 1 << 22, /* Don't insist that the extension-release file name matches the image name */
+        DISSECT_IMAGE_RELAX_EXTENSION_CHECK    = 1 << 22, /* Don't insist that the extension-release file name matches the image name */
         DISSECT_IMAGE_DISKSEQ_DEVNODE          = 1 << 23, /* Prefer /dev/disk/by-diskseq/… device nodes */
         DISSECT_IMAGE_ALLOW_EMPTY              = 1 << 24, /* Allow that no usable partitions is present */
 } DissectImageFlags;
@@ -107,6 +108,7 @@ struct DissectedImage {
         char **initrd_release;
         char **extension_release;
         int has_init_system;
+        ImageClass image_class;
 };
 
 struct MountOptions {
index ec231da7a80964a3b9e7531db787ccc627c8d2c4..b043eac562c38058c3d108c7fb86451d21f27aa1 100644 (file)
@@ -803,7 +803,7 @@ static int image_discover_and_read_metadata(Hashmap **ret_images) {
                 return log_error_errno(r, "Failed to discover images: %m");
 
         HASHMAP_FOREACH(img, images) {
-                r = image_read_metadata(img, &image_policy_sysext);
+                r = image_read_metadata(img, image_class_info[arg_image_class].default_image_policy);
                 if (r < 0)
                         return log_error_errno(r, "Failed to read metadata for image %s: %m", img->name);
         }
index f2eba949614c6a72bf7d7e48209863666eaa02d1..d9fe5562a1be1af27ae322c86887e50264116822 100644 (file)
@@ -78,6 +78,7 @@ TEST_RET(test_image_policy_to_string) {
         test_policy(&image_policy_deny, "~");
         test_policy(&image_policy_sysext, "sysext");
         test_policy(&image_policy_sysext_strict, "sysext-strict");
+        test_policy(&image_policy_confext, "confext");
         test_policy(&image_policy_container, "container");
         test_policy(&image_policy_host, "host");
         test_policy(&image_policy_service, "service");