sysext: use parse_extension_release and reject extension if not found
authorLuca Boccassi <luca.boccassi@microsoft.com>
Mon, 11 Jan 2021 23:00:58 +0000 (23:00 +0000)
committerLennart Poettering <lennart@poettering.net>
Tue, 19 Jan 2021 12:41:42 +0000 (13:41 +0100)
man/systemd-sysext.xml
src/sysext/sysext.c

index 14aab94dc9304657f8e26ebd51f93f3dfbd66ee4..6bda5f4fc6591426a39025042d3d8ecad1318b32 100644 (file)
 
     <para>Files and directories contained in the extension images outside of the <filename>/usr/</filename>
     and <filename>/opt/</filename> hierarchies are <emphasis>not</emphasis> merged, and hence have no effect
-    when included in a system extension image (with the exception of <filename>/etc/os-release</filename>,
-    see below). In particular, files in the <filename>/etc/</filename> and <filename>/var/</filename>
-    included in a system extension image will <emphasis>not</emphasis> appear in the respective hierarchies
-    after activation.</para>
+    when included in a system extension image. In particular, files in the <filename>/etc/</filename> and
+    <filename>/var/</filename> included in a system extension image will <emphasis>not</emphasis> appear in
+    the respective hierarchies after activation.</para>
 
     <para>System extension images are strictly read-only, and the host <filename>/usr/</filename> and
     <filename>/opt/</filename> hierarchies become read-only too while they are activated.</para>
     <para>Note that there is no concept of enabling/disabling installed system extension images: all
     installed extension images are automatically activated at boot.</para>
 
-    <para>A simple mechanism for version compatibility is enforced: a system extension image may carry an
-    <filename>/etc/os-release</filename> file that is compared with the host <filename>os-release</filename>
+    <para>A simple mechanism for version compatibility is enforced: a system extension image must carry a
+    <filename>/usr/lib/extension-release.d/extension-release.<replaceable>$name</replaceable></filename>
+    file, which must match its image name, that is compared with the host <filename>os-release</filename>
     file: the contained <varname>ID=</varname> fields have to match, as well as the
-    <varname>SYSEXT_LEVEL=</varname> field (if defined). If the latter is not defined the
+    <varname>SYSEXT_LEVEL=</varname> field (if defined). If the latter is not defined, the
     <varname>VERSION_ID=</varname> field has to match instead. System extensions should not ship a
     <filename>/usr/lib/os-release</filename> file (as that would be merged into the host
-    <filename>/usr/</filename> tree, overriding the host OS version data, which is not desirable).</para>
+    <filename>/usr/</filename> tree, overriding the host OS version data, which is not desirable). The
+    <filename>extension-release</filename> file follows the same format and semantics, and carries the same
+    content, as the <filename>os-release</filename> file of the OS, but it describes the resources carried
+    in the extension image.</para>
   </refsect1>
 
   <refsect1>
index c12f40c160da507d5e529110e9f49ce681f40a9b..8a8cd7535ed8588dfa5accf2fe1d0fdf25003d02 100644 (file)
@@ -441,7 +441,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_os_release_id = NULL, *extension_os_release_version_id = NULL, *extension_os_release_sysext_level = NULL;
+                        *extension_release_id = NULL, *extension_release_version_id = NULL, *extension_release_sysext_level = NULL;
 
                 p = path_join(workspace, "extensions", img->name);
                 if (!p)
@@ -535,36 +535,39 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
                                                "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_os_release(
+                r = parse_extension_release(
                                 p,
-                                "ID", &extension_os_release_id,
-                                "VERSION_ID", &extension_os_release_version_id,
-                                "SYSEXT_LEVEL", &extension_os_release_sysext_level,
+                                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 os-release data, not checking for version compatibility.", img->name);
-                else if (r < 0)
+                if (r == -ENOENT) {
+                        log_notice_errno(r, "Extension '%s' carries no extension-release data, ignoring extension.", img->name);
+                        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_os_release_id)) {
+                        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_os_release_id), strna(host_os_release_id));
+                                           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_os_release_sysext_level) {
-                                if (!streq_ptr(host_os_release_sysext_level, extension_os_release_sysext_level)) {
+                        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_os_release_sysext_level, strna(host_os_release_sysext_level));
+                                                   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_os_release_version_id)) {
+                                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_os_release_version_id, strna(host_os_release_version_id));
+                                                   img->name, extension_release_version_id, strna(host_os_release_version_id));
                                         n_ignored++;
                                         continue;
                                 }