along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
#include <libcryptsetup.h>
#endif
-#include <linux/dm-ioctl.h>
#include <sys/mount.h>
#include "architecture.h"
#include "blkid-util.h"
#include "dissect-image.h"
#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
#include "gpt.h"
+#include "hexdecoct.h"
+#include "linux-3.13/dm-ioctl.h"
#include "mount-util.h"
#include "path-util.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
+#include "strv.h"
#include "udev-util.h"
+#include "xattr-util.h"
-static int probe_filesystem(const char *node, char **ret_fstype) {
-#ifdef HAVE_BLKID
+_unused_ static int probe_filesystem(const char *node, char **ret_fstype) {
+#if HAVE_BLKID
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
const char *fstype;
int r;
log_debug("Failed to identify any partition type on partition %s", node);
goto not_found;
}
- if (r != 0) {
- if (errno == 0)
- return -EIO;
-
- return -errno;
- }
+ if (r != 0)
+ return -errno ?: -EIO;
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret) {
-#ifdef HAVE_BLKID
+#if HAVE_BLKID
sd_id128_t root_uuid = SD_ID128_NULL, verity_uuid = SD_ID128_NULL;
_cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
bool is_gpt, is_mbr, generic_rw, multiple_generic = false;
errno = 0;
r = blkid_probe_set_device(b, fd, 0, 0);
- if (r != 0) {
- if (errno == 0)
- return -ENOMEM;
-
- return -errno;
- }
+ if (r != 0)
+ return -errno ?: -ENOMEM;
if ((flags & DISSECT_IMAGE_GPT_ONLY) == 0) {
/* Look for file system superblocks, unless we only shall look for GPT partition tables */
log_debug("Failed to identify any partition table.");
return -ENOPKG;
}
- if (r != 0) {
- if (errno == 0)
- return -EIO;
-
- return -errno;
- }
+ if (r != 0)
+ return -errno ?: -EIO;
m = new0(DissectedImage, 1);
if (!m)
errno = 0;
pl = blkid_probe_get_partitions(b);
- if (!pl) {
- if (errno == 0)
- return -ENOMEM;
-
- return -errno;
- }
+ if (!pl)
+ return -errno ?: -ENOMEM;
udev = udev_new();
if (!udev)
_cleanup_udev_device_unref_ struct udev_device *q;
unsigned long long pflags;
blkid_partition pp;
- const char *node;
+ const char *node, *sysname;
dev_t qn;
int nr;
if (st.st_rdev == qn)
continue;
+ /* Filter out weird MMC RPMB partitions, which cannot reasonably be read, see
+ * https://github.com/systemd/systemd/issues/5806 */
+ sysname = udev_device_get_sysname(q);
+ if (sysname && startswith(sysname, "mmcblk") && endswith(sysname, "rpmb"))
+ continue;
+
node = udev_device_get_devnode(q);
if (!node)
continue;
sd_id128_t type_id, id;
bool rw = true;
- if (pflags & GPT_FLAG_NO_AUTO)
- continue;
-
sid = blkid_partition_get_uuid(pp);
if (!sid)
continue;
continue;
if (sd_id128_equal(type_id, GPT_HOME)) {
+
+ if (pflags & GPT_FLAG_NO_AUTO)
+ continue;
+
designator = PARTITION_HOME;
rw = !(pflags & GPT_FLAG_READ_ONLY);
} else if (sd_id128_equal(type_id, GPT_SRV)) {
+
+ if (pflags & GPT_FLAG_NO_AUTO)
+ continue;
+
designator = PARTITION_SRV;
rw = !(pflags & GPT_FLAG_READ_ONLY);
} else if (sd_id128_equal(type_id, GPT_ESP)) {
+
+ /* Note that we don't check the GPT_FLAG_NO_AUTO flag for the ESP, as it is not defined
+ * there. We instead check the GPT_FLAG_NO_BLOCK_IO_PROTOCOL, as recommended by the
+ * UEFI spec (See "12.3.3 Number and Location of System Partitions"). */
+
+ if (pflags & GPT_FLAG_NO_BLOCK_IO_PROTOCOL)
+ continue;
+
designator = PARTITION_ESP;
fstype = "vfat";
}
#ifdef GPT_ROOT_NATIVE
else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) {
+ if (pflags & GPT_FLAG_NO_AUTO)
+ continue;
+
/* If a root ID is specified, ignore everything but the root id */
if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id))
continue;
rw = !(pflags & GPT_FLAG_READ_ONLY);
} else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY)) {
+ if (pflags & GPT_FLAG_NO_AUTO)
+ continue;
+
m->can_verity = true;
/* Ignore verity unless a root hash is specified */
#ifdef GPT_ROOT_SECONDARY
else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY)) {
+ if (pflags & GPT_FLAG_NO_AUTO)
+ continue;
+
/* If a root ID is specified, ignore everything but the root id */
if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id))
continue;
architecture = SECONDARY_ARCHITECTURE;
rw = !(pflags & GPT_FLAG_READ_ONLY);
} else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY)) {
+
+ if (pflags & GPT_FLAG_NO_AUTO)
+ continue;
+
m->can_verity = true;
/* Ignore verity unless root has is specified */
}
#endif
else if (sd_id128_equal(type_id, GPT_SWAP)) {
+
+ if (pflags & GPT_FLAG_NO_AUTO)
+ continue;
+
designator = PARTITION_SWAP;
fstype = "swap";
} else if (sd_id128_equal(type_id, GPT_LINUX_GENERIC)) {
+ if (pflags & GPT_FLAG_NO_AUTO)
+ continue;
+
if (generic_node)
multiple_generic = true;
else {
if (streq_ptr(p->fstype, "crypto_LUKS"))
m->encrypted = true;
+
+ if (p->fstype && fstype_is_ro(p->fstype))
+ p->rw = false;
}
*ret = m;
DissectImageFlags flags) {
const char *p, *options = NULL, *node, *fstype;
+ _cleanup_free_ char *chased = NULL;
bool rw;
+ int r;
assert(m);
assert(where);
rw = m->rw && !(flags & DISSECT_IMAGE_READ_ONLY);
- if (directory)
- p = strjoina(where, directory);
- else
+ if (directory) {
+ r = chase_symlinks(directory, where, CHASE_PREFIX_ROOT, &chased);
+ if (r < 0)
+ return r;
+
+ p = chased;
+ } else
p = where;
/* If requested, turn on discard support. */
- if (STR_IN_SET(fstype, "btrfs", "ext4", "vfat", "xfs") &&
+ if (fstype_can_discard(fstype) &&
((flags & DISSECT_IMAGE_DISCARD) ||
((flags & DISSECT_IMAGE_DISCARD_ON_LOOP) && is_loop_device(m->node))))
options = "discard";
return r;
if (m->partitions[PARTITION_ESP].found) {
- const char *mp, *x;
+ const char *mp;
/* Mount the ESP to /efi if it exists and is empty. If it doesn't exist, use /boot instead. */
- mp = "/efi";
- x = strjoina(where, mp);
- r = dir_is_empty(x);
- if (r == -ENOENT) {
- mp = "/boot";
- x = strjoina(where, mp);
- r = dir_is_empty(x);
- }
- if (r > 0) {
- r = mount_partition(m->partitions + PARTITION_ESP, where, mp, flags);
+ FOREACH_STRING(mp, "/efi", "/boot") {
+ _cleanup_free_ char *p = NULL;
+
+ r = chase_symlinks(mp, where, CHASE_PREFIX_ROOT, &p);
if (r < 0)
- return r;
+ continue;
+
+ r = dir_is_empty(p);
+ if (r > 0) {
+ r = mount_partition(m->partitions + PARTITION_ESP, where, mp, flags);
+ if (r < 0)
+ return r;
+ }
}
}
return 0;
}
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
typedef struct DecryptedPartition {
struct crypt_device *device;
char *name;
#endif
DecryptedImage* decrypted_image_unref(DecryptedImage* d) {
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
size_t i;
int r;
return NULL;
}
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
static int make_dm_name_and_node(const void *original_node, const char *suffix, char **ret_name, char **ret_node) {
_cleanup_free_ char *name = NULL, *node = NULL;
r = crypt_init(&cd, m->node);
if (r < 0)
- return r;
+ return log_debug_errno(r, "Failed to initialize dm-crypt: %m");
r = crypt_load(cd, CRYPT_LUKS1, NULL);
- if (r < 0)
+ if (r < 0) {
+ log_debug_errno(r, "Failed to load LUKS metadata: %m");
goto fail;
+ }
r = crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, passphrase, strlen(passphrase),
((flags & DISSECT_IMAGE_READ_ONLY) ? CRYPT_ACTIVATE_READONLY : 0) |
((flags & DISSECT_IMAGE_DISCARD_ON_CRYPTO) ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0));
+ if (r < 0)
+ log_debug_errno(r, "Failed to activate LUKS device: %m");
if (r == -EPERM) {
r = -EKEYREJECTED;
goto fail;
DecryptedImage **ret) {
_cleanup_(decrypted_image_unrefp) DecryptedImage *d = NULL;
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
unsigned i;
int r;
#endif
*
* = 0 → There was nothing to decrypt
* > 0 → Decrypted successfully
- * -ENOKEY → There's some to decrypt but no key was supplied
+ * -ENOKEY → There's something to decrypt but no key was supplied
* -EKEYREJECTED → Passed key was not correct
*/
return 0;
}
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
if (m->encrypted && !passphrase)
return -ENOKEY;
}
}
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
static int deferred_remove(DecryptedPartition *p) {
struct dm_ioctl dm = {
int decrypted_image_relinquish(DecryptedImage *d) {
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
size_t i;
int r;
#endif
/* Turns on automatic removal after the last use ended for all DM devices of this image, and sets a boolean so
* that we don't clean it up ourselves either anymore */
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
for (i = 0; i < d->n_decrypted; i++) {
DecryptedPartition *p = d->decrypted + i;
return 0;
}
+int root_hash_load(const char *image, void **ret, size_t *ret_size) {
+ _cleanup_free_ char *text = NULL;
+ _cleanup_free_ void *k = NULL;
+ size_t l;
+ int r;
+
+ assert(image);
+ assert(ret);
+ assert(ret_size);
+
+ if (is_device_path(image)) {
+ /* If we are asked to load the root hash for a device node, exit early */
+ *ret = NULL;
+ *ret_size = 0;
+ return 0;
+ }
+
+ r = getxattr_malloc(image, "user.verity.roothash", &text, true);
+ if (r < 0) {
+ char *fn, *e, *n;
+
+ if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT))
+ return r;
+
+ fn = newa(char, strlen(image) + strlen(".roothash") + 1);
+ n = stpcpy(fn, image);
+ e = endswith(fn, ".raw");
+ if (e)
+ n = e;
+
+ strcpy(n, ".roothash");
+
+ r = read_one_line_file(fn, &text);
+ if (r == -ENOENT) {
+ *ret = NULL;
+ *ret_size = 0;
+ return 0;
+ }
+ if (r < 0)
+ return r;
+ }
+
+ r = unhexmem(text, strlen(text), &k, &l);
+ if (r < 0)
+ return r;
+ if (l < sizeof(sd_id128_t))
+ return -EINVAL;
+
+ *ret = k;
+ *ret_size = l;
+
+ k = NULL;
+
+ return 1;
+}
+
static const char *const partition_designator_table[] = {
[PARTITION_ROOT] = "root",
[PARTITION_ROOT_SECONDARY] = "root-secondary",