diff options
-rw-r--r-- | man/repart.d.xml | 23 | ||||
-rw-r--r-- | src/partition/repart.c | 75 | ||||
-rw-r--r-- | src/shared/gpt.c | 11 | ||||
-rw-r--r-- | src/shared/gpt.h | 2 |
4 files changed, 111 insertions, 0 deletions
diff --git a/man/repart.d.xml b/man/repart.d.xml index d404645588..5223f50364 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.</para></listitem> </varlistentry> + + <varlistentry> + <term><varname>Flags=</varname></term> + + <listitem><para>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 <varname>Type=</varname> 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 <varname>ReadOnly=</varname>, see below. Specify the flags value in + hexadecimal (by prefixing it with <literal>0x</literal>), binary (prefix <literal>0b</literal>) or + decimal (no prefix).</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>ReadOnly=</varname></term> + + <listitem><para>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 <varname>Flags=</varname> too, see above.</para> + + <para>If both <varname>Flags=</varname> and <varname>ReadOnly=</varname> are set the latter controls + the value of the flag.</para></listitem> + </varlistentry> </variablelist> </refsect1> diff --git a/src/partition/repart.c b/src/partition/repart.c index 12ad0dd49e..af319d2e33 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 5f2de0d947..846b2fe48f 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 22b1d68d5f..f3a74813f0 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); |