]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dissect-image: discover verity signature partitions
authorLennart Poettering <lennart@poettering.net>
Thu, 9 Sep 2021 09:43:13 +0000 (11:43 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 28 Sep 2021 15:02:27 +0000 (17:02 +0200)
This doesn't make use of the discovered partitions yet, but it finds
them at least.

src/dissect/dissect.c
src/nspawn/nspawn.c
src/shared/dissect-image.c
src/shared/dissect-image.h

index 3f464f8dadef078f6077947761fd11762e9381f8..d6db939dcbb751ab5ed7f958164179ddf073073c 100644 (file)
@@ -515,7 +515,9 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
                 if (arg_verity_settings.data_path)
                         r = table_add_cell(t, NULL, TABLE_STRING, "external");
                 else if (dissected_image_verity_candidate(m, i))
-                        r = table_add_cell(t, NULL, TABLE_STRING, yes_no(dissected_image_verity_ready(m, i)));
+                        r = table_add_cell(t, NULL, TABLE_STRING,
+                                           dissected_image_verity_sig_ready(m, i) ? "signed" :
+                                           yes_no(dissected_image_verity_ready(m, i)));
                 else
                         r = table_add_cell(t, NULL, TABLE_EMPTY, NULL);
                 if (r < 0)
index 97e55adc48fad53416c5589ea523b41760ead308..03e1467f2d0d0c1e799666d3374e3455c6f024f2 100644 (file)
@@ -5710,8 +5710,9 @@ static int run(int argc, char *argv[]) {
                 if (r < 0)
                         goto finish;
 
-                if (!arg_verity_settings.root_hash && dissected_image->has_verity)
-                        log_notice("Note: image %s contains verity information, but no root hash specified! Proceeding without integrity checking.", arg_image);
+                if (dissected_image->has_verity && !arg_verity_settings.root_hash && !dissected_image->has_verity_sig)
+                        log_notice("Note: image %s contains verity information, but no root hash specified and no embedded "
+                                   "root hash signature found! Proceeding without integrity checking.", arg_image);
 
                 r = dissected_image_decrypt_interactively(
                                 dissected_image,
index 1cfbde683d4609f32d17e798549b811b6a21173b..af8878f3b8e337534d0afc22ca4d91f96d5b35ab 100644 (file)
@@ -807,6 +807,10 @@ int dissect_image(
                                 verity->root_hash &&
                                 (verity->designator < 0 || verity->designator == PARTITION_ROOT);
 
+                        m->has_verity_sig = false; /* signature not embedded, must be specified */
+                        m->verity_sig_ready = m->verity_ready &&
+                                verity->root_hash_sig;
+
                         options = mount_options_from_designator(mount_options, PARTITION_ROOT);
                         if (options) {
                                 o = strdup(options);
@@ -982,14 +986,42 @@ int dissect_image(
 
                                 m->has_verity = true;
 
-                                /* Ignore verity unless a root hash is specified */
-                                if (sd_id128_is_null(root_verity_uuid) || !sd_id128_equal(root_verity_uuid, id))
+                                /* If no verity configuration is specified, then don't do verity */
+                                if (!verity)
+                                        continue;
+                                if (verity->designator >= 0 && verity->designator != PARTITION_ROOT)
+                                        continue;
+
+                                /* If root hash is specified, then ignore everything but the root id */
+                                if (!sd_id128_is_null(root_verity_uuid) && !sd_id128_equal(root_verity_uuid, id))
                                         continue;
 
                                 designator = PARTITION_ROOT_VERITY;
                                 fstype = "DM_verity_hash";
                                 architecture = native_architecture();
                                 rw = false;
+
+                        } else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY_SIG)) {
+
+                                check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
+
+                                if (pflags & GPT_FLAG_NO_AUTO)
+                                        continue;
+
+                                m->has_verity_sig = true;
+
+                                /* If root hash is specified explicitly, then ignore any embedded signature */
+                                if (!verity)
+                                        continue;
+                                if (verity->designator >= 0 && verity->designator != PARTITION_ROOT)
+                                        continue;
+                                if (verity->root_hash)
+                                        continue;
+
+                                designator = PARTITION_ROOT_VERITY_SIG;
+                                fstype = "verity_hash_signature";
+                                architecture = native_architecture();
+                                rw = false;
                         }
 #endif
 #ifdef GPT_ROOT_SECONDARY
@@ -1018,14 +1050,42 @@ int dissect_image(
 
                                 m->has_verity = true;
 
-                                /* Ignore verity unless root has is specified */
-                                if (sd_id128_is_null(root_verity_uuid) || !sd_id128_equal(root_verity_uuid, id))
+                                /* Don't do verity if no verity config is passed in */
+                                if (!verity)
+                                        continue;
+                                if (verity->designator >= 0 && verity->designator != PARTITION_ROOT)
+                                        continue;
+
+                                /* If root hash is specified, then ignore everything but the root id */
+                                if (!sd_id128_is_null(root_verity_uuid) && !sd_id128_equal(root_verity_uuid, id))
                                         continue;
 
                                 designator = PARTITION_ROOT_SECONDARY_VERITY;
                                 fstype = "DM_verity_hash";
                                 architecture = SECONDARY_ARCHITECTURE;
                                 rw = false;
+
+                        } else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY_SIG)) {
+
+                                check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
+
+                                if (pflags & GPT_FLAG_NO_AUTO)
+                                        continue;
+
+                                m->has_verity_sig = true;
+
+                                /* If root hash is specified explicitly, then ignore any embedded signature */
+                                if (!verity)
+                                        continue;
+                                if (verity->designator >= 0 && verity->designator != PARTITION_ROOT)
+                                        continue;
+                                if (verity->root_hash)
+                                        continue;
+
+                                designator = PARTITION_ROOT_SECONDARY_VERITY_SIG;
+                                fstype = "verity_hash_signature";
+                                architecture = native_architecture();
+                                rw = false;
                         }
 #endif
 #ifdef GPT_USR_NATIVE
@@ -1054,14 +1114,41 @@ int dissect_image(
 
                                 m->has_verity = true;
 
-                                /* Ignore verity unless a usr hash is specified */
-                                if (sd_id128_is_null(usr_verity_uuid) || !sd_id128_equal(usr_verity_uuid, id))
+                                if (!verity)
+                                        continue;
+                                if (verity->designator >= 0 && verity->designator != PARTITION_USR)
+                                        continue;
+
+                                /* If usr hash is specified, then ignore everything but the usr id */
+                                if (!sd_id128_is_null(usr_verity_uuid) && !sd_id128_equal(usr_verity_uuid, id))
                                         continue;
 
                                 designator = PARTITION_USR_VERITY;
                                 fstype = "DM_verity_hash";
                                 architecture = native_architecture();
                                 rw = false;
+
+                        } else if (sd_id128_equal(type_id, GPT_USR_NATIVE_VERITY_SIG)) {
+
+                                check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
+
+                                if (pflags & GPT_FLAG_NO_AUTO)
+                                        continue;
+
+                                m->has_verity_sig = true;
+
+                                /* If usr hash is specified explicitly, then ignore any embedded signature */
+                                if (!verity)
+                                        continue;
+                                if (verity->designator >= 0 && verity->designator != PARTITION_USR)
+                                        continue;
+                                if (verity->root_hash)
+                                        continue;
+
+                                designator = PARTITION_USR_VERITY_SIG;
+                                fstype = "verity_hash_signature";
+                                architecture = native_architecture();
+                                rw = false;
                         }
 #endif
 #ifdef GPT_USR_SECONDARY
@@ -1090,14 +1177,41 @@ int dissect_image(
 
                                 m->has_verity = true;
 
-                                /* Ignore verity unless usr has is specified */
-                                if (sd_id128_is_null(usr_verity_uuid) || !sd_id128_equal(usr_verity_uuid, id))
+                                if (!verity)
+                                        continue;
+                                if (verity->designator >= 0 && verity->designator != PARTITION_USR)
+                                        continue;
+
+                                /* If usr hash is specified, then ignore everything but the root id */
+                                if (!sd_id128_is_null(usr_verity_uuid) && !sd_id128_equal(usr_verity_uuid, id))
                                         continue;
 
                                 designator = PARTITION_USR_SECONDARY_VERITY;
                                 fstype = "DM_verity_hash";
                                 architecture = SECONDARY_ARCHITECTURE;
                                 rw = false;
+
+                        } else if (sd_id128_equal(type_id, GPT_USR_SECONDARY_VERITY_SIG)) {
+
+                                check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
+
+                                if (pflags & GPT_FLAG_NO_AUTO)
+                                        continue;
+
+                                m->has_verity_sig = true;
+
+                                /* If usr hash is specified explicitly, then ignore any embedded signature */
+                                if (!verity)
+                                        continue;
+                                if (verity->designator >= 0 && verity->designator != PARTITION_USR)
+                                        continue;
+                                if (verity->root_hash)
+                                        continue;
+
+                                designator = PARTITION_USR_SECONDARY_VERITY_SIG;
+                                fstype = "verity_hash_signature";
+                                architecture = native_architecture();
+                                rw = false;
                         }
 #endif
                         else if (sd_id128_equal(type_id, GPT_SWAP)) {
@@ -1293,10 +1407,13 @@ int dissect_image(
                  * since we never want to mount the secondary arch in this case. */
                 m->partitions[PARTITION_ROOT_SECONDARY].found = false;
                 m->partitions[PARTITION_ROOT_SECONDARY_VERITY].found = false;
+                m->partitions[PARTITION_ROOT_SECONDARY_VERITY_SIG].found = false;
                 m->partitions[PARTITION_USR_SECONDARY].found = false;
                 m->partitions[PARTITION_USR_SECONDARY_VERITY].found = false;
+                m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG].found = false;
 
-        } else if (m->partitions[PARTITION_ROOT_VERITY].found)
+        } else if (m->partitions[PARTITION_ROOT_VERITY].found ||
+                   m->partitions[PARTITION_ROOT_VERITY_SIG].found)
                 return -EADDRNOTAVAIL; /* Verity found but no matching rootfs? Something is off, refuse. */
 
         else if (m->partitions[PARTITION_ROOT_SECONDARY].found) {
@@ -1308,22 +1425,32 @@ int dissect_image(
                 zero(m->partitions[PARTITION_ROOT_SECONDARY]);
                 m->partitions[PARTITION_ROOT_VERITY] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY];
                 zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY]);
