Compare commits

..

9 Commits

Author SHA1 Message Date
Anita Zhang 80d48995f3
Merge pull request #14712 from wlhlm/root-storage-daemons-docs-fix
Tiny fix for example code in docs
2020-01-30 12:57:21 -08:00
Anita Zhang 1b9d61bcee
Merge pull request #14696 from poettering/dissect-tweaks
various tweaks to the image dissection logic
2020-01-30 12:46:03 -08:00
Wilhelm Schuster faec9de87f docs: Fix example code in ROOT_STORAGE_DAEMONS 2020-01-30 20:27:05 +00:00
Lennart Poettering ed2d966152 update TODO 2020-01-29 19:30:02 +01:00
Lennart Poettering 8d251485fa core: fsck images specified as RootImage= too before using them 2020-01-29 19:29:59 +01:00
Lennart Poettering 4fcb96ce25 nspawn: fsck all images when mounting things
Also, start logging about mount errors, things are hard to debug
otherwise.
2020-01-29 19:29:55 +01:00
Lennart Poettering e475f72977 dissect: add --fsck= option to systemd-dissect tool
Let's expose this fsck behaviour directly.
2020-01-29 19:29:52 +01:00
Lennart Poettering cf32c48657 dissect: optionally, run fsck before mounting dissected images
Some file systems want us to run fsck before mounting, hence do so,
optionally.
2020-01-29 19:29:44 +01:00
Lennart Poettering 0f7c9a3d81 dissect: complain if partition flags are set that we don't know 2020-01-29 19:29:39 +01:00
8 changed files with 124 additions and 14 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

@ -87,11 +87,11 @@ systemd 38:
Processes (run by the root user) whose first character of the zeroth command Processes (run by the root user) whose first character of the zeroth command
line argument is `@` are excluded from the killing spree, much the same way as line argument is `@` are excluded from the killing spree, much the same way as
kernel threads are excluded too. Thus, a daemon which wants to take advantage kernel threads are excluded too. Thus, a daemon which wants to take advantage
of this logic needs to place the following at the top of its main() function: of this logic needs to place the following at the top of its `main()` function:
```c ```c
... ...
[0][0] = '@'; argv[0][0] = '@';
... ...
``` ```

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