summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/repart.d.xml23
-rw-r--r--src/partition/repart.c75
-rw-r--r--src/shared/gpt.c11
-rw-r--r--src/shared/gpt.h2
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);