From: Lennart Poettering Date: Mon, 13 Jul 2026 13:41:21 +0000 (+0200) Subject: dissect-image: support activating luks+verity partitions X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1423d78dc91de6eb82d5e511e06187a43dde25e3;p=thirdparty%2Fsystemd.git dissect-image: support activating luks+verity partitions Let's properly activate images that have both LUKS and Verity enabled for a partition. --- diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 1bfb2492922..8835bca354c 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -2868,8 +2868,9 @@ static DecryptedImage* decrypted_image_free(DecryptedImage *d) { if (!d) return NULL; - for (size_t i = 0; i < d->n_decrypted; i++) { - DecryptedPartition *p = d->decrypted + i; + /* Detach in reverse order so that nested dm-verity and dm-crypt are detached in the right order. */ + for (size_t i = d->n_decrypted; i > 0; i--) { + DecryptedPartition *p = d->decrypted + i - 1; if (p->device && p->name && !p->relinquished) { _cleanup_free_ char *node = NULL; @@ -3005,6 +3006,13 @@ static int decrypt_partition( if (!FLAGS_SET(policy_flags, PARTITION_POLICY_ENCRYPTED)) return log_debug_errno(SYNTHETIC_ERRNO(ERFKILL), "Attempted to unlock partition via LUKS, but it's prohibited."); + /* If a dm-verity device was already set up on this partition, then the partition is both Verity + * protected and LUKS encrypted, with Verity being the outer envelope and LUKS the inner. In that + * case open the LUKS device on top of the verity device, so that everything we read is + * authenticated. Since verity devices are read-only, the LUKS layer must then be read-only, too. */ + const char *source_node = m->decrypted_node ?: m->node; + bool on_verity = !!m->decrypted_node; + r = dlopen_cryptsetup(LOG_DEBUG); if (r < 0) return r; @@ -3016,7 +3024,7 @@ static int decrypt_partition( if (!GREEDY_REALLOC0(d->decrypted, d->n_decrypted + 1)) return -ENOMEM; - r = sym_crypt_init(&cd, m->node); + r = sym_crypt_init(&cd, source_node); if (r < 0) return log_debug_errno(r, "Failed to initialize dm-crypt: %m"); @@ -3027,8 +3035,8 @@ static int decrypt_partition( return log_debug_errno(r, "Failed to load LUKS metadata: %m"); r = sym_crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), - ((flags & DISSECT_IMAGE_DEVICE_READ_ONLY) ? CRYPT_ACTIVATE_READONLY : 0) | - ((flags & DISSECT_IMAGE_DISCARD_ON_CRYPTO) ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0)); + ((flags & DISSECT_IMAGE_DEVICE_READ_ONLY) || on_verity ? CRYPT_ACTIVATE_READONLY : 0) | + ((flags & DISSECT_IMAGE_DISCARD_ON_CRYPTO) && !on_verity ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0)); if (r < 0) { log_debug_errno(r, "Failed to activate LUKS device: %m"); return r == -EPERM ? -EKEYREJECTED : r; @@ -3043,7 +3051,7 @@ static int decrypt_partition( .device = TAKE_PTR(cd), }; - m->decrypted_node = TAKE_PTR(node); + free_and_replace(m->decrypted_node, node); close_and_replace(m->mount_node_fd, fd); return 0; @@ -3542,7 +3550,7 @@ success: .device = TAKE_PTR(cd), }; - m->decrypted_node = TAKE_PTR(node); + free_and_replace(m->decrypted_node, node); close_and_replace(m->mount_node_fd, mount_node_fd); return 0; @@ -3602,10 +3610,10 @@ int dissected_image_decrypt( PartitionPolicyFlags fl = image_policy_get_exhaustively(policy, i); - r = decrypt_partition(m, p, passphrase, flags, fl, d); - if (r < 0) - return r; - + /* Set up Verity first, and only then LUKS: if a partition is both Verity protected and + * encrypted, Verity is the outer envelope and LUKS the inner, i.e. the Verity hash data + * covers the LUKS ciphertext, and decrypt_partition() then stacks the LUKS device on top of + * the verity device. */ k = partition_verity_hash_of(i); if (k >= 0) { r = verity_partition(m, i, p, m->partitions + k, root, verity, flags, fl, d); @@ -3613,6 +3621,10 @@ int dissected_image_decrypt( return r; } + r = decrypt_partition(m, p, passphrase, flags, fl, d); + if (r < 0) + return r; + if (!p->decrypted_fstype && p->mount_node_fd >= 0 && p->decrypted_node) { r = probe_filesystem_full(p->mount_node_fd, p->decrypted_node, 0, UINT64_MAX, /* bool restrict_fstypes= */ true, &p->decrypted_fstype); if (r < 0 && r != -EUCLEAN)