]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dissect: introduce new recognizable partition types for /var and /var/tmp
authorLennart Poettering <lennart@poettering.net>
Wed, 18 Dec 2019 11:22:40 +0000 (12:22 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 23 Dec 2019 13:43:59 +0000 (14:43 +0100)
This has been requested many times before. Let's add it finally.

GPT auto-discovery for /var is a bit more complex than for other
partition types: the other partitions can to some degree be shared
between multiple OS installations on the same disk (think: swap, /home,
/srv). However, /var is inherently something bound to an installation,
i.e. specific to its identity, or actually *is* its identity, and hence
something that cannot be shared.

To deal with this this new code is particularly careful when it comes to
/var: it will not mount things blindly, but insist that the UUID of the
partition matches a hashed version of the machine-id of the
installation, so that each installation has a very specific /var
associated with it, and would never use any other. (We actually use
HMAC-SHA256 on the GPT partition type for /var, keyed by the machine-id,
since machine-id is something we want to keep somewhat private).

Setting the right UUID for installations takes extra care. To make
things a bit simpler to set up, we avoid this safety check for nspawn
and RootImage= in unit files, under the assumption that such container
and service images unlikely will have multiple installations on them.
The check is hence only required when booting full machines, i.e. in
in systemd-gpt-auto-generator.

To help with putting together images for full machines, PR #14368
introduces a repartition tool that can automatically fill in correctly
calculated UUIDs on first boot if images have the var partition UUID
initialized to all zeroes. With that in place systems can be put
together in a way that on first boot the machine ID is determined and
the partition table automatically adjusted to have the /var partition
with the right UUID.

src/core/execute.c
src/dissect/dissect.c
src/gpt-auto-generator/gpt-auto-generator.c
src/nspawn/nspawn.c
src/portable/portable.c
src/shared/dissect-image.c
src/shared/dissect-image.h
src/shared/gpt.h
src/shared/machine-image.c
src/test/test-dissect-image.c

index 2cb2392d16bc1de107b7daca187f514bb31f2e20..4e75d8647287d86e90d9813041061e7c5eb8c150 100644 (file)
@@ -2581,7 +2581,7 @@ static int apply_mount_namespace(
                             needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
                             needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
                             context->mount_flags,
-                            DISSECT_IMAGE_DISCARD_ON_LOOP,
+                            DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK,
                             error_path);
 
         /* If we couldn't set up the namespace this is probably due to a missing capability. setup_namespace() reports
index c1be6c034c5619714e0992283294c345c12ecbbf..2fef95aa027b617216fac033fd974632e479be29 100644 (file)
@@ -22,7 +22,7 @@ static enum {
 } arg_action = ACTION_DISSECT;
 static const char *arg_image = NULL;
 static const char *arg_path = NULL;
-static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP;
+static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK;
 static void *arg_root_hash = NULL;
 static size_t arg_root_hash_size = 0;
 
index 4aac903aa6c7f33bb82535f73f380a208452a552..04691a62c4f7704bd4433c7b8ac67ca503a0dfd7 100644 (file)
@@ -697,6 +697,18 @@ static int enumerate_partitions(dev_t devnum) {
                         r = k;
         }
 
+        if (m->partitions[PARTITION_VAR].found) {
+                k = add_partition_mount(m->partitions + PARTITION_VAR, "var", "/var", "Variable Data Partition");
+                if (k < 0)
+                        r = k;
+        }
+
+        if (m->partitions[PARTITION_TMP].found) {
+                k = add_partition_mount(m->partitions + PARTITION_TMP, "var-tmp", "/var/tmp", "Temporary Data Partition");
+                if (k < 0)
+                        r = k;
+        }
+
         if (m->partitions[PARTITION_ROOT].found) {
                 k = add_root_rw(m->partitions + PARTITION_ROOT);
                 if (k < 0)
index 9113f6e323c667b59ce4b033f753332c4ca4abda..962b2d02099e3abb96493863b7ed49caaddb6d44 100644 (file)
@@ -5058,7 +5058,7 @@ static int run(int argc, char *argv[]) {
                                 loop->fd,
                                 arg_image,
                                 arg_root_hash, arg_root_hash_size,
-                                DISSECT_IMAGE_REQUIRE_ROOT,
+                                DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK,
                                 &dissected_image);
                 if (r == -ENOPKG) {
                         /* dissected_image_and_warn() already printed a brief error message. Extend on that with more details */
index 7a86398a4b5d8fe6c1edc12dd9a1544729e881f7..e18826ab268538312fd3c0a96d426d8ad86c5338 100644 (file)
@@ -387,7 +387,7 @@ static int portable_extract_by_path(
                 if (r < 0)
                         return log_debug_errno(r, "Failed to create temporary directory: %m");
 
-                r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP, &m);
+                r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
                 if (r == -ENOPKG)
                         sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Couldn't identify a suitable partition table or file system in '%s'.", path);
                 else if (r == -EADDRNOTAVAIL)
index 11d21c3a4d1b900af3883edf2e28034590a5521e..087c3dc3452d28aca9897777fd71fc7734e2225f 100644 (file)
@@ -598,6 +598,43 @@ int dissect_image(
                                         if (!generic_node)
                                                 return -ENOMEM;
                                 }
+
+                        } else if (sd_id128_equal(type_id, GPT_TMP)) {
+
+                                if (pflags & GPT_FLAG_NO_AUTO)
+                                        continue;
+
+                                designator = PARTITION_TMP;
+                                rw = !(pflags & GPT_FLAG_READ_ONLY);
+
+                        } else if (sd_id128_equal(type_id, GPT_VAR)) {
+
+                                if (pflags & GPT_FLAG_NO_AUTO)
+                                        continue;
+
+                                if (!FLAGS_SET(flags, DISSECT_IMAGE_RELAX_VAR_CHECK)) {
+                                        sd_id128_t var_uuid;
+
+                                        /* For /var we insist that the uuid of the partition matches the
+                                         * HMAC-SHA256 of the /var GPT partition type uuid, keyed by machine
+                                         * ID. Why? Unlike the other partitions /var is inherently
+                                         * installation specific, hence we need to be careful not to mount it
+                                         * in the wrong installation. By hashing the partition UUID from
+                                         * /etc/machine-id we can securely bind the partition to the
+                                         * installation. */
+
+                                        r = sd_id128_get_machine_app_specific(GPT_VAR, &var_uuid);
+                                        if (r < 0)
+                                                return r;
+
+                                        if (!sd_id128_equal(var_uuid, id)) {
+                                                log_debug("Found a /var/ partition, but its UUID didn't match our expectations, ignoring.");
+                                                continue;
+                                        }
+                                }
+
+                                designator = PARTITION_VAR;
+                                rw = !(pflags & GPT_FLAG_READ_ONLY);
                         }
 
                         if (designator != _PARTITION_DESIGNATOR_INVALID) {
@@ -910,6 +947,14 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
         if (r < 0)
                 return r;
 
+        r = mount_partition(m->partitions + PARTITION_VAR, where, "/var", uid_shift, flags);
+        if (r < 0)
+                return r;
+
+        r = mount_partition(m->partitions + PARTITION_TMP, where, "/var/tmp", uid_shift, flags);
+        if (r < 0)
+                return r;
+
         boot_mounted = mount_partition(m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, flags);
         if (boot_mounted < 0)
                 return boot_mounted;
@@ -1333,7 +1378,8 @@ int dissected_image_acquire_metadata(DissectedImage *m) {
                 [META_HOSTNAME]     = "/etc/hostname\0",
                 [META_MACHINE_ID]   = "/etc/machine-id\0",
                 [META_MACHINE_INFO] = "/etc/machine-info\0",
-                [META_OS_RELEASE]   = "/etc/os-release\0/usr/lib/os-release\0",
+                [META_OS_RELEASE]   = "/etc/os-release\0"
+                                      "/usr/lib/os-release\0",
         };
 
         _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL;
@@ -1528,6 +1574,8 @@ static const char *const partition_designator_table[] = {
         [PARTITION_SWAP] = "swap",
         [PARTITION_ROOT_VERITY] = "root-verity",
         [PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity",
+        [PARTITION_TMP] = "tmp",
+        [PARTITION_VAR] = "var",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(partition_designator, int);
index 40b8035ac7f6d870ba843c651eefb7dfa086235c..359dc877d5890d75c42f50c00a8035d65289b0c0 100644 (file)
@@ -33,6 +33,8 @@ enum  {
         PARTITION_SWAP,
         PARTITION_ROOT_VERITY, /* verity data for the PARTITION_ROOT partition */
         PARTITION_ROOT_SECONDARY_VERITY, /* verity data for the PARTITION_ROOT_SECONDARY partition */
+        PARTITION_TMP,
+        PARTITION_VAR,
         _PARTITION_DESIGNATOR_MAX,
         _PARTITION_DESIGNATOR_INVALID = -1
 };
@@ -59,6 +61,7 @@ typedef enum DissectImageFlags {
         DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY = 1 << 7,  /* Mount only non-root partitions */
         DISSECT_IMAGE_VALIDATE_OS         = 1 << 8,  /* Refuse mounting images that aren't identifiable as OS images */
         DISSECT_IMAGE_NO_UDEV             = 1 << 9,  /* Don't wait for udev initializing things */
+        DISSECT_IMAGE_RELAX_VAR_CHECK     = 1 << 10, /* Don't insist that the UUID of /var is hashed from /etc/machine-id */
 } DissectImageFlags;
 
 struct DissectedImage {
index 31e01bd5a5cc9afd2cf87fce25c34de7f83b5528..8e9b111857c40b722161bd200855e28a2269756c 100644 (file)
@@ -19,6 +19,8 @@
 #define GPT_SWAP        SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f)
 #define GPT_HOME        SD_ID128_MAKE(93,3a,c7,e1,2e,b4,4f,13,b8,44,0e,14,e2,ae,f9,15)
 #define GPT_SRV         SD_ID128_MAKE(3b,8f,84,25,20,e0,4f,3b,90,7f,1a,25,a7,6f,98,e8)
+#define GPT_VAR         SD_ID128_MAKE(4d,21,b0,16,b5,34,45,c2,a9,fb,5c,16,e0,91,fd,2d)
+#define GPT_TMP         SD_ID128_MAKE(7e,c6,f5,57,3b,c5,4a,ca,b2,93,16,ef,5d,f6,39,d1)
 
 /* Verity partitions for the root partitions above (we only define them for the root partitions, because only they are
  * are commonly read-only and hence suitable for verity). */
index 15fd514353a78f3fc9cc2deb8d51eb24413076d9..b45efcd1e6657d812b2953d76cfe41205dcbaf2f 100644 (file)
@@ -1171,7 +1171,7 @@ int image_read_metadata(Image *i) {
                 if (r < 0)
                         return r;
 
-                r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT, &m);
+                r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
                 if (r < 0)
                         return r;
 
index 12685dad1373de390555d5b7a779f3221470d798..a1ccf605b11c6580dcea23903da1badf4d41a37e 100644 (file)
@@ -28,7 +28,7 @@ int main(int argc, char *argv[]) {
                 return EXIT_FAILURE;
         }
 
-        r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT, &m);
+        r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
         if (r < 0) {
                 log_error_errno(r, "Failed to dissect image: %m");
                 return EXIT_FAILURE;