Merge pull request #14696 from poettering/dissect-tweaks

various tweaks to the image dissection logic
This commit is contained in:
Anita Zhang 2020-01-30 12:46:03 -08:00 committed by GitHub
commit 1b9d61bcee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 122 additions and 12 deletions

6
TODO
View File

@ -38,8 +38,6 @@ Features:
* by default, in systemd --user service bump the OOMAdjust to 100, as privs * by default, in systemd --user service bump the OOMAdjust to 100, as privs
allow so that systemd survives allow so that systemd survives
* when dissecting images, warn about unrecognized partition flags
* honour specifiers in unit files that resolve to some very basic * honour specifiers in unit files that resolve to some very basic
/etc/os-release data, such as ID, VERSION_ID, BUILD_ID, VARIANT_ID. /etc/os-release data, such as ID, VERSION_ID, BUILD_ID, VARIANT_ID.
@ -172,10 +170,6 @@ Features:
right) become genuine first class citizens, and we gain automatic, sane JSON right) become genuine first class citizens, and we gain automatic, sane JSON
output for them. output for them.
* dissector: invoke fsck on the file systems we encounter, after all ext4 is
still pretty popular (and we mount the ESP too with it after all, which is
fat)
* systemd-firstboot: teach it dissector magic, so that you can point it to some * systemd-firstboot: teach it dissector magic, so that you can point it to some
disk image and it will just set everything in it all behind the scenes. disk image and it will just set everything in it all behind the scenes.

View File

