dissect-image: process /usr/ GPT partition type

This commit is contained in:
Lennart Poettering 2020-08-22 12:21:51 +02:00
parent 2bc181dae7
commit aee36b4ea2
5 changed files with 294 additions and 66 deletions

View File

@ -942,7 +942,7 @@ static int mount_images(const MountEntry *m) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
_cleanup_(verity_settings_done) VeritySettings verity = {};
_cleanup_(verity_settings_done) VeritySettings verity = VERITY_SETTINGS_DEFAULT;
DissectImageFlags dissect_image_flags;
int r;
@ -1417,6 +1417,7 @@ static int verity_settings_prepare(
free_and_replace(verity->root_hash, d);
verity->root_hash_size = root_hash_size;
verity->designator = PARTITION_ROOT;
}
if (root_hash_sig) {
@ -1428,6 +1429,7 @@ static int verity_settings_prepare(
free_and_replace(verity->root_hash_sig, d);
verity->root_hash_sig_size = root_hash_sig_size;
verity->designator = PARTITION_ROOT;
}
if (verity_data_path) {
@ -1480,7 +1482,7 @@ int setup_namespace(
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
_cleanup_(verity_settings_done) VeritySettings verity = {};
_cleanup_(verity_settings_done) VeritySettings verity = VERITY_SETTINGS_DEFAULT;
MountEntry *m = NULL, *mounts = NULL;
bool require_prefix = false;
const char *root;

View File

@ -44,7 +44,7 @@ static const char *arg_path = NULL;
static const char *arg_source = NULL;
static const char *arg_target = NULL;
static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK;
static VeritySettings arg_verity_settings = {};
static VeritySettings arg_verity_settings = VERITY_SETTINGS_DEFAULT;
static bool arg_json = false;
static JsonFormatFlags arg_json_format_flags = 0;

View File

@ -201,7 +201,7 @@ static bool arg_notify_ready = false;
static bool arg_use_cgns = true;
static unsigned long arg_clone_ns_flags = CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS;
static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_TMPFS_TMP;
static VeritySettings arg_verity_settings = {};
static VeritySettings arg_verity_settings = VERITY_SETTINGS_DEFAULT;
static char **arg_syscall_allow_list = NULL;
static char **arg_syscall_deny_list = NULL;
#if HAVE_SECCOMP

View File

@ -310,7 +310,8 @@ int dissect_image(
DissectedImage **ret) {
#if HAVE_BLKID
sd_id128_t root_uuid = SD_ID128_NULL, verity_uuid = SD_ID128_NULL;
sd_id128_t root_uuid = SD_ID128_NULL, root_verity_uuid = SD_ID128_NULL,
usr_uuid = SD_ID128_NULL, usr_verity_uuid = SD_ID128_NULL;
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
bool is_gpt, is_mbr, generic_rw, multiple_generic = false;
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
@ -335,20 +336,32 @@ int dissect_image(
* Returns -EADDRNOTAVAIL if a root hash was specified but no matching root/verity partitions found. */
if (verity && verity->root_hash) {
/* If a root hash is supplied, then we use the root partition that has a UUID that match the first
* 128bit of the root hash. And we use the verity partition that has a UUID that match the final
* 128bit. */
sd_id128_t fsuuid, vuuid;
/* If a root hash is supplied, then we use the root partition that has a UUID that match the
* first 128bit of the root hash. And we use the verity partition that has a UUID that match
* the final 128bit. */
if (verity->root_hash_size < sizeof(sd_id128_t))
return -EINVAL;
memcpy(&root_uuid, verity->root_hash, sizeof(sd_id128_t));
memcpy(&verity_uuid, (const uint8_t*) verity->root_hash + verity->root_hash_size - sizeof(sd_id128_t), sizeof(sd_id128_t));
memcpy(&fsuuid, verity->root_hash, sizeof(sd_id128_t));
memcpy(&vuuid, (const uint8_t*) verity->root_hash + verity->root_hash_size - sizeof(sd_id128_t), sizeof(sd_id128_t));
if (sd_id128_is_null(root_uuid))
if (sd_id128_is_null(fsuuid))
return -EINVAL;
if (sd_id128_is_null(verity_uuid))
if (sd_id128_is_null(vuuid))
return -EINVAL;
/* If the verity data declares it's for the /usr partition, then search for that, in all
* other cases assume it's for the root partition. */
if (verity->designator == PARTITION_USR) {
usr_uuid = fsuuid;
usr_verity_uuid = vuuid;
} else {
root_uuid = fsuuid;
root_verity_uuid = vuuid;
}
}
if (fstat(fd, &st) < 0)
@ -395,6 +408,8 @@ int dissect_image(
(flags & DISSECT_IMAGE_NO_PARTITION_TABLE)) {
const char *usage = NULL;
/* If flags permit this, also allow using non-partitioned single-filesystem images */
(void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL);
if (STRPTR_IN_SET(usage, "filesystem", "crypto")) {
_cleanup_free_ char *t = NULL, *n = NULL, *o = NULL;
@ -414,7 +429,7 @@ int dissect_image(
return r;
m->single_file_system = true;
m->verity = verity && verity->root_hash && verity->data_path;
m->verity = verity && verity->root_hash && verity->data_path && (verity->designator < 0 || verity->designator == PARTITION_ROOT);
m->can_verity = verity && verity->data_path;
options = mount_options_from_designator(mount_options, PARTITION_ROOT);
@ -528,6 +543,7 @@ int dissect_image(
designator = PARTITION_HOME;
rw = !(pflags & GPT_FLAG_READ_ONLY);
} else if (sd_id128_equal(type_id, GPT_SRV)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
@ -537,11 +553,13 @@ int dissect_image(
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"). */
/* 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;
@ -574,6 +592,7 @@ int dissect_image(
designator = PARTITION_ROOT;
architecture = native_architecture();
rw = !(pflags & GPT_FLAG_READ_ONLY);
} else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
@ -584,7 +603,7 @@ int dissect_image(
m->can_verity = true;
/* Ignore verity unless a root hash is specified */
if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id))
if (sd_id128_is_null(root_verity_uuid) || !sd_id128_equal(root_verity_uuid, id))
continue;
designator = PARTITION_ROOT_VERITY;
@ -608,6 +627,7 @@ int dissect_image(
designator = PARTITION_ROOT_SECONDARY;
architecture = SECONDARY_ARCHITECTURE;
rw = !(pflags & GPT_FLAG_READ_ONLY);
} else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
@ -618,7 +638,7 @@ int dissect_image(
m->can_verity = true;
/* Ignore verity unless root has is specified */
if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id))
if (sd_id128_is_null(root_verity_uuid) || !sd_id128_equal(root_verity_uuid, id))
continue;
designator = PARTITION_ROOT_SECONDARY_VERITY;
@ -626,6 +646,76 @@ int dissect_image(
architecture = SECONDARY_ARCHITECTURE;
rw = false;
}
#endif
#ifdef GPT_USR_NATIVE
else if (sd_id128_equal(type_id, GPT_USR_NATIVE)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
if (pflags & GPT_FLAG_NO_AUTO)
continue;
/* If a usr ID is specified, ignore everything but the usr id */
if (!sd_id128_is_null(usr_uuid) && !sd_id128_equal(usr_uuid, id))
continue;
designator = PARTITION_USR;
architecture = native_architecture();
rw = !(pflags & GPT_FLAG_READ_ONLY);
} else if (sd_id128_equal(type_id, GPT_USR_NATIVE_VERITY)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
if (pflags & GPT_FLAG_NO_AUTO)
continue;
m->can_verity = true;
/* Ignore verity unless a usr hash is specified */
if (sd_id128_is_null(usr_verity_uuid) || !sd_id128_equal(usr_verity_uuid, id))
continue;
designator = PARTITION_USR_VERITY;
fstype = "DM_verity_hash";
architecture = native_architecture();
rw = false;
}
#endif
#ifdef GPT_USR_SECONDARY
else if (sd_id128_equal(type_id, GPT_USR_SECONDARY)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
if (pflags & GPT_FLAG_NO_AUTO)
continue;
/* If a usr ID is specified, ignore everything but the usr id */
if (!sd_id128_is_null(usr_uuid) && !sd_id128_equal(usr_uuid, id))
continue;
designator = PARTITION_USR_SECONDARY;
architecture = SECONDARY_ARCHITECTURE;
rw = !(pflags & GPT_FLAG_READ_ONLY);
} else if (sd_id128_equal(type_id, GPT_USR_SECONDARY_VERITY)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
if (pflags & GPT_FLAG_NO_AUTO)
continue;
m->can_verity = true;
/* Ignore verity unless usr has is specified */
if (sd_id128_is_null(usr_verity_uuid) || !sd_id128_equal(usr_verity_uuid, id))
continue;
designator = PARTITION_USR_SECONDARY_VERITY;
fstype = "DM_verity_hash";
architecture = SECONDARY_ARCHITECTURE;
rw = false;
}
#endif
else if (sd_id128_equal(type_id, GPT_SWAP)) {
@ -636,6 +726,7 @@ int dissect_image(
designator = PARTITION_SWAP;
fstype = "swap";
} else if (sd_id128_equal(type_id, GPT_LINUX_GENERIC)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
@ -798,6 +889,8 @@ int dissect_image(
* since we never want to mount the secondary arch in this case. */
m->partitions[PARTITION_ROOT_SECONDARY].found = false;
m->partitions[PARTITION_ROOT_SECONDARY_VERITY].found = false;
m->partitions[PARTITION_USR_SECONDARY].found = false;
m->partitions[PARTITION_USR_SECONDARY_VERITY].found = false;
} else {
/* No root partition found? Then let's see if ther's one for the secondary architecture. And if not
* either, then check if there's a single generic one, and use that. */
@ -805,13 +898,22 @@ int dissect_image(
if (m->partitions[PARTITION_ROOT_VERITY].found)
return -EADDRNOTAVAIL;
/* We didn't find a primary architecture root, but we found a primary architecture /usr? Refuse that for now. */
if (m->partitions[PARTITION_USR].found || m->partitions[PARTITION_USR_VERITY].found)
return -EADDRNOTAVAIL;
if (m->partitions[PARTITION_ROOT_SECONDARY].found) {
/* Upgrade secondary arch to first */
m->partitions[PARTITION_ROOT] = m->partitions[PARTITION_ROOT_SECONDARY];
zero(m->partitions[PARTITION_ROOT_SECONDARY]);
m->partitions[PARTITION_ROOT_VERITY] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY];
zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY]);
m->partitions[PARTITION_USR] = m->partitions[PARTITION_USR_SECONDARY];
zero(m->partitions[PARTITION_USR_SECONDARY]);
m->partitions[PARTITION_USR_VERITY] = m->partitions[PARTITION_USR_SECONDARY_VERITY];
zero(m->partitions[PARTITION_USR_SECONDARY_VERITY]);
} else if (flags & DISSECT_IMAGE_REQUIRE_ROOT) {
_cleanup_free_ char *o = NULL;
const char *options = NULL;
@ -849,14 +951,31 @@ int dissect_image(
}
}
/* Refuse if we found a verity partition for /usr but no matching file system partition */
if (!m->partitions[PARTITION_USR].found && m->partitions[PARTITION_USR_VERITY].found)
return -EADDRNOTAVAIL;
/* Combinations of verity /usr with verity-less root is OK, but the reverse is not */
if (m->partitions[PARTITION_ROOT_VERITY].found && !m->partitions[PARTITION_USR_VERITY].found)
return -EADDRNOTAVAIL;
if (verity && verity->root_hash) {
if (!m->partitions[PARTITION_ROOT_VERITY].found || !m->partitions[PARTITION_ROOT].found)
return -EADDRNOTAVAIL;
if (verity->designator < 0 || verity->designator == PARTITION_ROOT) {
if (!m->partitions[PARTITION_ROOT_VERITY].found || !m->partitions[PARTITION_ROOT].found)
return -EADDRNOTAVAIL;
/* If we found a verity setup, then the root partition is necessarily read-only. */
m->partitions[PARTITION_ROOT].rw = false;
/* If we found a verity setup, then the root partition is necessarily read-only. */
m->partitions[PARTITION_ROOT].rw = false;
m->verity = true;
}
m->verity = true;
if (verity->designator == PARTITION_USR) {
if (!m->partitions[PARTITION_USR_VERITY].found || !m->partitions[PARTITION_USR].found)
return -EADDRNOTAVAIL;
m->partitions[PARTITION_USR].rw = false;
m->verity = true;
}
}
blkid_free_probe(b);
@ -883,7 +1002,6 @@ int dissect_image(
}
*ret = TAKE_PTR(m);
return 0;
#else
return -EOPNOTSUPP;
@ -1089,6 +1207,17 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
r = mount_partition(m->partitions + PARTITION_ROOT, where, NULL, uid_shift, flags);
if (r < 0)
return r;
}
/* Mask DISSECT_IMAGE_MKDIR for all subdirs: the idea is that only the top-level mount point is
* created if needed, but the image itself not modified. */
flags &= ~DISSECT_IMAGE_MKDIR;
if ((flags & DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY) == 0) {
/* For us mounting root always means mounting /usr as well */
r = mount_partition(m->partitions + PARTITION_USR, where, "/usr", uid_shift, flags);
if (r < 0)
return r;
if (flags & DISSECT_IMAGE_VALIDATE_OS) {
r = path_is_os_tree(where);
@ -1102,10 +1231,6 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
if (flags & DISSECT_IMAGE_MOUNT_ROOT_ONLY)
return 0;
/* Mask DISSECT_IMAGE_MKDIR for all subdirs: the idea is that only the top-level mount point is
* created if needed, but the image itself not modified. */
flags &= ~DISSECT_IMAGE_MKDIR;
r = mount_partition(m->partitions + PARTITION_HOME, where, "/home", uid_shift, flags);
if (r < 0)
return r;
@ -1389,6 +1514,7 @@ static inline void dm_deferred_remove_clean(char *name) {
DEFINE_TRIVIAL_CLEANUP_FUNC(char *, dm_deferred_remove_clean);
static int verity_partition(
PartitionDesignator designator,
DissectedPartition *m,
DissectedPartition *v,
const VeritySettings *verity,
@ -1405,6 +1531,9 @@ static int verity_partition(
if (!verity || !verity->root_hash)
return 0;
if (!((verity->designator < 0 && designator == PARTITION_ROOT) ||
(verity->designator == designator)))
return 0;
if (!m->found || !m->node || !m->fstype)
return 0;
@ -1426,8 +1555,8 @@ static int verity_partition(
root_hash_encoded = hexmem(verity->root_hash, verity->root_hash_size);
if (!root_hash_encoded)
return -ENOMEM;
r = make_dm_name_and_node(root_hash_encoded, "-verity", &name, &node);
} else
r = make_dm_name_and_node(m->node, "-verity", &name, &node);
@ -1482,7 +1611,7 @@ static int verity_partition(
* Improvements in libcrypsetup can ensure this never happens:
* https://gitlab.com/cryptsetup/cryptsetup/-/merge_requests/96 */
if (r == -EINVAL && FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE))
return verity_partition(m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
return verity_partition(designator, m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
if (!IN_SET(r,
0, /* Success */
-EEXIST, /* Volume is already open and ready to be used */
@ -1508,7 +1637,7 @@ static int verity_partition(
r = verity_can_reuse(verity, name, &existing_cd);
/* Same as above, -EINVAL can randomly happen when it actually means -EEXIST */
if (r == -EINVAL && FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE))
return verity_partition(m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
return verity_partition(designator, m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
if (!IN_SET(r, 0, -ENODEV, -ENOENT, -EBUSY))
return log_debug_errno(r, "Checking whether existing verity device %s can be reused failed: %m", node);
if (r == 0) {
@ -1536,7 +1665,7 @@ static int verity_partition(
/* An existing verity device was reported by libcryptsetup/libdevmapper, but we can't use it at this time.
* Fall back to activating it with a unique device name. */
if (r != 0 && FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE))
return verity_partition(m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
return verity_partition(designator, m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
/* Everything looks good and we'll be able to mount the device, so deferred remove will be re-enabled at that point. */
restore_deferred_remove = mfree(restore_deferred_remove);
@ -1601,7 +1730,7 @@ int dissected_image_decrypt(
k = PARTITION_VERITY_OF(i);
if (k >= 0) {
r = verity_partition(p, m->partitions + k, verity, flags | DISSECT_IMAGE_VERITY_SHARE, d);
r = verity_partition(i, p, m->partitions + k, verity, flags | DISSECT_IMAGE_VERITY_SHARE, d);
if (r < 0)
return r;
}
@ -1727,39 +1856,84 @@ int verity_settings_load(
_cleanup_free_ void *root_hash = NULL, *root_hash_sig = NULL;
size_t root_hash_size = 0, root_hash_sig_size = 0;
_cleanup_free_ char *verity_data_path = NULL;
PartitionDesignator designator;
int r;
assert(verity);
assert(image);
assert(verity->designator < 0 || IN_SET(verity->designator, PARTITION_ROOT, PARTITION_USR));
/* If we are asked to load the root hash for a device node, exit early */
if (is_device_path(image))
return 0;
designator = verity->designator;
/* We only fill in what isn't already filled in */
if (!verity->root_hash) {
_cleanup_free_ char *text = NULL;
if (root_hash_path) {
/* If explicitly specified it takes precedence */
r = read_one_line_file(root_hash_path, &text);
if (r < 0)
return r;
if (designator < 0)
designator = PARTITION_ROOT;
} else {
r = getxattr_malloc(image, "user.verity.roothash", &text, true);
if (r < 0) {
_cleanup_free_ char *p = NULL;
/* Otherwise look for xattr and separate file, and first for the data for root and if
* that doesn't exist for /usr */
if (!IN_SET(r, -ENODATA, -ENOENT) && !ERRNO_IS_NOT_SUPPORTED(r))
return r;
if (designator < 0 || designator == PARTITION_ROOT) {
r = getxattr_malloc(image, "user.verity.roothash", &text, true);
if (r < 0) {
_cleanup_free_ char *p = NULL;
p = build_auxiliary_path(image, ".roothash");
if (!p)
return -ENOMEM;
if (!IN_SET(r, -ENODATA, -ENOENT) && !ERRNO_IS_NOT_SUPPORTED(r))
return r;
r = read_one_line_file(p, &text);
if (r < 0 && r != -ENOENT)
return r;
p = build_auxiliary_path(image, ".roothash");
if (!p)
return -ENOMEM;
r = read_one_line_file(p, &text);
if (r < 0 && r != -ENOENT)
return r;
}
if (text)
designator = PARTITION_ROOT;
}
if (!text && (designator < 0 || designator == PARTITION_USR)) {
/* So in the "roothash" xattr/file name above the "root" of course primarily
* refers to the root of the Verity Merkle tree. But coincidentally it also
* is the hash for the *root* file system, i.e. the "root" neatly refers to
* two distinct concepts called "root". Taking benefit of this happy
* coincidence we call the file with the root hash for the /usr/ file system
* `usrhash`, because `usrroothash` or `rootusrhash` would just be too
* confusing. We thus drop the reference to the root of the Merkle tree, and
* just indicate which file system it's about. */
r = getxattr_malloc(image, "user.verity.usrhash", &text, true);
if (r < 0) {
_cleanup_free_ char *p = NULL;
if (!IN_SET(r, -ENODATA, -ENOENT) && !ERRNO_IS_NOT_SUPPORTED(r))
return r;
p = build_auxiliary_path(image, ".usrhash");
if (!p)
return -ENOMEM;
r = read_one_line_file(p, &text);
if (r < 0 && r != -ENOENT)
return r;
}
if (text)
designator = PARTITION_USR;
}
}
@ -1772,24 +1946,47 @@ int verity_settings_load(
}
}
if (!verity->root_hash_sig) {
_cleanup_free_ char *p = NULL;
if (verity->root_hash && !verity->root_hash_sig) {
if (root_hash_sig_path) {
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, (char**) &root_hash_sig, &root_hash_sig_size);
if (r < 0 && r != -ENOENT)
return r;
if (!root_hash_sig_path) {
/* Follow naming convention recommended by the relevant RFC:
* https://tools.ietf.org/html/rfc5751#section-3.2.1 */
p = build_auxiliary_path(image, ".roothash.p7s");
if (!p)
return -ENOMEM;
if (designator < 0)
designator = PARTITION_ROOT;
} else {
if (designator < 0 || designator == PARTITION_ROOT) {
_cleanup_free_ char *p = NULL;
root_hash_sig_path = p;
/* Follow naming convention recommended by the relevant RFC:
* https://tools.ietf.org/html/rfc5751#section-3.2.1 */
p = build_auxiliary_path(image, ".roothash.p7s");
if (!p)
return -ENOMEM;
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, (char**) &root_hash_sig, &root_hash_sig_size);
if (r < 0 && r != -ENOENT)
return r;
if (r >= 0)
designator = PARTITION_ROOT;
}
if (!root_hash_sig && (designator < 0 || designator == PARTITION_USR)) {
_cleanup_free_ char *p = NULL;
p = build_auxiliary_path(image, ".usrhash.p7s");
if (!p)
return -ENOMEM;
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, (char**) &root_hash_sig, &root_hash_sig_size);
if (r < 0 && r != -ENOENT)
return r;
if (r >= 0)
designator = PARTITION_USR;
}
}
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, (char**) &root_hash_sig, &root_hash_sig_size);
if (r < 0) {
if (r != -ENOENT)
return r;
} else if (root_hash_sig_size == 0) /* refuse empty size signatures */
if (root_hash_sig && root_hash_sig_size == 0) /* refuse empty size signatures */
return -EINVAL;
}
@ -1820,6 +2017,9 @@ int verity_settings_load(
if (verity_data_path)
verity->data_path = TAKE_PTR(verity_data_path);
if (verity->designator < 0)
verity->designator = designator;
return 1;
}
@ -2018,7 +2218,6 @@ int dissect_image_and_warn(
}
r = dissect_image(fd, verity, mount_options, flags, ret);
switch (r) {
case -EOPNOTSUPP:
@ -2161,6 +2360,8 @@ int mount_image_privately_interactively(
static const char *const partition_designator_table[] = {
[PARTITION_ROOT] = "root",
[PARTITION_ROOT_SECONDARY] = "root-secondary",
[PARTITION_USR] = "usr",
[PARTITION_USR_SECONDARY] = "usr-secondary",
[PARTITION_HOME] = "home",
[PARTITION_SRV] = "srv",
[PARTITION_ESP] = "esp",
@ -2168,6 +2369,8 @@ static const char *const partition_designator_table[] = {
[PARTITION_SWAP] = "swap",
[PARTITION_ROOT_VERITY] = "root-verity",
[PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity",
[PARTITION_USR_VERITY] = "usr-verity",
[PARTITION_USR_SECONDARY_VERITY] = "usr-secondary-verity",
[PARTITION_TMP] = "tmp",
[PARTITION_VAR] = "var",
};

View File

@ -31,6 +31,8 @@ struct DissectedPartition {
typedef enum PartitionDesignator {
PARTITION_ROOT,
PARTITION_ROOT_SECONDARY, /* Secondary architecture */
PARTITION_USR,
PARTITION_USR_SECONDARY,
PARTITION_HOME,
PARTITION_SRV,
PARTITION_ESP,
@ -38,6 +40,8 @@ typedef enum PartitionDesignator {
PARTITION_SWAP,
PARTITION_ROOT_VERITY, /* verity data for the PARTITION_ROOT partition */
PARTITION_ROOT_SECONDARY_VERITY, /* verity data for the PARTITION_ROOT_SECONDARY partition */
PARTITION_USR_VERITY,
PARTITION_USR_SECONDARY_VERITY,
PARTITION_TMP,
PARTITION_VAR,
_PARTITION_DESIGNATOR_MAX,
@ -45,11 +49,23 @@ typedef enum PartitionDesignator {
} PartitionDesignator;
static inline PartitionDesignator PARTITION_VERITY_OF(PartitionDesignator p) {
if (p == PARTITION_ROOT)
switch (p) {
case PARTITION_ROOT:
return PARTITION_ROOT_VERITY;
if (p == PARTITION_ROOT_SECONDARY)
case PARTITION_ROOT_SECONDARY:
return PARTITION_ROOT_SECONDARY_VERITY;
return _PARTITION_DESIGNATOR_INVALID;
case PARTITION_USR:
return PARTITION_USR_VERITY;
case PARTITION_USR_SECONDARY:
return PARTITION_USR_SECONDARY_VERITY;
default:
return _PARTITION_DESIGNATOR_INVALID;
}
}
typedef enum DissectImageFlags {
@ -61,9 +77,9 @@ typedef enum DissectImageFlags {
DISSECT_IMAGE_DISCARD |
DISSECT_IMAGE_DISCARD_ON_CRYPTO,
DISSECT_IMAGE_GPT_ONLY = 1 << 4, /* Only recognize images with GPT partition tables */
DISSECT_IMAGE_REQUIRE_ROOT = 1 << 5, /* Don't accept disks without root partition */
DISSECT_IMAGE_MOUNT_ROOT_ONLY = 1 << 6, /* Mount only the root partition */
DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY = 1 << 7, /* Mount only non-root partitions */
DISSECT_IMAGE_REQUIRE_ROOT = 1 << 5, /* Don't accept disks without root partition (and if no partition table or only single generic partition, assume it's root) */
DISSECT_IMAGE_MOUNT_ROOT_ONLY = 1 << 6, /* Mount only the root and /usr partitions */
DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY = 1 << 7, /* Mount only the non-root and non-/usr partitions */
DISSECT_IMAGE_VALIDATE_OS = 1 << 8, /* Refuse mounting images that aren't identifiable as OS images */
DISSECT_IMAGE_NO_UDEV = 1 << 9, /* Don't wait for udev initializing things */
DISSECT_IMAGE_RELAX_VAR_CHECK = 1 << 10, /* Don't insist that the UUID of /var is hashed from /etc/machine-id */
@ -104,8 +120,15 @@ struct VeritySettings {
/* Path to the verity data file, if stored externally */
char *data_path;
/* PARTITION_ROOT or PARTITION_USR, depending on what these Verity settings are for */
PartitionDesignator designator;
};
#define VERITY_SETTINGS_DEFAULT { \
.designator = _PARTITION_DESIGNATOR_INVALID \
}
MountOptions* mount_options_free_all(MountOptions *options);
DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all);
const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator);