]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #25608 from poettering/dissect-moar
authorLennart Poettering <lennart@poettering.net>
Wed, 12 Apr 2023 11:46:08 +0000 (13:46 +0200)
committerGitHub <noreply@github.com>
Wed, 12 Apr 2023 11:46:08 +0000 (13:46 +0200)
dissect: add dissection policies

21 files changed:
1  2 
TODO
man/org.freedesktop.systemd1.xml
man/rules/meson.build
man/systemd-dissect.xml
man/systemd-sysext.xml
man/systemd.exec.xml
src/core/execute.c
src/core/namespace.c
src/firstboot/firstboot.c
src/nspawn/nspawn.c
src/partition/repart.c
src/portable/portable.c
src/portable/portabled-image-bus.c
src/shared/bus-unit-util.c
src/shared/discover-image.c
src/shared/discover-image.h
src/shared/dissect-image.c
src/sysext/sysext.c
test/units/testsuite-50.sh
test/units/testsuite-65.sh
units/systemd-sysext.service

diff --cc TODO
Simple merge
Simple merge
Simple merge
Simple merge
index f3a12e0a1c2bf8c75bf19d62da2e020addb3d454,2b7a87f5105bf8eaa7e3d34075ab59fbdaaa89fc..a257fa73bca298032154899cc033016c51849bea
          <term><option>--force</option></term>
  
          <listitem><para>When merging system extensions into <filename>/usr/</filename> and
 -        <filename>/opt/</filename>, ignore version incompatibilities, i.e. force merging regardless of
 -        whether the version information included in the extension images matches the host or
 -        not.</para></listitem>
 +        <filename>/opt/</filename> for sysext and <filename>/etc/</filename> for confext,
 +        ignore version incompatibilities, i.e. force merging regardless of
 +        whether the version information included in the images matches the host or not.</para></listitem>
        </varlistentry>
  
+       <varlistentry>
+         <term><option>--image-policy=<replaceable>policy</replaceable></option></term>
+         <listitem><para>Takes an image policy string as argument, as per
+         <citerefentry><refentrytitle>systemd.image-policy</refentrytitle><manvolnum>7</manvolnum></citerefentry>. The
+         policy is enforced when operating on system extension disk images. If not specified defaults to
+         <literal>root=verity+signed+encrypted+unprotected+absent:usr=verity+signed+encrypted+unprotected+absent</literal>,
+         i.e. only the root and <filename>/usr/</filename> file systems in the image are used. When run in the
+         initrd and operating on a system extension image stored in the <filename>/.extra/sysext/</filename>
+         directory a slightly stricter policy is used by default:
+         <literal>root=signed+absent:usr=signed+absent</literal>, see above for details.</para></listitem>
+       </varlistentry>
        <xi:include href="standard-options.xml" xpointer="no-pager" />
        <xi:include href="standard-options.xml" xpointer="no-legend" />
        <xi:include href="standard-options.xml" xpointer="json" />
Simple merge
index 93024b1ce4ca00896e28afe8322e48faa11fc0d4,cd11683407edbfe890dfc689d12941ed0667da61..8b09794089ad9d10d597dff69b8203ef85bf1f7b
@@@ -3785,50 -3801,65 +3785,57 @@@ static int apply_mount_namespace
  
          if (MANAGER_IS_SYSTEM(u->manager)) {
                  propagate_dir = path_join("/run/systemd/propagate/", u->id);
 -                if (!propagate_dir) {
 -                        r = -ENOMEM;
 -                        goto finalize;
 -                }
 +                if (!propagate_dir)
 +                        return -ENOMEM;
  
                  incoming_dir = strdup("/run/systemd/incoming");
 -                if (!incoming_dir) {
 -                        r = -ENOMEM;
 -                        goto finalize;
 -                }
 +                if (!incoming_dir)
 +                        return -ENOMEM;
  
                  extension_dir = strdup("/run/systemd/unit-extensions");
 -                if (!extension_dir) {
 -                        r = -ENOMEM;
 -                        goto finalize;
 -                }
 +                if (!extension_dir)
 +                        return -ENOMEM;
          } else
 -                if (asprintf(&extension_dir, "/run/user/" UID_FMT "/systemd/unit-extensions", geteuid()) < 0) {
 -                        r = -ENOMEM;
 -                        goto finalize;
 -                }
 +                if (asprintf(&extension_dir, "/run/user/" UID_FMT "/systemd/unit-extensions", geteuid()) < 0)
 +                        return -ENOMEM;
  
