mirror of
https://github.com/morgan9e/systemd
synced 2026-04-15 00:47:10 +09:00
validatefs: fix checks on file systems backed by multiple devices (i.e. verity) (#37434)
Fixes #37157
This commit is contained in:
@@ -962,12 +962,12 @@
|
||||
<varlistentry>
|
||||
<term><varname>AddValidateFS=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument. If enabled will set the <varname>user.validatefs.gpt_label</varname>,
|
||||
<varname>user.validatefs.gpt_type_uuid</varname> and <varname>user.validatefs.mount_point</varname>
|
||||
extended attributes on the root inode of the formatted file system to the partition label, partition
|
||||
type UUID and the intended mount point for the partition. Defaults to on if
|
||||
<varname>Format=</varname> is used and the specified argument is neither <literal>swap</literal> nor
|
||||
<literal>vfat</literal>.</para>
|
||||
<listitem><para>Takes a boolean argument. If enabled will set the
|
||||
<varname>user.validatefs.gpt_label</varname>, <varname>user.validatefs.gpt_type_uuid</varname> and
|
||||
<varname>user.validatefs.mount_point</varname> extended attributes on the root inode of the formatted
|
||||
file system to the partition labels, partition type UUIDs and the intended mount point for the file
|
||||
system. Defaults to on if <varname>Format=</varname> is used and the specified argument is neither
|
||||
<literal>swap</literal> nor <literal>vfat</literal>.</para>
|
||||
|
||||
<para>These extended attributes are read by
|
||||
<citerefentry><refentrytitle>systemd-validatefs@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
|
||||
@@ -50,13 +50,16 @@
|
||||
mounted to a location not matching any of the listed paths the validation check will
|
||||
fail.</para></listitem>
|
||||
|
||||
<listitem><para><varname>user.validatefs.gpt_label</varname>: this extended attribute may contain a
|
||||
free-form string. It is compared with the partition label string of the partition this file system is
|
||||
located on, and if different the validation will fail.</para></listitem>
|
||||
<listitem><para><varname>user.validatefs.gpt_label</varname>: this extended attribute may contain a one
|
||||
or more free-form strings, separated by NUL bytes. If set, all backing partitions of the file system
|
||||
are checked against this list, and if any backing partition's label is not listed, the validation will
|
||||
fail. Note that there may be multiple backing partition in case of Verity setups, which combines a data
|
||||
and a hash partition.</para></listitem>
|
||||
|
||||
<listitem><para><varname>user.validatefs.gpt_type_uuid</varname>: this extended attribute may contain a
|
||||
GPT partition type UUID formatted as string. It is compared with the partition type UUID of the
|
||||
partition this file system is located on, and if different the validation will fail.</para></listitem>
|
||||
<listitem><para><varname>user.validatefs.gpt_type_uuid</varname>: this extended attribute may contain
|
||||
one or more GPT partition type UUIDs, formatted as string, separated by NUL bytes. As above, all
|
||||
backing partitions of the file system are checked against this list, and if none is matching the
|
||||
validation will fail.</para></listitem>
|
||||
</orderedlist>
|
||||
|
||||
<para>The <filename>systemd-validatefs@.service</filename> unit is automatically pulled into the initial
|
||||
|
||||
@@ -5894,6 +5894,63 @@ static int set_default_subvolume(Partition *p, const char *root) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int partition_acquire_sibling_labels(const Partition *p, char ***ret) {
|
||||
assert(p);
|
||||
assert(ret);
|
||||
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
if (p->new_label) {
|
||||
l = strv_new(p->new_label);
|
||||
if (!l)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
FOREACH_ELEMENT(sibling, p->siblings) {
|
||||
Partition *s = *sibling;
|
||||
|
||||
if (!s || s == p || !s->new_label || strv_contains(l, s->new_label))
|
||||
continue;
|
||||
|
||||
if (strv_extend(&l, s->new_label) < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
strv_sort(l); /* bring into a systematic order to make things reproducible */
|
||||
|
||||
*ret = TAKE_PTR(l);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int partition_acquire_sibling_uuids(const Partition *p, char ***ret) {
|
||||
assert(p);
|
||||
assert(ret);
|
||||
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
l = strv_new(SD_ID128_TO_UUID_STRING(p->type.uuid));
|
||||
if (!l)
|
||||
return log_oom();
|
||||
|
||||
FOREACH_ELEMENT(sibling, p->siblings) {
|
||||
Partition *s = *sibling;
|
||||
|
||||
if (!s || s == p)
|
||||
continue;
|
||||
|
||||
const char *u = SD_ID128_TO_UUID_STRING(s->type.uuid);
|
||||
if (strv_contains(l, u))
|
||||
continue;
|
||||
|
||||
if (strv_extend(&l, u) < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
strv_sort(l); /* bring into a systematic order to make things reproducible */
|
||||
|
||||
*ret = TAKE_PTR(l);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int do_make_validatefs_xattrs(const Partition *p, const char *root) {
|
||||
int r;
|
||||
|
||||
@@ -5907,18 +5964,26 @@ static int do_make_validatefs_xattrs(const Partition *p, const char *root) {
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "Failed to open root inode '%s': %m", root);
|
||||
|
||||
if (p->new_label) {
|
||||
r = xsetxattr(fd, /* path= */ NULL, AT_EMPTY_PATH, "user.validatefs.gpt_label", p->new_label);
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
r = partition_acquire_sibling_labels(p, &l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!strv_isempty(l)) {
|
||||
r = xsetxattr_strv(fd, /* path= */ NULL, AT_EMPTY_PATH, "user.validatefs.gpt_label", l);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set 'user.validatefs.gpt_label' extended attribute: %m");
|
||||
}
|
||||
l = strv_free(l);
|
||||
|
||||
r = xsetxattr(fd, /* path= */ NULL, AT_EMPTY_PATH, "user.validatefs.gpt_type_uuid", SD_ID128_TO_UUID_STRING(p->type.uuid));
|
||||
r = partition_acquire_sibling_uuids(p, &l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = xsetxattr_strv(fd, /* path= */ NULL, AT_EMPTY_PATH, "user.validatefs.gpt_type_uuid", l);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set 'user.validatefs.gpt_type_uuid' extended attribute: %m");
|
||||
l = strv_free(l);
|
||||
|
||||
/* Prefer the data from MountPoint= if specified, otherwise use data we derive from the partition type */
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
if (p->n_mountpoints > 0) {
|
||||
FOREACH_ARRAY(m, p->mountpoints, p->n_mountpoints)
|
||||
if (strv_extend(&l, m->where) < 0)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "device-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "gpt.h"
|
||||
#include "initrd-util.h"
|
||||
#include "main-func.h"
|
||||
#include "mountpoint-util.h"
|
||||
@@ -119,18 +120,38 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
typedef struct ValidateFields {
|
||||
sd_id128_t gpt_type_uuid;
|
||||
char *gpt_label;
|
||||
sd_id128_t *gpt_type_uuid;
|
||||
size_t n_gpt_type_uuid;
|
||||
char **gpt_label;
|
||||
char **mount_point;
|
||||
} ValidateFields;
|
||||
|
||||
static void validate_fields_done(ValidateFields *f) {
|
||||
assert(f);
|
||||
|
||||
free(f->gpt_label);
|
||||
free(f->gpt_type_uuid);
|
||||
strv_free(f->gpt_label);
|
||||
strv_free(f->mount_point);
|
||||
}
|
||||
|
||||
static char* validate_fields_gpt_type_uuid_as_string(const ValidateFields *f) {
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
|
||||
assert(f);
|
||||
|
||||
FOREACH_ARRAY(u, f->gpt_type_uuid, f->n_gpt_type_uuid) {
|
||||
if (!strextend_with_separator(&joined, ", ", SD_ID128_TO_UUID_STRING(*u)))
|
||||
return NULL;
|
||||
|
||||
const char *id = gpt_partition_type_uuid_to_string(*u);
|
||||
if (id)
|
||||
(void) strextend(&joined, " (", id, ")");
|
||||
|
||||
}
|
||||
|
||||
return TAKE_PTR(joined);
|
||||
}
|
||||
|
||||
static int validate_fields_read(int fd, ValidateFields *ret) {
|
||||
_cleanup_(validate_fields_done) ValidateFields f = {};
|
||||
int r;
|
||||
@@ -138,27 +159,41 @@ static int validate_fields_read(int fd, ValidateFields *ret) {
|
||||
assert(fd >= 0);
|
||||
assert(ret);
|
||||
|
||||
_cleanup_free_ char *t = NULL;
|
||||
r = fgetxattr_malloc(fd, "user.validatefs.gpt_type_uuid", &t, /* ret_size= */ NULL);
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
r = getxattr_at_strv(fd, /* path= */ NULL, "user.validatefs.gpt_type_uuid", AT_EMPTY_PATH, &l);
|
||||
if (r < 0) {
|
||||
if (r != -ENODATA && !ERRNO_IS_NOT_SUPPORTED(r))
|
||||
return log_error_errno(r, "Failed to read 'user.validatefs.gpt_type_uuid' xattr: %m");
|
||||
} else {
|
||||
r = sd_id128_from_string(t, &f.gpt_type_uuid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse 'user.validatefs.gpt_type_uuid' xattr: %s", t);
|
||||
STRV_FOREACH(i, l) {
|
||||
if (!GREEDY_REALLOC(f.gpt_type_uuid, f.n_gpt_type_uuid+1))
|
||||
return log_oom();
|
||||
|
||||
r = sd_id128_from_string(*i, f.gpt_type_uuid + f.n_gpt_type_uuid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse 'user.validatefs.gpt_type_uuid' xattr: %s", *i);
|
||||
|
||||
f.n_gpt_type_uuid++;
|
||||
}
|
||||
}
|
||||
|
||||
r = fgetxattr_malloc(fd, "user.validatefs.gpt_label", &f.gpt_label, /* ret_size= */ NULL);
|
||||
l = strv_free(l);
|
||||
r = getxattr_at_strv(fd, /* path= */ NULL, "user.validatefs.gpt_label", AT_EMPTY_PATH, &l);
|
||||
if (r < 0) {
|
||||
if (r != -ENODATA && !ERRNO_IS_NOT_SUPPORTED(r))
|
||||
return log_error_errno(r, "Failed to read 'user.validatefs.gpt_label' xattr: %m");
|
||||
} else if (!utf8_is_valid(f.gpt_label) || string_has_cc(f.gpt_label, /* ok= */ NULL))
|
||||
return log_error_errno(
|
||||
SYNTHETIC_ERRNO(EINVAL),
|
||||
"Extended attribute 'user.validatefs.gpt_label' contains invalid characters, refusing.");
|
||||
} else {
|
||||
STRV_FOREACH(i, l)
|
||||
if (!utf8_is_valid(*i) ||
|
||||
string_has_cc(*i, /* ok= */ NULL))
|
||||
return log_error_errno(
|
||||
SYNTHETIC_ERRNO(EINVAL),
|
||||
"Extended attribute 'user.validatefs.gpt_label' contains invalid characters, refusing: %s", *i);
|
||||
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
f.gpt_label = TAKE_PTR(l);
|
||||
}
|
||||
|
||||
l = strv_free(l);
|
||||
r = getxattr_at_strv(fd, /* path= */ NULL, "user.validatefs.mount_point", AT_EMPTY_PATH, &l);
|
||||
if (r < 0) {
|
||||
if (r != -ENODATA && !ERRNO_IS_NOT_SUPPORTED(r))
|
||||
@@ -176,11 +211,170 @@ static int validate_fields_read(int fd, ValidateFields *ret) {
|
||||
f.mount_point = TAKE_PTR(l);
|
||||
}
|
||||
|
||||
r = !sd_id128_is_null(f.gpt_type_uuid) || f.gpt_label || !strv_isempty(f.mount_point);
|
||||
r = f.n_gpt_type_uuid > 0 || !strv_isempty(f.gpt_label) || !strv_isempty(f.mount_point);
|
||||
*ret = TAKE_STRUCT(f);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int validate_mount_point(const char *path, const ValidateFields *f) {
|
||||
assert(path);
|
||||
assert(f);
|
||||
|
||||
if (strv_isempty(f->mount_point))
|
||||
return 0;
|
||||
|
||||
STRV_FOREACH(i, f->mount_point) {
|
||||
_cleanup_free_ char *jj = NULL;
|
||||
const char *j;
|
||||
|
||||
if (arg_root) {
|
||||
jj = path_join(arg_root, *i);
|
||||
if (!jj)
|
||||
return log_oom();
|
||||
|
||||
j = jj;
|
||||
} else
|
||||
j = *i;
|
||||
|
||||
if (path_equal(path, j))
|
||||
return 0;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *joined = strv_join(f->mount_point, ", ");
|
||||
|
||||
return log_error_errno(
|
||||
SYNTHETIC_ERRNO(EPERM),
|
||||
"File system is supposed to be mounted on one of %s only, but is mounted on %s, refusing.",
|
||||
strna(joined), path);
|
||||
}
|
||||
|
||||
static int validate_gpt_metadata_one(sd_device *d, const char *path, const ValidateFields *f) {
|
||||
int r;
|
||||
|
||||
assert(d);
|
||||
assert(f);
|
||||
|
||||
_cleanup_close_ int block_fd = sd_device_open(d, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
|
||||
if (block_fd < 0)
|
||||
return log_error_errno(block_fd, "Failed to open block device backing '%s': %m", path);
|
||||
|
||||
_cleanup_(blkid_free_probep) blkid_probe b = blkid_new_probe();
|
||||
if (!b)
|
||||
return log_oom();
|
||||
|
||||
errno = 0;
|
||||
r = blkid_probe_set_device(b, block_fd, 0, 0);
|
||||
if (r != 0)
|
||||
return log_error_errno(errno_or_else(ENOMEM), "Failed to set up block device prober for '%s': %m", path);
|
||||
|
||||
(void) blkid_probe_enable_superblocks(b, 1);
|
||||
(void) blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_LABEL);
|
||||
(void) blkid_probe_enable_partitions(b, 1);
|
||||
(void) blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_do_safeprobe(b);
|
||||
if (r == _BLKID_SAFEPROBE_ERROR)
|
||||
return log_error_errno(errno_or_else(EIO), "Failed to probe block device of '%s': %m", path);
|
||||
if (r == _BLKID_SAFEPROBE_AMBIGUOUS)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "Found multiple file system labels on block device '%s'.", path);
|
||||
if (r == _BLKID_SAFEPROBE_NOT_FOUND)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "Found no file system label on block device '%s'.", path);
|
||||
|
||||
assert(r == _BLKID_SAFEPROBE_FOUND);
|
||||
|
||||
const char *v = NULL;
|
||||
(void) blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, /* ret_len= */ NULL);
|
||||
if (!streq_ptr(v, "gpt"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "File system is supposed to be on a GPT partition table, but is not, refusing.");
|
||||
|
||||
if (!strv_isempty(f->gpt_label)) {
|
||||
v = NULL;
|
||||
(void) blkid_probe_lookup_value(b, "PART_ENTRY_NAME", &v, /* ret_len= */ NULL);
|
||||
|
||||
if (!strv_contains(f->gpt_label, strempty(v))) {
|
||||
_cleanup_free_ char *joined = strv_join(f->gpt_label, "', '");
|
||||
|
||||
return log_error_errno(
|
||||
SYNTHETIC_ERRNO(EPERM),
|
||||
"File system is supposed to be placed in a partition with labels '%s' only, but is placed in one labelled '%s', refusing.",
|
||||
strna(joined), strempty(v));
|
||||
}
|
||||
}
|
||||
|
||||
if (f->n_gpt_type_uuid > 0) {
|
||||
v = NULL;
|
||||
(void) blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, /* ret_len= */ NULL);
|
||||
|
||||
sd_id128_t id;
|
||||
if (!v || sd_id128_from_string(v, &id) < 0) {
|
||||
_cleanup_free_ char *joined = validate_fields_gpt_type_uuid_as_string(f);
|
||||
|
||||
return log_error_errno(
|
||||
SYNTHETIC_ERRNO(EPERM),
|
||||
"File system is supposed to be placed in a partition of type UUIDs %s only, but has no type, refusing.",
|
||||
strna(joined));
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
FOREACH_ARRAY(u, f->gpt_type_uuid, f->n_gpt_type_uuid)
|
||||
if (sd_id128_equal(*u, id)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
_cleanup_free_ char *joined = validate_fields_gpt_type_uuid_as_string(f);
|
||||
|
||||
return log_error_errno(
|
||||
SYNTHETIC_ERRNO(EPERM),
|
||||
"File system is supposed to be placed in a partition of type UUIDs %s only, but has type '%s', refusing.",
|
||||
strna(joined), SD_ID128_TO_UUID_STRING(id));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int validate_gpt_metadata(int fd, const char *path, const ValidateFields *f) {
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(path);
|
||||
assert(f);
|
||||
|
||||
if (strv_isempty(f->gpt_label) && f->n_gpt_type_uuid == 0)
|
||||
return 0;
|
||||
|
||||
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
|
||||
r = block_device_new_from_fd(fd, BLOCK_DEVICE_LOOKUP_BACKING, &d);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to find block device backing '%s': %m", path);
|
||||
|
||||
/* Now validate all subordinate devices individually. */
|
||||
bool have_slaves = false;
|
||||
const char *suffix;
|
||||
FOREACH_DEVICE_CHILD_WITH_SUFFIX(d, child, suffix) {
|
||||
if (!path_startswith(suffix, "slaves"))
|
||||
continue;
|
||||
|
||||
have_slaves = true;
|
||||
|
||||
r = validate_gpt_metadata_one(child, path, f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* If this device has no subordinate devices, then validate the device itself instead */
|
||||
if (!have_slaves) {
|
||||
r = validate_gpt_metadata_one(d, path, f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int validate_fields_check(int fd, const char *path, const ValidateFields *f) {
|
||||
int r;
|
||||
|
||||
@@ -188,108 +382,13 @@ static int validate_fields_check(int fd, const char *path, const ValidateFields
|
||||
assert(path);
|
||||
assert(f);
|
||||
|
||||
if (!strv_isempty(f->mount_point)) {
|
||||
bool good = false;
|
||||
r = validate_mount_point(path, f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
STRV_FOREACH(i, f->mount_point) {
|
||||
_cleanup_free_ char *jj = NULL;
|
||||
const char *j;
|
||||
|
||||
if (arg_root) {
|
||||
jj = path_join(arg_root, *i);
|
||||
if (!jj)
|
||||
return log_oom();
|
||||
|
||||
j = jj;
|
||||
} else
|
||||
j = *i;
|
||||
|
||||
if (path_equal(path, j)) {
|
||||
good = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!good) {
|
||||
_cleanup_free_ char *joined = strv_join(f->mount_point, ", ");
|
||||
|
||||
return log_error_errno(
|
||||
SYNTHETIC_ERRNO(EPERM),
|
||||
"File system is supposed to be mounted on one of %s only, but is mounted on %s, refusing.",
|
||||
strna(joined), path);
|
||||
}
|
||||
}
|
||||
|
||||
if (f->gpt_label || !sd_id128_is_null(f->gpt_type_uuid)) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
|
||||
|
||||
r = block_device_new_from_fd(fd, BLOCK_DEVICE_LOOKUP_ORIGINATING|BLOCK_DEVICE_LOOKUP_BACKING, &d);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to find block device backing '%s': %m", path);
|
||||
|
||||
_cleanup_close_ int block_fd = sd_device_open(d, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
|
||||
if (block_fd < 0)
|
||||
return log_error_errno(block_fd, "Failed to open block device backing '%s': %m", path);
|
||||
|
||||
_cleanup_(blkid_free_probep) blkid_probe b = blkid_new_probe();
|
||||
if (!b)
|
||||
return log_oom();
|
||||
|
||||
errno = 0;
|
||||
r = blkid_probe_set_device(b, block_fd, 0, 0);
|
||||
if (r != 0)
|
||||
return log_error_errno(errno_or_else(ENOMEM), "Failed to set up block device prober for '%s': %m", path);
|
||||
|
||||
(void) blkid_probe_enable_superblocks(b, 1);
|
||||
(void) blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_LABEL);
|
||||
(void) blkid_probe_enable_partitions(b, 1);
|
||||
(void) blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_do_safeprobe(b);
|
||||
if (r == _BLKID_SAFEPROBE_ERROR)
|
||||
return log_error_errno(errno_or_else(EIO), "Failed to probe block device of '%s': %m", path);
|
||||
if (r == _BLKID_SAFEPROBE_AMBIGUOUS)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "Found multiple file system labels on block device '%s'.", path);
|
||||
if (r == _BLKID_SAFEPROBE_NOT_FOUND)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "Found no file system label on block device '%s'.", path);
|
||||
|
||||
assert(r == _BLKID_SAFEPROBE_FOUND);
|
||||
|
||||
const char *v = NULL;
|
||||
(void) blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, /* ret_len= */ NULL);
|
||||
if (!streq_ptr(v, "gpt"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "File system is supposed to be on a GPT partition table, but is not, refusing.");
|
||||
|
||||
if (f->gpt_label) {
|
||||
v = NULL;
|
||||
(void) blkid_probe_lookup_value(b, "PART_ENTRY_NAME", &v, /* ret_len= */ NULL);
|
||||
|
||||
if (!streq(f->gpt_label, strempty(v)))
|
||||
return log_error_errno(
|
||||
SYNTHETIC_ERRNO(EPERM),
|
||||
"File system is supposed to be placed in a partition with label '%s' only, but is placed in one labelled '%s', refusing.",
|
||||
f->gpt_label, strempty(v));
|
||||
}
|
||||
|
||||
if (!sd_id128_is_null(f->gpt_type_uuid)) {
|
||||
v = NULL;
|
||||
(void) blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, /* ret_len= */ NULL);
|
||||
|
||||
sd_id128_t id = SD_ID128_NULL;
|
||||
if (!v || sd_id128_from_string(v, &id) < 0)
|
||||
return log_error_errno(
|
||||
SYNTHETIC_ERRNO(EPERM),
|
||||
"File system is supposed to be placed in a partition of type UUID '%s' only, but has no type, refusing.",
|
||||
SD_ID128_TO_UUID_STRING(f->gpt_type_uuid));
|
||||
|
||||
if (!sd_id128_equal(f->gpt_type_uuid, id))
|
||||
return log_error_errno(
|
||||
SYNTHETIC_ERRNO(EPERM),
|
||||
"File system is supposed to be placed in a partition of type UUID '%s' only, but has type '%s', refusing.",
|
||||
SD_ID128_TO_UUID_STRING(f->gpt_type_uuid), SD_ID128_TO_UUID_STRING(id));
|
||||
}
|
||||
}
|
||||
r = validate_gpt_metadata(fd, path, f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_info("File system '%s' passed validation constraints, proceeding.", path);
|
||||
return 0;
|
||||
|
||||
@@ -40,6 +40,16 @@ cat > /tmp/validatefs-test/validatefs-usr.conf <<EOF
|
||||
Type=usr
|
||||
Label=plisch
|
||||
Format=ext4
|
||||
Verity=data
|
||||
VerityMatchKey=mupf
|
||||
EOF
|
||||
|
||||
cat > /tmp/validatefs-test/validatefs-usr-verity.conf <<EOF
|
||||
[Partition]
|
||||
Type=usr-verity
|
||||
Label=plisch-verity
|
||||
Verity=hash
|
||||
VerityMatchKey=mupf
|
||||
EOF
|
||||
|
||||
cat > /tmp/validatefs-test/validatefs-home.conf <<EOF
|
||||
@@ -76,8 +86,8 @@ getfattr --dump /tmp/validatefs-test.mount/ | grep -q user.validatefs.mount_poin
|
||||
(! /usr/lib/systemd/systemd-validatefs /tmp/validatefs-test.mount/ )
|
||||
|
||||
getfattr --dump /tmp/validatefs-test.mount/usr
|
||||
getfattr --dump /tmp/validatefs-test.mount/usr | grep -q user.validatefs.gpt_type_uuid=
|
||||
getfattr --dump /tmp/validatefs-test.mount/usr | grep -q user.validatefs.gpt_label=\"plisch\"
|
||||
getfattr --dump /tmp/validatefs-test.mount/usr | grep -q user.validatefs.gpt_type_uuid='".*\\000.*"'
|
||||
getfattr --dump /tmp/validatefs-test.mount/usr | grep -q user.validatefs.gpt_label='"plisch\\000plisch-verity"'
|
||||
getfattr --dump /tmp/validatefs-test.mount/usr | grep -q user.validatefs.mount_point=\"/usr\"
|
||||
/usr/lib/systemd/systemd-validatefs --root=/tmp/validatefs-test.mount /tmp/validatefs-test.mount/usr
|
||||
(! /usr/lib/systemd/systemd-validatefs /tmp/validatefs-test.mount/usr )
|
||||
|
||||
Reference in New Issue
Block a user