From 2bc181dae797a131d430468afc8e5eeae596c014 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Aug 2020 12:23:01 +0200 Subject: [PATCH 1/5] gpt: add new GPT partition types of /usr partitions --- src/shared/gpt.c | 18 ++++++++++++++++++ src/shared/gpt.h | 34 +++++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/shared/gpt.c b/src/shared/gpt.c index 725374485d..53a3f4bfe6 100644 --- a/src/shared/gpt.c +++ b/src/shared/gpt.c @@ -21,6 +21,24 @@ const GptPartitionType gpt_partition_type_table[] = { #ifdef GPT_ROOT_SECONDARY { GPT_ROOT_SECONDARY, "root-secondary" }, { GPT_ROOT_SECONDARY_VERITY, "root-secondary-verity" }, +#endif + { GPT_USR_X86, "usr-x86" }, + { GPT_USR_X86_VERITY, "usr-x86-verity" }, + { GPT_USR_X86_64, "usr-x86-64" }, + { GPT_USR_X86_64_VERITY, "usr-x86-64-verity" }, + { GPT_USR_ARM, "usr-arm" }, + { GPT_USR_ARM_VERITY, "usr-arm-verity" }, + { GPT_USR_ARM_64, "usr-arm64" }, + { GPT_USR_ARM_64_VERITY, "usr-arm64-verity" }, + { GPT_USR_IA64, "usr-ia64" }, + { GPT_USR_IA64_VERITY, "usr-ia64-verity" }, +#ifdef GPT_USR_NATIVE + { GPT_USR_NATIVE, "usr" }, + { GPT_USR_NATIVE_VERITY, "usr-verity" }, +#endif +#ifdef GPT_USR_SECONDARY + { GPT_USR_SECONDARY, "usr-secondary" }, + { GPT_USR_SECONDARY_VERITY, "usr-secondary-verity" }, #endif { GPT_ESP, "esp" }, { GPT_XBOOTLDR, "xbootldr" }, diff --git a/src/shared/gpt.h b/src/shared/gpt.h index 30fcb88056..b162eb9d0d 100644 --- a/src/shared/gpt.h +++ b/src/shared/gpt.h @@ -15,6 +15,11 @@ #define GPT_ROOT_ARM SD_ID128_MAKE(69,da,d7,10,2c,e4,4e,3c,b1,6c,21,a1,d4,9a,be,d3) #define GPT_ROOT_ARM_64 SD_ID128_MAKE(b9,21,b0,45,1d,f0,41,c3,af,44,4c,6f,28,0d,3f,ae) #define GPT_ROOT_IA64 SD_ID128_MAKE(99,3d,8d,3d,f8,0e,42,25,85,5a,9d,af,8e,d7,ea,97) +#define GPT_USR_X86 SD_ID128_MAKE(75,25,0d,76,8c,c6,45,8e,bd,66,bd,47,cc,81,a8,12) +#define GPT_USR_X86_64 SD_ID128_MAKE(84,84,68,0c,95,21,48,c6,9c,11,b0,72,06,56,f6,9e) +#define GPT_USR_ARM SD_ID128_MAKE(7d,03,59,a3,02,b3,4f,0a,86,5c,65,44,03,e7,06,25) +#define GPT_USR_ARM_64 SD_ID128_MAKE(b0,e0,10,50,ee,5f,43,90,94,9a,91,01,b1,71,04,e9) +#define GPT_USR_IA64 SD_ID128_MAKE(43,01,d2,a6,4e,3b,4b,2a,bb,94,9e,0b,2c,42,25,ea) #define GPT_ESP SD_ID128_MAKE(c1,2a,73,28,f8,1f,11,d2,ba,4b,00,a0,c9,3e,c9,3b) #define GPT_XBOOTLDR SD_ID128_MAKE(bc,13,c2,ff,59,e6,42,62,a3,52,b2,75,fd,6f,71,72) #define GPT_SWAP SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f) @@ -25,27 +30,40 @@ #define GPT_USER_HOME SD_ID128_MAKE(77,3f,91,ef,66,d4,49,b5,bd,83,d6,83,bf,40,ad,16) #define GPT_LINUX_GENERIC SD_ID128_MAKE(0f,c6,3d,af,84,83,47,72,8e,79,3d,69,d8,47,7d,e4) -/* Verity partitions for the root partitions above (we only define them for the root partitions, because only - * they are are commonly read-only and hence suitable for verity). */ +/* Verity partitions for the root partitions above (we only define them for the root and /usr partitions, + * because only they are are commonly read-only and hence suitable for verity). */ #define GPT_ROOT_X86_VERITY SD_ID128_MAKE(d1,3c,5d,3b,b5,d1,42,2a,b2,9f,94,54,fd,c8,9d,76) #define GPT_ROOT_X86_64_VERITY SD_ID128_MAKE(2c,73,57,ed,eb,d2,46,d9,ae,c1,23,d4,37,ec,2b,f5) #define GPT_ROOT_ARM_VERITY SD_ID128_MAKE(73,86,cd,f2,20,3c,47,a9,a4,98,f2,ec,ce,45,a2,d6) #define GPT_ROOT_ARM_64_VERITY SD_ID128_MAKE(df,33,00,ce,d6,9f,4c,92,97,8c,9b,fb,0f,38,d8,20) #define GPT_ROOT_IA64_VERITY SD_ID128_MAKE(86,ed,10,d5,b6,07,45,bb,89,57,d3,50,f2,3d,05,71) +#define GPT_USR_X86_VERITY SD_ID128_MAKE(8f,46,1b,0d,14,ee,4e,81,9a,a9,04,9b,6f,b9,7a,bd) +#define GPT_USR_X86_64_VERITY SD_ID128_MAKE(77,ff,5f,63,e7,b6,46,33,ac,f4,15,65,b8,64,c0,e6) +#define GPT_USR_ARM_VERITY SD_ID128_MAKE(c2,15,d7,51,7b,cd,46,49,be,90,66,27,49,0a,4c,05) +#define GPT_USR_ARM_64_VERITY SD_ID128_MAKE(6e,11,a4,e7,fb,ca,4d,ed,b9,e9,e1,a5,12,bb,66,4e) +#define GPT_USR_IA64_VERITY SD_ID128_MAKE(6a,49,1e,03,3b,e7,45,45,8e,38,83,32,0e,0e,a8,80) #if defined(__x86_64__) # define GPT_ROOT_NATIVE GPT_ROOT_X86_64 # define GPT_ROOT_SECONDARY GPT_ROOT_X86 # define GPT_ROOT_NATIVE_VERITY GPT_ROOT_X86_64_VERITY # define GPT_ROOT_SECONDARY_VERITY GPT_ROOT_X86_VERITY +# define GPT_USR_NATIVE GPT_USR_X86_64 +# define GPT_USR_SECONDARY GPT_USR_X86 +# define GPT_USR_NATIVE_VERITY GPT_USR_X86_64_VERITY +# define GPT_USR_SECONDARY_VERITY GPT_USR_X86_VERITY #elif defined(__i386__) # define GPT_ROOT_NATIVE GPT_ROOT_X86 # define GPT_ROOT_NATIVE_VERITY GPT_ROOT_X86_VERITY +# define GPT_USR_NATIVE GPT_USR_X86 +# define GPT_USR_NATIVE_VERITY GPT_USR_X86_VERITY #endif #if defined(__ia64__) # define GPT_ROOT_NATIVE GPT_ROOT_IA64 # define GPT_ROOT_NATIVE_VERITY GPT_ROOT_IA64_VERITY +# define GPT_USR_NATIVE GPT_USR_IA64 +# define GPT_USR_NATIVE_VERITY GPT_USR_IA64_VERITY #endif #if defined(__aarch64__) && (__BYTE_ORDER != __BIG_ENDIAN) @@ -53,18 +71,24 @@ # define GPT_ROOT_SECONDARY GPT_ROOT_ARM # define GPT_ROOT_NATIVE_VERITY GPT_ROOT_ARM_64_VERITY # define GPT_ROOT_SECONDARY_VERITY GPT_ROOT_ARM_VERITY +# define GPT_USR_NATIVE GPT_USR_ARM_64 +# define GPT_USR_SECONDARY GPT_USR_ARM +# define GPT_USR_NATIVE_VERITY GPT_USR_ARM_64_VERITY +# define GPT_USR_SECONDARY_VERITY GPT_USR_ARM_VERITY #elif defined(__arm__) && (__BYTE_ORDER != __BIG_ENDIAN) # define GPT_ROOT_NATIVE GPT_ROOT_ARM # define GPT_ROOT_NATIVE_VERITY GPT_ROOT_ARM_VERITY +# define GPT_USR_NATIVE GPT_USR_ARM +# define GPT_USR_NATIVE_VERITY GPT_USR_ARM_VERITY #endif #define GPT_FLAG_REQUIRED_PARTITION (1ULL << 0) #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 doing auto-discovery. These happen to - * be identical to what Microsoft defines for its own Basic Data Partitions, but that's just because we saw - * no point in defining any other values here. */ +/* Flags we recognize on the root, usr, xbootldr, swap, home, srv, var, tmp partitions when doing + * auto-discovery. These happen to be identical to what Microsoft defines for its own Basic Data Partitions, + * but that's just because we saw no point in defining any other values here. */ #define GPT_FLAG_READ_ONLY (1ULL << 60) #define GPT_FLAG_NO_AUTO (1ULL << 63) From aee36b4ea22cabe2904bc1b0ba4866f097685a14 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Aug 2020 12:21:51 +0200 Subject: [PATCH 2/5] dissect-image: process /usr/ GPT partition type --- src/core/namespace.c | 6 +- src/dissect/dissect.c | 2 +- src/nspawn/nspawn.c | 2 +- src/shared/dissect-image.c | 315 ++++++++++++++++++++++++++++++------- src/shared/dissect-image.h | 35 ++++- 5 files changed, 294 insertions(+), 66 deletions(-) diff --git a/src/core/namespace.c b/src/core/namespace.c index 8932785239..f2754f9d02 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -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; diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index dd80e86fee..237395a444 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -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; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 11a82090b0..42ba0f5e47 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -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 diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index b704268db2..e24740d449 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -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", }; diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index 5c1f5bd7b5..f5db7327bd 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -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); From 461836a4e9db75453045a96f2bafb9ce19b34e68 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 17 Sep 2020 18:00:26 +0200 Subject: [PATCH 3/5] man: emphasize that part table shown by systemd-dissect is not complete --- man/systemd-dissect.xml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/man/systemd-dissect.xml b/man/systemd-dissect.xml index 55e7076b43..a2e77281c8 100644 --- a/man/systemd-dissect.xml +++ b/man/systemd-dissect.xml @@ -74,6 +74,15 @@ switch, and be used as root file system for system service using the RootImage= unit file setting, see system.exec5. + + Note that the partition table shown when invoked without command switch (as listed below) does not + necessarily show all partitions included in the image, but just the partitions that are understood and + considered part of an OS disk image. Specifically, partitions of unknown types are ignored, as well as + duplicate partitions (i.e. more than one per partition type), as are root and /usr/ + partitions of architectures not compatible with the local system. In other words: this tool will display + what it operates with when mounting the image. To display the complete list of partitions use a tool such + as fdisk8. @@ -246,7 +255,8 @@ system-nspawn1, system.exec5, Discoverable Partitions Specification, - umount8 + umount8, + fdisk8 From 329cde79c4f802f9318855cef5b6aa823e437216 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 17 Sep 2020 18:57:27 +0200 Subject: [PATCH 4/5] doc: document the new GPT partition type UUIDs --- docs/DISCOVERABLE_PARTITIONS.md | 76 +++++++++++++++++++-------------- man/repart.d.xml | 70 ++++++++++++++++++++++++++++++ man/systemd-nspawn.xml | 17 +++++++- man/systemd.exec.xml | 15 +++++++ 4 files changed, 143 insertions(+), 35 deletions(-) diff --git a/docs/DISCOVERABLE_PARTITIONS.md b/docs/DISCOVERABLE_PARTITIONS.md index 380dee142e..0e021e064c 100644 --- a/docs/DISCOVERABLE_PARTITIONS.md +++ b/docs/DISCOVERABLE_PARTITIONS.md @@ -51,6 +51,16 @@ Interface](https://systemd.io/BOOT_LOADER_INTERFACE). | `7386cdf2-203c-47a9-a498-f2ecce45a2d6` | _Root Verity Partition (32-bit ARM)_ | ditto | ditto | | `df3300ce-d69f-4c92-978c-9bfb0f38d820` | _Root Verity Partition (64-bit ARM/AArch64)_ | ditto | ditto | | `86ed10d5-b607-45bb-8957-d350f23d0571` | _Root Verity Partition (Itanium/IA-64)_ | ditto | ditto | +| `75250d76-8cc6-458e-bd66-bd47cc81a812` | _`/usr/` Partition (x86)_ | Any native, optionally in LUKS | Similar semantics to root partition, but just the `/usr/` partition. | +| `8484680c-9521-48c6-9c11-b0720656f69e` | _`/usr/` Partition (x86-64)_ | ditto | ditto | +| `7d0359a3-02b3-4f0a-865c-654403e70625` | _`/usr/` Partition (32-bit ARM)_ | ditto | ditto | +| `b0e01050-ee5f-4390-949a-9101b17104e9` | _`/usr/` Partition (64-bit ARM/AArch64)_ | ditto | ditto | +| `4301d2a6-4e3b-4b2a-bb94-9e0b2c4225ea` | _`/usr/` Partition (Itanium/IA-64)_ | ditto | ditto | +| `8f461b0d-14ee-4e81-9aa9-049b6fb97abd` | _`/usr/` Verity Partition (x86)_ | Any native, optionally in LUKS | Similar semantics to root Verity partition, but just for the `/usr/` partition. | +| `77ff5f63-e7b6-4633-acf4-1565b864c0e6` | _`/usr/` Verity Partition (x86-64)_ | ditto | ditto | +| `c215d751-7bcd-4649-be90-6627490a4c05` | _`/usr/` Verity Partition (32-bit ARM)_ | ditto | ditto | +| `6e11a4e7-fbca-4ded-b9e9-e1a512bb664e` | _`/usr/` Verity Partition (64-bit ARM/AArch64)_ | ditto | ditto | +| `6a491e03-3be7-4545-8e38-83320e0ea880` | _`/usr/` Verity Partition (Itanium/IA-64)_ | ditto | ditto | | `933ac7e1-2eb4-4f13-b844-0e14e2aef915` | _Home Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/home/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/home`. | | `3b8f8425-20e0-4f3b-907f-1a25a76f98e8` | _Server Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/srv/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/srv`. | | `4d21b016-b534-45c2-a9fb-5c16e091fd2d` | _Variable Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/var/` — under the condition that its partition UUID matches the first 128 bit of `HMAC-SHA256(machine-id, 0x4d21b016b53445c2a9fb5c16e091fd2d)` (i.e. the SHA256 HMAC hash of the binary type UUID keyed by the machine ID as read from [`/etc/machine-id`](https://www.freedesktop.org/software/systemd/man/machine-id.html). This special requirement is made because `/var/` (unlike the other partition types listed here) is inherently private to a specific installation and cannot possibly be shared between multiple OS installations on the same disk, and thus should be bound to a specific instance of the OS, identified by its machine ID. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/var`. | @@ -76,21 +86,21 @@ localized. ## Partition Flags -For the root, server data, home, variable data, temporary data and swap +For the root, `/usr/`, server data, home, variable data, temporary data and swap partitions, the partition flag bit 63 ("*no-auto*") may be used to turn off auto-discovery for the specific partition. If set, the partition will not be automatically mounted or enabled. -For the root, server data, home, variable data and temporary data partitions, -the partition flag bit 60 ("*read-only*") may be used to mark a partition for -read-only mounts only. If set, the partition will be mounted read-only instead -of read-write. Note that the variable data partition and the temporary data -partition will generally not be able to serve their purpose if marked -read-only, since by their very definition they are supposed to be mutable. (The -home and server data partitions are generally assumed to be mutable as well, -but the requirement for them is not equally strong.) Because of that, while the -read-only flag is defined and supported, it's almost never a good idea to -actually use it for these partitions. +For the root, `/usr/` server data, home, variable data and temporary data +partitions, the partition flag bit 60 ("*read-only*") may be used to mark a +partition for read-only mounts only. If set, the partition will be mounted +read-only instead of read-write. Note that the variable data partition and the +temporary data partition will generally not be able to serve their purpose if +marked read-only, since by their very definition they are supposed to be +mutable. (The home and server data partitions are generally assumed to be +mutable as well, but the requirement for them is not equally strong.) Because +of that, while the read-only flag is defined and supported, it's almost never a +good idea to actually use it for these partitions. Note that these two flag definitions happen to map nicely to the ones used by Microsoft Basic Data Partitions. @@ -104,8 +114,8 @@ An *installer* which supports a "manual partitioning" interface _may_ choose to pre-populate the interface with swap, `/home/`, `/srv/`, `/var/tmp/` partitions of pre-existing Linux installations, identified with the GPT type UUIDs above. The installer should not pre-populate such an interface with any -identified root or `/var/` partition unless the intention is to overwrite an -existing operating system that might be installed. +identified root, `/usr` or `/var/` partition unless the intention is to +overwrite an existing operating system that might be installed. An *installer* _may_ omit creating entries in `/etc/fstab` for root, `/home/`, `/srv/`, `/var/`, `/var/tmp` and for the swap partitions if they use these UUID @@ -119,17 +129,17 @@ in `/etc/fstab`. The `root=` parameter passed to the kernel by the boot loader may be omitted if the root partition is the first one on the disk of its type. If the root partition is not the first one on the disk, the `root=` parameter _must_ be passed to the kernel by the boot loader. An installer that mounts a -root, `/home/`, `/srv/`, `/var/`, or `/var/tmp/` file system with the partition -types defined as above which contains a LUKS header _must_ call the device -mapper device "root", "home", "srv", "var" or "tmp", respectively. This is -necessary to ensure that the automatic discovery will never result in different -device mapper names than any static configuration by the installer, thus -eliminating possible naming conflicts and ambiguities. +root, `/usr/`, `/home/`, `/srv/`, `/var/`, or `/var/tmp/` file system with the +partition types defined as above which contains a LUKS header _must_ call the +device mapper device "root", "usr", "home", "srv", "var" or "tmp", +respectively. This is necessary to ensure that the automatic discovery will +never result in different device mapper names than any static configuration by +the installer, thus eliminating possible naming conflicts and ambiguities. An *operating* *system* _should_ automatically discover and mount the first root partition that does not have the no-auto flag set (as described above) by scanning the disk containing the currently used EFI ESP. It _should_ -automatically discover and mount the first `/home/`, `/srv/`, `/var/`, +automatically discover and mount the first `/usr/`, `/home/`, `/srv/`, `/var/`, `/var/tmp/` and swap partitions that do not have the no-auto flag set by scanning the disk containing the discovered root partition. It should automatically discover and mount the partition containing the currently used @@ -138,19 +148,19 @@ and mount the partition containing the currently used Extended Boot Loader Partition to `/boot/`. It _should not_ discover or automatically mount partitions with other UUID partition types, or partitions located on other disks, or partitions with the no-auto flag set. User configuration shall -always override automatic discovery and mounting. If a root, `/home/`, -`/srv/`, `/boot/`, `/var/`, `/var/tmp/`, `/efi/`, `/boot/` or swap partition is -listed in `/etc/fstab` or with `root=` on the kernel command line, it _must_ -take precedence over automatically discovered partitions. If a `/home/`, -`/srv/`, `/boot/`, `/var/`, `/var/tmp/`, `/efi/` or `/boot/` directory is found -to be populated already in the root partition, the automatic discovery _must -not_ mount any discovered file system over it. +always override automatic discovery and mounting. If a root, `/usr/`, +`/home/`, `/srv/`, `/boot/`, `/var/`, `/var/tmp/`, `/efi/`, `/boot/` or swap +partition is listed in `/etc/fstab` or with `root=` on the kernel command line, +it _must_ take precedence over automatically discovered partitions. If a +`/home/`, `/usr/`, `/srv/`, `/boot/`, `/var/`, `/var/tmp/`, `/efi/` or `/boot/` +directory is found to be populated already in the root partition, the automatic +discovery _must not_ mount any discovered file system over it. A *container* *manager* should automatically discover and mount the root, -`/home/`, `/srv/`, `/var/`, `/var/tmp/` partitions inside a container disk -image. It may choose to mount any discovered ESP and/or XBOOOTLDR partition to -`/efi/` or `/boot/`. It should ignore any swap should they be included in a -container disk image. +`/usr/`, `/home/`, `/srv/`, `/var/`, `/var/tmp/` partitions inside a container +disk image. It may choose to mount any discovered ESP and/or XBOOOTLDR +partition to `/efi/` or `/boot/`. It should ignore any swap should they be +included in a container disk image. If a btrfs file system is automatically discovered and mounted by the operating system/container manager it will be mounted with its *default* subvolume. The @@ -161,8 +171,8 @@ subvolume set-default". If two Linux-based operating systems are installed on the same disk, the scheme above suggests that they may share the swap, `/home/`, `/srv/`, `/var/tmp/`, -ESP, XBOOTLDR. However, they should each have their own root and `/var/` -partition. +ESP, XBOOTLDR. However, they should each have their own root, `/usr/` and +`/var/` partition. ## Frequently Asked Questions diff --git a/man/repart.d.xml b/man/repart.d.xml index 9714a3602a..5cc978b873 100644 --- a/man/repart.d.xml +++ b/man/repart.d.xml @@ -197,6 +197,76 @@ root-ia64-verity Verity data for the ia64 root file system partition + + + usr + /usr/ file system partition type appropriate for the local architecture (an alias for an architecture /usr/ file system partition type listed below, e.g. usr-x86-64) + + + + usr-verity + Verity data for the /usr/ file system partition for the local architecture + + + + usr-secondary + /usr/ file system partition of the secondary architecture of the local architecture (usually the matching 32bit architecture for the local 64bit architecture) + + + + usr-secondary-verity + Verity data for the /usr/ file system partition of the secondary architecture + + + + usr-x86 + /usr/ file system partition for the x86 (32bit, aka i386) architecture + + + + usr-x86-verity + Verity data for the x86 (32bit) /usr/ file system partition + + + + usr-x86-64 + /usr/ file system partition for the x86_64 (64bit, aka amd64) architecture + + + + usr-x86-64-verity + Verity data for the x86_64 (64bit) /usr/ file system partition + + + + usr-arm + /usr/ file system partition for the ARM (32bit) architecture + + + + usr-arm-verity + Verity data for the ARM (32bit) /usr/ file system partition + + + + usr-arm64 + /usr/ file system partition for the ARM (64bit, aka aarch64) architecture + + + + usr-arm64-verity + Verity data for the ARM (64bit, aka aarch64) /usr/ file system partition + + + + usr-ia64 + /usr/ file system partition for the ia64 architecture + + + + usr-ia64-verity + Verity data for the ia64 /usr/ file system partition + diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index c8fbb01d00..7c89bc4423 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -396,7 +396,15 @@ is not supported by the underlying file system), but a file with the .roothash suffix is found next to the image file, bearing otherwise the same name (except if the image has the .raw suffix, in which case the root hash file must not have it in its name), the root hash - is read from it and automatically used, also as formatted hexadecimal characters. + is read from it and automatically used, also as formatted hexadecimal characters. + + Note that this configures the root hash for the root file system. Disk images may also contain + separate file systems for the /usr/ hierarchy, which may be Verity protected as + well. The root hash for this protection may be configured via the + user.verity.usrhash extended file attribute or via a .usrhash + file adjacent to the disk image, following the same format and logic as for the root hash for the + root file system described here. Note that there's currently no switch to configure the root hash for + the /usr/ from the command line. @@ -408,7 +416,12 @@ string is valid and done by a public key present in the kernel keyring. If this option is not specified, but a file with the .roothash.p7s suffix is found next to the image file, bearing otherwise the same name (except if the image has the .raw suffix, in which case the signature file must - not have it in its name), the signature is read from it and automatically used. + not have it in its name), the signature is read from it and automatically used. + + The root hash for the /usr/ file system included in a disk image may be + configured via a .usrhash.p7s file adjacent to the disk image. There's currently + no switch to configure the signature of the root hash of the /usr/ file system + from the command line. diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index d0bb5fc962..ed657831f6 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -193,6 +193,9 @@ var + + usr + @@ -216,6 +219,12 @@ .raw suffix, in which case the root hash file must not have it in its name), the root hash is read from it and automatically used, also as formatted hexadecimal characters. + If the disk image contains a separate /usr/ partition it may also be + Verity protected, in which case the root hash may configured via an extended attribute + user.verity.usrhash or a .usrhash file adjacent to the disk + image. There's currently no option to configure the root hash for the /usr/ file + system via the unit file directly. + @@ -230,6 +239,12 @@ the same name (except if the image has the .raw suffix, in which case the signature file must not have it in its name), the signature is read from it and automatically used. + If the disk image contains a separate /usr/ partition it may also be + Verity protected, in which case the signature for the root hash may configured via a + .usrhash.p7s file adjacent to the disk image. There's currently no option to + configure the root hash signature for the /usr/ via the unit file + directly. + From cd8de997f2f2baf2e9bb6091595d390e46d84372 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 17 Sep 2020 18:59:10 +0200 Subject: [PATCH 5/5] update TODO --- TODO | 3 --- 1 file changed, 3 deletions(-) diff --git a/TODO b/TODO index 3eb046116f..7a441c8c39 100644 --- a/TODO +++ b/TODO @@ -841,9 +841,6 @@ Features: * add new gpt type for btrfs volumes -* support empty /etc boots nicely: - - nspawn/gpt-generator: introduce new gpt partition type for /usr - * generator that automatically discovers btrfs subvolumes, identifies their purpose based on some xattr on them. * a way for container managers to turn off getty starting via $container_headless= or so...