-         r = setup_namespace(root_dir, root_image, context->root_image_options,
-                             &ns_info, read_write_paths,
-                             needs_sandboxing ? context->read_only_paths : NULL,
-                             needs_sandboxing ? context->inaccessible_paths : NULL,
-                             needs_sandboxing ? context->exec_paths : NULL,
-                             needs_sandboxing ? context->no_exec_paths : NULL,
-                             empty_directories,
-                             symlinks,
-                             bind_mounts,
-                             n_bind_mounts,
-                             context->temporary_filesystems,
-                             context->n_temporary_filesystems,
-                             context->mount_images,
-                             context->n_mount_images,
-                             tmp_dir,
-                             var_tmp_dir,
-                             creds_path,
-                             context->log_namespace,
-                             context->mount_propagation_flag,
-                             context->root_hash, context->root_hash_size, context->root_hash_path,
-                             context->root_hash_sig, context->root_hash_sig_size, context->root_hash_sig_path,
-                             context->root_verity,
-                             context->extension_images,
-                             context->n_extension_images,
-                             context->extension_directories,
-                             propagate_dir,
-                             incoming_dir,
-                             extension_dir,
-                             root_dir || root_image ? params->notify_socket : NULL,
-                             error_path);
+         r = setup_namespace(
+                         root_dir,
+                         root_image,
+                         context->root_image_options,
+                         context->root_image_policy ?: &image_policy_service,
+                         &ns_info,
+                         read_write_paths,
+                         needs_sandboxing ? context->read_only_paths : NULL,
+                         needs_sandboxing ? context->inaccessible_paths : NULL,
+                         needs_sandboxing ? context->exec_paths : NULL,
+                         needs_sandboxing ? context->no_exec_paths : NULL,
+                         empty_directories,
+                         symlinks,
+                         bind_mounts,
+                         n_bind_mounts,
+                         context->temporary_filesystems,
+                         context->n_temporary_filesystems,
+                         context->mount_images,
+                         context->n_mount_images,
+                         context->mount_image_policy ?: &image_policy_service,
+                         tmp_dir,
+                         var_tmp_dir,
+                         creds_path,
+                         context->log_namespace,
+                         context->mount_propagation_flag,
+                         context->root_hash, context->root_hash_size, context->root_hash_path,
+                         context->root_hash_sig, context->root_hash_sig_size, context->root_hash_sig_path,
+                         context->root_verity,
+                         context->extension_images,
+                         context->n_extension_images,
+                         context->extension_image_policy ?: &image_policy_sysext,
+                         context->extension_directories,
+                         propagate_dir,
+                         incoming_dir,
+                         extension_dir,
+                         root_dir || root_image ? params->notify_socket : NULL,
+                         error_path);
  
          /* If we couldn't set up the namespace this is probably due to a missing capability. setup_namespace() reports
           * that with a special, recognizable error ENOANO. In this case, silently proceed, but only if exclusively
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index d0b3245a271724e3b6b4b023566b6c109fee0f43,df3d5b77656d77b98a1308d353109064cf5772d5..ac6a8033ddb4928ec19320eb532afc2af90e94ed
@@@ -63,16 -64,24 +64,29 @@@ static const char* const image_search_p
           * because extension images are supposed to extend /usr/, so you get into recursive races, especially
           * with directory-based extensions, as the kernel's OverlayFS explicitly checks for this and errors
           * out with -ELOOP if it finds that a lowerdir= is a child of another lowerdir=. */
 -        [IMAGE_EXTENSION] = "/etc/extensions\0"             /* only place symlinks here */
 -                            "/run/extensions\0"             /* and here too */
 -                            "/var/lib/extensions\0",        /* the main place for images */
 +        [IMAGE_SYSEXT] =    "/etc/extensions\0"            /* only place symlinks here */
 +                            "/run/extensions\0"            /* and here too */
 +                            "/var/lib/extensions\0",       /* the main place for images */
 +
 +        [IMAGE_CONFEXT] =   "/run/confexts\0"              /* only place symlinks here */
 +                            "/var/lib/confexts\0"          /* the main place for images */
 +                            "/usr/local/lib/confexts\0"
 +                            "/usr/lib/confexts\0",
  };
  
