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