LCOV - code coverage report
Current view: top level - shared - dissect-image.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 1 801 0.1 %
Date: 2019-08-22 15:41:25 Functions: 2 23 8.7 %

          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);

Generated by: LCOV version 1.14