+ /* Inside the initrd, use a slightly different set of search path (i.e. include .extra/sysext in extension
+  * search dir) */
+ static const char* const image_search_path_initrd[_IMAGE_CLASS_MAX] = {
+         /* (entries that aren't listed here will get the same search path as for the non initrd-case) */
+         [IMAGE_EXTENSION] = "/etc/extensions\0"             /* only place symlinks here */
+                             "/run/extensions\0"             /* and here too */
+                             "/var/lib/extensions\0"         /* the main place for images */
+                             "/usr/local/lib/extensions\0"
+                             "/usr/lib/extensions\0"
+                             "/.extra/sysext\0"              /* put sysext picked up by systemd-stub last, since not trusted */
+ };
  static Image *image_free(Image *i) {
          assert(i);
  
index 342b1615774d5a0285ffcae64aa19aad219903e0,c423132a62b3855cc17b89f2f2bfa5d855b9bfb7..edfb1412a446d61d940f641f54a69889db210d56
@@@ -7,9 -7,9 +7,10 @@@
  #include "sd-id128.h"
  
  #include "hashmap.h"
+ #include "image-policy.h"
  #include "lock-util.h"
  #include "macro.h"
 +#include "os-util.h"
  #include "path-util.h"
  #include "string-util.h"
  #include "time-util.h"
Simple merge
index d235073743985f5f07a7dda0338305797bd81fbd,f784627e82036860b5bdc794817fa562531c6c3a..3fc6b910c4e1ff97be9492b25317825a3be8af54
@@@ -45,43 -45,12 +45,45 @@@ static JsonFormatFlags arg_json_format_
  static PagerFlags arg_pager_flags = 0;
  static bool arg_legend = true;
  static bool arg_force = false;
+ static ImagePolicy *arg_image_policy = NULL;
  
 +/* Is set to IMAGE_CONFEXT when systemd is called with the confext functionality instead of the default */
 +static ImageClass arg_image_class = IMAGE_SYSEXT;
 +
  STATIC_DESTRUCTOR_REGISTER(arg_hierarchies, strv_freep);
  STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
+ STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
  
 +/* Helper struct for naming simplicity and reusability */
 +static const struct {
 +        const char *dot_directory_name;
 +        const char *directory_name;
 +        const char *short_identifier;
 +        const char *short_identifier_plural;
 +        const char *level_env;
 +        const char *scope_env;
 +        const char *name_env;
 +} image_class_info[_IMAGE_CLASS_MAX] = {
 +        [IMAGE_SYSEXT] = {
 +                .dot_directory_name = ".systemd-sysext",
 +                .directory_name = "systemd-sysext",
 +                .short_identifier = "sysext",
 +                .short_identifier_plural = "extensions",
 +                .level_env = "SYSEXT_LEVEL",
 +                .scope_env = "SYSEXT_SCOPE",
 +                .name_env = "SYSTEMD_SYSEXT_HIERARCHIES",
 +        },
 +        [IMAGE_CONFEXT] = {
 +                .dot_directory_name = ".systemd-confext",
 +                .directory_name = "systemd-confext",
 +                .short_identifier = "confext",
 +                .short_identifier_plural = "confexts",
 +                .level_env = "CONFEXT_LEVEL",
 +                .scope_env = "CONFEXT_SCOPE",
 +                .name_env = "SYSTEMD_CONFEXT_HIERARCHIES",
 +        }
 +};
 +
  static int is_our_mount_point(const char *p) {
          _cleanup_free_ char *buf = NULL, *f = NULL;
          struct stat st;
@@@ -441,9 -410,27 +443,27 @@@ static int strverscmp_improvedp(char *c
          return strverscmp_improved(*a, *b);
  }
  
+ static const ImagePolicy *pick_image_policy(const Image *img) {
+         assert(img);
+         assert(img->path);
+         /* Explicitly specified policy always wins */
+         if (arg_image_policy)
+                 return arg_image_policy;
+         /* If located in /.extra/sysext/ in the initrd, then it was placed there by systemd-stub, and was
+          * picked up from an untrusted ESP. Thus, require a stricter policy by default for them. (For the
+          * other directories we assume the appropriate level of trust was already established already.  */
+         if (in_initrd() && path_startswith(img->path, "/.extra/sysext/"))
+                 return &image_policy_sysext_strict;
+         return &image_policy_sysext;
+ }
  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;
 +            *host_os_release_confext_level = NULL, *buf = NULL;
          _cleanup_strv_free_ char **extensions = NULL, **paths = NULL;
          size_t n_extensions = 0;
          unsigned n_ignored = 0;
@@@ -765,12 -750,12 +786,12 @@@ static int image_discover_and_read_meta
          if (!images)
                  return log_oom();
  
 -        r = image_discover(IMAGE_EXTENSION, arg_root, images);
 +        r = image_discover(arg_image_class, arg_root, images);
          if (r < 0)
 -                return log_error_errno(r, "Failed to discover extension images: %m");
 +                return log_error_errno(r, "Failed to discover images: %m");
  
          HASHMAP_FOREACH(img, images) {
-                 r = image_read_metadata(img);
+                 r = image_read_metadata(img, &image_policy_sysext);
                  if (r < 0)
                          return log_error_errno(r, "Failed to read metadata for image %s: %m", img->name);
          }
Simple merge
Simple merge
Simple merge