@ -2603,7 +2603,7 @@ static int apply_mount_namespace(
needs_sandboxing ? context->protect_home : PROTECT_HOME_NO, needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO, needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
context->mount_flags, context->mount_flags,
DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK, DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
error_path); error_path);
/* If we couldn't set up the namespace this is probably due to a missing capability. setup_namespace() reports /* If we couldn't set up the namespace this is probably due to a missing capability. setup_namespace() reports

View File

@ -11,6 +11,7 @@
#include "log.h" #include "log.h"
#include "loop-util.h" #include "loop-util.h"
#include "main-func.h" #include "main-func.h"
#include "parse-util.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "user-util.h" #include "user-util.h"
@ -22,7 +23,7 @@ static enum {
} arg_action = ACTION_DISSECT; } arg_action = ACTION_DISSECT;
static const char *arg_image = NULL; static const char *arg_image = NULL;
static const char *arg_path = NULL; static const char *arg_path = NULL;
static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK; static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK;
static void *arg_root_hash = NULL; static void *arg_root_hash = NULL;
static size_t arg_root_hash_size = 0; static size_t arg_root_hash_size = 0;
@ -36,6 +37,7 @@ static void help(void) {
" --version Show package version\n" " --version Show package version\n"
" -m --mount Mount the image to the specified directory\n" " -m --mount Mount the image to the specified directory\n"
" -r --read-only Mount read-only\n" " -r --read-only Mount read-only\n"
" --fsck=BOOL Run fsck before mounting\n"
" --discard=MODE Choose 'discard' mode (disabled, loop, all, crypto)\n" " --discard=MODE Choose 'discard' mode (disabled, loop, all, crypto)\n"
" --root-hash=HASH Specify root hash for verity\n", " --root-hash=HASH Specify root hash for verity\n",
program_invocation_short_name, program_invocation_short_name,
@ -48,6 +50,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VERSION = 0x100, ARG_VERSION = 0x100,
ARG_DISCARD, ARG_DISCARD,
ARG_ROOT_HASH, ARG_ROOT_HASH,
ARG_FSCK,
}; };
static const struct option options[] = { static const struct option options[] = {
@ -57,6 +60,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "read-only", no_argument, NULL, 'r' }, { "read-only", no_argument, NULL, 'r' },
{ "discard", required_argument, NULL, ARG_DISCARD }, { "discard", required_argument, NULL, ARG_DISCARD },
{ "root-hash", required_argument, NULL, ARG_ROOT_HASH }, { "root-hash", required_argument, NULL, ARG_ROOT_HASH },
{ "fsck", required_argument, NULL, ARG_FSCK },
{} {}
}; };
@ -123,6 +127,14 @@ static int parse_argv(int argc, char *argv[]) {
break; break;
} }
case ARG_FSCK:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --fsck= parameter: %s", optarg);
SET_FLAG(arg_flags, DISSECT_IMAGE_FSCK, r);
break;
case '?': case '?':
return -EINVAL; return -EINVAL;
@ -261,6 +273,8 @@ static int run(int argc, char *argv[]) {
return r; return r;
r = dissected_image_mount(m, arg_path, UID_INVALID, arg_flags); r = dissected_image_mount(m, arg_path, UID_INVALID, arg_flags);
if (r == -EUCLEAN)
return log_error_errno(r, "File system check on image failed: %m");
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to mount image: %m"); return log_error_errno(r, "Failed to mount image: %m");

View File

@ -3309,10 +3309,12 @@ static int outer_child(
r = dissected_image_mount(dissected_image, directory, arg_uid_shift, r = dissected_image_mount(dissected_image, directory, arg_uid_shift,
DISSECT_IMAGE_MOUNT_ROOT_ONLY|DISSECT_IMAGE_DISCARD_ON_LOOP| DISSECT_IMAGE_MOUNT_ROOT_ONLY|DISSECT_IMAGE_DISCARD_ON_LOOP|
(arg_read_only ? DISSECT_IMAGE_READ_ONLY : 0)| (arg_read_only ? DISSECT_IMAGE_READ_ONLY : DISSECT_IMAGE_FSCK)|
(arg_start_mode == START_BOOT ? DISSECT_IMAGE_VALIDATE_OS : 0)); (arg_start_mode == START_BOOT ? DISSECT_IMAGE_VALIDATE_OS : 0));
if (r == -EUCLEAN)
return log_error_errno(r, "File system check for image failed: %m");
if (r < 0) if (r < 0)
return r; return log_error_errno(r, "Failed to mount image root file system: %m");
} }
r = determine_uid_shift(directory); r = determine_uid_shift(directory);
@ -3396,9 +3398,11 @@ static int outer_child(
if (dissected_image) { if (dissected_image) {
/* Now we know the uid shift, let's now mount everything else that might be in the image. */ /* Now we know the uid shift, let's now mount everything else that might be in the image. */
r = dissected_image_mount(dissected_image, directory, arg_uid_shift, r = dissected_image_mount(dissected_image, directory, arg_uid_shift,
DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY|DISSECT_IMAGE_DISCARD_ON_LOOP|(arg_read_only ? DISSECT_IMAGE_READ_ONLY : 0)); DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY|DISSECT_IMAGE_DISCARD_ON_LOOP|(arg_read_only ? DISSECT_IMAGE_READ_ONLY : DISSECT_IMAGE_FSCK));
if (r == -EUCLEAN)
return log_error_errno(r, "File system check for image failed: %m");
if (r < 0) if (r < 0)
return r; return log_error_errno(r, "Failed to mount image file system: %m");
} }
if (arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_UNKNOWN) { if (arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_UNKNOWN) {

View File

@ -28,6 +28,7 @@
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "fs-util.h" #include "fs-util.h"
#include "fsck-util.h"
#include "gpt.h" #include "gpt.h"
#include "hexdecoct.h" #include "hexdecoct.h"
#include "hostname-util.h" #include "hostname-util.h"
@ -278,6 +279,29 @@ static int loop_wait_for_partitions_to_appear(
N_DEVICE_NODE_LIST_ATTEMPTS); N_DEVICE_NODE_LIST_ATTEMPTS);
} }
static void check_partition_flags(
const char *node,
unsigned long long pflags,
unsigned long long supported) {
assert(node);
/* Mask away all flags supported by this partition's type and the three flags the UEFI spec defines generically */
pflags &= ~(supported | GPT_FLAG_REQUIRED_PARTITION | GPT_FLAG_NO_BLOCK_IO_PROTOCOL | GPT_FLAG_LEGACY_BIOS_BOOTABLE);
if (pflags == 0)
return;
/* If there are other bits set, then log about it, to make things discoverable */
for (unsigned i = 0; i < sizeof(pflags) * 8; i++) {
unsigned long long bit = 1ULL << i;
if (!FLAGS_SET(pflags, bit))
continue;
log_debug("Unexpected partition flag %llu set on %s!", bit, node);
}
}
#endif #endif
int dissect_image( int dissect_image(
@ -484,6 +508,8 @@ int dissect_image(
if (sd_id128_equal(type_id, GPT_HOME)) { if (sd_id128_equal(type_id, GPT_HOME)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
if (pflags & GPT_FLAG_NO_AUTO) if (pflags & GPT_FLAG_NO_AUTO)
continue; continue;
@ -491,6 +517,8 @@ int dissect_image(
rw = !(pflags & GPT_FLAG_READ_ONLY); rw = !(pflags & GPT_FLAG_READ_ONLY);
} else if (sd_id128_equal(type_id, GPT_SRV)) { } else if (sd_id128_equal(type_id, GPT_SRV)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
if (pflags & GPT_FLAG_NO_AUTO) if (pflags & GPT_FLAG_NO_AUTO)
continue; continue;
@ -510,6 +538,8 @@ int dissect_image(
} else if (sd_id128_equal(type_id, GPT_XBOOTLDR)) { } else if (sd_id128_equal(type_id, GPT_XBOOTLDR)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
if (pflags & GPT_FLAG_NO_AUTO) if (pflags & GPT_FLAG_NO_AUTO)
continue; continue;
@ -519,6 +549,8 @@ int dissect_image(
#ifdef GPT_ROOT_NATIVE #ifdef GPT_ROOT_NATIVE
else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) { else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
if (pflags & GPT_FLAG_NO_AUTO) if (pflags & GPT_FLAG_NO_AUTO)
continue; continue;
@ -531,6 +563,8 @@ int dissect_image(
rw = !(pflags & GPT_FLAG_READ_ONLY); rw = !(pflags & GPT_FLAG_READ_ONLY);
} else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY)) { } else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
if (pflags & GPT_FLAG_NO_AUTO) if (pflags & GPT_FLAG_NO_AUTO)
continue; continue;
@ -549,6 +583,8 @@ int dissect_image(
#ifdef GPT_ROOT_SECONDARY #ifdef GPT_ROOT_SECONDARY
else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY)) { else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
if (pflags & GPT_FLAG_NO_AUTO) if (pflags & GPT_FLAG_NO_AUTO)
continue; continue;
@ -561,6 +597,8 @@ int dissect_image(
rw = !(pflags & GPT_FLAG_READ_ONLY); rw = !(pflags & GPT_FLAG_READ_ONLY);
} else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY)) { } else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
if (pflags & GPT_FLAG_NO_AUTO) if (pflags & GPT_FLAG_NO_AUTO)
continue; continue;
@ -578,6 +616,8 @@ int dissect_image(
#endif #endif
else if (sd_id128_equal(type_id, GPT_SWAP)) { else if (sd_id128_equal(type_id, GPT_SWAP)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO);
if (pflags & GPT_FLAG_NO_AUTO) if (pflags & GPT_FLAG_NO_AUTO)
continue; continue;
@ -585,6 +625,8 @@ int dissect_image(
fstype = "swap"; fstype = "swap";
} else if (sd_id128_equal(type_id, GPT_LINUX_GENERIC)) { } else if (sd_id128_equal(type_id, GPT_LINUX_GENERIC)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
if (pflags & GPT_FLAG_NO_AUTO) if (pflags & GPT_FLAG_NO_AUTO)
continue; continue;
@ -601,6 +643,8 @@ int dissect_image(
} else if (sd_id128_equal(type_id, GPT_TMP)) { } else if (sd_id128_equal(type_id, GPT_TMP)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
if (pflags & GPT_FLAG_NO_AUTO) if (pflags & GPT_FLAG_NO_AUTO)
continue; continue;
@ -609,6 +653,8 @@ int dissect_image(
} else if (sd_id128_equal(type_id, GPT_VAR)) { } else if (sd_id128_equal(type_id, GPT_VAR)) {
check_partition_flags(node, pflags, GPT_FLAG_NO_AUTO|GPT_FLAG_READ_ONLY);
if (pflags & GPT_FLAG_NO_AUTO) if (pflags & GPT_FLAG_NO_AUTO)
continue; continue;
@ -851,6 +897,49 @@ static int is_loop_device(const char *path) {
return true; return true;
} }
static int run_fsck(const char *node, const char *fstype) {
int r, exit_status;
pid_t pid;
assert(node);
assert(fstype);
r = fsck_exists(fstype);
if (r < 0) {
log_debug_errno(r, "Couldn't determine whether fsck for %s exists, proceeding anyway.", fstype);
return 0;
}
if (r == 0) {
log_debug("Not checking partition %s, as fsck for %s does not exist.", node, fstype);
return 0;
}
r = safe_fork("(fsck)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_NULL_STDIO, &pid);
if (r < 0)
return log_debug_errno(r, "Failed to fork off fsck: %m");
if (r == 0) {
/* Child */
execl("/sbin/fsck", "/sbin/fsck", "-aT", node, NULL);
log_debug_errno(errno, "Failed to execl() fsck: %m");
_exit(FSCK_OPERATIONAL_ERROR);
}
exit_status = wait_for_terminate_and_check("fsck", pid, 0);
if (exit_status < 0)
return log_debug_errno(exit_status, "Failed to fork off /sbin/fsck: %m");
if ((exit_status & ~FSCK_ERROR_CORRECTED) != FSCK_SUCCESS) {
log_debug("fsck failed with exit status %i.", exit_status);
if ((exit_status & (FSCK_SYSTEM_SHOULD_REBOOT|FSCK_ERRORS_LEFT_UNCORRECTED)) != 0)
return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN), "File system is corrupted, refusing.");
log_debug("Ignoring fsck error.");
}
return 0;
}
static int mount_partition( static int mount_partition(
DissectedPartition *m, DissectedPartition *m,
const char *where, const char *where,
@ -878,6 +967,12 @@ static int mount_partition(
rw = m->rw && !(flags & DISSECT_IMAGE_READ_ONLY); rw = m->rw && !(flags & DISSECT_IMAGE_READ_ONLY);
if (FLAGS_SET(flags, DISSECT_IMAGE_FSCK) && rw) {
r = run_fsck(node, fstype);
if (r < 0)
return r;
}
if (directory) { if (directory) {
r = chase_symlinks(directory, where, CHASE_PREFIX_ROOT, &chased, NULL); r = chase_symlinks(directory, where, CHASE_PREFIX_ROOT, &chased, NULL);
if (r < 0) if (r < 0)

View File

@ -62,6 +62,7 @@ typedef enum DissectImageFlags {
DISSECT_IMAGE_VALIDATE_OS = 1 << 8, /* Refuse mounting images that aren't identifiable as OS images */ 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_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 */ DISSECT_IMAGE_RELAX_VAR_CHECK = 1 << 10, /* Don't insist that the UUID of /var is hashed from /etc/machine-id */
DISSECT_IMAGE_FSCK = 1 << 11, /* File system check the partition before mounting (no effect when combined with DISSECT_IMAGE_READ_ONLY) */
} DissectImageFlags; } DissectImageFlags;
struct DissectedImage { struct DissectedImage {

View File

@ -58,7 +58,9 @@
# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_ARM_VERITY # define GPT_ROOT_NATIVE_VERITY GPT_ROOT_ARM_VERITY
#endif #endif
#define GPT_FLAG_REQUIRED_PARTITION (1ULL << 0)
#define GPT_FLAG_NO_BLOCK_IO_PROTOCOL (1ULL << 1) #define GPT_FLAG_NO_BLOCK_IO_PROTOCOL (1ULL << 1)
#define GPT_FLAG_LEGACY_BIOS_BOOTABLE (1ULL << 2)
/* Flags we recognize on the root, swap, home and srv partitions when /* Flags we recognize on the root, swap, home and srv partitions when
* doing auto-discovery. These happen to be identical to what * doing auto-discovery. These happen to be identical to what