automatically measured into PCR 15 on activation, via
<citerefentry><refentrytitle>systemd-pcrfs@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+ <para>Mount constraint metadata contained in the file systems is validated by pulling in
+ <citerefentry><refentrytitle>systemd-validatefs@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ for generated mounts.</para>
+
<para><filename>systemd-gpt-auto-generator</filename> implements
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
</refsect1>
<member><citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-cryptsetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-pcrfs@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
+ <member><citerefentry><refentrytitle>systemd-validatefs@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
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>
</orderedlist>
+
+ <para>The <filename>systemd-validatefs@.service</filename> unit is automatically pulled into the initial
+ transaction by
+ <citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ for all file systems it discovers and generates mounts
+ for. <citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ will do this for all mounts with the <option>x-systemd.validatefs</option> mount option in
+ <filename>/etc/fstab</filename>.</para>
</refsect1>
<refsect1>
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>x-systemd.validatefs</option></term>
+
+ <listitem><para>Validates mount constraint metadata of the mounted file system after mounting
+ it. This ensures the
+ <citerefentry><refentrytitle>systemd-validatefs@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ service is pulled in by the mount unit.</para>
+
+ <para>Note that this option can only be used in <filename>/etc/fstab</filename>, and will be ignored
+ when part of the <varname>Options=</varname> setting in a unit file. It is also implied for all
+ partitions discovered by
+ <citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+
+ <xi:include href="version-info.xml" xpointer="v258"/></listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>x-systemd.rw-only</option></term>
#define SPECIAL_GROWFS_ROOT_SERVICE "systemd-growfs-root.service"
#define SPECIAL_PCRFS_SERVICE "systemd-pcrfs@.service"
#define SPECIAL_PCRFS_ROOT_SERVICE "systemd-pcrfs-root.service"
+#define SPECIAL_VALIDATEFS_SERVICE "systemd-validatefs@.service"
#define SPECIAL_HIBERNATE_RESUME_SERVICE "systemd-hibernate-resume.service"
/* Services systemd relies on */
#include "volatile-util.h"
typedef enum MountPointFlags {
- MOUNT_NOAUTO = 1 << 0,
- MOUNT_NOFAIL = 1 << 1,
- MOUNT_AUTOMOUNT = 1 << 2,
- MOUNT_MAKEFS = 1 << 3,
- MOUNT_GROWFS = 1 << 4,
- MOUNT_RW_ONLY = 1 << 5,
- MOUNT_PCRFS = 1 << 6,
- MOUNT_QUOTA = 1 << 7,
+ MOUNT_NOAUTO = 1 << 0,
+ MOUNT_NOFAIL = 1 << 1,
+ MOUNT_AUTOMOUNT = 1 << 2,
+ MOUNT_MAKEFS = 1 << 3,
+ MOUNT_GROWFS = 1 << 4,
+ MOUNT_RW_ONLY = 1 << 5,
+ MOUNT_PCRFS = 1 << 6,
+ MOUNT_QUOTA = 1 << 7,
+ MOUNT_VALIDATEFS = 1 << 8,
} MountPointFlags;
typedef struct Mount {
return true;
}
- log_debug("Found swap entry what=%s makefs=%s growfs=%s pcrfs=%s noauto=%s nofail=%s",
+ log_debug("Found swap entry what=%s makefs=%s growfs=%s pcrfs=%s validatefs=%s noauto=%s nofail=%s",
what,
- yes_no(flags & MOUNT_MAKEFS), yes_no(flags & MOUNT_GROWFS), yes_no(flags & MOUNT_PCRFS),
+ yes_no(flags & MOUNT_MAKEFS), yes_no(flags & MOUNT_GROWFS),
+ yes_no(flags & MOUNT_PCRFS), yes_no(flags & MOUNT_VALIDATEFS),
yes_no(flags & MOUNT_NOAUTO), yes_no(flags & MOUNT_NOFAIL));
r = unit_name_from_path(what, ".swap", &name);
log_warning("%s: growing swap devices is currently unsupported.", what);
if (flags & MOUNT_PCRFS)
log_warning("%s: measuring swap devices is currently unsupported.", what);
+ if (flags & MOUNT_VALIDATEFS)
+ log_warning("%s: validating swap devices is currently unsupported.", what);
if (!(flags & MOUNT_NOAUTO)) {
r = generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET,
}
}
+ if (flags & MOUNT_VALIDATEFS) {
+ r = generator_hook_up_validatefs(dest, where, target_unit);
+ if (r < 0)
+ return r;
+ }
+
if (flags & MOUNT_QUOTA) {
r = generator_hook_up_quotacheck(dest, what, where, target_unit, fstype);
if (r < 0) {
flags |= MOUNT_GROWFS;
if (fstab_test_option(options, "x-systemd.pcrfs\0"))
flags |= MOUNT_PCRFS;
+ if (fstab_test_option(options, "x-systemd.validatefs\0"))
+ flags |= MOUNT_VALIDATEFS;
if (fstab_test_option(options, "usrquota\0" "grpquota\0" "quota\0" "usrjquota\0" "grpjquota\0" "prjquota\0"))
flags |= MOUNT_QUOTA;
if (fstab_test_yes_no_option(options, "noauto\0" "auto\0"))
free_and_replace(what, p);
}
- log_debug("Found entry what=%s where=%s type=%s makefs=%s growfs=%s pcrfs=%s noauto=%s nofail=%s",
+ log_debug("Found entry what=%s where=%s type=%s makefs=%s growfs=%s pcrfs=%s validatefs=%s noauto=%s nofail=%s",
what, where, strna(fstype),
- yes_no(flags & MOUNT_MAKEFS), yes_no(flags & MOUNT_GROWFS), yes_no(flags & MOUNT_PCRFS),
+ yes_no(flags & MOUNT_MAKEFS), yes_no(flags & MOUNT_GROWFS),
+ yes_no(flags & MOUNT_PCRFS), yes_no(flags & MOUNT_VALIDATEFS),
yes_no(flags & MOUNT_NOAUTO), yes_no(flags & MOUNT_NOFAIL));
bool is_sysroot = in_initrd() && path_equal(where, "/sysroot");
#include "unit-name.h"
#include "virt.h"
+typedef enum MountPointFlags {
+ MOUNT_RW = 1 << 0,
+ MOUNT_GROWFS = 1 << 1,
+ MOUNT_MEASURE = 1 << 2,
+ MOUNT_VALIDATEFS = 1 << 3,
+} MountPointFlags;
+
static const char *arg_dest = NULL;
static bool arg_enabled = true;
static GptAutoRoot arg_auto_root = _GPT_AUTO_ROOT_INVALID;
const char *id,
const char *what,
const char *mount_opts,
- bool rw,
+ MountPointFlags flags,
bool require,
- bool measure,
char **ret_device) {
#if HAVE_LIBCRYPTSETUP
"After=%s\n",
d, d);
- if (!rw) {
+ if (!FLAGS_SET(flags, MOUNT_RW)) {
options = strdup("read-only");
if (!options)
return log_oom();
if (!strextend_with_separator(&options, ",", "tpm2-device=auto"))
return log_oom();
- if (measure) {
+ if (FLAGS_SET(flags, MOUNT_MEASURE)) {
/* We only measure the root volume key into PCR 15 if we are booted with sd-stub (i.e. in a
* UKI), and sd-stub measured the UKI. We do this in order not to step into people's own PCR
* assignment, under the assumption that people who are fine to use sd-stub with its PCR
const char *what,
const char *where,
const char *fstype,
- bool rw,
- bool growfs,
- bool measure,
+ MountPointFlags flags,
const char *options,
const char *description,
const char *post) {
if (streq_ptr(fstype, "crypto_LUKS")) {
/* Mount options passed are determined by partition_pick_mount_options(), whose result
* is known to not contain timeout options. */
- r = add_cryptsetup(id, what, /* mount_opts = */ NULL, rw, /* require= */ true, measure, &crypto_what);
+ r = add_cryptsetup(id, what, /* mount_opts = */ NULL, flags, /* require= */ true, &crypto_what);
if (r < 0)
return r;
if (r < 0)
return log_error_errno(r, "Failed to write unit %s: %m", unit);
- if (growfs) {
+ if (FLAGS_SET(flags, MOUNT_VALIDATEFS)) {
+ r = generator_hook_up_validatefs(arg_dest, where, post);
+ if (r < 0)
+ return r;
+ }
+
+ if (FLAGS_SET(flags, MOUNT_GROWFS)) {
r = generator_hook_up_growfs(arg_dest, where, post);
if (r < 0)
return r;
}
- if (measure) {
+ if (FLAGS_SET(flags, MOUNT_MEASURE)) {
r = generator_hook_up_pcrfs(arg_dest, where, post);
if (r < 0)
return r;
p->node,
where,
p->fstype,
- p->rw,
- p->growfs,
- /* measure= */ STR_IN_SET(id, "root", "var"), /* by default measure rootfs and /var, since they contain the "identity" of the system */
+ (p->rw ? MOUNT_RW : 0) |
+ MOUNT_VALIDATEFS |
+ (p->growfs ? MOUNT_GROWFS : 0) |
+ (STR_IN_SET(id, "root", "var") ? MOUNT_MEASURE : 0), /* by default measure rootfs and /var, since they contain the "identity" of the system */
options,
description,
SPECIAL_LOCAL_FS_TARGET);
}
if (streq_ptr(p->fstype, "crypto_LUKS")) {
- r = add_cryptsetup("swap", p->node, /* mount_opts = */ NULL, /* rw= */ true, /* require= */ true, /* measure= */ false, &crypto_what);
+ r = add_cryptsetup("swap", p->node, /* mount_opts = */ NULL, MOUNT_RW, /* require= */ true, &crypto_what);
if (r < 0)
return r;
what = crypto_what;
const char *what,
const char *where,
const char *fstype,
- bool rw,
- bool growfs,
+ MountPointFlags flags,
const char *options,
const char *description,
usec_t timeout) {
what,
where,
fstype,
- rw,
- growfs,
- /* measure= */ false,
+ flags,
options,
description,
- NULL);
+ /* post= */ NULL);
if (r < 0)
return r;
p->node,
"/boot",
p->fstype,
- /* rw= */ true,
- /* growfs= */ false,
+ MOUNT_RW,
options,
"Boot Loader Partition",
LOADER_PARTITION_IDLE_USEC);
p->node,
esp_path,
p->fstype,
- /* rw= */ true,
- /* growfs= */ false,
+ MOUNT_RW,
options,
"EFI System Partition Automount",
LOADER_PARTITION_IDLE_USEC);
bdev = "/dev/gpt-auto-root-luks-ignore-factory-reset";
}
- return add_cryptsetup("root", bdev, arg_root_options, /* rw= */ true, /* require= */ false, /* measure= */ true, NULL);
+ return add_cryptsetup("root", bdev, arg_root_options, MOUNT_RW|MOUNT_MEASURE, /* require= */ false, NULL);
#else
return 0;
#endif
bdev,
in_initrd() ? "/sysroot" : "/",
arg_root_fstype,
- /* rw= */ arg_root_rw > 0,
- /* growfs= */ false,
- /* measure= */ true,
+ (arg_root_rw > 0 ? MOUNT_RW : 0) |
+ (in_initrd() ? MOUNT_VALIDATEFS : 0) |
+ MOUNT_MEASURE,
options,
"Root Partition",
in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
return generator_add_symlink_full(dir, where_unit, "wants", pcrfs_unit_path, instance);
}
+int generator_hook_up_validatefs(
+ const char *dir,
+ const char *where,
+ const char *target) {
+
+ _cleanup_free_ char *where_unit = NULL, *instance = NULL;
+ const char *validatefs_unit, *validatefs_unit_path;
+ int r;
+
+ assert(dir);
+ assert(where);
+
+ /* never hook this in for the actual root fs, because it's too late then, we already are running from
+ * the root fs, it makes no sense to validate it anymore */
+ if (empty_or_root(where))
+ return 0;
+
+ r = unit_name_from_path(where, ".mount", &where_unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit name from path '%s': %m", where);
+
+ validatefs_unit = SPECIAL_VALIDATEFS_SERVICE;
+ validatefs_unit_path = SYSTEM_DATA_UNIT_DIR "/" SPECIAL_VALIDATEFS_SERVICE;
+
+ r = unit_name_path_escape(where, &instance);
+ if (r < 0)
+ return log_error_errno(r, "Failed to escape path '%s': %m", where);
+
+ if (target) {
+ r = generator_add_ordering(dir, target, "After", validatefs_unit, instance);
+ if (r < 0)
+ return r;
+ }
+
+ return generator_add_symlink_full(dir, where_unit, "wants", validatefs_unit_path, instance);
+}
+
int generator_hook_up_quotacheck(
const char *dir,
const char *what,
const char *dir,
const char *where,
const char *target);
+int generator_hook_up_validatefs(
+ const char *dir,
+ const char *where,
+ const char *target);
int generator_hook_up_quotacheck(
const char *dir,
const char *what,