1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-10 01:17:44 +03:00

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.
This commit is contained in:
Lennart Poettering 2021-03-23 16:16:42 +01:00
parent 5c08da586f
commit e73309c532
4 changed files with 111 additions and 0 deletions

View File

@ -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>

View File

@ -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);

View File

@ -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 */
}

View File

@ -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);