1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2016 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <sys/mount.h>
22 #include <sys/prctl.h>
27 #include "architecture.h"
28 #include "ask-password-api.h"
29 #include "blkid-util.h"
30 #include "blockdev-util.h"
32 #include "crypt-util.h"
34 #include "device-nodes.h"
35 #include "dissect-image.h"
40 #include "hexdecoct.h"
41 #include "hostname-util.h"
42 #include "id128-util.h"
43 #include "linux-3.13/dm-ioctl.h"
45 #include "mount-util.h"
46 #include "path-util.h"
47 #include "process-util.h"
48 #include "raw-clone.h"
49 #include "signal-util.h"
50 #include "stat-util.h"
51 #include "stdio-util.h"
52 #include "string-table.h"
53 #include "string-util.h"
55 #include "udev-util.h"
56 #include "user-util.h"
57 #include "xattr-util.h"
59 int probe_filesystem(const char *node
, char **ret_fstype
) {
60 /* Try to find device content type and return it in *ret_fstype. If nothing is found,
61 * 0/NULL will be returned. -EUCLEAN will be returned for ambigous results, and an
62 * different error otherwise. */
65 _cleanup_blkid_free_probe_ blkid_probe b
= NULL
;
70 b
= blkid_new_probe_from_filename(node
);
72 return -errno
?: -ENOMEM
;
74 blkid_probe_enable_superblocks(b
, 1);
75 blkid_probe_set_superblocks_flags(b
, BLKID_SUBLKS_TYPE
);
78 r
= blkid_do_safeprobe(b
);
80 log_debug("No type detected on partition %s", node
);
84 log_debug("Results ambiguous for partition %s", node
);
88 return -errno
?: -EIO
;
90 (void) blkid_probe_lookup_value(b
, "TYPE", &fstype
, NULL
);
111 int dissect_image(int fd
, const void *root_hash
, size_t root_hash_size
, DissectImageFlags flags
, DissectedImage
**ret
) {
114 sd_id128_t root_uuid
= SD_ID128_NULL
, verity_uuid
= SD_ID128_NULL
;
115 _cleanup_udev_enumerate_unref_
struct udev_enumerate
*e
= NULL
;
116 bool is_gpt
, is_mbr
, generic_rw
, multiple_generic
= false;
117 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
118 _cleanup_(dissected_image_unrefp
) DissectedImage
*m
= NULL
;
119 _cleanup_blkid_free_probe_ blkid_probe b
= NULL
;
120 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
121 _cleanup_free_
char *generic_node
= NULL
;
122 sd_id128_t generic_uuid
= SD_ID128_NULL
;
123 const char *pttype
= NULL
;
124 struct udev_list_entry
*first
, *item
;
132 assert(root_hash
|| root_hash_size
== 0);
134 /* Probes a disk image, and returns information about what it found in *ret.
136 * Returns -ENOPKG if no suitable partition table or file system could be found.
137 * Returns -EADDRNOTAVAIL if a root hash was specified but no matching root/verity partitions found. */
140 /* If a root hash is supplied, then we use the root partition that has a UUID that match the first
141 * 128bit of the root hash. And we use the verity partition that has a UUID that match the final
144 if (root_hash_size
< sizeof(sd_id128_t
))
147 memcpy(&root_uuid
, root_hash
, sizeof(sd_id128_t
));
148 memcpy(&verity_uuid
, (const uint8_t*) root_hash
+ root_hash_size
- sizeof(sd_id128_t
), sizeof(sd_id128_t
));
150 if (sd_id128_is_null(root_uuid
))
152 if (sd_id128_is_null(verity_uuid
))
156 if (fstat(fd
, &st
) < 0)
159 if (!S_ISBLK(st
.st_mode
))
162 b
= blkid_new_probe();
167 r
= blkid_probe_set_device(b
, fd
, 0, 0);
169 return -errno
?: -ENOMEM
;
171 if ((flags
& DISSECT_IMAGE_GPT_ONLY
) == 0) {
172 /* Look for file system superblocks, unless we only shall look for GPT partition tables */
173 blkid_probe_enable_superblocks(b
, 1);
174 blkid_probe_set_superblocks_flags(b
, BLKID_SUBLKS_TYPE
|BLKID_SUBLKS_USAGE
);
177 blkid_probe_enable_partitions(b
, 1);
178 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
181 r
= blkid_do_safeprobe(b
);
182 if (IN_SET(r
, -2, 1)) {
183 log_debug("Failed to identify any partition table.");
187 return -errno
?: -EIO
;
189 m
= new0(DissectedImage
, 1);
193 if (!(flags
& DISSECT_IMAGE_GPT_ONLY
) &&
194 (flags
& DISSECT_IMAGE_REQUIRE_ROOT
)) {
195 const char *usage
= NULL
;
197 (void) blkid_probe_lookup_value(b
, "USAGE", &usage
, NULL
);
198 if (STRPTR_IN_SET(usage
, "filesystem", "crypto")) {
199 _cleanup_free_
char *t
= NULL
, *n
= NULL
;
200 const char *fstype
= NULL
;
202 /* OK, we have found a file system, that's our root partition then. */
203 (void) blkid_probe_lookup_value(b
, "TYPE", &fstype
, NULL
);
211 if (asprintf(&n
, "/dev/block/%u:%u", major(st
.st_rdev
), minor(st
.st_rdev
)) < 0)
214 m
->partitions
[PARTITION_ROOT
] = (DissectedPartition
) {
218 .architecture
= _ARCHITECTURE_INVALID
,
225 m
->encrypted
= streq(fstype
, "crypto_LUKS");
234 (void) blkid_probe_lookup_value(b
, "PTTYPE", &pttype
, NULL
);
238 is_gpt
= streq_ptr(pttype
, "gpt");
239 is_mbr
= streq_ptr(pttype
, "dos");
241 if (!is_gpt
&& ((flags
& DISSECT_IMAGE_GPT_ONLY
) || !is_mbr
))
245 pl
= blkid_probe_get_partitions(b
);
247 return -errno
?: -ENOMEM
;
253 d
= udev_device_new_from_devnum(udev
, 'b', st
.st_rdev
);
261 log_debug("Kernel partitions never appeared.");
265 e
= udev_enumerate_new(udev
);
269 r
= udev_enumerate_add_match_parent(e
, d
);
273 r
= udev_enumerate_scan_devices(e
);
277 /* Count the partitions enumerated by the kernel */
279 first
= udev_enumerate_get_list_entry(e
);
280 udev_list_entry_foreach(item
, first
)
283 /* Count the partitions enumerated by blkid */
284 z
= blkid_partlist_numof_partitions(pl
);
288 log_debug("blkid and kernel partition list do not match.");
294 /* The kernel has probed fewer partitions than blkid? Maybe the kernel prober is still running
295 * or it got EBUSY because udev already opened the device. Let's reprobe the device, which is a
296 * synchronous call that waits until probing is complete. */
302 if (ioctl(fd
, BLKRRPART
, 0) < 0) {
306 struct loop_info64 info
;
308 /* If we are running on a loop device that has partition scanning off,
309 * return an explicit recognizable error about this, so that callers
310 * can generate a proper message explaining the situation. */
312 if (ioctl(fd
, LOOP_GET_STATUS64
, &info
) >= 0 && (info
.lo_flags
& LO_FLAGS_PARTSCAN
) == 0) {
313 log_debug("Device is loop device and partition scanning is off!");
314 return -EPROTONOSUPPORT
;
322 /* If something else has the device open, such as an udev rule, the ioctl will return
323 * EBUSY. Since there's no way to wait until it isn't busy anymore, let's just wait a
324 * bit, and try again.
326 * This is really something they should fix in the kernel! */
328 (void) usleep(50 * USEC_PER_MSEC
);
332 e
= udev_enumerate_unref(e
);
335 first
= udev_enumerate_get_list_entry(e
);
336 udev_list_entry_foreach(item
, first
) {
337 _cleanup_udev_device_unref_
struct udev_device
*q
;
338 unsigned long long pflags
;
340 const char *node
, *sysname
;
344 q
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(item
));
348 qn
= udev_device_get_devnum(q
);
352 if (st
.st_rdev
== qn
)
355 /* Filter out weird MMC RPMB partitions, which cannot reasonably be read, see
356 * https://github.com/systemd/systemd/issues/5806 */
357 sysname
= udev_device_get_sysname(q
);
358 if (sysname
&& startswith(sysname
, "mmcblk") &&
359 (endswith(sysname
, "rpmb") || endswith(sysname
, "boot0" ) || endswith(sysname
, "boot1")))
362 node
= udev_device_get_devnode(q
);
366 pp
= blkid_partlist_devno_to_partition(pl
, qn
);
370 pflags
= blkid_partition_get_flags(pp
);
372 nr
= blkid_partition_get_partno(pp
);
377 int designator
= _PARTITION_DESIGNATOR_INVALID
, architecture
= _ARCHITECTURE_INVALID
;
378 const char *stype
, *sid
, *fstype
= NULL
;
379 sd_id128_t type_id
, id
;
382 sid
= blkid_partition_get_uuid(pp
);
385 if (sd_id128_from_string(sid
, &id
) < 0)
388 stype
= blkid_partition_get_type_string(pp
);
391 if (sd_id128_from_string(stype
, &type_id
) < 0)
394 if (sd_id128_equal(type_id
, GPT_HOME
)) {
396 if (pflags
& GPT_FLAG_NO_AUTO
)
399 designator
= PARTITION_HOME
;
400 rw
= !(pflags
& GPT_FLAG_READ_ONLY
);
401 } else if (sd_id128_equal(type_id
, GPT_SRV
)) {
403 if (pflags
& GPT_FLAG_NO_AUTO
)
406 designator
= PARTITION_SRV
;
407 rw
= !(pflags
& GPT_FLAG_READ_ONLY
);
408 } else if (sd_id128_equal(type_id
, GPT_ESP
)) {
410 /* Note that we don't check the GPT_FLAG_NO_AUTO flag for the ESP, as it is not defined
411 * there. We instead check the GPT_FLAG_NO_BLOCK_IO_PROTOCOL, as recommended by the
412 * UEFI spec (See "12.3.3 Number and Location of System Partitions"). */
414 if (pflags
& GPT_FLAG_NO_BLOCK_IO_PROTOCOL
)
417 designator
= PARTITION_ESP
;
420 #ifdef GPT_ROOT_NATIVE
421 else if (sd_id128_equal(type_id
, GPT_ROOT_NATIVE
)) {
423 if (pflags
& GPT_FLAG_NO_AUTO
)
426 /* If a root ID is specified, ignore everything but the root id */
427 if (!sd_id128_is_null(root_uuid
) && !sd_id128_equal(root_uuid
, id
))
430 designator
= PARTITION_ROOT
;
431 architecture
= native_architecture();
432 rw
= !(pflags
& GPT_FLAG_READ_ONLY
);
433 } else if (sd_id128_equal(type_id
, GPT_ROOT_NATIVE_VERITY
)) {
435 if (pflags
& GPT_FLAG_NO_AUTO
)
438 m
->can_verity
= true;
440 /* Ignore verity unless a root hash is specified */
441 if (sd_id128_is_null(verity_uuid
) || !sd_id128_equal(verity_uuid
, id
))
444 designator
= PARTITION_ROOT_VERITY
;
445 fstype
= "DM_verity_hash";
446 architecture
= native_architecture();
450 #ifdef GPT_ROOT_SECONDARY
451 else if (sd_id128_equal(type_id
, GPT_ROOT_SECONDARY
)) {
453 if (pflags
& GPT_FLAG_NO_AUTO
)
456 /* If a root ID is specified, ignore everything but the root id */
457 if (!sd_id128_is_null(root_uuid
) && !sd_id128_equal(root_uuid
, id
))
460 designator
= PARTITION_ROOT_SECONDARY
;
461 architecture
= SECONDARY_ARCHITECTURE
;
462 rw
= !(pflags
& GPT_FLAG_READ_ONLY
);
463 } else if (sd_id128_equal(type_id
, GPT_ROOT_SECONDARY_VERITY
)) {
465 if (pflags
& GPT_FLAG_NO_AUTO
)
468 m
->can_verity
= true;
470 /* Ignore verity unless root has is specified */
471 if (sd_id128_is_null(verity_uuid
) || !sd_id128_equal(verity_uuid
, id
))
474 designator
= PARTITION_ROOT_SECONDARY_VERITY
;
475 fstype
= "DM_verity_hash";
476 architecture
= SECONDARY_ARCHITECTURE
;
480 else if (sd_id128_equal(type_id
, GPT_SWAP
)) {
482 if (pflags
& GPT_FLAG_NO_AUTO
)
485 designator
= PARTITION_SWAP
;
487 } else if (sd_id128_equal(type_id
, GPT_LINUX_GENERIC
)) {
489 if (pflags
& GPT_FLAG_NO_AUTO
)
493 multiple_generic
= true;
496 generic_rw
= !(pflags
& GPT_FLAG_READ_ONLY
);
498 generic_node
= strdup(node
);
504 if (designator
!= _PARTITION_DESIGNATOR_INVALID
) {
505 _cleanup_free_
char *t
= NULL
, *n
= NULL
;
508 if (m
->partitions
[designator
].found
)
521 m
->partitions
[designator
] = (DissectedPartition
) {
525 .architecture
= architecture
,
536 if (pflags
!= 0x80) /* Bootable flag */
539 if (blkid_partition_get_type(pp
) != 0x83) /* Linux partition */
543 multiple_generic
= true;
547 generic_node
= strdup(node
);
554 if (!m
->partitions
[PARTITION_ROOT
].found
) {
555 /* No root partition found? Then let's see if ther's one for the secondary architecture. And if not
556 * either, then check if there's a single generic one, and use that. */
558 if (m
->partitions
[PARTITION_ROOT_VERITY
].found
)
559 return -EADDRNOTAVAIL
;
561 if (m
->partitions
[PARTITION_ROOT_SECONDARY
].found
) {
562 m
->partitions
[PARTITION_ROOT
] = m
->partitions
[PARTITION_ROOT_SECONDARY
];
563 zero(m
->partitions
[PARTITION_ROOT_SECONDARY
]);
565 m
->partitions
[PARTITION_ROOT_VERITY
] = m
->partitions
[PARTITION_ROOT_SECONDARY_VERITY
];
566 zero(m
->partitions
[PARTITION_ROOT_SECONDARY_VERITY
]);
568 } else if (flags
& DISSECT_IMAGE_REQUIRE_ROOT
) {
570 /* If the root has was set, then we won't fallback to a generic node, because the root hash
573 return -EADDRNOTAVAIL
;
575 /* If we didn't find a generic node, then we can't fix this up either */
579 /* If we didn't find a properly marked root partition, but we did find a single suitable
580 * generic Linux partition, then use this as root partition, if the caller asked for it. */
581 if (multiple_generic
)
584 m
->partitions
[PARTITION_ROOT
] = (DissectedPartition
) {
587 .partno
= generic_nr
,
588 .architecture
= _ARCHITECTURE_INVALID
,
589 .node
= generic_node
,
590 .uuid
= generic_uuid
,
598 if (!m
->partitions
[PARTITION_ROOT_VERITY
].found
|| !m
->partitions
[PARTITION_ROOT
].found
)
599 return -EADDRNOTAVAIL
;
601 /* If we found the primary root with the hash, then we definitely want to suppress any secondary root
602 * (which would be weird, after all the root hash should only be assigned to one pair of
604 m
->partitions
[PARTITION_ROOT_SECONDARY
].found
= false;
605 m
->partitions
[PARTITION_ROOT_SECONDARY_VERITY
].found
= false;
607 /* If we found a verity setup, then the root partition is necessarily read-only. */
608 m
->partitions
[PARTITION_ROOT
].rw
= false;
616 /* Fill in file system types if we don't know them yet. */
617 for (i
= 0; i
< _PARTITION_DESIGNATOR_MAX
; i
++) {
618 DissectedPartition
*p
= m
->partitions
+ i
;
623 if (!p
->fstype
&& p
->node
) {
624 r
= probe_filesystem(p
->node
, &p
->fstype
);
625 if (r
< 0 && r
!= -EUCLEAN
)
629 if (streq_ptr(p
->fstype
, "crypto_LUKS"))
632 if (p
->fstype
&& fstype_is_ro(p
->fstype
))
645 DissectedImage
* dissected_image_unref(DissectedImage
*m
) {
651 for (i
= 0; i
< _PARTITION_DESIGNATOR_MAX
; i
++) {
652 free(m
->partitions
[i
].fstype
);
653 free(m
->partitions
[i
].node
);
654 free(m
->partitions
[i
].decrypted_fstype
);
655 free(m
->partitions
[i
].decrypted_node
);
659 strv_free(m
->machine_info
);
660 strv_free(m
->os_release
);
665 static int is_loop_device(const char *path
) {
666 char s
[SYS_BLOCK_PATH_MAX("/../loop/")];
671 if (stat(path
, &st
) < 0)
674 if (!S_ISBLK(st
.st_mode
))
677 xsprintf_sys_block_path(s
, "/loop/", st
.st_dev
);
678 if (access(s
, F_OK
) < 0) {
682 /* The device itself isn't a loop device, but maybe it's a partition and its parent is? */
683 xsprintf_sys_block_path(s
, "/../loop/", st
.st_dev
);
684 if (access(s
, F_OK
) < 0)
685 return errno
== ENOENT
? false : -errno
;
691 static int mount_partition(
692 DissectedPartition
*m
,
694 const char *directory
,
696 DissectImageFlags flags
) {
698 _cleanup_free_
char *chased
= NULL
, *options
= NULL
;
699 const char *p
, *node
, *fstype
;
706 node
= m
->decrypted_node
?: m
->node
;
707 fstype
= m
->decrypted_fstype
?: m
->fstype
;
709 if (!m
->found
|| !node
|| !fstype
)
712 /* Stacked encryption? Yuck */
713 if (streq_ptr(fstype
, "crypto_LUKS"))
716 rw
= m
->rw
&& !(flags
& DISSECT_IMAGE_READ_ONLY
);
719 r
= chase_symlinks(directory
, where
, CHASE_PREFIX_ROOT
, &chased
);
727 /* If requested, turn on discard support. */
728 if (fstype_can_discard(fstype
) &&
729 ((flags
& DISSECT_IMAGE_DISCARD
) ||
730 ((flags
& DISSECT_IMAGE_DISCARD_ON_LOOP
) && is_loop_device(m
->node
)))) {
731 options
= strdup("discard");
736 if (uid_is_valid(uid_shift
) && uid_shift
!= 0 && fstype_can_uid_gid(fstype
)) {
737 _cleanup_free_
char *uid_option
= NULL
;
739 if (asprintf(&uid_option
, "uid=" UID_FMT
",gid=" GID_FMT
, uid_shift
, (gid_t
) uid_shift
) < 0)
742 if (!strextend_with_separator(&options
, ",", uid_option
, NULL
))
746 return mount_verbose(LOG_DEBUG
, node
, p
, fstype
, MS_NODEV
|(rw
? 0 : MS_RDONLY
), options
);
749 int dissected_image_mount(DissectedImage
*m
, const char *where
, uid_t uid_shift
, DissectImageFlags flags
) {
755 if (!m
->partitions
[PARTITION_ROOT
].found
)
758 if ((flags
& DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY
) == 0) {
759 r
= mount_partition(m
->partitions
+ PARTITION_ROOT
, where
, NULL
, uid_shift
, flags
);
764 if ((flags
& DISSECT_IMAGE_MOUNT_ROOT_ONLY
))
767 r
= mount_partition(m
->partitions
+ PARTITION_HOME
, where
, "/home", uid_shift
, flags
);
771 r
= mount_partition(m
->partitions
+ PARTITION_SRV
, where
, "/srv", uid_shift
, flags
);
775 if (m
->partitions
[PARTITION_ESP
].found
) {
778 /* Mount the ESP to /efi if it exists and is empty. If it doesn't exist, use /boot instead. */
780 FOREACH_STRING(mp
, "/efi", "/boot") {
781 _cleanup_free_
char *p
= NULL
;
783 r
= chase_symlinks(mp
, where
, CHASE_PREFIX_ROOT
, &p
);
789 r
= mount_partition(m
->partitions
+ PARTITION_ESP
, where
, mp
, uid_shift
, flags
);
799 #if HAVE_LIBCRYPTSETUP
800 typedef struct DecryptedPartition
{
801 struct crypt_device
*device
;
804 } DecryptedPartition
;
806 struct DecryptedImage
{
807 DecryptedPartition
*decrypted
;
813 DecryptedImage
* decrypted_image_unref(DecryptedImage
* d
) {
814 #if HAVE_LIBCRYPTSETUP
821 for (i
= 0; i
< d
->n_decrypted
; i
++) {
822 DecryptedPartition
*p
= d
->decrypted
+ i
;
824 if (p
->device
&& p
->name
&& !p
->relinquished
) {
825 r
= crypt_deactivate(p
->device
, p
->name
);
827 log_debug_errno(r
, "Failed to deactivate encrypted partition %s", p
->name
);
831 crypt_free(p
->device
);
840 #if HAVE_LIBCRYPTSETUP
842 static int make_dm_name_and_node(const void *original_node
, const char *suffix
, char **ret_name
, char **ret_node
) {
843 _cleanup_free_
char *name
= NULL
, *node
= NULL
;
846 assert(original_node
);
851 base
= strrchr(original_node
, '/');
858 name
= strjoin(base
, suffix
);
861 if (!filename_is_valid(name
))
864 node
= strjoin(crypt_get_dir(), "/", name
);
875 static int decrypt_partition(
876 DissectedPartition
*m
,
877 const char *passphrase
,
878 DissectImageFlags flags
,
881 _cleanup_free_
char *node
= NULL
, *name
= NULL
;
882 _cleanup_(crypt_freep
) struct crypt_device
*cd
= NULL
;
888 if (!m
->found
|| !m
->node
|| !m
->fstype
)
891 if (!streq(m
->fstype
, "crypto_LUKS"))
897 r
= make_dm_name_and_node(m
->node
, "-decrypted", &name
, &node
);
901 if (!GREEDY_REALLOC0(d
->decrypted
, d
->n_allocated
, d
->n_decrypted
+ 1))
904 r
= crypt_init(&cd
, m
->node
);
906 return log_debug_errno(r
, "Failed to initialize dm-crypt: %m");
908 r
= crypt_load(cd
, CRYPT_LUKS
, NULL
);
910 return log_debug_errno(r
, "Failed to load LUKS metadata: %m");
912 r
= crypt_activate_by_passphrase(cd
, name
, CRYPT_ANY_SLOT
, passphrase
, strlen(passphrase
),
913 ((flags
& DISSECT_IMAGE_READ_ONLY
) ? CRYPT_ACTIVATE_READONLY
: 0) |
914 ((flags
& DISSECT_IMAGE_DISCARD_ON_CRYPTO
) ? CRYPT_ACTIVATE_ALLOW_DISCARDS
: 0));
916 log_debug_errno(r
, "Failed to activate LUKS device: %m");
917 return r
== -EPERM
? -EKEYREJECTED
: r
;
920 d
->decrypted
[d
->n_decrypted
].name
= name
;
923 d
->decrypted
[d
->n_decrypted
].device
= cd
;
927 m
->decrypted_node
= node
;
933 static int verity_partition(
934 DissectedPartition
*m
,
935 DissectedPartition
*v
,
936 const void *root_hash
,
937 size_t root_hash_size
,
938 DissectImageFlags flags
,
941 _cleanup_free_
char *node
= NULL
, *name
= NULL
;
942 _cleanup_(crypt_freep
) struct crypt_device
*cd
= NULL
;
951 if (!m
->found
|| !m
->node
|| !m
->fstype
)
953 if (!v
->found
|| !v
->node
|| !v
->fstype
)
956 if (!streq(v
->fstype
, "DM_verity_hash"))
959 r
= make_dm_name_and_node(m
->node
, "-verity", &name
, &node
);
963 if (!GREEDY_REALLOC0(d
->decrypted
, d
->n_allocated
, d
->n_decrypted
+ 1))
966 r
= crypt_init(&cd
, v
->node
);
970 r
= crypt_load(cd
, CRYPT_VERITY
, NULL
);
974 r
= crypt_set_data_device(cd
, m
->node
);
978 r
= crypt_activate_by_volume_key(cd
, name
, root_hash
, root_hash_size
, CRYPT_ACTIVATE_READONLY
);
982 d
->decrypted
[d
->n_decrypted
].name
= name
;
985 d
->decrypted
[d
->n_decrypted
].device
= cd
;
989 m
->decrypted_node
= node
;
996 int dissected_image_decrypt(
998 const char *passphrase
,
999 const void *root_hash
,
1000 size_t root_hash_size
,
1001 DissectImageFlags flags
,
1002 DecryptedImage
**ret
) {
1004 #if HAVE_LIBCRYPTSETUP
1005 _cleanup_(decrypted_image_unrefp
) DecryptedImage
*d
= NULL
;
1011 assert(root_hash
|| root_hash_size
== 0);
1015 * = 0 → There was nothing to decrypt
1016 * > 0 → Decrypted successfully
1017 * -ENOKEY → There's something to decrypt but no key was supplied
1018 * -EKEYREJECTED → Passed key was not correct
1021 if (root_hash
&& root_hash_size
< sizeof(sd_id128_t
))
1024 if (!m
->encrypted
&& !m
->verity
) {
1029 #if HAVE_LIBCRYPTSETUP
1030 d
= new0(DecryptedImage
, 1);
1034 for (i
= 0; i
< _PARTITION_DESIGNATOR_MAX
; i
++) {
1035 DissectedPartition
*p
= m
->partitions
+ i
;
1041 r
= decrypt_partition(p
, passphrase
, flags
, d
);
1045 k
= PARTITION_VERITY_OF(i
);
1047 r
= verity_partition(p
, m
->partitions
+ k
, root_hash
, root_hash_size
, flags
, d
);
1052 if (!p
->decrypted_fstype
&& p
->decrypted_node
) {
1053 r
= probe_filesystem(p
->decrypted_node
, &p
->decrypted_fstype
);
1054 if (r
< 0 && r
!= -EUCLEAN
)
1068 int dissected_image_decrypt_interactively(
1070 const char *passphrase
,
1071 const void *root_hash
,
1072 size_t root_hash_size
,
1073 DissectImageFlags flags
,
1074 DecryptedImage
**ret
) {
1076 _cleanup_strv_free_erase_
char **z
= NULL
;
1083 r
= dissected_image_decrypt(m
, passphrase
, root_hash
, root_hash_size
, flags
, ret
);
1086 if (r
== -EKEYREJECTED
)
1087 log_error_errno(r
, "Incorrect passphrase, try again!");
1088 else if (r
!= -ENOKEY
) {
1089 log_error_errno(r
, "Failed to decrypt image: %m");
1094 log_error("Too many retries.");
1095 return -EKEYREJECTED
;
1100 r
= ask_password_auto("Please enter image passphrase!", NULL
, "dissect", "dissect", USEC_INFINITY
, 0, &z
);
1102 return log_error_errno(r
, "Failed to query for passphrase: %m");
1108 #if HAVE_LIBCRYPTSETUP
1109 static int deferred_remove(DecryptedPartition
*p
) {
1111 struct dm_ioctl dm
= {
1115 DM_VERSION_PATCHLEVEL
1117 .data_size
= sizeof(dm
),
1118 .flags
= DM_DEFERRED_REMOVE
,
1121 _cleanup_close_
int fd
= -1;
1125 /* Unfortunately, libcryptsetup doesn't provide a proper API for this, hence call the ioctl() directly. */
1127 fd
= open("/dev/mapper/control", O_RDWR
|O_CLOEXEC
);
1131 strncpy(dm
.name
, p
->name
, sizeof(dm
.name
));
1133 if (ioctl(fd
, DM_DEV_REMOVE
, &dm
))
1140 int decrypted_image_relinquish(DecryptedImage
*d
) {
1142 #if HAVE_LIBCRYPTSETUP
1149 /* Turns on automatic removal after the last use ended for all DM devices of this image, and sets a boolean so
1150 * that we don't clean it up ourselves either anymore */
1152 #if HAVE_LIBCRYPTSETUP
1153 for (i
= 0; i
< d
->n_decrypted
; i
++) {
1154 DecryptedPartition
*p
= d
->decrypted
+ i
;
1156 if (p
->relinquished
)
1159 r
= deferred_remove(p
);
1161 return log_debug_errno(r
, "Failed to mark %s for auto-removal: %m", p
->name
);
1163 p
->relinquished
= true;
1170 int root_hash_load(const char *image
, void **ret
, size_t *ret_size
) {
1171 _cleanup_free_
char *text
= NULL
;
1172 _cleanup_free_
void *k
= NULL
;
1180 if (is_device_path(image
)) {
1181 /* If we are asked to load the root hash for a device node, exit early */
1187 r
= getxattr_malloc(image
, "user.verity.roothash", &text
, true);
1191 if (!IN_SET(r
, -ENODATA
, -EOPNOTSUPP
, -ENOENT
))
1194 fn
= newa(char, strlen(image
) + STRLEN(".roothash") + 1);
1195 n
= stpcpy(fn
, image
);
1196 e
= endswith(fn
, ".raw");
1200 strcpy(n
, ".roothash");
1202 r
= read_one_line_file(fn
, &text
);
1212 r
= unhexmem(text
, strlen(text
), &k
, &l
);
1215 if (l
< sizeof(sd_id128_t
))
1226 int dissected_image_acquire_metadata(DissectedImage
*m
) {
1236 static const char *const paths
[_META_MAX
] = {
1237 [META_HOSTNAME
] = "/etc/hostname\0",
1238 [META_MACHINE_ID
] = "/etc/machine-id\0",
1239 [META_MACHINE_INFO
] = "/etc/machine-info\0",
1240 [META_OS_RELEASE
] = "/etc/os-release\0/usr/lib/os-release\0",
1243 _cleanup_strv_free_
char **machine_info
= NULL
, **os_release
= NULL
;
1244 _cleanup_(rmdir_and_freep
) char *t
= NULL
;
1245 _cleanup_(sigkill_waitp
) pid_t child
= 0;
1246 sd_id128_t machine_id
= SD_ID128_NULL
;
1247 _cleanup_free_
char *hostname
= NULL
;
1248 unsigned n_meta_initialized
= 0, k
;
1249 int fds
[2 * _META_MAX
], r
;
1251 BLOCK_SIGNALS(SIGCHLD
);
1255 for (; n_meta_initialized
< _META_MAX
; n_meta_initialized
++)
1256 if (pipe2(fds
+ 2*n_meta_initialized
, O_CLOEXEC
) < 0) {
1261 r
= mkdtemp_malloc("/tmp/dissect-XXXXXX", &t
);
1265 r
= safe_fork("(sd-dissect)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
|FORK_NEW_MOUNTNS
, &child
);
1269 /* Make sure we never propagate to the host */
1270 if (mount(NULL
, "/", NULL
, MS_SLAVE
| MS_REC
, NULL
) < 0)
1271 _exit(EXIT_FAILURE
);
1273 r
= dissected_image_mount(m
, t
, UID_INVALID
, DISSECT_IMAGE_READ_ONLY
);
1275 _exit(EXIT_FAILURE
);
1277 for (k
= 0; k
< _META_MAX
; k
++) {
1278 _cleanup_close_
int fd
= -1;
1281 fds
[2*k
] = safe_close(fds
[2*k
]);
1283 NULSTR_FOREACH(p
, paths
[k
]) {
1284 _cleanup_free_
char *q
= NULL
;
1286 r
= chase_symlinks(p
, t
, CHASE_PREFIX_ROOT
, &q
);
1290 fd
= open(q
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1297 r
= copy_bytes(fd
, fds
[2*k
+1], (uint64_t) -1, 0);
1299 _exit(EXIT_FAILURE
);
1301 fds
[2*k
+1] = safe_close(fds
[2*k
+1]);
1304 _exit(EXIT_SUCCESS
);
1307 for (k
= 0; k
< _META_MAX
; k
++) {
1308 _cleanup_fclose_
FILE *f
= NULL
;
1310 fds
[2*k
+1] = safe_close(fds
[2*k
+1]);
1312 f
= fdopen(fds
[2*k
], "re");
1323 r
= read_etc_hostname_stream(f
, &hostname
);
1325 log_debug_errno(r
, "Failed to read /etc/hostname: %m");
1329 case META_MACHINE_ID
: {
1330 _cleanup_free_
char *line
= NULL
;
1332 r
= read_line(f
, LONG_LINE_MAX
, &line
);
1334 log_debug_errno(r
, "Failed to read /etc/machine-id: %m");
1336 r
= sd_id128_from_string(line
, &machine_id
);
1338 log_debug_errno(r
, "Image contains invalid /etc/machine-id: %s", line
);
1340 log_debug("/etc/machine-id file is empty.");
1342 log_debug("/etc/machine-id has unexpected length %i.", r
);
1347 case META_MACHINE_INFO
:
1348 r
= load_env_file_pairs(f
, "machine-info", NULL
, &machine_info
);
1350 log_debug_errno(r
, "Failed to read /etc/machine-info: %m");
1354 case META_OS_RELEASE
:
1355 r
= load_env_file_pairs(f
, "os-release", NULL
, &os_release
);
1357 log_debug_errno(r
, "Failed to read OS release file: %m");
1363 r
= wait_for_terminate_and_check("(sd-dissect)", child
, 0);
1367 if (r
!= EXIT_SUCCESS
)
1370 free_and_replace(m
->hostname
, hostname
);
1371 m
->machine_id
= machine_id
;
1372 strv_free_and_replace(m
->machine_info
, machine_info
);
1373 strv_free_and_replace(m
->os_release
, os_release
);
1376 for (k
= 0; k
< n_meta_initialized
; k
++)
1377 safe_close_pair(fds
+ 2*k
);
1382 static const char *const partition_designator_table
[] = {
1383 [PARTITION_ROOT
] = "root",
1384 [PARTITION_ROOT_SECONDARY
] = "root-secondary",
1385 [PARTITION_HOME
] = "home",
1386 [PARTITION_SRV
] = "srv",
1387 [PARTITION_ESP
] = "esp",
1388 [PARTITION_SWAP
] = "swap",
1389 [PARTITION_ROOT_VERITY
] = "root-verity",
1390 [PARTITION_ROOT_SECONDARY_VERITY
] = "root-secondary-verity",
1393 DEFINE_STRING_TABLE_LOOKUP(partition_designator
, int);