+                m->partitions[PARTITION_ROOT_VERITY_SIG] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY_SIG];
+                zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY_SIG]);
 
                 m->partitions[PARTITION_USR] = m->partitions[PARTITION_USR_SECONDARY];
                 zero(m->partitions[PARTITION_USR_SECONDARY]);
                 m->partitions[PARTITION_USR_VERITY] = m->partitions[PARTITION_USR_SECONDARY_VERITY];
                 zero(m->partitions[PARTITION_USR_SECONDARY_VERITY]);
+                m->partitions[PARTITION_USR_VERITY_SIG] = m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG];
+                zero(m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG]);
 
-        } else if (m->partitions[PARTITION_ROOT_SECONDARY_VERITY].found)
+        } else if (m->partitions[PARTITION_ROOT_SECONDARY_VERITY].found ||
+                   m->partitions[PARTITION_ROOT_SECONDARY_VERITY_SIG].found)
                 return -EADDRNOTAVAIL; /* as above */
 
-        if (m->partitions[PARTITION_USR].found) {
+        /* Hmm, we found a signature partition but no Verity data? Something is off. */
+        if (m->partitions[PARTITION_ROOT_VERITY_SIG].found && !m->partitions[PARTITION_ROOT_VERITY].found)
+                return -EADDRNOTAVAIL;
 
+        if (m->partitions[PARTITION_USR].found) {
                 /* Invalidate secondary arch /usr/ if we found the primary arch */
                 m->partitions[PARTITION_USR_SECONDARY].found = false;
                 m->partitions[PARTITION_USR_SECONDARY_VERITY].found = false;
+                m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG].found = false;
 
-        } else if (m->partitions[PARTITION_USR_VERITY].found)
+        } else if (m->partitions[PARTITION_USR_VERITY].found ||
+                   m->partitions[PARTITION_USR_VERITY_SIG].found)
                 return -EADDRNOTAVAIL; /* as above */
 
         else if (m->partitions[PARTITION_USR_SECONDARY].found) {
@@ -1333,10 +1460,17 @@ int dissect_image(
                 zero(m->partitions[PARTITION_USR_SECONDARY]);
                 m->partitions[PARTITION_USR_VERITY] = m->partitions[PARTITION_USR_SECONDARY_VERITY];
                 zero(m->partitions[PARTITION_USR_SECONDARY_VERITY]);
+                m->partitions[PARTITION_USR_VERITY_SIG] = m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG];
+                zero(m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG]);
 
