From: Lennart Poettering Date: Tue, 23 Mar 2021 15:16:42 +0000 (+0100) Subject: repart: add new ReadOnly= and Flags= settings for repart dropins X-Git-Tag: v249-rc1~388^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e73309c532999cb15490a78575dd882b24bbe96f;p=thirdparty%2Fsystemd.git repart: add new ReadOnly= and Flags= settings for repart dropins Let's make the GPT partition flags configurable when creating new partitions. This is primarily useful for the read-only flag (which we want to set for verity enabled partitions). This adds two settings for this: Flags= and ReadOnly=, which strictly speaking are redundant. The main reason to have both is that usually the ReadOnly= setting is the one wants to control, and it' more generic. Moreover we might later on introduce inherting of flags from CopyBlocks= partitions, where one might want to control most flags as is except for the RO flag and similar, hence let's keep them separate. --- diff --git a/man/repart.d.xml b/man/repart.d.xml index d404645588f..5223f503649 100644 --- a/man/repart.d.xml +++ b/man/repart.d.xml @@ -565,6 +565,29 @@ factory reset operation. This functionality is useful to implement schemes where images can be reset into their original state by removing partitions and creating them anew. Defaults to off. + + + Flags= + + Configures the 64bit GPT partition flags to set for the partition when creating + it. This option has no effect if the partition already exists. If not specified the flags values is + set to all zeroes, except if the partition type (as configured with Type= above) + refers to a Verity partition, in wich case bit 60 is set (i.e. the read-only bit). This bit may also + be configured separately via ReadOnly=, see below. Specify the flags value in + hexadecimal (by prefixing it with 0x), binary (prefix 0b) or + decimal (no prefix). + + + + ReadOnly= + + Configures the Read-Only partition flags (bit 60) of the partition table entry. This + option is a friendly way to set bit 60 of the partition flags value without setting any of the other + bits, and may be set via Flags= too, see above. + + If both Flags= and ReadOnly= are set the latter controls + the value of the flag. + diff --git a/src/partition/repart.c b/src/partition/repart.c index 12ad0dd49e5..af319d2e33c 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -168,6 +168,9 @@ struct Partition { char **make_directories; EncryptMode encrypt; + uint64_t gpt_flags; + int read_only; + LIST_FIELDS(Partition, partitions); }; @@ -239,6 +242,7 @@ static Partition *partition_new(void) { .offset = UINT64_MAX, .copy_blocks_fd = -1, .copy_blocks_size = UINT64_MAX, + .read_only = -1, }; return p; @@ -1263,6 +1267,34 @@ static int config_parse_make_dirs( static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_encrypt, encrypt_mode, EncryptMode, ENCRYPT_OFF, "Invalid encryption mode"); +static int config_parse_gpt_flags( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + uint64_t *gpt_flags = data; + int r; + + assert(rvalue); + assert(gpt_flags); + + r = safe_atou64(rvalue, gpt_flags); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse Flags= value, ignoring: %s", rvalue); + return 0; + } + + return 0; +} + static int partition_read_definition(Partition *p, const char *path) { ConfigTableItem table[] = { @@ -1282,6 +1314,8 @@ static int partition_read_definition(Partition *p, const char *path) { { "Partition", "CopyFiles", config_parse_copy_files, 0, p }, { "Partition", "MakeDirectories", config_parse_make_dirs, 0, p }, { "Partition", "Encrypt", config_parse_encrypt, 0, &p->encrypt }, + { "Partition", "Flags", config_parse_gpt_flags, 0, &p->gpt_flags }, + { "Partition", "ReadOnly", config_parse_tristate, 0, &p->read_only }, {} }; int r; @@ -1323,6 +1357,12 @@ static int partition_read_definition(Partition *p, const char *path) { return log_oom(); } + /* Verity partitions are read only, let's imply the RO flag hence, unless explicitly configured otherwise. */ + if ((gpt_partition_type_is_root_verity(p->type_uuid) || + gpt_partition_type_is_usr_verity(p->type_uuid)) && + p->read_only < 0) + p->read_only = true; + return 0; } @@ -3184,6 +3224,24 @@ static int context_acquire_partition_uuids_and_labels(Context *context) { return 0; } +static int set_gpt_flags(struct fdisk_partition *q, uint64_t flags) { + _cleanup_free_ char *a = NULL; + + for (unsigned i = 0; i < sizeof(flags) * 8; i++) { + uint64_t bit = UINT64_C(1) << i; + char buf[DECIMAL_STR_MAX(unsigned)+1]; + + if (!FLAGS_SET(flags, bit)) + continue; + + xsprintf(buf, "%u", i); + if (!strextend_with_separator(&a, ",", buf)) + return -ENOMEM; + } + + return fdisk_partition_set_attrs(q, a); +} + static int context_mangle_partitions(Context *context) { Partition *p; int r; @@ -3252,6 +3310,7 @@ static int context_mangle_partitions(Context *context) { _cleanup_(fdisk_unref_partitionp) struct fdisk_partition *q = NULL; _cleanup_(fdisk_unref_parttypep) struct fdisk_parttype *t = NULL; char ids[ID128_UUID_STRING_MAX]; + uint64_t f; assert(!p->new_partition); assert(p->offset % 512 == 0); @@ -3299,6 +3358,22 @@ static int context_mangle_partitions(Context *context) { if (r < 0) return log_error_errno(r, "Failed to set partition label: %m"); + /* Merge the read only setting with the literal flags */ + f = p->gpt_flags; + if (p->read_only >= 0) { + if (gpt_partition_type_knows_read_only(p->type_uuid)) + SET_FLAG(f, GPT_FLAG_READ_ONLY, p->read_only); + else { + char buffer[ID128_UUID_STRING_MAX]; + log_warning("Configured ReadOnly=yes for partition type '%s' that doesn't support it, ignoring.", + gpt_partition_type_uuid_to_string_harder(p->type_uuid, buffer)); + } + } + + r = set_gpt_flags(q, f); + if (r < 0) + return log_error_errno(r, "Failed to set GPT partition flags: %m"); + log_info("Adding new partition %" PRIu64 " to partition table.", p->partno); r = fdisk_add_partition(context->fdisk_context, q, NULL); diff --git a/src/shared/gpt.c b/src/shared/gpt.c index 5f2de0d947e..846b2fe48ff 100644 --- a/src/shared/gpt.c +++ b/src/shared/gpt.c @@ -146,3 +146,14 @@ bool gpt_partition_type_is_usr_verity(sd_id128_t id) { sd_id128_equal(id, GPT_USR_RISCV32_VERITY) || sd_id128_equal(id, GPT_USR_RISCV64_VERITY); } + +bool gpt_partition_type_knows_read_only(sd_id128_t id) { + return gpt_partition_type_is_root(id) || + gpt_partition_type_is_usr(id) || + sd_id128_equal(id, GPT_HOME) || + sd_id128_equal(id, GPT_SRV) || + sd_id128_equal(id, GPT_VAR) || + sd_id128_equal(id, GPT_TMP) || + gpt_partition_type_is_root_verity(id) || /* pretty much implied, but let's set the bit to make things really clear */ + gpt_partition_type_is_usr_verity(id); /* ditto */ +} diff --git a/src/shared/gpt.h b/src/shared/gpt.h index 22b1d68d5f0..f3a74813f07 100644 --- a/src/shared/gpt.h +++ b/src/shared/gpt.h @@ -133,3 +133,5 @@ bool gpt_partition_type_is_root(sd_id128_t id); bool gpt_partition_type_is_root_verity(sd_id128_t id); bool gpt_partition_type_is_usr(sd_id128_t id); bool gpt_partition_type_is_usr_verity(sd_id128_t id); + +bool gpt_partition_type_knows_read_only(sd_id128_t id);