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