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