]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
extension-release.d/: add a new field SYSEXT_SCOPE= for clarifying what a system...
authorLennart Poettering <lennart@poettering.net>
Thu, 18 Nov 2021 21:00:31 +0000 (22:00 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 23 Nov 2021 21:55:11 +0000 (22:55 +0100)
This should make things a bit more robust since it ensures system
extension can only applied to the right environments. Right now three
different "scopes" are defined:

1. "system" (for regular OS systems, after the initrd transition)
2. "initrd" (for sysext images that apply to the initrd environment)
3. "portable" (for sysext images that apply to portable images)

If not specified we imply a default of "system portable", i.e. any image
where the field is not specified is implicitly OK for application to OS
images and for portable services – but not for initrds.

man/os-release.xml
src/core/namespace.c
src/portable/portable.c
src/shared/dissect-image.c
src/shared/dissect-image.h
src/shared/extension-release.c
src/shared/extension-release.h
src/shared/mount-util.c
src/sysext/sysext.c

index ef5ef8b2e143addbe7643f9023120b464bc9f390..a985151b4d4658c734456cdba1021c6ec3a7ca64 100644 (file)
           <para>Examples: <literal>SYSEXT_LEVEL=2</literal>, <literal>SYSEXT_LEVEL=15.14</literal>.
           </para></listitem>
         </varlistentry>
+
+        <varlistentry>
+          <term><varname>SYSEXT_SCOPE=</varname></term>
+          <listitem><para>Takes a space-separated list of one or more of the strings
+          <literal>system</literal>, <literal>initrd</literal> and <literal>portable</literal>. This field is
+          only supported in <filename>extension-release.d/</filename> files and indicates what environments
+          the system extension is applicable to: i.e. to regular systems, to initial RAM filesystems
+          ("initrd") or to portable service images. If unspecified, <literal>SYSEXT_SCOPE=system
+          portable</literal> is implied, i.e. any system extension without this field is applicable to
+          regular systems and to portable service environments, but not to initrd
+          environments.</para></listitem>
+        </varlistentry>
       </variablelist>
     </refsect2>
 
index c8e7e65e2722cd2b5a9a5d8d61dcaefe800899c5..9393a202c47f7adcd22499d3f48a7a17ddd43193 100644 (file)
@@ -1149,7 +1149,7 @@ static int mount_image(const MountEntry *m, const char *root_directory) {
 
         r = verity_dissect_and_mount(
                                 mount_entry_source(m), mount_entry_path(m), m->image_options,
-                                host_os_release_id, host_os_release_version_id, host_os_release_sysext_level);
+                                host_os_release_id, host_os_release_version_id, host_os_release_sysext_level, NULL);
         if (r == -ENOENT && m->ignore)
                 return 0;
         if (r == -ESTALE && host_os_release_id)
index 8ccb8f5228ed4eb829c2017e69dc9a55eafb3a1f..612893b688b3db9af7607c74307f84797f7a6636 100644 (file)
@@ -595,7 +595,7 @@ static int extract_image_and_extensions(
                 if (r < 0)
                         return r;
 
-                r = extension_release_validate(ext->path, id, version_id, sysext_level, extension_release);
+                r = extension_release_validate(ext->path, id, version_id, sysext_level, "portable", extension_release);
                 if (r == 0)
                         return sd_bus_error_set_errnof(error, SYNTHETIC_ERRNO(ESTALE), "Image %s extension-release metadata does not match the root's", ext->path);
                 if (r < 0)
index b92df413a930d46caaa259987a9909adba2a3b77..06d0319f7509b87fb85557f7dc43d5bab4ec8fb1 100644 (file)
@@ -3525,7 +3525,8 @@ int verity_dissect_and_mount(
                 const MountOptions *options,
                 const char *required_host_os_release_id,
                 const char *required_host_os_release_version_id,
-                const char *required_host_os_release_sysext_level) {
+                const char *required_host_os_release_sysext_level,
+                const char *required_sysext_scope) {
 
         _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
         _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
@@ -3611,11 +3612,12 @@ int verity_dissect_and_mount(
                         return log_debug_errno(r, "Failed to parse image %s extension-release metadata: %m", dissected_image->image_name);
 
                 r = extension_release_validate(
-                        dissected_image->image_name,
-                        required_host_os_release_id,
-                        required_host_os_release_version_id,
-                        required_host_os_release_sysext_level,
-                        extension_release);
+                                dissected_image->image_name,
+                                required_host_os_release_id,
+                                required_host_os_release_version_id,
+                                required_host_os_release_sysext_level,
+                                required_sysext_scope,
+                                extension_release);
                 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 b75b86ab99bf7ecfb8ff9e2444ba57e8059358b8..8ad26bc45b6c7684bc9e878dbbc44a1887d2550d 100644 (file)
@@ -228,4 +228,4 @@ bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesi
 
 int mount_image_privately_interactively(const char *path, DissectImageFlags flags, char **ret_directory, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image);
 
-int verity_dissect_and_mount(const char *src, const char *dest, const MountOptions *options, const char *required_host_os_release_id, const char *required_host_os_release_version_id, const char *required_host_os_release_sysext_level);
+int verity_dissect_and_mount(const char *src, const char *dest, const MountOptions *options, const char *required_host_os_release_id, const char *required_host_os_release_version_id, const char *required_host_os_release_sysext_level, const char *required_sysext_scope);
index 29cbecbf57d02a5f6a359b55749668474d1e70a3..dccc9999079a267ee5d07036936878d9e920b24e 100644 (file)
@@ -12,6 +12,7 @@ int extension_release_validate(
                 const char *host_os_release_id,
                 const char *host_os_release_version_id,
                 const char *host_os_release_sysext_level,
+                const char *host_sysext_scope,
                 char **extension_release) {
 
         const char *extension_release_id = NULL, *extension_release_sysext_level = NULL;
@@ -25,6 +26,28 @@ int extension_release_validate(
                 return 0;
         }
 
+        if (host_sysext_scope) {
+                _cleanup_strv_free_ char **extension_sysext_scope_list = NULL;
+                const char *extension_sysext_scope;
+                bool valid;
+
+                extension_sysext_scope = strv_env_pairs_get(extension_release, "SYSEXT_SCOPE");
+                if (extension_sysext_scope) {
+                        extension_sysext_scope_list = strv_split(extension_sysext_scope, WHITESPACE);
+                        if (!extension_sysext_scope_list)
+                                return -ENOMEM;
+                }
+
+                /* by default extension are good for attachment in portable service and on the system */
+                valid = strv_contains(
+                                extension_sysext_scope_list ?: STRV_MAKE("system", "portable"),
+                                host_sysext_scope);
+                if (!valid) {
+                        log_debug("Extension '%s' is not suitable for scope %s, ignoring extension.", name, host_sysext_scope);
+                        return 0;
+                }
+        }
+
         extension_release_id = strv_env_pairs_get(extension_release, "ID");
         if (isempty(extension_release_id)) {
                 log_debug("Extension '%s' does not contain ID in extension-release but requested to match '%s'",
index d026a9b225b6ca74d62a155af31d43f6c3ff173f..5c3fee24bef99319cc410409d69a03a6a382c340 100644 (file)
@@ -9,6 +9,7 @@ int extension_release_validate(
                 const char *host_os_release_id,
                 const char *host_os_release_version_id,
                 const char *host_os_release_sysext_level,
+                const char *host_sysext_scope,
                 char **extension_release);
 
 /* Parse SYSTEMD_SYSEXT_HIERARCHIES and if not set, return "/usr /opt" */
index 8d4a6cd25a3693620e2b181c0190dbee69ec6f21..c75c02f5be3210e127a7efee5f026c8d9db3da98 100644 (file)
@@ -874,7 +874,7 @@ static int mount_in_namespace(
         mount_tmp_created = true;
 
         if (is_image)
-                r = verity_dissect_and_mount(FORMAT_PROC_FD_PATH(chased_src_fd), mount_tmp, options, NULL, NULL, NULL);
+                r = verity_dissect_and_mount(FORMAT_PROC_FD_PATH(chased_src_fd), mount_tmp, options, NULL, NULL, NULL, NULL);
         else
                 r = mount_follow_verbose(LOG_DEBUG, FORMAT_PROC_FD_PATH(chased_src_fd), mount_tmp, NULL, MS_BIND, NULL);
         if (r < 0)
index b9387e904a62528354a4ee63257e595fda7e8116..5abf1bb418389223c82ab5e05730cae5e8cb1511 100644 (file)
@@ -432,12 +432,17 @@ static int validate_version(
                 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.");
 
-        return extension_release_validate(
+        r = extension_release_validate(
                         img->name,
                         host_os_release_id,
                         host_os_release_version_id,
                         host_os_release_sysext_level,
+                        in_initrd() ? "initrd" : "system",
                         img->extension_release);
+        if (r < 0)
+                return log_error_errno(r, "Failed to validate extension release information: %m");
+
+        return r;
 }
 
 static int merge_subprocess(Hashmap *images, const char *workspace) {