-        } else if (m->partitions[PARTITION_USR_SECONDARY_VERITY].found)
+        } else if (m->partitions[PARTITION_USR_SECONDARY_VERITY].found ||
+                   m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG].found)
                 return -EADDRNOTAVAIL; /* as above */
 
+        /* Hmm, we found a signature partition but no Verity data? Something is off. */
+        if (m->partitions[PARTITION_USR_VERITY_SIG].found && !m->partitions[PARTITION_USR_VERITY].found)
+                return -EADDRNOTAVAIL;
+
         /* If root and /usr are combined then insist that the architecture matches */
         if (m->partitions[PARTITION_ROOT].found &&
             m->partitions[PARTITION_USR].found &&
@@ -1407,6 +1541,9 @@ int dissect_image(
                         return -EADDRNOTAVAIL;
 
                 if (verity->root_hash) {
+                        /* If we have an explicit root hash and found the partitions for it, then we are ready to use
+                         * Verity, set things up for it */
+
                         if (verity->designator < 0 || verity->designator == PARTITION_ROOT) {
                                 if (!m->partitions[PARTITION_ROOT_VERITY].found || !m->partitions[PARTITION_ROOT].found)
                                         return -EADDRNOTAVAIL;
@@ -1424,6 +1561,16 @@ int dissect_image(
                                 m->partitions[PARTITION_USR].rw = false;
                                 m->verity_ready = true;
                         }
+
+                        if (m->verity_ready)
+                                m->verity_sig_ready = !!verity->root_hash_sig;
+
+                } else if (m->partitions[verity->designator == PARTITION_USR ? PARTITION_USR_VERITY_SIG : PARTITION_ROOT_VERITY_SIG].found) {
+
+                        /* If we found an embedded signature partition, we are ready, too. */
+
+                        m->verity_ready = m->verity_sig_ready = true;
+                        m->partitions[verity->designator == PARTITION_USR ? PARTITION_USR : PARTITION_ROOT].rw = false;
                 }
         }
 
@@ -2901,6 +3048,23 @@ bool dissected_image_verity_ready(const DissectedImage *image, PartitionDesignat
         return k >= 0 && image->partitions[k].found;
 }
 
+bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesignator partition_designator) {
+        PartitionDesignator k;
+
+        assert(image);
+
+        /* Checks if this partition has verity signature data available that we can use. */
+
+        if (!image->verity_sig_ready)
+                return false;
+
+        if (image->single_file_system)
+                return partition_designator == PARTITION_ROOT;
+
+        k = PARTITION_VERITY_SIG_OF(partition_designator);
+        return k >= 0 && image->partitions[k].found;
+}
+
 MountOptions* mount_options_free_all(MountOptions *options) {
         MountOptions *m;
 
@@ -3014,6 +3178,10 @@ static const char *const partition_designator_table[] = {
         [PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity",
         [PARTITION_USR_VERITY] = "usr-verity",
         [PARTITION_USR_SECONDARY_VERITY] = "usr-secondary-verity",
+        [PARTITION_ROOT_VERITY_SIG] = "root-verity-sig",
+        [PARTITION_ROOT_SECONDARY_VERITY_SIG] = "root-secondary-verity-sig",
+        [PARTITION_USR_VERITY_SIG] = "usr-verity-sig",
+        [PARTITION_USR_SECONDARY_VERITY_SIG] = "usr-secondary-verity-sig",
         [PARTITION_TMP] = "tmp",
         [PARTITION_VAR] = "var",
 };
index 55c8f29c2834ea97f4ea17f5013e20df4816354b..84b14cae804329f078e80468e423ea24f322a86f 100644 (file)
@@ -44,6 +44,10 @@ typedef enum PartitionDesignator {
         PARTITION_ROOT_SECONDARY_VERITY, /* verity data for the PARTITION_ROOT_SECONDARY partition */
         PARTITION_USR_VERITY,
         PARTITION_USR_SECONDARY_VERITY,
+        PARTITION_ROOT_VERITY_SIG, /* PKCS#7 signature for root hash for the PARTITION_ROOT partition */
+        PARTITION_ROOT_SECONDARY_VERITY_SIG, /* ditto for the PARTITION_ROOT_SECONDARY partition */
+        PARTITION_USR_VERITY_SIG,
+        PARTITION_USR_SECONDARY_VERITY_SIG,
         PARTITION_TMP,
         PARTITION_VAR,
         _PARTITION_DESIGNATOR_MAX,
@@ -64,7 +68,11 @@ static inline bool PARTITION_DESIGNATOR_VERSIONED(PartitionDesignator d) {
                       PARTITION_ROOT_VERITY,
                       PARTITION_ROOT_SECONDARY_VERITY,
                       PARTITION_USR_VERITY,
-                      PARTITION_USR_SECONDARY_VERITY);
+                      PARTITION_USR_SECONDARY_VERITY,
+                      PARTITION_ROOT_VERITY_SIG,
+                      PARTITION_ROOT_SECONDARY_VERITY_SIG,
+                      PARTITION_USR_VERITY_SIG,
+                      PARTITION_USR_SECONDARY_VERITY_SIG);
 }
 
 static inline PartitionDesignator PARTITION_VERITY_OF(PartitionDesignator p) {
@@ -87,6 +95,26 @@ static inline PartitionDesignator PARTITION_VERITY_OF(PartitionDesignator p) {
         }
 }
 
+static inline PartitionDesignator PARTITION_VERITY_SIG_OF(PartitionDesignator p) {
+        switch (p) {
+
+        case PARTITION_ROOT:
+                return PARTITION_ROOT_VERITY_SIG;
+
+        case PARTITION_ROOT_SECONDARY:
+                return PARTITION_ROOT_SECONDARY_VERITY_SIG;
+
+        case PARTITION_USR:
+                return PARTITION_USR_VERITY_SIG;
+
+        case PARTITION_USR_SECONDARY:
+                return PARTITION_USR_SECONDARY_VERITY_SIG;
+
+        default:
+                return _PARTITION_DESIGNATOR_INVALID;
+        }
+}
+
 typedef enum DissectImageFlags {
         DISSECT_IMAGE_DEVICE_READ_ONLY    = 1 << 0,  /* Make device read-only */
         DISSECT_IMAGE_DISCARD_ON_LOOP     = 1 << 1,  /* Turn on "discard" if on a loop device and file system supports it */
@@ -119,11 +147,14 @@ typedef enum DissectImageFlags {
 struct DissectedImage {
         bool encrypted:1;
         bool has_verity:1;         /* verity available in image, but not necessarily used */
+        bool has_verity_sig:1;     /* pkcs#7 signature embedded in image */
         bool verity_ready:1;       /* verity available, fully specified and usable */
+        bool verity_sig_ready:1;   /* verity signature logic, fully specified and usable */
         bool single_file_system:1; /* MBR/GPT or single file system */
 
         DissectedPartition partitions[_PARTITION_DESIGNATOR_MAX];
 
+        /* Meta information extracted from /etc/os-release and similar */
         char *image_name;
         char *hostname;
         sd_id128_t machine_id;
@@ -188,6 +219,7 @@ void verity_settings_done(VeritySettings *verity);
 
 bool dissected_image_verity_candidate(const DissectedImage *image, PartitionDesignator d);
 bool dissected_image_verity_ready(const DissectedImage *image, PartitionDesignator d);
+bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesignator d);
 
 int mount_image_privately_interactively(const char *path, DissectImageFlags flags, char **ret_directory, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image);