]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/dissect-image.c
core,nspawn,dissect: make nspawn's .roothash file search reusable
[thirdparty/systemd.git] / src / shared / dissect-image.c
CommitLineData
8c1be37e
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2016 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
18b5886e
LP
20#ifdef HAVE_LIBCRYPTSETUP
21#include <libcryptsetup.h>
22#endif
23#include <linux/dm-ioctl.h>
8c1be37e
LP
24#include <sys/mount.h>
25
26#include "architecture.h"
18b5886e 27#include "ask-password-api.h"
8c1be37e
LP
28#include "blkid-util.h"
29#include "dissect-image.h"
18b5886e 30#include "fd-util.h"
78ebe980 31#include "fileio.h"
2eedfd2d 32#include "fs-util.h"
8c1be37e 33#include "gpt.h"
78ebe980 34#include "hexdecoct.h"
8c1be37e
LP
35#include "mount-util.h"
36#include "path-util.h"
37#include "stat-util.h"
18b5886e 38#include "stdio-util.h"
8c1be37e
LP
39#include "string-table.h"
40#include "string-util.h"
2eedfd2d 41#include "strv.h"
8c1be37e
LP
42#include "udev-util.h"
43
18b5886e
LP
44static int probe_filesystem(const char *node, char **ret_fstype) {
45#ifdef HAVE_BLKID
46 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
47 const char *fstype;
48 int r;
49
50 b = blkid_new_probe_from_filename(node);
51 if (!b)
52 return -ENOMEM;
53
54 blkid_probe_enable_superblocks(b, 1);
55 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
56
57 errno = 0;
58 r = blkid_do_safeprobe(b);
59 if (r == -2 || r == 1) {
60 log_debug("Failed to identify any partition type on partition %s", node);
61 goto not_found;
62 }
63 if (r != 0) {
64 if (errno == 0)
65 return -EIO;
66
67 return -errno;
68 }
69
70 (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
71
72 if (fstype) {
73 char *t;
74
75 t = strdup(fstype);
76 if (!t)
77 return -ENOMEM;
78
79 *ret_fstype = t;
80 return 1;
81 }
82
83not_found:
84 *ret_fstype = NULL;
85 return 0;
86#else
87 return -EOPNOTSUPP;
88#endif
89}
90
9b6deb03 91int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret) {
8c1be37e
LP
92
93#ifdef HAVE_BLKID
4623e8e6 94 sd_id128_t root_uuid = SD_ID128_NULL, verity_uuid = SD_ID128_NULL;
8c1be37e
LP
95 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
96 bool is_gpt, is_mbr, generic_rw, multiple_generic = false;
97 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
98 _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
99 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
100 _cleanup_udev_unref_ struct udev *udev = NULL;
101 _cleanup_free_ char *generic_node = NULL;
be30ad41 102 sd_id128_t generic_uuid = SD_ID128_NULL;
9b6deb03 103 const char *pttype = NULL;
8c1be37e
LP
104 struct udev_list_entry *first, *item;
105 blkid_partlist pl;
106 int r, generic_nr;
107 struct stat st;
108 unsigned i;
109
110 assert(fd >= 0);
111 assert(ret);
4623e8e6 112 assert(root_hash || root_hash_size == 0);
8c1be37e
LP
113
114 /* Probes a disk image, and returns information about what it found in *ret.
115 *
4623e8e6
LP
116 * Returns -ENOPKG if no suitable partition table or file system could be found.
117 * Returns -EADDRNOTAVAIL if a root hash was specified but no matching root/verity partitions found. */
118
119 if (root_hash) {
120 /* If a root hash is supplied, then we use the root partition that has a UUID that match the first
121 * 128bit of the root hash. And we use the verity partition that has a UUID that match the final
122 * 128bit. */
123
124 if (root_hash_size < sizeof(sd_id128_t))
125 return -EINVAL;
126
127 memcpy(&root_uuid, root_hash, sizeof(sd_id128_t));
128 memcpy(&verity_uuid, (const uint8_t*) root_hash + root_hash_size - sizeof(sd_id128_t), sizeof(sd_id128_t));
129
130 if (sd_id128_is_null(root_uuid))
131 return -EINVAL;
132 if (sd_id128_is_null(verity_uuid))
133 return -EINVAL;
134 }
8c1be37e
LP
135
136 if (fstat(fd, &st) < 0)
137 return -errno;
138
139 if (!S_ISBLK(st.st_mode))
140 return -ENOTBLK;
141
142 b = blkid_new_probe();
143 if (!b)
144 return -ENOMEM;
145
146 errno = 0;
147 r = blkid_probe_set_device(b, fd, 0, 0);
148 if (r != 0) {
149 if (errno == 0)
150 return -ENOMEM;
151
152 return -errno;
153 }
154
9b6deb03
LP
155 if ((flags & DISSECT_IMAGE_GPT_ONLY) == 0) {
156 /* Look for file system superblocks, unless we only shall look for GPT partition tables */
157 blkid_probe_enable_superblocks(b, 1);
158 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_USAGE);
159 }
160
8c1be37e
LP
161 blkid_probe_enable_partitions(b, 1);
162 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
163
164 errno = 0;
165 r = blkid_do_safeprobe(b);
166 if (r == -2 || r == 1) {
167 log_debug("Failed to identify any partition table.");
168 return -ENOPKG;
169 }
170 if (r != 0) {
171 if (errno == 0)
172 return -EIO;
173
174 return -errno;
175 }
176
177 m = new0(DissectedImage, 1);
178 if (!m)
179 return -ENOMEM;
180
e0f9e7bd
LP
181 if (!(flags & DISSECT_IMAGE_GPT_ONLY) &&
182 (flags & DISSECT_IMAGE_REQUIRE_ROOT)) {
9b6deb03 183 const char *usage = NULL;
8c1be37e 184
9b6deb03
LP
185 (void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL);
186 if (STRPTR_IN_SET(usage, "filesystem", "crypto")) {
187 _cleanup_free_ char *t = NULL, *n = NULL;
188 const char *fstype = NULL;
8c1be37e 189
9b6deb03
LP
190 /* OK, we have found a file system, that's our root partition then. */
191 (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
8c1be37e 192
9b6deb03
LP
193 if (fstype) {
194 t = strdup(fstype);
195 if (!t)
196 return -ENOMEM;
197 }
198
199 if (asprintf(&n, "/dev/block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0)
200 return -ENOMEM;
8c1be37e 201
9b6deb03
LP
202 m->partitions[PARTITION_ROOT] = (DissectedPartition) {
203 .found = true,
204 .rw = true,
205 .partno = -1,
206 .architecture = _ARCHITECTURE_INVALID,
207 .fstype = t,
208 .node = n,
209 };
8c1be37e 210
9b6deb03 211 t = n = NULL;
8c1be37e 212
9b6deb03 213 m->encrypted = streq(fstype, "crypto_LUKS");
18b5886e 214
9b6deb03
LP
215 *ret = m;
216 m = NULL;
8c1be37e 217
9b6deb03
LP
218 return 0;
219 }
8c1be37e
LP
220 }
221
222 (void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
223 if (!pttype)
224 return -ENOPKG;
225
226 is_gpt = streq_ptr(pttype, "gpt");
227 is_mbr = streq_ptr(pttype, "dos");
228
9b6deb03 229 if (!is_gpt && ((flags & DISSECT_IMAGE_GPT_ONLY) || !is_mbr))
8c1be37e
LP
230 return -ENOPKG;
231
232 errno = 0;
233 pl = blkid_probe_get_partitions(b);
234 if (!pl) {
235 if (errno == 0)
236 return -ENOMEM;
237
238 return -errno;
239 }
240
241 udev = udev_new();
242 if (!udev)
243 return -errno;
244
245 d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
246 if (!d)
247 return -ENOMEM;
248
249 for (i = 0;; i++) {
250 int n, z;
251
252 if (i >= 10) {
253 log_debug("Kernel partitions never appeared.");
254 return -ENXIO;
255 }
256
257 e = udev_enumerate_new(udev);
258 if (!e)
259 return -errno;
260
261 r = udev_enumerate_add_match_parent(e, d);
262 if (r < 0)
263 return r;
264
265 r = udev_enumerate_scan_devices(e);
266 if (r < 0)
267 return r;
268
269 /* Count the partitions enumerated by the kernel */
270 n = 0;
271 first = udev_enumerate_get_list_entry(e);
272 udev_list_entry_foreach(item, first)
273 n++;
274
275 /* Count the partitions enumerated by blkid */
276 z = blkid_partlist_numof_partitions(pl);
277 if (n == z + 1)
278 break;
279 if (n > z + 1) {
280 log_debug("blkid and kernel partition list do not match.");
281 return -EIO;
282 }
283 if (n < z + 1) {
284 unsigned j;
285
286 /* The kernel has probed fewer partitions than blkid? Maybe the kernel prober is still running
287 * or it got EBUSY because udev already opened the device. Let's reprobe the device, which is a
288 * synchronous call that waits until probing is complete. */
289
290 for (j = 0; j < 20; j++) {
291
292 r = ioctl(fd, BLKRRPART, 0);
293 if (r < 0)
294 r = -errno;
295 if (r >= 0 || r != -EBUSY)
296 break;
297
298 /* If something else has the device open, such as an udev rule, the ioctl will return
299 * EBUSY. Since there's no way to wait until it isn't busy anymore, let's just wait a
300 * bit, and try again.
301 *
302 * This is really something they should fix in the kernel! */
303
304 usleep(50 * USEC_PER_MSEC);
305 }
306
307 if (r < 0)
308 return r;
309 }
310
311 e = udev_enumerate_unref(e);
312 }
313
314 first = udev_enumerate_get_list_entry(e);
315 udev_list_entry_foreach(item, first) {
316 _cleanup_udev_device_unref_ struct udev_device *q;
9b6deb03 317 unsigned long long pflags;
8c1be37e
LP
318 blkid_partition pp;
319 const char *node;
320 dev_t qn;
321 int nr;
322
323 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
324 if (!q)
325 return -errno;
326
327 qn = udev_device_get_devnum(q);
328 if (major(qn) == 0)
329 continue;
330
331 if (st.st_rdev == qn)
332 continue;
333
334 node = udev_device_get_devnode(q);
335 if (!node)
336 continue;
337
338 pp = blkid_partlist_devno_to_partition(pl, qn);
339 if (!pp)
340 continue;
341
9b6deb03 342 pflags = blkid_partition_get_flags(pp);
8c1be37e
LP
343
344 nr = blkid_partition_get_partno(pp);
345 if (nr < 0)
346 continue;
347
348 if (is_gpt) {
349 int designator = _PARTITION_DESIGNATOR_INVALID, architecture = _ARCHITECTURE_INVALID;
4623e8e6
LP
350 const char *stype, *sid, *fstype = NULL;
351 sd_id128_t type_id, id;
8c1be37e
LP
352 bool rw = true;
353
9b6deb03 354 if (pflags & GPT_FLAG_NO_AUTO)
8c1be37e
LP
355 continue;
356
4623e8e6
LP
357 sid = blkid_partition_get_uuid(pp);
358 if (!sid)
359 continue;
360 if (sd_id128_from_string(sid, &id) < 0)
361 continue;
362
8c1be37e
LP
363 stype = blkid_partition_get_type_string(pp);
364 if (!stype)
365 continue;
8c1be37e
LP
366 if (sd_id128_from_string(stype, &type_id) < 0)
367 continue;
368
369 if (sd_id128_equal(type_id, GPT_HOME)) {
370 designator = PARTITION_HOME;
9b6deb03 371 rw = !(pflags & GPT_FLAG_READ_ONLY);
8c1be37e
LP
372 } else if (sd_id128_equal(type_id, GPT_SRV)) {
373 designator = PARTITION_SRV;
9b6deb03 374 rw = !(pflags & GPT_FLAG_READ_ONLY);
8c1be37e
LP
375 } else if (sd_id128_equal(type_id, GPT_ESP)) {
376 designator = PARTITION_ESP;
377 fstype = "vfat";
378 }
379#ifdef GPT_ROOT_NATIVE
380 else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) {
4623e8e6
LP
381
382 /* If a root ID is specified, ignore everything but the root id */
383 if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id))
384 continue;
385
8c1be37e
LP
386 designator = PARTITION_ROOT;
387 architecture = native_architecture();
9b6deb03 388 rw = !(pflags & GPT_FLAG_READ_ONLY);
4f8b86e3 389 } else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY)) {
4623e8e6
LP
390
391 m->can_verity = true;
392
393 /* Ignore verity unless a root hash is specified */
394 if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id))
395 continue;
396
397 designator = PARTITION_ROOT_VERITY;
398 fstype = "DM_verity_hash";
399 architecture = native_architecture();
400 rw = false;
401 }
402#endif
8c1be37e
LP
403#ifdef GPT_ROOT_SECONDARY
404 else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY)) {
4623e8e6
LP
405
406 /* If a root ID is specified, ignore everything but the root id */
407 if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id))
408 continue;
409
8c1be37e
LP
410 designator = PARTITION_ROOT_SECONDARY;
411 architecture = SECONDARY_ARCHITECTURE;
9b6deb03 412 rw = !(pflags & GPT_FLAG_READ_ONLY);
4f8b86e3 413 } else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY)) {
4623e8e6
LP
414 m->can_verity = true;
415
416 /* Ignore verity unless root has is specified */
417 if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id))
418 continue;
419
420 designator = PARTITION_ROOT_SECONDARY_VERITY;
421 fstype = "DM_verity_hash";
422 architecture = SECONDARY_ARCHITECTURE;
423 rw = false;
424 }
8c1be37e
LP
425#endif
426 else if (sd_id128_equal(type_id, GPT_SWAP)) {
427 designator = PARTITION_SWAP;
428 fstype = "swap";
429 } else if (sd_id128_equal(type_id, GPT_LINUX_GENERIC)) {
430
431 if (generic_node)
432 multiple_generic = true;
433 else {
434 generic_nr = nr;
9b6deb03 435 generic_rw = !(pflags & GPT_FLAG_READ_ONLY);
be30ad41 436 generic_uuid = id;
8c1be37e
LP
437 generic_node = strdup(node);
438 if (!generic_node)
439 return -ENOMEM;
440 }
441 }
442
443 if (designator != _PARTITION_DESIGNATOR_INVALID) {
444 _cleanup_free_ char *t = NULL, *n = NULL;
445
446 /* First one wins */
447 if (m->partitions[designator].found)
448 continue;
449
450 if (fstype) {
451 t = strdup(fstype);
452 if (!t)
453 return -ENOMEM;
454 }
455
456 n = strdup(node);
457 if (!n)
458 return -ENOMEM;
459
460 m->partitions[designator] = (DissectedPartition) {
461 .found = true,
462 .partno = nr,
463 .rw = rw,
464 .architecture = architecture,
465 .node = n,
466 .fstype = t,
be30ad41 467 .uuid = id,
8c1be37e
LP
468 };
469
470 n = t = NULL;
471 }
472
473 } else if (is_mbr) {
474
9b6deb03 475 if (pflags != 0x80) /* Bootable flag */
8c1be37e
LP
476 continue;
477
478 if (blkid_partition_get_type(pp) != 0x83) /* Linux partition */
479 continue;
480
481 if (generic_node)
482 multiple_generic = true;
483 else {
484 generic_nr = nr;
485 generic_rw = true;
486 generic_node = strdup(node);
487 if (!generic_node)
488 return -ENOMEM;
489 }
490 }
491 }
492
493 if (!m->partitions[PARTITION_ROOT].found) {
494 /* No root partition found? Then let's see if ther's one for the secondary architecture. And if not
495 * either, then check if there's a single generic one, and use that. */
496
4623e8e6 497 if (m->partitions[PARTITION_ROOT_VERITY].found)
e0f9e7bd 498 return -EADDRNOTAVAIL;
4623e8e6 499
8c1be37e
LP
500 if (m->partitions[PARTITION_ROOT_SECONDARY].found) {
501 m->partitions[PARTITION_ROOT] = m->partitions[PARTITION_ROOT_SECONDARY];
502 zero(m->partitions[PARTITION_ROOT_SECONDARY]);
4623e8e6
LP
503
504 m->partitions[PARTITION_ROOT_VERITY] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY];
505 zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY]);
506
e0f9e7bd
LP
507 } else if (flags & DISSECT_IMAGE_REQUIRE_ROOT) {
508
509 /* If the root has was set, then we won't fallback to a generic node, because the root hash
510 * decides */
511 if (root_hash)
512 return -EADDRNOTAVAIL;
8c1be37e 513
e0f9e7bd
LP
514 /* If we didn't find a generic node, then we can't fix this up either */
515 if (!generic_node)
516 return -ENXIO;
517
518 /* If we didn't find a properly marked root partition, but we did find a single suitable
519 * generic Linux partition, then use this as root partition, if the caller asked for it. */
8c1be37e
LP
520 if (multiple_generic)
521 return -ENOTUNIQ;
522
523 m->partitions[PARTITION_ROOT] = (DissectedPartition) {
524 .found = true,
525 .rw = generic_rw,
526 .partno = generic_nr,
527 .architecture = _ARCHITECTURE_INVALID,
528 .node = generic_node,
be30ad41 529 .uuid = generic_uuid,
8c1be37e
LP
530 };
531
532 generic_node = NULL;
e0f9e7bd 533 }
8c1be37e
LP
534 }
535
4623e8e6 536 if (root_hash) {
e0f9e7bd 537 if (!m->partitions[PARTITION_ROOT_VERITY].found || !m->partitions[PARTITION_ROOT].found)
4623e8e6
LP
538 return -EADDRNOTAVAIL;
539
540 /* If we found the primary root with the hash, then we definitely want to suppress any secondary root
541 * (which would be weird, after all the root hash should only be assigned to one pair of
542 * partitions... */
543 m->partitions[PARTITION_ROOT_SECONDARY].found = false;
544 m->partitions[PARTITION_ROOT_SECONDARY_VERITY].found = false;
545
546 /* If we found a verity setup, then the root partition is necessarily read-only. */
547 m->partitions[PARTITION_ROOT].rw = false;
548
549 m->verity = true;
550 }
551
18b5886e
LP
552 blkid_free_probe(b);
553 b = NULL;
554
8c1be37e
LP
555 /* Fill in file system types if we don't know them yet. */
556 for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
18b5886e 557 DissectedPartition *p = m->partitions + i;
8c1be37e 558
18b5886e 559 if (!p->found)
8c1be37e
LP
560 continue;
561
18b5886e
LP
562 if (!p->fstype && p->node) {
563 r = probe_filesystem(p->node, &p->fstype);
564 if (r < 0)
565 return r;
8c1be37e
LP
566 }
567
18b5886e
LP
568 if (streq_ptr(p->fstype, "crypto_LUKS"))
569 m->encrypted = true;
8c1be37e
LP
570 }
571
572 *ret = m;
573 m = NULL;
574
575 return 0;
576#else
577 return -EOPNOTSUPP;
578#endif
579}
580
581DissectedImage* dissected_image_unref(DissectedImage *m) {
582 unsigned i;
583
584 if (!m)
585 return NULL;
586
587 for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
588 free(m->partitions[i].fstype);
589 free(m->partitions[i].node);
18b5886e
LP
590 free(m->partitions[i].decrypted_fstype);
591 free(m->partitions[i].decrypted_node);
8c1be37e
LP
592 }
593
594 free(m);
595 return NULL;
596}
597
18b5886e
LP
598static int is_loop_device(const char *path) {
599 char s[strlen("/sys/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t) + strlen("/../loop/")];
600 struct stat st;
601
602 assert(path);
603
604 if (stat(path, &st) < 0)
605 return -errno;
606
607 if (!S_ISBLK(st.st_mode))
608 return -ENOTBLK;
609
610 xsprintf(s, "/sys/dev/block/%u:%u/loop/", major(st.st_rdev), minor(st.st_rdev));
611 if (access(s, F_OK) < 0) {
612 if (errno != ENOENT)
613 return -errno;
614
615 /* The device itself isn't a loop device, but maybe it's a partition and its parent is? */
616 xsprintf(s, "/sys/dev/block/%u:%u/../loop/", major(st.st_rdev), minor(st.st_rdev));
617 if (access(s, F_OK) < 0)
618 return errno == ENOENT ? false : -errno;
619 }
620
621 return true;
622}
623
624static int mount_partition(
625 DissectedPartition *m,
626 const char *where,
627 const char *directory,
628 DissectImageFlags flags) {
629
630 const char *p, *options = NULL, *node, *fstype;
2eedfd2d 631 _cleanup_free_ char *chased = NULL;
8c1be37e 632 bool rw;
2eedfd2d 633 int r;
8c1be37e
LP
634
635 assert(m);
636 assert(where);
637
18b5886e
LP
638 node = m->decrypted_node ?: m->node;
639 fstype = m->decrypted_fstype ?: m->fstype;
640
641 if (!m->found || !node || !fstype)
8c1be37e
LP
642 return 0;
643
18b5886e
LP
644 /* Stacked encryption? Yuck */
645 if (streq_ptr(fstype, "crypto_LUKS"))
646 return -ELOOP;
647
648 rw = m->rw && !(flags & DISSECT_IMAGE_READ_ONLY);
8c1be37e 649
2eedfd2d
LP
650 if (directory) {
651 r = chase_symlinks(directory, where, CHASE_PREFIX_ROOT, &chased);
652 if (r < 0)
653 return r;
654
655 p = chased;
656 } else
8c1be37e
LP
657 p = where;
658
18b5886e
LP
659 /* If requested, turn on discard support. */
660 if (STR_IN_SET(fstype, "btrfs", "ext4", "vfat", "xfs") &&
661 ((flags & DISSECT_IMAGE_DISCARD) ||
662 ((flags & DISSECT_IMAGE_DISCARD_ON_LOOP) && is_loop_device(m->node))))
663 options = "discard";
8c1be37e 664
18b5886e 665 return mount_verbose(LOG_DEBUG, node, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), options);
8c1be37e
LP
666}
667
18b5886e 668int dissected_image_mount(DissectedImage *m, const char *where, DissectImageFlags flags) {
8c1be37e
LP
669 int r;
670
671 assert(m);
672 assert(where);
673
674 if (!m->partitions[PARTITION_ROOT].found)
675 return -ENXIO;
676
677 r = mount_partition(m->partitions + PARTITION_ROOT, where, NULL, flags);
678 if (r < 0)
679 return r;
680
681 r = mount_partition(m->partitions + PARTITION_HOME, where, "/home", flags);
682 if (r < 0)
683 return r;
684
685 r = mount_partition(m->partitions + PARTITION_SRV, where, "/srv", flags);
686 if (r < 0)
687 return r;
688
689 if (m->partitions[PARTITION_ESP].found) {
2eedfd2d 690 const char *mp;
8c1be37e
LP
691
692 /* Mount the ESP to /efi if it exists and is empty. If it doesn't exist, use /boot instead. */
693
2eedfd2d
LP
694 FOREACH_STRING(mp, "/efi", "/boot") {
695 _cleanup_free_ char *p = NULL;
696
697 r = chase_symlinks(mp, where, CHASE_PREFIX_ROOT, &p);
8c1be37e 698 if (r < 0)
2eedfd2d
LP
699 continue;
700
701 r = dir_is_empty(p);
702 if (r > 0) {
703 r = mount_partition(m->partitions + PARTITION_ESP, where, mp, flags);
704 if (r < 0)
705 return r;
706 }
8c1be37e
LP
707 }
708 }
709
710 return 0;
711}
712
18b5886e
LP
713#ifdef HAVE_LIBCRYPTSETUP
714typedef struct DecryptedPartition {
715 struct crypt_device *device;
716 char *name;
717 bool relinquished;
718} DecryptedPartition;
719
720struct DecryptedImage {
721 DecryptedPartition *decrypted;
722 size_t n_decrypted;
723 size_t n_allocated;
724};
725#endif
726
727DecryptedImage* decrypted_image_unref(DecryptedImage* d) {
728#ifdef HAVE_LIBCRYPTSETUP
729 size_t i;
730 int r;
731
732 if (!d)
733 return NULL;
734
735 for (i = 0; i < d->n_decrypted; i++) {
736 DecryptedPartition *p = d->decrypted + i;
737
738 if (p->device && p->name && !p->relinquished) {
739 r = crypt_deactivate(p->device, p->name);
740 if (r < 0)
741 log_debug_errno(r, "Failed to deactivate encrypted partition %s", p->name);
742 }
743
744 if (p->device)
745 crypt_free(p->device);
746 free(p->name);
747 }
748
749 free(d);
750#endif
751 return NULL;
752}
753
754#ifdef HAVE_LIBCRYPTSETUP
4623e8e6
LP
755
756static int make_dm_name_and_node(const void *original_node, const char *suffix, char **ret_name, char **ret_node) {
757 _cleanup_free_ char *name = NULL, *node = NULL;
758 const char *base;
759
760 assert(original_node);
761 assert(suffix);
762 assert(ret_name);
763 assert(ret_node);
764
765 base = strrchr(original_node, '/');
766 if (!base)
767 return -EINVAL;
768 base++;
769 if (isempty(base))
770 return -EINVAL;
771
772 name = strjoin(base, suffix);
773 if (!name)
774 return -ENOMEM;
775 if (!filename_is_valid(name))
776 return -EINVAL;
777
778 node = strjoin(crypt_get_dir(), "/", name);
779 if (!node)
780 return -ENOMEM;
781
782 *ret_name = name;
783 *ret_node = node;
784
785 name = node = NULL;
786 return 0;
787}
788
18b5886e
LP
789static int decrypt_partition(
790 DissectedPartition *m,
791 const char *passphrase,
792 DissectImageFlags flags,
793 DecryptedImage *d) {
794
795 _cleanup_free_ char *node = NULL, *name = NULL;
796 struct crypt_device *cd;
18b5886e
LP
797 int r;
798
799 assert(m);
800 assert(d);
801
802 if (!m->found || !m->node || !m->fstype)
803 return 0;
804
805 if (!streq(m->fstype, "crypto_LUKS"))
806 return 0;
807
4623e8e6
LP
808 r = make_dm_name_and_node(m->node, "-decrypted", &name, &node);
809 if (r < 0)
810 return r;
18b5886e
LP
811
812 if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1))
813 return -ENOMEM;
814
815 r = crypt_init(&cd, m->node);
816 if (r < 0)
817 return r;
818
819 r = crypt_load(cd, CRYPT_LUKS1, NULL);
820 if (r < 0)
821 goto fail;
822
823 r = crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, passphrase, strlen(passphrase),
824 ((flags & DISSECT_IMAGE_READ_ONLY) ? CRYPT_ACTIVATE_READONLY : 0) |
825 ((flags & DISSECT_IMAGE_DISCARD_ON_CRYPTO) ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0));
826 if (r == -EPERM) {
827 r = -EKEYREJECTED;
828 goto fail;
829 }
830 if (r < 0)
831 goto fail;
832
833 d->decrypted[d->n_decrypted].name = name;
834 name = NULL;
835
836 d->decrypted[d->n_decrypted].device = cd;
837 d->n_decrypted++;
838
839 m->decrypted_node = node;
840 node = NULL;
841
842 return 0;
843
4623e8e6
LP
844fail:
845 crypt_free(cd);
846 return r;
847}
848
849static int verity_partition(
850 DissectedPartition *m,
851 DissectedPartition *v,
852 const void *root_hash,
853 size_t root_hash_size,
854 DissectImageFlags flags,
855 DecryptedImage *d) {
856
857 _cleanup_free_ char *node = NULL, *name = NULL;
858 struct crypt_device *cd;
859 int r;
860
861 assert(m);
862 assert(v);
863
864 if (!root_hash)
865 return 0;
866
867 if (!m->found || !m->node || !m->fstype)
868 return 0;
869 if (!v->found || !v->node || !v->fstype)
870 return 0;
871
872 if (!streq(v->fstype, "DM_verity_hash"))
873 return 0;
874
875 r = make_dm_name_and_node(m->node, "-verity", &name, &node);
876 if (r < 0)
877 return r;
878
879 if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1))
880 return -ENOMEM;
881
882 r = crypt_init(&cd, v->node);
883 if (r < 0)
884 return r;
885
886 r = crypt_load(cd, CRYPT_VERITY, NULL);
887 if (r < 0)
888 goto fail;
889
890 r = crypt_set_data_device(cd, m->node);
891 if (r < 0)
892 goto fail;
893
894 r = crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY);
895 if (r < 0)
896 goto fail;
897
898 d->decrypted[d->n_decrypted].name = name;
899 name = NULL;
900
901 d->decrypted[d->n_decrypted].device = cd;
902 d->n_decrypted++;
903
904 m->decrypted_node = node;
905 node = NULL;
906
907 return 0;
908
18b5886e
LP
909fail:
910 crypt_free(cd);
911 return r;
912}
913#endif
914
915int dissected_image_decrypt(
916 DissectedImage *m,
917 const char *passphrase,
4623e8e6
LP
918 const void *root_hash,
919 size_t root_hash_size,
18b5886e
LP
920 DissectImageFlags flags,
921 DecryptedImage **ret) {
922
923 _cleanup_(decrypted_image_unrefp) DecryptedImage *d = NULL;
924#ifdef HAVE_LIBCRYPTSETUP
925 unsigned i;
926 int r;
927#endif
928
929 assert(m);
4623e8e6 930 assert(root_hash || root_hash_size == 0);
18b5886e
LP
931
932 /* Returns:
933 *
934 * = 0 → There was nothing to decrypt
935 * > 0 → Decrypted successfully
936 * -ENOKEY → There's some to decrypt but no key was supplied
937 * -EKEYREJECTED → Passed key was not correct
938 */
939
4623e8e6
LP
940 if (root_hash && root_hash_size < sizeof(sd_id128_t))
941 return -EINVAL;
942
943 if (!m->encrypted && !m->verity) {
18b5886e
LP
944 *ret = NULL;
945 return 0;
946 }
947
948#ifdef HAVE_LIBCRYPTSETUP
4623e8e6 949 if (m->encrypted && !passphrase)
18b5886e
LP
950 return -ENOKEY;
951
952 d = new0(DecryptedImage, 1);
953 if (!d)
954 return -ENOMEM;
955
956 for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
957 DissectedPartition *p = m->partitions + i;
4623e8e6 958 int k;
18b5886e
LP
959
960 if (!p->found)
961 continue;
962
963 r = decrypt_partition(p, passphrase, flags, d);
964 if (r < 0)
965 return r;
966
4623e8e6
LP
967 k = PARTITION_VERITY_OF(i);
968 if (k >= 0) {
969 r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, flags, d);
970 if (r < 0)
971 return r;
972 }
973
18b5886e
LP
974 if (!p->decrypted_fstype && p->decrypted_node) {
975 r = probe_filesystem(p->decrypted_node, &p->decrypted_fstype);
976 if (r < 0)
977 return r;
978 }
979 }
980
981 *ret = d;
982 d = NULL;
983
984 return 1;
985#else
986 return -EOPNOTSUPP;
987#endif
988}
989
990int dissected_image_decrypt_interactively(
991 DissectedImage *m,
992 const char *passphrase,
4623e8e6
LP
993 const void *root_hash,
994 size_t root_hash_size,
18b5886e
LP
995 DissectImageFlags flags,
996 DecryptedImage **ret) {
997
998 _cleanup_strv_free_erase_ char **z = NULL;
999 int n = 3, r;
1000
1001 if (passphrase)
1002 n--;
1003
1004 for (;;) {
4623e8e6 1005 r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, flags, ret);
18b5886e
LP
1006 if (r >= 0)
1007 return r;
1008 if (r == -EKEYREJECTED)
1009 log_error_errno(r, "Incorrect passphrase, try again!");
1010 else if (r != -ENOKEY) {
1011 log_error_errno(r, "Failed to decrypt image: %m");
1012 return r;
1013 }
1014
1015 if (--n < 0) {
1016 log_error("Too many retries.");
1017 return -EKEYREJECTED;
1018 }
1019
1020 z = strv_free(z);
1021
1022 r = ask_password_auto("Please enter image passphrase!", NULL, "dissect", "dissect", USEC_INFINITY, 0, &z);
1023 if (r < 0)
1024 return log_error_errno(r, "Failed to query for passphrase: %m");
1025
1026 passphrase = z[0];
1027 }
1028}
1029
1030#ifdef HAVE_LIBCRYPTSETUP
1031static int deferred_remove(DecryptedPartition *p) {
1032
1033 struct dm_ioctl dm = {
1034 .version = {
1035 DM_VERSION_MAJOR,
1036 DM_VERSION_MINOR,
1037 DM_VERSION_PATCHLEVEL
1038 },
1039 .data_size = sizeof(dm),
1040 .flags = DM_DEFERRED_REMOVE,
1041 };
1042
1043 _cleanup_close_ int fd = -1;
1044
1045 assert(p);
1046
1047 /* Unfortunately, libcryptsetup doesn't provide a proper API for this, hence call the ioctl() directly. */
1048
1049 fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
1050 if (fd < 0)
1051 return -errno;
1052
1053 strncpy(dm.name, p->name, sizeof(dm.name));
1054
1055 if (ioctl(fd, DM_DEV_REMOVE, &dm))
1056 return -errno;
1057
1058 return 0;
1059}
1060#endif
1061
1062int decrypted_image_relinquish(DecryptedImage *d) {
1063
1064#ifdef HAVE_LIBCRYPTSETUP
1065 size_t i;
1066 int r;
1067#endif
1068
1069 assert(d);
1070
1071 /* Turns on automatic removal after the last use ended for all DM devices of this image, and sets a boolean so
1072 * that we don't clean it up ourselves either anymore */
1073
1074#ifdef HAVE_LIBCRYPTSETUP
1075 for (i = 0; i < d->n_decrypted; i++) {
1076 DecryptedPartition *p = d->decrypted + i;
1077
1078 if (p->relinquished)
1079 continue;
1080
1081 r = deferred_remove(p);
1082 if (r < 0)
1083 return log_debug_errno(r, "Failed to mark %s for auto-removal: %m", p->name);
1084
1085 p->relinquished = true;
1086 }
1087#endif
1088
1089 return 0;
1090}
1091
78ebe980
LP
1092int root_hash_load(const char *image, void **ret, size_t *ret_size) {
1093 _cleanup_free_ char *text = NULL;
1094 _cleanup_free_ void *k = NULL;
1095 char *fn, *e, *n;
1096 size_t l;
1097 int r;
1098
1099 assert(image);
1100 assert(ret);
1101 assert(ret_size);
1102
1103 if (is_device_path(image)) {
1104 /* If we are asked to load the root hash for a device node, exit early */
1105 *ret = NULL;
1106 *ret_size = 0;
1107 return 0;
1108 }
1109
1110 fn = newa(char, strlen(image) + strlen(".roothash") + 1);
1111 n = stpcpy(fn, image);
1112 e = endswith(fn, ".raw");
1113 if (e)
1114 n = e;
1115
1116 strcpy(n, ".roothash");
1117
1118 r = read_one_line_file(fn, &text);
1119 if (r == -ENOENT) {
1120 *ret = NULL;
1121 *ret_size = 0;
1122 return 0;
1123 }
1124 if (r < 0)
1125 return r;
1126
1127 r = unhexmem(text, strlen(text), &k, &l);
1128 if (r < 0)
1129 return r;
1130 if (l < sizeof(sd_id128_t))
1131 return -EINVAL;
1132
1133 *ret = k;
1134 *ret_size = l;
1135
1136 k = NULL;
1137
1138 return 1;
1139}
1140
8c1be37e
LP
1141static const char *const partition_designator_table[] = {
1142 [PARTITION_ROOT] = "root",
1143 [PARTITION_ROOT_SECONDARY] = "root-secondary",
1144 [PARTITION_HOME] = "home",
1145 [PARTITION_SRV] = "srv",
1146 [PARTITION_ESP] = "esp",
1147 [PARTITION_SWAP] = "swap",
4623e8e6
LP
1148 [PARTITION_ROOT_VERITY] = "root-verity",
1149 [PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity",
8c1be37e
LP
1150};
1151
1152DEFINE_STRING_TABLE_LOOKUP(partition_designator, int);