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