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>
25 #include "architecture.h"
26 #include "ask-password-api.h"
27 #include "blkid-util.h"
28 #include "blockdev-util.h"
30 #include "crypt-util.h"
32 #include "device-nodes.h"
33 #include "dissect-image.h"
38 #include "hexdecoct.h"
39 #include "hostname-util.h"
40 #include "id128-util.h"
41 #include "linux-3.13/dm-ioctl.h"
43 #include "mount-util.h"
44 #include "path-util.h"
45 #include "process-util.h"
46 #include "raw-clone.h"
47 #include "signal-util.h"
48 #include "stat-util.h"
49 #include "stdio-util.h"
50 #include "string-table.h"
51 #include "string-util.h"
53 #include "udev-util.h"
54 #include "user-util.h"
55 #include "xattr-util.h"
57 int probe_filesystem(const char *node
, char **ret_fstype
) {
58 /* Try to find device content type and return it in *ret_fstype. If nothing is found,
59 * 0/NULL will be returned. -EUCLEAN will be returned for ambigous results, and an
60 * different error otherwise. */
63 _cleanup_blkid_free_probe_ blkid_probe b
= NULL
;
68 b
= blkid_new_probe_from_filename(node
);
70 return -errno
?: -ENOMEM
;
72 blkid_probe_enable_superblocks(b
, 1);
73 blkid_probe_set_superblocks_flags(b
, BLKID_SUBLKS_TYPE
);
76 r
= blkid_do_safeprobe(b
);
78 log_debug("No type detected on partition %s", node
);
82 log_debug("Results ambiguous for partition %s", node
);
86 return -errno
?: -EIO
;
88 (void) blkid_probe_lookup_value(b
, "TYPE", &fstype
, NULL
);
109 int dissect_image(int fd
, const void *root_hash
, size_t root_hash_size
, DissectImageFlags flags
, DissectedImage
**ret
) {
112 sd_id128_t root_uuid
= SD_ID128_NULL
, verity_uuid
= SD_ID128_NULL
;
113 _cleanup_udev_enumerate_unref_
struct udev_enumerate
*e
= NULL
;
114 bool is_gpt
, is_mbr
, generic_rw
, multiple_generic
= false;
115 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
116 _cleanup_(dissected_image_unrefp
) DissectedImage
*m
= NULL
;
117 _cleanup_blkid_free_probe_ blkid_probe b
= NULL
;
118 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
119 _cleanup_free_
char *generic_node
= NULL
;
120 sd_id128_t generic_uuid
= SD_ID128_NULL
;
121 const char *pttype
= NULL
;
122 struct udev_list_entry
*first
, *item
;
130 assert(root_hash
|| root_hash_size
== 0);
132 /* Probes a disk image, and returns information about what it found in *ret.
134 * Returns -ENOPKG if no suitable partition table or file system could be found.
135 * Returns -EADDRNOTAVAIL if a root hash was specified but no matching root/verity partitions found. */
138 /* If a root hash is supplied, then we use the root partition that has a UUID that match the first
139 * 128bit of the root hash. And we use the verity partition that has a UUID that match the final
142 if (root_hash_size
< sizeof(sd_id128_t
))
145 memcpy(&root_uuid
, root_hash
, sizeof(sd_id128_t
));
146 memcpy(&verity_uuid
, (const uint8_t*) root_hash
+ root_hash_size
- sizeof(sd_id128_t
), sizeof(sd_id128_t
));
148 if (sd_id128_is_null(root_uuid
))
150 if (sd_id128_is_null(verity_uuid
))
154 if (fstat(fd
, &st
) < 0)
157 if (!S_ISBLK(st
.st_mode
))
160 b
= blkid_new_probe();
165 r
= blkid_probe_set_device(b
, fd
, 0, 0);
167 return -errno
?: -ENOMEM
;
169 if ((flags
& DISSECT_IMAGE_GPT_ONLY
) == 0) {
170 /* Look for file system superblocks, unless we only shall look for GPT partition tables */
171 blkid_probe_enable_superblocks(b
, 1);
172 blkid_probe_set_superblocks_flags(b
, BLKID_SUBLKS_TYPE
|BLKID_SUBLKS_USAGE
);
175 blkid_probe_enable_partitions(b
, 1);
176 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
179 r
= blkid_do_safeprobe(b
);
180 if (IN_SET(r
, -2, 1)) {
181 log_debug("Failed to identify any partition table.");
185 return -errno
?: -EIO
;
187 m
= new0(DissectedImage
, 1);
191 if (!(flags
& DISSECT_IMAGE_GPT_ONLY
) &&
192 (flags
& DISSECT_IMAGE_REQUIRE_ROOT
)) {
193 const char *usage
= NULL
;
195 (void) blkid_probe_lookup_value(b
, "USAGE", &usage
, NULL
);
196 if (STRPTR_IN_SET(usage
, "filesystem", "crypto")) {
197 _cleanup_free_
char *t
= NULL
, *n
= NULL
;
198 const char *fstype
= NULL
;
200 /* OK, we have found a file system, that's our root partition then. */
201 (void) blkid_probe_lookup_value(b
, "TYPE", &fstype
, NULL
);
209 if (asprintf(&n
, "/dev/block/%u:%u", major(st
.st_rdev
), minor(st
.st_rdev
)) < 0)
212 m
->partitions
[PARTITION_ROOT
] = (DissectedPartition
) {
216 .architecture
= _ARCHITECTURE_INVALID
,
223 m
->encrypted
= streq(fstype
, "crypto_LUKS");
232 (void) blkid_probe_lookup_value(b
, "PTTYPE", &pttype
, NULL
);
236 is_gpt
= streq_ptr(pttype
, "gpt");
237 is_mbr
= streq_ptr(pttype
, "dos");
239 if (!is_gpt
&& ((flags
& DISSECT_IMAGE_GPT_ONLY
) || !is_mbr
))
243 pl
= blkid_probe_get_partitions(b
);
245 return -errno
?: -ENOMEM
;
251 d
= udev_device_new_from_devnum(udev
, 'b', st
.st_rdev
);
259 log_debug("Kernel partitions never appeared.");
263 e
= udev_enumerate_new(udev
);
267 r
= udev_enumerate_add_match_parent(e
, d
);
271 r
= udev_enumerate_scan_devices(e
);
275 /* Count the partitions enumerated by the kernel */
277 first
= udev_enumerate_get_list_entry(e
);
278 udev_list_entry_foreach(item
, first
)
281 /* Count the partitions enumerated by blkid */
282 z
= blkid_partlist_numof_partitions(pl
);
286 log_debug("blkid and kernel partition list do not match.");
292 /* The kernel has probed fewer partitions than blkid? Maybe the kernel prober is still running
293 * or it got EBUSY because udev already opened the device. Let's reprobe the device, which is a
294 * synchronous call that waits until probing is complete. */
300 if (ioctl(fd
, BLKRRPART
, 0) < 0) {
304 struct loop_info64 info
;
306 /* If we are running on a loop device that has partition scanning off,
307 * return an explicit recognizable error about this, so that callers
308 * can generate a proper message explaining the situation. */
310 if (ioctl(fd
, LOOP_GET_STATUS64
, &info
) >= 0 && (info
.lo_flags
& LO_FLAGS_PARTSCAN
) == 0) {
311 log_debug("Device is loop device and partition scanning is off!");
312 return -EPROTONOSUPPORT
;
320 /* If something else has the device open, such as an udev rule, the ioctl will return
321 * EBUSY. Since there's no way to wait until it isn't busy anymore, let's just wait a
322 * bit, and try again.
324 * This is really something they should fix in the kernel! */
326 (void) usleep(50 * USEC_PER_MSEC
);
330 e
= udev_enumerate_unref(e
);
333 first
= udev_enumerate_get_list_entry(e
);
334 udev_list_entry_foreach(item
, first
) {
335 _cleanup_udev_device_unref_
struct udev_device
*q
;
336 unsigned long long pflags
;
338 const char *node
, *sysname
;
342 q
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(item
));
346 qn
= udev_device_get_devnum(q
);
350 if (st
.st_rdev
== qn
)
353 /* Filter out weird MMC RPMB partitions, which cannot reasonably be read, see
354 * https://github.com/systemd/systemd/issues/5806 */
355 sysname
= udev_device_get_sysname(q
);
356 if (sysname
&& startswith(sysname
, "mmcblk") && endswith(sysname
, "rpmb"))
359 node
= udev_device_get_devnode(q
);
363 pp
= blkid_partlist_devno_to_partition(pl
, qn
);
367 pflags
= blkid_partition_get_flags(pp
);
369 nr
= blkid_partition_get_partno(pp
);
374 int designator
= _PARTITION_DESIGNATOR_INVALID
, architecture
= _ARCHITECTURE_INVALID
;
375 const char *stype
, *sid
, *fstype
= NULL
;
376 sd_id128_t type_id
, id
;
379 sid
= blkid_partition_get_uuid(pp
);
382 if (sd_id128_from_string(sid
, &id
) < 0)
385 stype
= blkid_partition_get_type_string(pp
);
388 if (sd_id128_from_string(stype
, &type_id
) < 0)
391 if (sd_id128_equal(type_id
, GPT_HOME
)) {
393 if (pflags
& GPT_FLAG_NO_AUTO
)
396 designator
= PARTITION_HOME
;
397 rw
= !(pflags
& GPT_FLAG_READ_ONLY
);
398 } else if (sd_id128_equal(type_id
, GPT_SRV
)) {
400 if (pflags
& GPT_FLAG_NO_AUTO
)
403 designator
= PARTITION_SRV
;
404 rw
= !(pflags
& GPT_FLAG_READ_ONLY
);
405 } else if (sd_id128_equal(type_id
, GPT_ESP
)) {
407 /* Note that we don't check the GPT_FLAG_NO_AUTO flag for the ESP, as it is not defined
408 * there. We instead check the GPT_FLAG_NO_BLOCK_IO_PROTOCOL, as recommended by the
409 * UEFI spec (See "12.3.3 Number and Location of System Partitions"). */
411 if (pflags
& GPT_FLAG_NO_BLOCK_IO_PROTOCOL
)
414 designator
= PARTITION_ESP
;
417 #ifdef GPT_ROOT_NATIVE
418 else if (sd_id128_equal(type_id
, GPT_ROOT_NATIVE
)) {
420 if (pflags
& GPT_FLAG_NO_AUTO
)
423 /* If a root ID is specified, ignore everything but the root id */
424 if (!sd_id128_is_null(root_uuid
) && !sd_id128_equal(root_uuid
, id
))
427 designator
= PARTITION_ROOT
;
428 architecture
= native_architecture();
429 rw
= !(pflags
& GPT_FLAG_READ_ONLY
);
430 } else if (sd_id128_equal(type_id
, GPT_ROOT_NATIVE_VERITY
)) {
432 if (pflags
& GPT_FLAG_NO_AUTO
)
435 m
->can_verity
= true;
437 /* Ignore verity unless a root hash is specified */
438 if (sd_id128_is_null(verity_uuid
) || !sd_id128_equal(verity_uuid
, id
))
441 designator
= PARTITION_ROOT_VERITY
;
442 fstype
= "DM_verity_hash";
443 architecture
= native_architecture();
447 #ifdef GPT_ROOT_SECONDARY
448 else if (sd_id128_equal(type_id
, GPT_ROOT_SECONDARY
)) {
450 if (pflags
& GPT_FLAG_NO_AUTO
)
453 /* If a root ID is specified, ignore everything but the root id */
454 if (!sd_id128_is_null(root_uuid
) && !sd_id128_equal(root_uuid
, id
))
457 designator
= PARTITION_ROOT_SECONDARY
;
458 architecture
= SECONDARY_ARCHITECTURE
;
459 rw
= !(pflags
& GPT_FLAG_READ_ONLY
);
460 } else if (sd_id128_equal(type_id
, GPT_ROOT_SECONDARY_VERITY
)) {
462 if (pflags
& GPT_FLAG_NO_AUTO
)
465 m
->can_verity
= true;
467 /* Ignore verity unless root has is specified */
468 if (sd_id128_is_null(verity_uuid
) || !sd_id128_equal(verity_uuid
, id
))
471 designator
= PARTITION_ROOT_SECONDARY_VERITY
;
472 fstype
= "DM_verity_hash";
473 architecture
= SECONDARY_ARCHITECTURE
;
477 else if (sd_id128_equal(type_id
, GPT_SWAP
)) {
479 if (pflags
& GPT_FLAG_NO_AUTO
)
482 designator
= PARTITION_SWAP
;
484 } else if (sd_id128_equal(type_id
, GPT_LINUX_GENERIC
)) {
486 if (pflags
& GPT_FLAG_NO_AUTO
)
490 multiple_generic
= true;
493 generic_rw
= !(pflags
& GPT_FLAG_READ_ONLY
);
495 generic_node
= strdup(node
);
501 if (designator
!= _PARTITION_DESIGNATOR_INVALID
) {
502 _cleanup_free_
char *t
= NULL
, *n
= NULL
;
505 if (m
->partitions
[designator
].found
)
518 m
->partitions
[designator
] = (DissectedPartition
) {
522 .architecture
= architecture
,
533 if (pflags
!= 0x80) /* Bootable flag */
536 if (blkid_partition_get_type(pp
) != 0x83) /* Linux partition */
540 multiple_generic
= true;
544 generic_node
= strdup(node
);
551 if (!m
->partitions
[PARTITION_ROOT
].found
) {
552 /* No root partition found? Then let's see if ther's one for the secondary architecture. And if not
553 * either, then check if there's a single generic one, and use that. */
555 if (m
->partitions
[PARTITION_ROOT_VERITY
].found
)
556 return -EADDRNOTAVAIL
;
558 if (m
->partitions
[PARTITION_ROOT_SECONDARY
].found
) {
559 m
->partitions
[PARTITION_ROOT
] = m
->partitions
[PARTITION_ROOT_SECONDARY
];
560 zero(m
->partitions
[PARTITION_ROOT_SECONDARY
]);
562 m
->partitions
[PARTITION_ROOT_VERITY
] = m
->partitions
[PARTITION_ROOT_SECONDARY_VERITY
];
563 zero(m
->partitions
[PARTITION_ROOT_SECONDARY_VERITY
]);
565 } else if (flags
& DISSECT_IMAGE_REQUIRE_ROOT
) {
567 /* If the root has was set, then we won't fallback to a generic node, because the root hash
570 return -EADDRNOTAVAIL
;
572 /* If we didn't find a generic node, then we can't fix this up either */
576 /* If we didn't find a properly marked root partition, but we did find a single suitable
577 * generic Linux partition, then use this as root partition, if the caller asked for it. */
578 if (multiple_generic
)
581 m
->partitions
[PARTITION_ROOT
] = (DissectedPartition
) {
584 .partno
= generic_nr
,
585 .architecture
= _ARCHITECTURE_INVALID
,
586 .node
= generic_node
,
587 .uuid
= generic_uuid
,
595 if (!m
->partitions
[PARTITION_ROOT_VERITY
].found
|| !m
->partitions
[PARTITION_ROOT
].found
)
596 return -EADDRNOTAVAIL
;
598 /* If we found the primary root with the hash, then we definitely want to suppress any secondary root
599 * (which would be weird, after all the root hash should only be assigned to one pair of
601 m
->partitions
[PARTITION_ROOT_SECONDARY
].found
= false;
602 m
->partitions
[PARTITION_ROOT_SECONDARY_VERITY
].found
= false;
604 /* If we found a verity setup, then the root partition is necessarily read-only. */
605 m
->partitions
[PARTITION_ROOT
].rw
= false;
613 /* Fill in file system types if we don't know them yet. */
614 for (i
= 0; i
< _PARTITION_DESIGNATOR_MAX
; i
++) {
615 DissectedPartition
*p
= m
->partitions
+ i
;
620 if (!p
->fstype
&& p
->node
) {
621 r
= probe_filesystem(p
->node
, &p
->fstype
);
622 if (r
< 0 && r
!= -EUCLEAN
)
626 if (streq_ptr(p
->fstype
, "crypto_LUKS"))
629 if (p
->fstype
&& fstype_is_ro(p
->fstype
))
642 DissectedImage
* dissected_image_unref(DissectedImage
*m
) {
648 for (i
= 0; i
< _PARTITION_DESIGNATOR_MAX
; i
++) {
649 free(m
->partitions
[i
].fstype
);
650 free(m
->partitions
[i
].node
);
651 free(m
->partitions
[i
].decrypted_fstype
);
652 free(m
->partitions
[i
].decrypted_node
);
656 strv_free(m
->machine_info
);
657 strv_free(m
->os_release
);
662 static int is_loop_device(const char *path
) {
663 char s
[SYS_BLOCK_PATH_MAX("/../loop/")];
668 if (stat(path
, &st
) < 0)
671 if (!S_ISBLK(st
.st_mode
))
674 xsprintf_sys_block_path(s
, "/loop/", st
.st_dev
);
675 if (access(s
, F_OK
) < 0) {
679 /* The device itself isn't a loop device, but maybe it's a partition and its parent is? */
680 xsprintf_sys_block_path(s
, "/../loop/", st
.st_dev
);
681 if (access(s
, F_OK
) < 0)
682 return errno
== ENOENT
? false : -errno
;
688 static int mount_partition(
689 DissectedPartition
*m
,
691 const char *directory
,
693 DissectImageFlags flags
) {
695 _cleanup_free_
char *chased
= NULL
, *options
= NULL
;
696 const char *p
, *node
, *fstype
;
703 node
= m
->decrypted_node
?: m
->node
;
704 fstype
= m
->decrypted_fstype
?: m
->fstype
;
706 if (!m
->found
|| !node
|| !fstype
)
709 /* Stacked encryption? Yuck */
710 if (streq_ptr(fstype
, "crypto_LUKS"))
713 rw
= m
->rw
&& !(flags
& DISSECT_IMAGE_READ_ONLY
);
716 r
= chase_symlinks(directory
, where
, CHASE_PREFIX_ROOT
, &chased
);
724 /* If requested, turn on discard support. */
725 if (fstype_can_discard(fstype
) &&
726 ((flags
& DISSECT_IMAGE_DISCARD
) ||
727 ((flags
& DISSECT_IMAGE_DISCARD_ON_LOOP
) && is_loop_device(m
->node
)))) {
728 options
= strdup("discard");
733 if (uid_is_valid(uid_shift
) && uid_shift
!= 0 && fstype_can_uid_gid(fstype
)) {
734 _cleanup_free_
char *uid_option
= NULL
;
736 if (asprintf(&uid_option
, "uid=" UID_FMT
",gid=" GID_FMT
, uid_shift
, (gid_t
) uid_shift
) < 0)
739 if (!strextend_with_separator(&options
, ",", uid_option
, NULL
))
743 return mount_verbose(LOG_DEBUG
, node
, p
, fstype
, MS_NODEV
|(rw
? 0 : MS_RDONLY
), options
);
746 int dissected_image_mount(DissectedImage
*m
, const char *where
, uid_t uid_shift
, DissectImageFlags flags
) {
752 if (!m
->partitions
[PARTITION_ROOT
].found
)
755 if ((flags
& DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY
) == 0) {
756 r
= mount_partition(m
->partitions
+ PARTITION_ROOT
, where
, NULL
, uid_shift
, flags
);
761 if ((flags
& DISSECT_IMAGE_MOUNT_ROOT_ONLY
))
764 r
= mount_partition(m
->partitions
+ PARTITION_HOME
, where
, "/home", uid_shift
, flags
);
768 r
= mount_partition(m
->partitions
+ PARTITION_SRV
, where
, "/srv", uid_shift
, flags
);
772 if (m
->partitions
[PARTITION_ESP
].found
) {
775 /* Mount the ESP to /efi if it exists and is empty. If it doesn't exist, use /boot instead. */
777 FOREACH_STRING(mp
, "/efi", "/boot") {
778 _cleanup_free_
char *p
= NULL
;
780 r
= chase_symlinks(mp
, where
, CHASE_PREFIX_ROOT
, &p
);
786 r
= mount_partition(m
->partitions
+ PARTITION_ESP
, where
, mp
, uid_shift
, flags
);
796 #if HAVE_LIBCRYPTSETUP
797 typedef struct DecryptedPartition
{
798 struct crypt_device
*device
;
801 } DecryptedPartition
;
803 struct DecryptedImage
{
804 DecryptedPartition
*decrypted
;
810 DecryptedImage
* decrypted_image_unref(DecryptedImage
* d
) {
811 #if HAVE_LIBCRYPTSETUP
818 for (i
= 0; i
< d
->n_decrypted
; i
++) {
819 DecryptedPartition
*p
= d
->decrypted
+ i
;
821 if (p
->device
&& p
->name
&& !p
->relinquished
) {
822 r
= crypt_deactivate(p
->device
, p
->name
);
824 log_debug_errno(r
, "Failed to deactivate encrypted partition %s", p
->name
);
828 crypt_free(p
->device
);
837 #if HAVE_LIBCRYPTSETUP
839 static int make_dm_name_and_node(const void *original_node
, const char *suffix
, char **ret_name
, char **ret_node
) {
840 _cleanup_free_
char *name
= NULL
, *node
= NULL
;
843 assert(original_node
);
848 base
= strrchr(original_node
, '/');
855 name
= strjoin(base
, suffix
);
858 if (!filename_is_valid(name
))
861 node
= strjoin(crypt_get_dir(), "/", name
);
872 static int decrypt_partition(
873 DissectedPartition
*m
,
874 const char *passphrase
,
875 DissectImageFlags flags
,
878 _cleanup_free_
char *node
= NULL
, *name
= NULL
;
879 _cleanup_(crypt_freep
) struct crypt_device
*cd
= NULL
;
885 if (!m
->found
|| !m
->node
|| !m
->fstype
)
888 if (!streq(m
->fstype
, "crypto_LUKS"))
894 r
= make_dm_name_and_node(m
->node
, "-decrypted", &name
, &node
);
898 if (!GREEDY_REALLOC0(d
->decrypted
, d
->n_allocated
, d
->n_decrypted
+ 1))
901 r
= crypt_init(&cd
, m
->node
);
903 return log_debug_errno(r
, "Failed to initialize dm-crypt: %m");
905 r
= crypt_load(cd
, CRYPT_LUKS
, NULL
);
907 return log_debug_errno(r
, "Failed to load LUKS metadata: %m");
909 r
= crypt_activate_by_passphrase(cd
, name
, CRYPT_ANY_SLOT
, passphrase
, strlen(passphrase
),
910 ((flags
& DISSECT_IMAGE_READ_ONLY
) ? CRYPT_ACTIVATE_READONLY
: 0) |
911 ((flags
& DISSECT_IMAGE_DISCARD_ON_CRYPTO
) ? CRYPT_ACTIVATE_ALLOW_DISCARDS
: 0));
913 log_debug_errno(r
, "Failed to activate LUKS device: %m");
914 return r
== -EPERM
? -EKEYREJECTED
: r
;
917 d
->decrypted
[d
->n_decrypted
].name
= name
;
920 d
->decrypted
[d
->n_decrypted
].device
= cd
;
924 m
->decrypted_node
= node
;
930 static int verity_partition(
931 DissectedPartition
*m
,
932 DissectedPartition
*v
,
933 const void *root_hash
,
934 size_t root_hash_size
,
935 DissectImageFlags flags
,
938 _cleanup_free_
char *node
= NULL
, *name
= NULL
;
939 _cleanup_(crypt_freep
) struct crypt_device
*cd
= NULL
;
948 if (!m
->found
|| !m
->node
|| !m
->fstype
)
950 if (!v
->found
|| !v
->node
|| !v
->fstype
)
953 if (!streq(v
->fstype
, "DM_verity_hash"))
956 r
= make_dm_name_and_node(m
->node
, "-verity", &name
, &node
);
960 if (!GREEDY_REALLOC0(d
->decrypted
, d
->n_allocated
, d
->n_decrypted
+ 1))
963 r
= crypt_init(&cd
, v
->node
);
967 r
= crypt_load(cd
, CRYPT_VERITY
, NULL
);
971 r
= crypt_set_data_device(cd
, m
->node
);
975 r
= crypt_activate_by_volume_key(cd
, name
, root_hash
, root_hash_size
, CRYPT_ACTIVATE_READONLY
);
979 d
->decrypted
[d
->n_decrypted
].name
= name
;
982 d
->decrypted
[d
->n_decrypted
].device
= cd
;
986 m
->decrypted_node
= node
;
993 int dissected_image_decrypt(
995 const char *passphrase
,
996 const void *root_hash
,
997 size_t root_hash_size
,
998 DissectImageFlags flags
,
999 DecryptedImage
**ret
) {
1001 #if HAVE_LIBCRYPTSETUP
1002 _cleanup_(decrypted_image_unrefp
) DecryptedImage
*d
= NULL
;
1008 assert(root_hash
|| root_hash_size
== 0);
1012 * = 0 → There was nothing to decrypt
1013 * > 0 → Decrypted successfully
1014 * -ENOKEY → There's something to decrypt but no key was supplied
1015 * -EKEYREJECTED → Passed key was not correct
1018 if (root_hash
&& root_hash_size
< sizeof(sd_id128_t
))
1021 if (!m
->encrypted
&& !m
->verity
) {
1026 #if HAVE_LIBCRYPTSETUP
1027 d
= new0(DecryptedImage
, 1);
1031 for (i
= 0; i
< _PARTITION_DESIGNATOR_MAX
; i
++) {
1032 DissectedPartition
*p
= m
->partitions
+ i
;
1038 r
= decrypt_partition(p
, passphrase
, flags
, d
);
1042 k
= PARTITION_VERITY_OF(i
);
1044 r
= verity_partition(p
, m
->partitions
+ k
, root_hash
, root_hash_size
, flags
, d
);
1049 if (!p
->decrypted_fstype
&& p
->decrypted_node
) {
1050 r
= probe_filesystem(p
->decrypted_node
, &p
->decrypted_fstype
);
1051 if (r
< 0 && r
!= -EUCLEAN
)
1065 int dissected_image_decrypt_interactively(
1067 const char *passphrase
,
1068 const void *root_hash
,
1069 size_t root_hash_size
,
1070 DissectImageFlags flags
,
1071 DecryptedImage
**ret
) {
1073 _cleanup_strv_free_erase_
char **z
= NULL
;
1080 r
= dissected_image_decrypt(m
, passphrase
, root_hash
, root_hash_size
, flags
, ret
);
1083 if (r
== -EKEYREJECTED
)
1084 log_error_errno(r
, "Incorrect passphrase, try again!");
1085 else if (r
!= -ENOKEY
) {
1086 log_error_errno(r
, "Failed to decrypt image: %m");
1091 log_error("Too many retries.");
1092 return -EKEYREJECTED
;
1097 r
= ask_password_auto("Please enter image passphrase!", NULL
, "dissect", "dissect", USEC_INFINITY
, 0, &z
);
1099 return log_error_errno(r
, "Failed to query for passphrase: %m");
1105 #if HAVE_LIBCRYPTSETUP
1106 static int deferred_remove(DecryptedPartition
*p
) {
1108 struct dm_ioctl dm
= {
1112 DM_VERSION_PATCHLEVEL
1114 .data_size
= sizeof(dm
),
1115 .flags
= DM_DEFERRED_REMOVE
,
1118 _cleanup_close_
int fd
= -1;
1122 /* Unfortunately, libcryptsetup doesn't provide a proper API for this, hence call the ioctl() directly. */
1124 fd
= open("/dev/mapper/control", O_RDWR
|O_CLOEXEC
);
1128 strncpy(dm
.name
, p
->name
, sizeof(dm
.name
));
1130 if (ioctl(fd
, DM_DEV_REMOVE
, &dm
))
1137 int decrypted_image_relinquish(DecryptedImage
*d
) {
1139 #if HAVE_LIBCRYPTSETUP
1146 /* Turns on automatic removal after the last use ended for all DM devices of this image, and sets a boolean so
1147 * that we don't clean it up ourselves either anymore */
1149 #if HAVE_LIBCRYPTSETUP
1150 for (i
= 0; i
< d
->n_decrypted
; i
++) {
1151 DecryptedPartition
*p
= d
->decrypted
+ i
;
1153 if (p
->relinquished
)
1156 r
= deferred_remove(p
);
1158 return log_debug_errno(r
, "Failed to mark %s for auto-removal: %m", p
->name
);
1160 p
->relinquished
= true;
1167 int root_hash_load(const char *image
, void **ret
, size_t *ret_size
) {
1168 _cleanup_free_
char *text
= NULL
;
1169 _cleanup_free_
void *k
= NULL
;
1177 if (is_device_path(image
)) {
1178 /* If we are asked to load the root hash for a device node, exit early */
1184 r
= getxattr_malloc(image
, "user.verity.roothash", &text
, true);
1188 if (!IN_SET(r
, -ENODATA
, -EOPNOTSUPP
, -ENOENT
))
1191 fn
= newa(char, strlen(image
) + STRLEN(".roothash") + 1);
1192 n
= stpcpy(fn
, image
);
1193 e
= endswith(fn
, ".raw");
1197 strcpy(n
, ".roothash");
1199 r
= read_one_line_file(fn
, &text
);
1209 r
= unhexmem(text
, strlen(text
), &k
, &l
);
1212 if (l
< sizeof(sd_id128_t
))
1223 int dissected_image_acquire_metadata(DissectedImage
*m
) {
1233 static const char *const paths
[_META_MAX
] = {
1234 [META_HOSTNAME
] = "/etc/hostname\0",
1235 [META_MACHINE_ID
] = "/etc/machine-id\0",
1236 [META_MACHINE_INFO
] = "/etc/machine-info\0",
1237 [META_OS_RELEASE
] = "/etc/os-release\0/usr/lib/os-release\0",
1240 _cleanup_strv_free_
char **machine_info
= NULL
, **os_release
= NULL
;
1241 _cleanup_(rmdir_and_freep
) char *t
= NULL
;
1242 _cleanup_(sigkill_waitp
) pid_t child
= 0;
1243 sd_id128_t machine_id
= SD_ID128_NULL
;
1244 _cleanup_free_
char *hostname
= NULL
;
1245 unsigned n_meta_initialized
= 0, k
;
1246 int fds
[2 * _META_MAX
], r
;
1248 BLOCK_SIGNALS(SIGCHLD
);
1252 for (; n_meta_initialized
< _META_MAX
; n_meta_initialized
++)
1253 if (pipe2(fds
+ 2*n_meta_initialized
, O_CLOEXEC
) < 0) {
1258 r
= mkdtemp_malloc("/tmp/dissect-XXXXXX", &t
);
1262 child
= raw_clone(SIGCHLD
|CLONE_NEWNS
);
1270 (void) reset_all_signal_handlers();
1271 (void) reset_signal_mask();
1272 assert_se(prctl(PR_SET_PDEATHSIG
, SIGTERM
) == 0);
1274 /* Make sure we never propagate to the host */
1275 if (mount(NULL
, "/", NULL
, MS_SLAVE
| MS_REC
, NULL
) < 0)
1276 _exit(EXIT_FAILURE
);
1278 r
= dissected_image_mount(m
, t
, UID_INVALID
, DISSECT_IMAGE_READ_ONLY
);
1280 _exit(EXIT_FAILURE
);
1282 for (k
= 0; k
< _META_MAX
; k
++) {
1283 _cleanup_close_
int fd
= -1;
1286 fds
[2*k
] = safe_close(fds
[2*k
]);
1288 NULSTR_FOREACH(p
, paths
[k
]) {
1289 _cleanup_free_
char *q
= NULL
;
1291 r
= chase_symlinks(p
, t
, CHASE_PREFIX_ROOT
, &q
);
1295 fd
= open(q
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1302 r
= copy_bytes(fd
, fds
[2*k
+1], (uint64_t) -1, 0);
1304 _exit(EXIT_FAILURE
);
1306 fds
[2*k
+1] = safe_close(fds
[2*k
+1]);
1309 _exit(EXIT_SUCCESS
);
1312 for (k
= 0; k
< _META_MAX
; k
++) {
1313 _cleanup_fclose_
FILE *f
= NULL
;
1315 fds
[2*k
+1] = safe_close(fds
[2*k
+1]);
1317 f
= fdopen(fds
[2*k
], "re");
1328 r
= read_etc_hostname_stream(f
, &hostname
);
1330 log_debug_errno(r
, "Failed to read /etc/hostname: %m");
1334 case META_MACHINE_ID
: {
1335 _cleanup_free_
char *line
= NULL
;
1337 r
= read_line(f
, LONG_LINE_MAX
, &line
);
1339 log_debug_errno(r
, "Failed to read /etc/machine-id: %m");
1341 r
= sd_id128_from_string(line
, &machine_id
);
1343 log_debug_errno(r
, "Image contains invalid /etc/machine-id: %s", line
);
1345 log_debug("/etc/machine-id file is empty.");
1347 log_debug("/etc/machine-id has unexpected length %i.", r
);
1352 case META_MACHINE_INFO
:
1353 r
= load_env_file_pairs(f
, "machine-info", NULL
, &machine_info
);
1355 log_debug_errno(r
, "Failed to read /etc/machine-info: %m");
1359 case META_OS_RELEASE
:
1360 r
= load_env_file_pairs(f
, "os-release", NULL
, &os_release
);
1362 log_debug_errno(r
, "Failed to read OS release file: %m");
1368 r
= wait_for_terminate_and_check("(sd-dissect)", child
, 0);
1372 if (r
!= EXIT_SUCCESS
)
1375 free_and_replace(m
->hostname
, hostname
);
1376 m
->machine_id
= machine_id
;
1377 strv_free_and_replace(m
->machine_info
, machine_info
);
1378 strv_free_and_replace(m
->os_release
, os_release
);
1381 for (k
= 0; k
< n_meta_initialized
; k
++)
1382 safe_close_pair(fds
+ 2*k
);
1387 static const char *const partition_designator_table
[] = {
1388 [PARTITION_ROOT
] = "root",
1389 [PARTITION_ROOT_SECONDARY
] = "root-secondary",
1390 [PARTITION_HOME
] = "home",
1391 [PARTITION_SRV
] = "srv",
1392 [PARTITION_ESP
] = "esp",
1393 [PARTITION_SWAP
] = "swap",
1394 [PARTITION_ROOT_VERITY
] = "root-verity",
1395 [PARTITION_ROOT_SECONDARY_VERITY
] = "root-secondary-verity",
1398 DEFINE_STRING_TABLE_LOOKUP(partition_designator
, int);