dissect-image: split DISSECT_IMAGE_REQUIRE_ROOT in two

Previously, the flag did two things at once: enable support for using
generic partitions as root fs if there were only one/allow use of
partition-table-less images as root fs. And secondly, insist that there
was a rootfs, and fail if not. Let's split these two in two separate
options so that they can be used independently of each other.

There are cases where one wants to use one without the other (i.e. when
inspecting things with systemd-dissect tool it should be OK to do so
even if image has no root fs), and it's cleaner anyway.
This commit is contained in:
Lennart Poettering
2021-03-16 14:57:40 +01:00
parent 2679f40735
commit 4b5de5dd6c
12 changed files with 78 additions and 42 deletions
+1 -1
View File
@@ -1825,7 +1825,7 @@ int setup_namespace(
mount_flags = MS_SHARED;
if (root_image) {
dissect_image_flags |= DISSECT_IMAGE_REQUIRE_ROOT;
dissect_image_flags |= DISSECT_IMAGE_GENERIC_ROOT | DISSECT_IMAGE_REQUIRE_ROOT;
/* Make the whole image read-only if we can determine that we only access it in a read-only fashion. */
if (root_read_only(read_only_paths,
+7 -1
View File
@@ -44,7 +44,13 @@ static const char *arg_image = NULL;
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|DISSECT_IMAGE_USR_NO_ROOT;
static DissectImageFlags arg_flags =
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_DISCARD_ON_LOOP |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK |
DISSECT_IMAGE_USR_NO_ROOT;
static VeritySettings arg_verity_settings = VERITY_SETTINGS_DEFAULT;
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
static PagerFlags arg_pager_flags = 0;
+5 -1
View File
@@ -1291,7 +1291,11 @@ static int run(int argc, char *argv[]) {
r = mount_image_privately_interactively(
arg_image,
DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_VALIDATE_OS |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK,
&unlink_dir,
&loop_device,
&decrypted_image);
+4 -1
View File
@@ -2150,7 +2150,10 @@ int main(int argc, char *argv[]) {
r = mount_image_privately_interactively(
arg_image,
DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_RELAX_VAR_CHECK|
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_VALIDATE_OS |
DISSECT_IMAGE_RELAX_VAR_CHECK |
(arg_action == ACTION_UPDATE_CATALOG ? DISSECT_IMAGE_FSCK : DISSECT_IMAGE_READ_ONLY),
&unlink_dir,
&loop_device,
+1
View File
@@ -5389,6 +5389,7 @@ static int run(int argc, char *argv[]) {
} else {
DissectImageFlags dissect_image_flags =
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_USR_NO_ROOT;
+10 -1
View File
@@ -380,7 +380,16 @@ static int portable_extract_by_path(
if (r < 0)
return log_debug_errno(r, "Failed to create temporary directory: %m");
r = dissect_image(d->fd, NULL, NULL, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_USR_NO_ROOT, &m);
r = dissect_image(
d->fd,
NULL, NULL,
DISSECT_IMAGE_READ_ONLY |
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_DISCARD_ON_LOOP |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_USR_NO_ROOT,
&m);
if (r == -ENOPKG)
sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Couldn't identify a suitable partition table or file system in '%s'.", path);
else if (r == -EADDRNOTAVAIL)
+3 -2
View File
@@ -1201,8 +1201,9 @@ int image_read_metadata(Image *i) {
r = dissect_image(
d->fd,
NULL, NULL,
DISSECT_IMAGE_REQUIRE_ROOT|
DISSECT_IMAGE_RELAX_VAR_CHECK|
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_USR_NO_ROOT, &m);
if (r < 0)
return r;
+31 -29
View File
@@ -630,7 +630,7 @@ int dissect_image(
}
if ((!(flags & DISSECT_IMAGE_GPT_ONLY) &&
(flags & DISSECT_IMAGE_REQUIRE_ROOT)) ||
(flags & DISSECT_IMAGE_GENERIC_ROOT)) ||
(flags & DISSECT_IMAGE_NO_PARTITION_TABLE)) {
const char *usage = NULL;
@@ -1178,45 +1178,47 @@ int dissect_image(
} else if (m->partitions[PARTITION_USR_SECONDARY_VERITY].found)
return -EADDRNOTAVAIL; /* as above */
else if (flags & DISSECT_IMAGE_REQUIRE_ROOT) {
_cleanup_free_ char *o = NULL;
const char *options = NULL;
else if ((flags & DISSECT_IMAGE_GENERIC_ROOT) &&
(!verity || !verity->root_hash)) {
/* OK, we found nothing usable, then check if there's a single generic one distro, and use
* that. */
/* If the root hash was set, then we won't fall back to a generic node, because the root hash
* decides. */
if (verity && verity->root_hash)
return -EADDRNOTAVAIL;
/* If we didn't find a generic node, then we can't fix this up either */
if (!generic_node)
return -ENXIO;
* that. If the root hash was set however, then we won't fall back to a generic node, because
* the root hash decides. */
/* If we didn't find a properly marked root partition, but we did find a single suitable
* generic Linux partition, then use this as root partition, if the caller asked for it. */
if (multiple_generic)
return -ENOTUNIQ;
options = mount_options_from_designator(mount_options, PARTITION_ROOT);
if (options) {
o = strdup(options);
if (!o)
return -ENOMEM;
}
/* If we didn't find a generic node, then we can't fix this up either */
if (generic_node) {
_cleanup_free_ char *o = NULL;
const char *options;
m->partitions[PARTITION_ROOT] = (DissectedPartition) {
.found = true,
.rw = generic_rw,
.partno = generic_nr,
.architecture = _ARCHITECTURE_INVALID,
.node = TAKE_PTR(generic_node),
.uuid = generic_uuid,
.mount_options = TAKE_PTR(o),
};
options = mount_options_from_designator(mount_options, PARTITION_ROOT);
if (options) {
o = strdup(options);
if (!o)
return -ENOMEM;
}
m->partitions[PARTITION_ROOT] = (DissectedPartition) {
.found = true,
.rw = generic_rw,
.partno = generic_nr,
.architecture = _ARCHITECTURE_INVALID,
.node = TAKE_PTR(generic_node),
.uuid = generic_uuid,
.mount_options = TAKE_PTR(o),
};
}
}
/* Check if we have a root fs if we are told to do check. /usr alone is fine too, but only if appropriate flag for that is set too */
if (FLAGS_SET(flags, DISSECT_IMAGE_REQUIRE_ROOT) &&
!(m->partitions[PARTITION_ROOT].found || (m->partitions[PARTITION_USR].found && FLAGS_SET(flags, DISSECT_IMAGE_USR_NO_ROOT))))
return -ENXIO;
/* 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;
+2 -1
View File
@@ -95,7 +95,7 @@ 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 (and if no partition table or only single generic partition, assume it's root) */
DISSECT_IMAGE_GENERIC_ROOT = 1 << 5, /* If no partition table or only single generic partition, assume it's the root fs */
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 */
@@ -106,6 +106,7 @@ typedef enum DissectImageFlags {
DISSECT_IMAGE_VERITY_SHARE = 1 << 13, /* When activating a verity device, reuse existing one if already open */
DISSECT_IMAGE_MKDIR = 1 << 14, /* Make top-level directory to mount right before mounting, if missing */
DISSECT_IMAGE_USR_NO_ROOT = 1 << 15, /* If no root fs is in the image, but /usr is, then allow this (so that we can mount the rootfs as tmpfs or so */
DISSECT_IMAGE_REQUIRE_ROOT = 1 << 16, /* Don't accept disks without root partition (or at least /usr partition if DISSECT_IMAGE_USR_NO_ROOT is set) */
} DissectImageFlags;
struct DissectedImage {
+4 -3
View File
@@ -510,9 +510,10 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
_cleanup_(decrypted_image_unrefp) DecryptedImage *di = NULL;
_cleanup_(verity_settings_done) VeritySettings verity_settings = VERITY_SETTINGS_DEFAULT;
DissectImageFlags flags =
DISSECT_IMAGE_READ_ONLY|
DISSECT_IMAGE_REQUIRE_ROOT|
DISSECT_IMAGE_MOUNT_ROOT_ONLY|
DISSECT_IMAGE_READ_ONLY |
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_MOUNT_ROOT_ONLY |
DISSECT_IMAGE_USR_NO_ROOT;
r = verity_settings_load(&verity_settings, img->path, NULL, NULL);
+5 -1
View File
@@ -1946,7 +1946,11 @@ static int run(int argc, char *argv[]) {
r = mount_image_privately_interactively(
arg_image,
DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_VALIDATE_OS |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK,
&unlink_dir,
&loop_device,
&decrypted_image);
+5 -1
View File
@@ -3431,7 +3431,11 @@ static int run(int argc, char *argv[]) {
r = mount_image_privately_interactively(
arg_image,
DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_VALIDATE_OS |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK,
&unlink_dir,
&loop_device,
&decrypted_image);