]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/dissect-image.c
util: make device_wait_for_initialization() optionally takes timeout value
[thirdparty/systemd.git] / src / shared / dissect-image.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
8c1be37e 2
01234e1f
YW
3#include <linux/dm-ioctl.h>
4#include <linux/loop.h>
8c1be37e 5#include <sys/mount.h>
3b925504
LP
6#include <sys/prctl.h>
7#include <sys/wait.h>
8c1be37e 8
3c1f2cee 9#include "sd-device.h"
dccca82b
LP
10#include "sd-id128.h"
11
8c1be37e 12#include "architecture.h"
18b5886e 13#include "ask-password-api.h"
8c1be37e 14#include "blkid-util.h"
18c528e9 15#include "blockdev-util.h"
3b925504 16#include "copy.h"
294bd454 17#include "crypt-util.h"
3b925504 18#include "def.h"
553e15f2 19#include "device-nodes.h"
8437c059 20#include "device-util.h"
8c1be37e 21#include "dissect-image.h"
686d13b9 22#include "env-file.h"
18b5886e 23#include "fd-util.h"
78ebe980 24#include "fileio.h"
2eedfd2d 25#include "fs-util.h"
8c1be37e 26#include "gpt.h"
78ebe980 27#include "hexdecoct.h"
3b925504
LP
28#include "hostname-util.h"
29#include "id128-util.h"
ffc01f06 30#include "missing.h"
8c1be37e 31#include "mount-util.h"
e4de7287 32#include "mountpoint-util.h"
d8b4d14d 33#include "nulstr-util.h"
d58ad743 34#include "os-util.h"
8c1be37e 35#include "path-util.h"
3b925504
LP
36#include "process-util.h"
37#include "raw-clone.h"
38#include "signal-util.h"
8c1be37e 39#include "stat-util.h"
18b5886e 40#include "stdio-util.h"
8c1be37e
LP
41#include "string-table.h"
42#include "string-util.h"
2eedfd2d 43#include "strv.h"
e4de7287 44#include "tmpfile-util.h"
a8040b6d 45#include "udev-util.h"
2d3a5a73 46#include "user-util.h"
41488e1f 47#include "xattr-util.h"
8c1be37e 48
c34b75a1 49int probe_filesystem(const char *node, char **ret_fstype) {
7cc84b2c 50 /* Try to find device content type and return it in *ret_fstype. If nothing is found,
5238e957 51 * 0/NULL will be returned. -EUCLEAN will be returned for ambiguous results, and an
7cc84b2c
ZJS
52 * different error otherwise. */
53
349cc4a5 54#if HAVE_BLKID
8e766630 55 _cleanup_(blkid_free_probep) blkid_probe b = NULL;
18b5886e
LP
56 const char *fstype;
57 int r;
58
995fa2e5 59 errno = 0;
18b5886e
LP
60 b = blkid_new_probe_from_filename(node);
61 if (!b)
995fa2e5 62 return -errno ?: -ENOMEM;
18b5886e
LP
63
64 blkid_probe_enable_superblocks(b, 1);
65 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
66
67 errno = 0;
68 r = blkid_do_safeprobe(b);
7cc84b2c
ZJS
69 if (r == 1) {
70 log_debug("No type detected on partition %s", node);
18b5886e
LP
71 goto not_found;
72 }
7cc84b2c
ZJS
73 if (r == -2) {
74 log_debug("Results ambiguous for partition %s", node);
75 return -EUCLEAN;
76 }
b382db9f
ZJS
77 if (r != 0)
78 return -errno ?: -EIO;
18b5886e
LP
79
80 (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
81
82 if (fstype) {
83 char *t;
84
85 t = strdup(fstype);
86 if (!t)
87 return -ENOMEM;
88
89 *ret_fstype = t;
90 return 1;
91 }
92
93not_found:
94 *ret_fstype = NULL;
95 return 0;
d1c536f5
ZJS
96#else
97 return -EOPNOTSUPP;
a75e27eb 98#endif
d1c536f5 99}
18b5886e 100
40c10d3f 101#if HAVE_BLKID
cde942f6
JPRV
102/* Detect RPMB and Boot partitions, which are not listed by blkid.
103 * See https://github.com/systemd/systemd/issues/5806. */
3c1f2cee 104static bool device_is_mmc_special_partition(sd_device *d) {
aae22eb3
LP
105 const char *sysname;
106
f70e7f70
LP
107 assert(d);
108
3c1f2cee
YW
109 if (sd_device_get_sysname(d, &sysname) < 0)
110 return false;
111
112 return startswith(sysname, "mmcblk") &&
0cfa78dd 113 (endswith(sysname, "rpmb") || endswith(sysname, "boot0") || endswith(sysname, "boot1"));
cde942f6
JPRV
114}
115
3c1f2cee 116static bool device_is_block(sd_device *d) {
aae22eb3
LP
117 const char *ss;
118
f70e7f70
LP
119 assert(d);
120
3c1f2cee 121 if (sd_device_get_subsystem(d, &ss) < 0)
aae22eb3
LP
122 return false;
123
124 return streq(ss, "block");
125}
ea887be0
ZJS
126
127static int enumerator_for_parent(sd_device *d, sd_device_enumerator **ret) {
128 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
129 int r;
130
f70e7f70
LP
131 assert(d);
132 assert(ret);
133
ea887be0
ZJS
134 r = sd_device_enumerator_new(&e);
135 if (r < 0)
136 return r;
137
138 r = sd_device_enumerator_allow_uninitialized(e);
139 if (r < 0)
140 return r;
141
142 r = sd_device_enumerator_add_match_parent(e, d);
143 if (r < 0)
144 return r;
145
146 *ret = TAKE_PTR(e);
147 return 0;
148}
149
150/* how many times to wait for the device nodes to appear */
151#define N_DEVICE_NODE_LIST_ATTEMPTS 10
152
153static int wait_for_partitions_to_appear(
154 int fd,
155 sd_device *d,
156 unsigned num_partitions,
052eaf5c 157 DissectImageFlags flags,
ea887be0
ZJS
158 sd_device_enumerator **ret_enumerator) {
159
160 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
161 sd_device *q;
162 unsigned n;
163 int r;
164
f70e7f70
LP
165 assert(fd >= 0);
166 assert(d);
167 assert(ret_enumerator);
168
ea887be0
ZJS
169 r = enumerator_for_parent(d, &e);
170 if (r < 0)
171 return r;
172
173 /* Count the partitions enumerated by the kernel */
174 n = 0;
175 FOREACH_DEVICE(e, q) {
176 if (sd_device_get_devnum(q, NULL) < 0)
177 continue;
178 if (!device_is_block(q))
179 continue;
180 if (device_is_mmc_special_partition(q))
181 continue;
182
052eaf5c 183 if (!FLAGS_SET(flags, DISSECT_IMAGE_NO_UDEV)) {
1b47436e 184 r = device_wait_for_initialization(q, "block", USEC_INFINITY, NULL);
052eaf5c
LP
185 if (r < 0)
186 return r;
187 }
a8040b6d 188
ea887be0
ZJS
189 n++;
190 }
191
192 if (n == num_partitions + 1) {
193 *ret_enumerator = TAKE_PTR(e);
194 return 0; /* success! */
195 }
196 if (n > num_partitions + 1)
197 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
198 "blkid and kernel partition lists do not match.");
199
200 /* The kernel has probed fewer partitions than blkid? Maybe the kernel prober is still running or it
201 * got EBUSY because udev already opened the device. Let's reprobe the device, which is a synchronous
202 * call that waits until probing is complete. */
203
204 for (unsigned j = 0; ; j++) {
205 if (j++ > 20)
206 return -EBUSY;
207
208 if (ioctl(fd, BLKRRPART, 0) >= 0)
209 break;
210 r = -errno;
211 if (r == -EINVAL) {
212 struct loop_info64 info;
213
214 /* If we are running on a loop device that has partition scanning off, return
215 * an explicit recognizable error about this, so that callers can generate a
216 * proper message explaining the situation. */
217
218 if (ioctl(fd, LOOP_GET_STATUS64, &info) >= 0 && (info.lo_flags & LO_FLAGS_PARTSCAN) == 0) {
219 log_debug("Device is a loop device and partition scanning is off!");
220 return -EPROTONOSUPPORT;
221 }
222 }
223 if (r != -EBUSY)
224 return r;
225
226 /* If something else has the device open, such as an udev rule, the ioctl will return
227 * EBUSY. Since there's no way to wait until it isn't busy anymore, let's just wait a bit,
228 * and try again.
229 *
230 * This is really something they should fix in the kernel! */
231 (void) usleep(50 * USEC_PER_MSEC);
232
233 }
234
235 return -EAGAIN; /* no success yet, try again */
236}
237
238static int loop_wait_for_partitions_to_appear(
239 int fd,
240 sd_device *d,
241 unsigned num_partitions,
052eaf5c 242 DissectImageFlags flags,
ea887be0 243 sd_device_enumerator **ret_enumerator) {
a8040b6d 244 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
ea887be0
ZJS
245 int r;
246
f70e7f70
LP
247 assert(fd >= 0);
248 assert(d);
249 assert(ret_enumerator);
250
b887c8b8
ZJS
251 log_debug("Waiting for device (parent + %d partitions) to appear...", num_partitions);
252
052eaf5c 253 if (!FLAGS_SET(flags, DISSECT_IMAGE_NO_UDEV)) {
1b47436e 254 r = device_wait_for_initialization(d, "block", USEC_INFINITY, &device);
052eaf5c
LP
255 if (r < 0)
256 return r;
257 } else
258 device = sd_device_ref(d);
a8040b6d 259
ea887be0 260 for (unsigned i = 0; i < N_DEVICE_NODE_LIST_ATTEMPTS; i++) {
052eaf5c 261 r = wait_for_partitions_to_appear(fd, device, num_partitions, flags, ret_enumerator);
ea887be0
ZJS
262 if (r != -EAGAIN)
263 return r;
264 }
265
266 return log_debug_errno(SYNTHETIC_ERRNO(ENXIO),
267 "Kernel partitions dit not appear within %d attempts",
268 N_DEVICE_NODE_LIST_ATTEMPTS);
269}
270
40c10d3f 271#endif
aae22eb3 272
4526113f
LP
273int dissect_image(
274 int fd,
275 const void *root_hash,
276 size_t root_hash_size,
277 DissectImageFlags flags,
278 DissectedImage **ret) {
8c1be37e 279
349cc4a5 280#if HAVE_BLKID
4623e8e6 281 sd_id128_t root_uuid = SD_ID128_NULL, verity_uuid = SD_ID128_NULL;
3c1f2cee 282 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
8c1be37e 283 bool is_gpt, is_mbr, generic_rw, multiple_generic = false;
3c1f2cee 284 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
8c1be37e 285 _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
8e766630 286 _cleanup_(blkid_free_probep) blkid_probe b = NULL;
8c1be37e 287 _cleanup_free_ char *generic_node = NULL;
be30ad41 288 sd_id128_t generic_uuid = SD_ID128_NULL;
9b6deb03 289 const char *pttype = NULL;
8c1be37e
LP
290 blkid_partlist pl;
291 int r, generic_nr;
292 struct stat st;
3c1f2cee 293 sd_device *q;
8c1be37e
LP
294 unsigned i;
295
296 assert(fd >= 0);
297 assert(ret);
4623e8e6 298 assert(root_hash || root_hash_size == 0);
8c1be37e
LP
299
300 /* Probes a disk image, and returns information about what it found in *ret.
301 *
4623e8e6
LP
302 * Returns -ENOPKG if no suitable partition table or file system could be found.
303 * Returns -EADDRNOTAVAIL if a root hash was specified but no matching root/verity partitions found. */
304
305 if (root_hash) {
306 /* If a root hash is supplied, then we use the root partition that has a UUID that match the first
307 * 128bit of the root hash. And we use the verity partition that has a UUID that match the final
308 * 128bit. */
309
310 if (root_hash_size < sizeof(sd_id128_t))
311 return -EINVAL;
312
313 memcpy(&root_uuid, root_hash, sizeof(sd_id128_t));
314 memcpy(&verity_uuid, (const uint8_t*) root_hash + root_hash_size - sizeof(sd_id128_t), sizeof(sd_id128_t));
315
316 if (sd_id128_is_null(root_uuid))
317 return -EINVAL;
318 if (sd_id128_is_null(verity_uuid))
319 return -EINVAL;
320 }
8c1be37e
LP
321
322 if (fstat(fd, &st) < 0)
323 return -errno;
324
325 if (!S_ISBLK(st.st_mode))
326 return -ENOTBLK;
327
328 b = blkid_new_probe();
329 if (!b)
330 return -ENOMEM;
331
332 errno = 0;
333 r = blkid_probe_set_device(b, fd, 0, 0);
b382db9f
ZJS
334 if (r != 0)
335 return -errno ?: -ENOMEM;
8c1be37e 336
9b6deb03
LP
337 if ((flags & DISSECT_IMAGE_GPT_ONLY) == 0) {
338 /* Look for file system superblocks, unless we only shall look for GPT partition tables */
339 blkid_probe_enable_superblocks(b, 1);
340 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_USAGE);
341 }
342
8c1be37e
LP
343 blkid_probe_enable_partitions(b, 1);
344 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
345
346 errno = 0;
347 r = blkid_do_safeprobe(b);
59ba6d0c
LP
348 if (IN_SET(r, -2, 1))
349 return log_debug_errno(SYNTHETIC_ERRNO(ENOPKG), "Failed to identify any partition table.");
b382db9f
ZJS
350 if (r != 0)
351 return -errno ?: -EIO;
8c1be37e
LP
352
353 m = new0(DissectedImage, 1);
354 if (!m)
355 return -ENOMEM;
356
b887c8b8
ZJS
357 r = sd_device_new_from_devnum(&d, 'b', st.st_rdev);
358 if (r < 0)
359 return r;
360
e0f9e7bd
LP
361 if (!(flags & DISSECT_IMAGE_GPT_ONLY) &&
362 (flags & DISSECT_IMAGE_REQUIRE_ROOT)) {
9b6deb03 363 const char *usage = NULL;
8c1be37e 364
9b6deb03
LP
365 (void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL);
366 if (STRPTR_IN_SET(usage, "filesystem", "crypto")) {
367 _cleanup_free_ char *t = NULL, *n = NULL;
368 const char *fstype = NULL;
8c1be37e 369
9b6deb03
LP
370 /* OK, we have found a file system, that's our root partition then. */
371 (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
8c1be37e 372
9b6deb03
LP
373 if (fstype) {
374 t = strdup(fstype);
375 if (!t)
376 return -ENOMEM;
377 }
378
54b22b26
LP
379 r = device_path_make_major_minor(st.st_mode, st.st_rdev, &n);
380 if (r < 0)
381 return r;
8c1be37e 382
9b6deb03
LP
383 m->partitions[PARTITION_ROOT] = (DissectedPartition) {
384 .found = true,
385 .rw = true,
386 .partno = -1,
387 .architecture = _ARCHITECTURE_INVALID,
1cc6c93a
YW
388 .fstype = TAKE_PTR(t),
389 .node = TAKE_PTR(n),
9b6deb03 390 };
8c1be37e 391
4db1879a 392 m->encrypted = streq_ptr(fstype, "crypto_LUKS");
18b5886e 393
052eaf5c 394 r = loop_wait_for_partitions_to_appear(fd, d, 0, flags, &e);
b887c8b8
ZJS
395 if (r < 0)
396 return r;
397
1cc6c93a 398 *ret = TAKE_PTR(m);
8c1be37e 399
9b6deb03
LP
400 return 0;
401 }
8c1be37e
LP
402 }
403
404 (void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
405 if (!pttype)
406 return -ENOPKG;
407
408 is_gpt = streq_ptr(pttype, "gpt");
409 is_mbr = streq_ptr(pttype, "dos");
410
9b6deb03 411 if (!is_gpt && ((flags & DISSECT_IMAGE_GPT_ONLY) || !is_mbr))
8c1be37e
LP
412 return -ENOPKG;
413
414 errno = 0;
415 pl = blkid_probe_get_partitions(b);
b382db9f
ZJS
416 if (!pl)
417 return -errno ?: -ENOMEM;
8c1be37e 418
052eaf5c 419 r = loop_wait_for_partitions_to_appear(fd, d, blkid_partlist_numof_partitions(pl), flags, &e);
ea887be0
ZJS
420 if (r < 0)
421 return r;
8c1be37e 422
8437c059 423 FOREACH_DEVICE(e, q) {
9b6deb03 424 unsigned long long pflags;
8c1be37e 425 blkid_partition pp;
cde942f6 426 const char *node;
8c1be37e
LP
427 dev_t qn;
428 int nr;
429
3c1f2cee
YW
430 r = sd_device_get_devnum(q, &qn);
431 if (r < 0)
8c1be37e
LP
432 continue;
433
434 if (st.st_rdev == qn)
435 continue;
436
aae22eb3
LP
437 if (!device_is_block(q))
438 continue;
439
cde942f6 440 if (device_is_mmc_special_partition(q))
7be1420f
LP
441 continue;
442
3c1f2cee
YW
443 r = sd_device_get_devname(q, &node);
444 if (r < 0)
8c1be37e
LP
445 continue;
446
447 pp = blkid_partlist_devno_to_partition(pl, qn);
448 if (!pp)
449 continue;
450
9b6deb03 451 pflags = blkid_partition_get_flags(pp);
8c1be37e
LP
452
453 nr = blkid_partition_get_partno(pp);
454 if (nr < 0)
455 continue;
456
457 if (is_gpt) {
458 int designator = _PARTITION_DESIGNATOR_INVALID, architecture = _ARCHITECTURE_INVALID;
4623e8e6
LP
459 const char *stype, *sid, *fstype = NULL;
460 sd_id128_t type_id, id;
8c1be37e
LP
461 bool rw = true;
462
4623e8e6
LP
463 sid = blkid_partition_get_uuid(pp);
464 if (!sid)
465 continue;
466 if (sd_id128_from_string(sid, &id) < 0)
467 continue;
468
8c1be37e
LP
469 stype = blkid_partition_get_type_string(pp);
470 if (!stype)
471 continue;
8c1be37e
LP
472 if (sd_id128_from_string(stype, &type_id) < 0)
473 continue;
474
475 if (sd_id128_equal(type_id, GPT_HOME)) {
a48dd347
LP
476
477 if (pflags & GPT_FLAG_NO_AUTO)
478 continue;
479
8c1be37e 480 designator = PARTITION_HOME;
9b6deb03 481 rw = !(pflags & GPT_FLAG_READ_ONLY);
8c1be37e 482 } else if (sd_id128_equal(type_id, GPT_SRV)) {
a48dd347
LP
483
484 if (pflags & GPT_FLAG_NO_AUTO)
485 continue;
486
8c1be37e 487 designator = PARTITION_SRV;
9b6deb03 488 rw = !(pflags & GPT_FLAG_READ_ONLY);
8c1be37e 489 } else if (sd_id128_equal(type_id, GPT_ESP)) {
a48dd347
LP
490
491 /* Note that we don't check the GPT_FLAG_NO_AUTO flag for the ESP, as it is not defined
492 * there. We instead check the GPT_FLAG_NO_BLOCK_IO_PROTOCOL, as recommended by the
493 * UEFI spec (See "12.3.3 Number and Location of System Partitions"). */
494
495 if (pflags & GPT_FLAG_NO_BLOCK_IO_PROTOCOL)
496 continue;
497
8c1be37e
LP
498 designator = PARTITION_ESP;
499 fstype = "vfat";
a8c47660
LP
500
501 } else if (sd_id128_equal(type_id, GPT_XBOOTLDR)) {
502
503 if (pflags & GPT_FLAG_NO_AUTO)
504 continue;
505
506 designator = PARTITION_XBOOTLDR;
507 rw = !(pflags & GPT_FLAG_READ_ONLY);
8c1be37e
LP
508 }
509#ifdef GPT_ROOT_NATIVE
510 else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) {
4623e8e6 511
a48dd347
LP
512 if (pflags & GPT_FLAG_NO_AUTO)
513 continue;
514
4623e8e6
LP
515 /* If a root ID is specified, ignore everything but the root id */
516 if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id))
517 continue;
518
8c1be37e
LP
519 designator = PARTITION_ROOT;
520 architecture = native_architecture();
9b6deb03 521 rw = !(pflags & GPT_FLAG_READ_ONLY);
4f8b86e3 522 } else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY)) {
4623e8e6 523
a48dd347
LP
524 if (pflags & GPT_FLAG_NO_AUTO)
525 continue;
526
4623e8e6
LP
527 m->can_verity = true;
528
529 /* Ignore verity unless a root hash is specified */
530 if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id))
531 continue;
532
533 designator = PARTITION_ROOT_VERITY;
534 fstype = "DM_verity_hash";
535 architecture = native_architecture();
536 rw = false;
537 }
538#endif
8c1be37e
LP
539#ifdef GPT_ROOT_SECONDARY
540 else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY)) {
4623e8e6 541
a48dd347
LP
542 if (pflags & GPT_FLAG_NO_AUTO)
543 continue;
544
4623e8e6
LP
545 /* If a root ID is specified, ignore everything but the root id */
546 if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id))
547 continue;
548
8c1be37e
LP
549 designator = PARTITION_ROOT_SECONDARY;
550 architecture = SECONDARY_ARCHITECTURE;
9b6deb03 551 rw = !(pflags & GPT_FLAG_READ_ONLY);
4f8b86e3 552 } else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY)) {
a48dd347
LP
553
554 if (pflags & GPT_FLAG_NO_AUTO)
555 continue;
556
4623e8e6
LP
557 m->can_verity = true;
558
559 /* Ignore verity unless root has is specified */
560 if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id))
561 continue;
562
563 designator = PARTITION_ROOT_SECONDARY_VERITY;
564 fstype = "DM_verity_hash";
565 architecture = SECONDARY_ARCHITECTURE;
566 rw = false;
567 }
8c1be37e
LP
568#endif
569 else if (sd_id128_equal(type_id, GPT_SWAP)) {
a48dd347
LP
570
571 if (pflags & GPT_FLAG_NO_AUTO)
572 continue;
573
8c1be37e
LP
574 designator = PARTITION_SWAP;
575 fstype = "swap";
576 } else if (sd_id128_equal(type_id, GPT_LINUX_GENERIC)) {
577
a48dd347
LP
578 if (pflags & GPT_FLAG_NO_AUTO)
579 continue;
580
8c1be37e
LP
581 if (generic_node)
582 multiple_generic = true;
583 else {
584 generic_nr = nr;
9b6deb03 585 generic_rw = !(pflags & GPT_FLAG_READ_ONLY);
be30ad41 586 generic_uuid = id;
8c1be37e
LP
587 generic_node = strdup(node);
588 if (!generic_node)
589 return -ENOMEM;
590 }
591 }
592
593 if (designator != _PARTITION_DESIGNATOR_INVALID) {
594 _cleanup_free_ char *t = NULL, *n = NULL;
595
596 /* First one wins */
597 if (m->partitions[designator].found)
598 continue;
599
600 if (fstype) {
601 t = strdup(fstype);
602 if (!t)
603 return -ENOMEM;
604 }
605
606 n = strdup(node);
607 if (!n)
608 return -ENOMEM;
609
610 m->partitions[designator] = (DissectedPartition) {
611 .found = true,
612 .partno = nr,
613 .rw = rw,
614 .architecture = architecture,
1cc6c93a
YW
615 .node = TAKE_PTR(n),
616 .fstype = TAKE_PTR(t),
be30ad41 617 .uuid = id,
8c1be37e 618 };
8c1be37e
LP
619 }
620
621 } else if (is_mbr) {
622
a8c47660 623 switch (blkid_partition_get_type(pp)) {
8c1be37e 624
a8c47660
LP
625 case 0x83: /* Linux partition */
626
627 if (pflags != 0x80) /* Bootable flag */
628 continue;
8c1be37e 629
a8c47660
LP
630 if (generic_node)
631 multiple_generic = true;
632 else {
633 generic_nr = nr;
634 generic_rw = true;
635 generic_node = strdup(node);
636 if (!generic_node)
637 return -ENOMEM;
638 }
639
640 break;
641
642 case 0xEA: { /* Boot Loader Spec extended $BOOT partition */
643 _cleanup_free_ char *n = NULL;
644 sd_id128_t id = SD_ID128_NULL;
645 const char *sid;
646
647 /* First one wins */
648 if (m->partitions[PARTITION_XBOOTLDR].found)
649 continue;
650
651 sid = blkid_partition_get_uuid(pp);
652 if (sid)
653 (void) sd_id128_from_string(sid, &id);
654
655 n = strdup(node);
656 if (!n)
8c1be37e 657 return -ENOMEM;
a8c47660
LP
658
659 m->partitions[PARTITION_XBOOTLDR] = (DissectedPartition) {
660 .found = true,
661 .partno = nr,
662 .rw = true,
663 .architecture = _ARCHITECTURE_INVALID,
664 .node = TAKE_PTR(n),
665 .uuid = id,
666 };
667
668 break;
669 }}
8c1be37e
LP
670 }
671 }
672
673 if (!m->partitions[PARTITION_ROOT].found) {
674 /* No root partition found? Then let's see if ther's one for the secondary architecture. And if not
675 * either, then check if there's a single generic one, and use that. */
676
4623e8e6 677 if (m->partitions[PARTITION_ROOT_VERITY].found)
e0f9e7bd 678 return -EADDRNOTAVAIL;
4623e8e6 679
8c1be37e
LP
680 if (m->partitions[PARTITION_ROOT_SECONDARY].found) {
681 m->partitions[PARTITION_ROOT] = m->partitions[PARTITION_ROOT_SECONDARY];
682 zero(m->partitions[PARTITION_ROOT_SECONDARY]);
4623e8e6
LP
683
684 m->partitions[PARTITION_ROOT_VERITY] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY];
685 zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY]);
686
e0f9e7bd
LP
687 } else if (flags & DISSECT_IMAGE_REQUIRE_ROOT) {
688
689 /* If the root has was set, then we won't fallback to a generic node, because the root hash
690 * decides */
691 if (root_hash)
692 return -EADDRNOTAVAIL;
8c1be37e 693
e0f9e7bd
LP
694 /* If we didn't find a generic node, then we can't fix this up either */
695 if (!generic_node)
696 return -ENXIO;
697
698 /* If we didn't find a properly marked root partition, but we did find a single suitable
699 * generic Linux partition, then use this as root partition, if the caller asked for it. */
8c1be37e
LP
700 if (multiple_generic)
701 return -ENOTUNIQ;
702
703 m->partitions[PARTITION_ROOT] = (DissectedPartition) {
704 .found = true,
705 .rw = generic_rw,
706 .partno = generic_nr,
707 .architecture = _ARCHITECTURE_INVALID,
1cc6c93a 708 .node = TAKE_PTR(generic_node),
be30ad41 709 .uuid = generic_uuid,
8c1be37e 710 };
e0f9e7bd 711 }
8c1be37e
LP
712 }
713
4623e8e6 714 if (root_hash) {
e0f9e7bd 715 if (!m->partitions[PARTITION_ROOT_VERITY].found || !m->partitions[PARTITION_ROOT].found)
4623e8e6
LP
716 return -EADDRNOTAVAIL;
717
718 /* If we found the primary root with the hash, then we definitely want to suppress any secondary root
719 * (which would be weird, after all the root hash should only be assigned to one pair of
720 * partitions... */
721 m->partitions[PARTITION_ROOT_SECONDARY].found = false;
722 m->partitions[PARTITION_ROOT_SECONDARY_VERITY].found = false;
723
724 /* If we found a verity setup, then the root partition is necessarily read-only. */
725 m->partitions[PARTITION_ROOT].rw = false;
726
727 m->verity = true;
728 }
729
18b5886e
LP
730 blkid_free_probe(b);
731 b = NULL;
732
8c1be37e
LP
733 /* Fill in file system types if we don't know them yet. */
734 for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
18b5886e 735 DissectedPartition *p = m->partitions + i;
8c1be37e 736
18b5886e 737 if (!p->found)
8c1be37e
LP
738 continue;
739
18b5886e
LP
740 if (!p->fstype && p->node) {
741 r = probe_filesystem(p->node, &p->fstype);
7cc84b2c 742 if (r < 0 && r != -EUCLEAN)
18b5886e 743 return r;
8c1be37e
LP
744 }
745
18b5886e
LP
746 if (streq_ptr(p->fstype, "crypto_LUKS"))
747 m->encrypted = true;
896f937f
LP
748
749 if (p->fstype && fstype_is_ro(p->fstype))
750 p->rw = false;
8c1be37e
LP
751 }
752
1cc6c93a 753 *ret = TAKE_PTR(m);
8c1be37e
LP
754
755 return 0;
756#else
757 return -EOPNOTSUPP;
758#endif
759}
760
761DissectedImage* dissected_image_unref(DissectedImage *m) {
762 unsigned i;
763
764 if (!m)
765 return NULL;
766
767 for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
768 free(m->partitions[i].fstype);
769 free(m->partitions[i].node);
18b5886e
LP
770 free(m->partitions[i].decrypted_fstype);
771 free(m->partitions[i].decrypted_node);
8c1be37e
LP
772 }
773
3b925504
LP
774 free(m->hostname);
775 strv_free(m->machine_info);
776 strv_free(m->os_release);
777
5fecf46d 778 return mfree(m);
8c1be37e
LP
779}
780
18b5886e 781static int is_loop_device(const char *path) {
553e15f2 782 char s[SYS_BLOCK_PATH_MAX("/../loop/")];
18b5886e
LP
783 struct stat st;
784
785 assert(path);
786
787 if (stat(path, &st) < 0)
788 return -errno;
789
790 if (!S_ISBLK(st.st_mode))
791 return -ENOTBLK;
792
553e15f2 793 xsprintf_sys_block_path(s, "/loop/", st.st_dev);
18b5886e
LP
794 if (access(s, F_OK) < 0) {
795 if (errno != ENOENT)
796 return -errno;
797
798 /* The device itself isn't a loop device, but maybe it's a partition and its parent is? */
553e15f2 799 xsprintf_sys_block_path(s, "/../loop/", st.st_dev);
18b5886e
LP
800 if (access(s, F_OK) < 0)
801 return errno == ENOENT ? false : -errno;
802 }
803
804 return true;
805}
806
807static int mount_partition(
808 DissectedPartition *m,
809 const char *where,
810 const char *directory,
2d3a5a73 811 uid_t uid_shift,
18b5886e
LP
812 DissectImageFlags flags) {
813
2d3a5a73
LP
814 _cleanup_free_ char *chased = NULL, *options = NULL;
815 const char *p, *node, *fstype;
8c1be37e 816 bool rw;
2eedfd2d 817 int r;
8c1be37e
LP
818
819 assert(m);
820 assert(where);
821
18b5886e
LP
822 node = m->decrypted_node ?: m->node;
823 fstype = m->decrypted_fstype ?: m->fstype;
824
825 if (!m->found || !node || !fstype)
8c1be37e
LP
826 return 0;
827
18b5886e
LP
828 /* Stacked encryption? Yuck */
829 if (streq_ptr(fstype, "crypto_LUKS"))
830 return -ELOOP;
831
832 rw = m->rw && !(flags & DISSECT_IMAGE_READ_ONLY);
8c1be37e 833
2eedfd2d
LP
834 if (directory) {
835 r = chase_symlinks(directory, where, CHASE_PREFIX_ROOT, &chased);
836 if (r < 0)
837 return r;
838
839 p = chased;
840 } else
8c1be37e
LP
841 p = where;
842
18b5886e 843 /* If requested, turn on discard support. */
154d2269 844 if (fstype_can_discard(fstype) &&
18b5886e 845 ((flags & DISSECT_IMAGE_DISCARD) ||
2d3a5a73
LP
846 ((flags & DISSECT_IMAGE_DISCARD_ON_LOOP) && is_loop_device(m->node)))) {
847 options = strdup("discard");
848 if (!options)
849 return -ENOMEM;
850 }
851
852 if (uid_is_valid(uid_shift) && uid_shift != 0 && fstype_can_uid_gid(fstype)) {
853 _cleanup_free_ char *uid_option = NULL;
854
855 if (asprintf(&uid_option, "uid=" UID_FMT ",gid=" GID_FMT, uid_shift, (gid_t) uid_shift) < 0)
856 return -ENOMEM;
857
858 if (!strextend_with_separator(&options, ",", uid_option, NULL))
859 return -ENOMEM;
860 }
8c1be37e 861
d9223c07
LP
862 r = mount_verbose(LOG_DEBUG, node, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), options);
863 if (r < 0)
864 return r;
865
866 return 1;
8c1be37e
LP
867}
868
2d3a5a73 869int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, DissectImageFlags flags) {
d9223c07 870 int r, boot_mounted;
8c1be37e
LP
871
872 assert(m);
873 assert(where);
874
875 if (!m->partitions[PARTITION_ROOT].found)
876 return -ENXIO;
877
2d3a5a73
LP
878 if ((flags & DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY) == 0) {
879 r = mount_partition(m->partitions + PARTITION_ROOT, where, NULL, uid_shift, flags);
880 if (r < 0)
881 return r;
03bcb6d4
LP
882
883 if (flags & DISSECT_IMAGE_VALIDATE_OS) {
884 r = path_is_os_tree(where);
885 if (r < 0)
886 return r;
887 if (r == 0)
888 return -EMEDIUMTYPE;
889 }
2d3a5a73
LP
890 }
891
705727fd 892 if (flags & DISSECT_IMAGE_MOUNT_ROOT_ONLY)
2d3a5a73 893 return 0;
8c1be37e 894
2d3a5a73 895 r = mount_partition(m->partitions + PARTITION_HOME, where, "/home", uid_shift, flags);
8c1be37e
LP
896 if (r < 0)
897 return r;
898
2d3a5a73 899 r = mount_partition(m->partitions + PARTITION_SRV, where, "/srv", uid_shift, flags);
8c1be37e
LP
900 if (r < 0)
901 return r;
902
d9223c07
LP
903 boot_mounted = mount_partition(m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, flags);
904 if (boot_mounted < 0)
905 return boot_mounted;
906
8c1be37e 907 if (m->partitions[PARTITION_ESP].found) {
d9223c07
LP
908 /* Mount the ESP to /efi if it exists. If it doesn't exist, use /boot instead, but only if it
909 * exists and is empty, and we didn't already mount the XBOOTLDR partition into it. */
8c1be37e 910
d9223c07
LP
911 r = chase_symlinks("/efi", where, CHASE_PREFIX_ROOT, NULL);
912 if (r >= 0) {
913 r = mount_partition(m->partitions + PARTITION_ESP, where, "/efi", uid_shift, flags);
914 if (r < 0)
915 return r;
8c1be37e 916
d9223c07 917 } else if (boot_mounted <= 0) {
2eedfd2d
LP
918 _cleanup_free_ char *p = NULL;
919
d9223c07
LP
920 r = chase_symlinks("/boot", where, CHASE_PREFIX_ROOT, &p);
921 if (r >= 0 && dir_is_empty(p) > 0) {
922 r = mount_partition(m->partitions + PARTITION_ESP, where, "/boot", uid_shift, flags);
2eedfd2d
LP
923 if (r < 0)
924 return r;
925 }
8c1be37e
LP
926 }
927 }
928
929 return 0;
930}
931
349cc4a5 932#if HAVE_LIBCRYPTSETUP
18b5886e
LP
933typedef struct DecryptedPartition {
934 struct crypt_device *device;
935 char *name;
936 bool relinquished;
937} DecryptedPartition;
938
939struct DecryptedImage {
940 DecryptedPartition *decrypted;
941 size_t n_decrypted;
942 size_t n_allocated;
943};
944#endif
945
946DecryptedImage* decrypted_image_unref(DecryptedImage* d) {
349cc4a5 947#if HAVE_LIBCRYPTSETUP
18b5886e
LP
948 size_t i;
949 int r;
950
951 if (!d)
952 return NULL;
953
954 for (i = 0; i < d->n_decrypted; i++) {
955 DecryptedPartition *p = d->decrypted + i;
956
957 if (p->device && p->name && !p->relinquished) {
958 r = crypt_deactivate(p->device, p->name);
959 if (r < 0)
960 log_debug_errno(r, "Failed to deactivate encrypted partition %s", p->name);
961 }
962
963 if (p->device)
964 crypt_free(p->device);
965 free(p->name);
966 }
967
968 free(d);
969#endif
970 return NULL;
971}
972
349cc4a5 973#if HAVE_LIBCRYPTSETUP
4623e8e6
LP
974
975static int make_dm_name_and_node(const void *original_node, const char *suffix, char **ret_name, char **ret_node) {
976 _cleanup_free_ char *name = NULL, *node = NULL;
977 const char *base;
978
979 assert(original_node);
980 assert(suffix);
981 assert(ret_name);
982 assert(ret_node);
983
984 base = strrchr(original_node, '/');
985 if (!base)
986 return -EINVAL;
987 base++;
988 if (isempty(base))
989 return -EINVAL;
990
991 name = strjoin(base, suffix);
992 if (!name)
993 return -ENOMEM;
994 if (!filename_is_valid(name))
995 return -EINVAL;
996
997 node = strjoin(crypt_get_dir(), "/", name);
998 if (!node)
999 return -ENOMEM;
1000
1cc6c93a
YW
1001 *ret_name = TAKE_PTR(name);
1002 *ret_node = TAKE_PTR(node);
4623e8e6 1003
4623e8e6
LP
1004 return 0;
1005}
1006
18b5886e
LP
1007static int decrypt_partition(
1008 DissectedPartition *m,
1009 const char *passphrase,
1010 DissectImageFlags flags,
1011 DecryptedImage *d) {
1012
1013 _cleanup_free_ char *node = NULL, *name = NULL;
294bd454 1014 _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
18b5886e
LP
1015 int r;
1016
1017 assert(m);
1018 assert(d);
1019
1020 if (!m->found || !m->node || !m->fstype)
1021 return 0;
1022
1023 if (!streq(m->fstype, "crypto_LUKS"))
1024 return 0;
1025
bdd73ac5
ZJS
1026 if (!passphrase)
1027 return -ENOKEY;
1028
4623e8e6
LP
1029 r = make_dm_name_and_node(m->node, "-decrypted", &name, &node);
1030 if (r < 0)
1031 return r;
18b5886e
LP
1032
1033 if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1))
1034 return -ENOMEM;
1035
1036 r = crypt_init(&cd, m->node);
1037 if (r < 0)
715cbb81 1038 return log_debug_errno(r, "Failed to initialize dm-crypt: %m");
18b5886e 1039
dd59868b 1040 r = crypt_load(cd, CRYPT_LUKS, NULL);
294bd454
ZJS
1041 if (r < 0)
1042 return log_debug_errno(r, "Failed to load LUKS metadata: %m");
18b5886e
LP
1043
1044 r = crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, passphrase, strlen(passphrase),
1045 ((flags & DISSECT_IMAGE_READ_ONLY) ? CRYPT_ACTIVATE_READONLY : 0) |
1046 ((flags & DISSECT_IMAGE_DISCARD_ON_CRYPTO) ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0));
294bd454 1047 if (r < 0) {
715cbb81 1048 log_debug_errno(r, "Failed to activate LUKS device: %m");
294bd454 1049 return r == -EPERM ? -EKEYREJECTED : r;
18b5886e 1050 }
18b5886e 1051
1cc6c93a
YW
1052 d->decrypted[d->n_decrypted].name = TAKE_PTR(name);
1053 d->decrypted[d->n_decrypted].device = TAKE_PTR(cd);
18b5886e
LP
1054 d->n_decrypted++;
1055
1cc6c93a 1056 m->decrypted_node = TAKE_PTR(node);
18b5886e
LP
1057
1058 return 0;
4623e8e6
LP
1059}
1060
1061static int verity_partition(
1062 DissectedPartition *m,
1063 DissectedPartition *v,
1064 const void *root_hash,
1065 size_t root_hash_size,
1066 DissectImageFlags flags,
1067 DecryptedImage *d) {
1068
1069 _cleanup_free_ char *node = NULL, *name = NULL;
294bd454 1070 _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
4623e8e6
LP
1071 int r;
1072
1073 assert(m);
1074 assert(v);
1075
1076 if (!root_hash)
1077 return 0;
1078
1079 if (!m->found || !m->node || !m->fstype)
1080 return 0;
1081 if (!v->found || !v->node || !v->fstype)
1082 return 0;
1083
1084 if (!streq(v->fstype, "DM_verity_hash"))
1085 return 0;
1086
1087 r = make_dm_name_and_node(m->node, "-verity", &name, &node);
1088 if (r < 0)
1089 return r;
1090
1091 if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1))
1092 return -ENOMEM;
1093
1094 r = crypt_init(&cd, v->node);
1095 if (r < 0)
1096 return r;
1097
1098 r = crypt_load(cd, CRYPT_VERITY, NULL);
1099 if (r < 0)
294bd454 1100 return r;
4623e8e6
LP
1101
1102 r = crypt_set_data_device(cd, m->node);
1103 if (r < 0)
294bd454 1104 return r;
4623e8e6
LP
1105
1106 r = crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY);
1107 if (r < 0)
294bd454 1108 return r;
4623e8e6 1109
1cc6c93a
YW
1110 d->decrypted[d->n_decrypted].name = TAKE_PTR(name);
1111 d->decrypted[d->n_decrypted].device = TAKE_PTR(cd);
4623e8e6
LP
1112 d->n_decrypted++;
1113
1cc6c93a 1114 m->decrypted_node = TAKE_PTR(node);
4623e8e6
LP
1115
1116 return 0;
18b5886e
LP
1117}
1118#endif
1119
1120int dissected_image_decrypt(
1121 DissectedImage *m,
1122 const char *passphrase,
4623e8e6
LP
1123 const void *root_hash,
1124 size_t root_hash_size,
18b5886e
LP
1125 DissectImageFlags flags,
1126 DecryptedImage **ret) {
1127
349cc4a5 1128#if HAVE_LIBCRYPTSETUP
49b5b3b4 1129 _cleanup_(decrypted_image_unrefp) DecryptedImage *d = NULL;
18b5886e
LP
1130 unsigned i;
1131 int r;
1132#endif
1133
1134 assert(m);
4623e8e6 1135 assert(root_hash || root_hash_size == 0);
18b5886e
LP
1136
1137 /* Returns:
1138 *
1139 * = 0 → There was nothing to decrypt
1140 * > 0 → Decrypted successfully
d1c536f5 1141 * -ENOKEY → There's something to decrypt but no key was supplied
18b5886e
LP
1142 * -EKEYREJECTED → Passed key was not correct
1143 */
1144
4623e8e6
LP
1145 if (root_hash && root_hash_size < sizeof(sd_id128_t))
1146 return -EINVAL;
1147
1148 if (!m->encrypted && !m->verity) {
18b5886e
LP
1149 *ret = NULL;
1150 return 0;
1151 }
1152
349cc4a5 1153#if HAVE_LIBCRYPTSETUP
18b5886e
LP
1154 d = new0(DecryptedImage, 1);
1155 if (!d)
1156 return -ENOMEM;
1157
1158 for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
1159 DissectedPartition *p = m->partitions + i;
4623e8e6 1160 int k;
18b5886e
LP
1161
1162 if (!p->found)
1163 continue;
1164
1165 r = decrypt_partition(p, passphrase, flags, d);
1166 if (r < 0)
1167 return r;
1168
4623e8e6
LP
1169 k = PARTITION_VERITY_OF(i);
1170 if (k >= 0) {
1171 r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, flags, d);
1172 if (r < 0)
1173 return r;
1174 }
1175
18b5886e
LP
1176 if (!p->decrypted_fstype && p->decrypted_node) {
1177 r = probe_filesystem(p->decrypted_node, &p->decrypted_fstype);
7cc84b2c 1178 if (r < 0 && r != -EUCLEAN)
18b5886e
LP
1179 return r;
1180 }
1181 }
1182
1cc6c93a 1183 *ret = TAKE_PTR(d);
18b5886e
LP
1184
1185 return 1;
1186#else
1187 return -EOPNOTSUPP;
1188#endif
1189}
1190
1191int dissected_image_decrypt_interactively(
1192 DissectedImage *m,
1193 const char *passphrase,
4623e8e6
LP
1194 const void *root_hash,
1195 size_t root_hash_size,
18b5886e
LP
1196 DissectImageFlags flags,
1197 DecryptedImage **ret) {
1198
1199 _cleanup_strv_free_erase_ char **z = NULL;
1200 int n = 3, r;
1201
1202 if (passphrase)
1203 n--;
1204
1205 for (;;) {
4623e8e6 1206 r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, flags, ret);
18b5886e
LP
1207 if (r >= 0)
1208 return r;
1209 if (r == -EKEYREJECTED)
1210 log_error_errno(r, "Incorrect passphrase, try again!");
fc95c359
YW
1211 else if (r != -ENOKEY)
1212 return log_error_errno(r, "Failed to decrypt image: %m");
18b5886e 1213
baaa35ad
ZJS
1214 if (--n < 0)
1215 return log_error_errno(SYNTHETIC_ERRNO(EKEYREJECTED),
1216 "Too many retries.");
18b5886e
LP
1217
1218 z = strv_free(z);
1219
a1c111c2 1220 r = ask_password_auto("Please enter image passphrase:", NULL, "dissect", "dissect", USEC_INFINITY, 0, &z);
18b5886e
LP
1221 if (r < 0)
1222 return log_error_errno(r, "Failed to query for passphrase: %m");
1223
1224 passphrase = z[0];
1225 }
1226}
1227
349cc4a5 1228#if HAVE_LIBCRYPTSETUP
18b5886e 1229static int deferred_remove(DecryptedPartition *p) {
18b5886e
LP
1230 struct dm_ioctl dm = {
1231 .version = {
1232 DM_VERSION_MAJOR,
1233 DM_VERSION_MINOR,
1234 DM_VERSION_PATCHLEVEL
1235 },
1236 .data_size = sizeof(dm),
1237 .flags = DM_DEFERRED_REMOVE,
1238 };
1239
1240 _cleanup_close_ int fd = -1;
1241
1242 assert(p);
1243
1244 /* Unfortunately, libcryptsetup doesn't provide a proper API for this, hence call the ioctl() directly. */
1245
1246 fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
1247 if (fd < 0)
1248 return -errno;
1249
cd8c98d7
ZJS
1250 if (strlen(p->name) > sizeof(dm.name))
1251 return -ENAMETOOLONG;
1252
18b5886e
LP
1253 strncpy(dm.name, p->name, sizeof(dm.name));
1254
1255 if (ioctl(fd, DM_DEV_REMOVE, &dm))
1256 return -errno;
1257
1258 return 0;
1259}
1260#endif
1261
1262int decrypted_image_relinquish(DecryptedImage *d) {
1263
349cc4a5 1264#if HAVE_LIBCRYPTSETUP
18b5886e
LP
1265 size_t i;
1266 int r;
1267#endif
1268
1269 assert(d);
1270
1271 /* Turns on automatic removal after the last use ended for all DM devices of this image, and sets a boolean so
1272 * that we don't clean it up ourselves either anymore */
1273
349cc4a5 1274#if HAVE_LIBCRYPTSETUP
18b5886e
LP
1275 for (i = 0; i < d->n_decrypted; i++) {
1276 DecryptedPartition *p = d->decrypted + i;
1277
1278 if (p->relinquished)
1279 continue;
1280
1281 r = deferred_remove(p);
1282 if (r < 0)
1283 return log_debug_errno(r, "Failed to mark %s for auto-removal: %m", p->name);
1284
1285 p->relinquished = true;
1286 }
1287#endif
1288
1289 return 0;
1290}
1291
78ebe980
LP
1292int root_hash_load(const char *image, void **ret, size_t *ret_size) {
1293 _cleanup_free_ char *text = NULL;
1294 _cleanup_free_ void *k = NULL;
78ebe980
LP
1295 size_t l;
1296 int r;
1297
1298 assert(image);
1299 assert(ret);
1300 assert(ret_size);
1301
1302 if (is_device_path(image)) {
1303 /* If we are asked to load the root hash for a device node, exit early */
1304 *ret = NULL;
1305 *ret_size = 0;
1306 return 0;
1307 }
1308
41488e1f
LP
1309 r = getxattr_malloc(image, "user.verity.roothash", &text, true);
1310 if (r < 0) {
1311 char *fn, *e, *n;
78ebe980 1312
41488e1f
LP
1313 if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT))
1314 return r;
78ebe980 1315
fbd0b64f 1316 fn = newa(char, strlen(image) + STRLEN(".roothash") + 1);
41488e1f
LP
1317 n = stpcpy(fn, image);
1318 e = endswith(fn, ".raw");
1319 if (e)
1320 n = e;
1321
1322 strcpy(n, ".roothash");
1323
1324 r = read_one_line_file(fn, &text);
1325 if (r == -ENOENT) {
1326 *ret = NULL;
1327 *ret_size = 0;
1328 return 0;
1329 }
1330 if (r < 0)
1331 return r;
78ebe980 1332 }
78ebe980
LP
1333
1334 r = unhexmem(text, strlen(text), &k, &l);
1335 if (r < 0)
1336 return r;
1337 if (l < sizeof(sd_id128_t))
1338 return -EINVAL;
1339
1cc6c93a 1340 *ret = TAKE_PTR(k);
78ebe980
LP
1341 *ret_size = l;
1342
78ebe980
LP
1343 return 1;
1344}
1345
3b925504
LP
1346int dissected_image_acquire_metadata(DissectedImage *m) {
1347
1348 enum {
1349 META_HOSTNAME,
1350 META_MACHINE_ID,
1351 META_MACHINE_INFO,
1352 META_OS_RELEASE,
1353 _META_MAX,
1354 };
1355
1356 static const char *const paths[_META_MAX] = {
1357 [META_HOSTNAME] = "/etc/hostname\0",
1358 [META_MACHINE_ID] = "/etc/machine-id\0",
1359 [META_MACHINE_INFO] = "/etc/machine-info\0",
1360 [META_OS_RELEASE] = "/etc/os-release\0/usr/lib/os-release\0",
1361 };
1362
1363 _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL;
1364 _cleanup_(rmdir_and_freep) char *t = NULL;
1365 _cleanup_(sigkill_waitp) pid_t child = 0;
1366 sd_id128_t machine_id = SD_ID128_NULL;
1367 _cleanup_free_ char *hostname = NULL;
1368 unsigned n_meta_initialized = 0, k;
1369 int fds[2 * _META_MAX], r;
3b925504
LP
1370
1371 BLOCK_SIGNALS(SIGCHLD);
1372
1373 assert(m);
1374
1375 for (; n_meta_initialized < _META_MAX; n_meta_initialized ++)
1376 if (pipe2(fds + 2*n_meta_initialized, O_CLOEXEC) < 0) {
1377 r = -errno;
1378 goto finish;
1379 }
1380
1381 r = mkdtemp_malloc("/tmp/dissect-XXXXXX", &t);
1382 if (r < 0)
1383 goto finish;
1384
e2047ba9 1385 r = safe_fork("(sd-dissect)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE, &child);
be39f6ee 1386 if (r < 0)
3b925504 1387 goto finish;
be39f6ee 1388 if (r == 0) {
03bcb6d4 1389 r = dissected_image_mount(m, t, UID_INVALID, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_MOUNT_ROOT_ONLY|DISSECT_IMAGE_VALIDATE_OS);
429d4e41
LP
1390 if (r < 0) {
1391 log_debug_errno(r, "Failed to mount dissected image: %m");
3b925504 1392 _exit(EXIT_FAILURE);
429d4e41 1393 }
3b925504
LP
1394
1395 for (k = 0; k < _META_MAX; k++) {
1396 _cleanup_close_ int fd = -1;
1397 const char *p;
1398
1399 fds[2*k] = safe_close(fds[2*k]);
1400
1401 NULSTR_FOREACH(p, paths[k]) {
36952d19 1402 fd = chase_symlinks_and_open(p, t, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL);
3b925504
LP
1403 if (fd >= 0)
1404 break;
1405 }
36952d19
LP
1406 if (fd < 0) {
1407 log_debug_errno(fd, "Failed to read %s file of image, ignoring: %m", paths[k]);
3b925504 1408 continue;
36952d19 1409 }
3b925504
LP
1410
1411 r = copy_bytes(fd, fds[2*k+1], (uint64_t) -1, 0);
1412 if (r < 0)
1413 _exit(EXIT_FAILURE);
1414
1415 fds[2*k+1] = safe_close(fds[2*k+1]);
1416 }
1417
1418 _exit(EXIT_SUCCESS);
1419 }
1420
1421 for (k = 0; k < _META_MAX; k++) {
1422 _cleanup_fclose_ FILE *f = NULL;
1423
1424 fds[2*k+1] = safe_close(fds[2*k+1]);
1425
e92aaed3 1426 f = fdopen(fds[2*k], "r");
3b925504
LP
1427 if (!f) {
1428 r = -errno;
1429 goto finish;
1430 }
1431
1432 fds[2*k] = -1;
1433
1434 switch (k) {
1435
1436 case META_HOSTNAME:
1437 r = read_etc_hostname_stream(f, &hostname);
1438 if (r < 0)
1439 log_debug_errno(r, "Failed to read /etc/hostname: %m");
1440
1441 break;
1442
1443 case META_MACHINE_ID: {
1444 _cleanup_free_ char *line = NULL;
1445
1446 r = read_line(f, LONG_LINE_MAX, &line);
1447 if (r < 0)
1448 log_debug_errno(r, "Failed to read /etc/machine-id: %m");
1449 else if (r == 33) {
1450 r = sd_id128_from_string(line, &machine_id);
1451 if (r < 0)
1452 log_debug_errno(r, "Image contains invalid /etc/machine-id: %s", line);
1453 } else if (r == 0)
1454 log_debug("/etc/machine-id file is empty.");
1455 else
1456 log_debug("/etc/machine-id has unexpected length %i.", r);
1457
1458 break;
1459 }
1460
1461 case META_MACHINE_INFO:
aa8fbc74 1462 r = load_env_file_pairs(f, "machine-info", &machine_info);
3b925504
LP
1463 if (r < 0)
1464 log_debug_errno(r, "Failed to read /etc/machine-info: %m");
1465
1466 break;
1467
1468 case META_OS_RELEASE:
aa8fbc74 1469 r = load_env_file_pairs(f, "os-release", &os_release);
3b925504
LP
1470 if (r < 0)
1471 log_debug_errno(r, "Failed to read OS release file: %m");
1472
1473 break;
1474 }
1475 }
1476
2e87a1fd 1477 r = wait_for_terminate_and_check("(sd-dissect)", child, 0);
3b925504 1478 child = 0;
2e87a1fd 1479 if (r < 0)
3b925504 1480 goto finish;
2e87a1fd
LP
1481 if (r != EXIT_SUCCESS)
1482 return -EPROTO;
3b925504
LP
1483
1484 free_and_replace(m->hostname, hostname);
1485 m->machine_id = machine_id;
1486 strv_free_and_replace(m->machine_info, machine_info);
1487 strv_free_and_replace(m->os_release, os_release);
1488
1489finish:
1490 for (k = 0; k < n_meta_initialized; k++)
1491 safe_close_pair(fds + 2*k);
1492
1493 return r;
1494}
1495
4526113f
LP
1496int dissect_image_and_warn(
1497 int fd,
1498 const char *name,
1499 const void *root_hash,
1500 size_t root_hash_size,
1501 DissectImageFlags flags,
1502 DissectedImage **ret) {
1503
1504 _cleanup_free_ char *buffer = NULL;
1505 int r;
1506
1507 if (!name) {
1508 r = fd_get_path(fd, &buffer);
1509 if (r < 0)
1510 return r;
1511
1512 name = buffer;
1513 }
1514
1515 r = dissect_image(fd, root_hash, root_hash_size, flags, ret);
1516
1517 switch (r) {
1518
1519 case -EOPNOTSUPP:
1520 return log_error_errno(r, "Dissecting images is not supported, compiled without blkid support.");
1521
1522 case -ENOPKG:
1523 return log_error_errno(r, "Couldn't identify a suitable partition table or file system in '%s'.", name);
1524
1525 case -EADDRNOTAVAIL:
1526 return log_error_errno(r, "No root partition for specified root hash found in '%s'.", name);
1527
1528 case -ENOTUNIQ:
1529 return log_error_errno(r, "Multiple suitable root partitions found in image '%s'.", name);
1530
1531 case -ENXIO:
1532 return log_error_errno(r, "No suitable root partition found in image '%s'.", name);
1533
1534 case -EPROTONOSUPPORT:
1535 return log_error_errno(r, "Device '%s' is loopback block device with partition scanning turned off, please turn it on.", name);
1536
1537 default:
1538 if (r < 0)
1539 return log_error_errno(r, "Failed to dissect image '%s': %m", name);
1540
1541 return r;
1542 }
1543}
1544
8c1be37e
LP
1545static const char *const partition_designator_table[] = {
1546 [PARTITION_ROOT] = "root",
1547 [PARTITION_ROOT_SECONDARY] = "root-secondary",
1548 [PARTITION_HOME] = "home",
1549 [PARTITION_SRV] = "srv",
1550 [PARTITION_ESP] = "esp",
a8c47660 1551 [PARTITION_XBOOTLDR] = "xbootldr",
8c1be37e 1552 [PARTITION_SWAP] = "swap",
4623e8e6
LP
1553 [PARTITION_ROOT_VERITY] = "root-verity",
1554 [PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity",
8c1be37e
LP
1555};
1556
1557DEFINE_STRING_TABLE_LOOKUP(partition_designator, int);