dissect-image: turn verity device sharing into opt-in

Sharing verity volumes is problematic for a veriety of reasons, for
example because it might pin the wrong backing device at the wrong time.

Let's hence turn this around: unless verity sharing is enabled, leave it
off, and turn $SYSTEMD_VERITY_SHARING into a true boolean that can be
set both ways.

The primary usecase for verity sharing is RootImage=, where it probably
makes sense to leave on, hence set the flag there.

This is crucial when putting together installers which install an OS on
a second disk: if verity sharing is always on we might mount the wrong
of the two disks at the wrong time.
This commit is contained in:
Lennart Poettering
2025-09-19 17:57:37 +02:00
parent 675fa49f69
commit 57d1ceffb3
4 changed files with 17 additions and 9 deletions

View File

@@ -123,8 +123,12 @@ All tools:
* `$SYSTEMD_NETLINK_DEFAULT_TIMEOUT` — specifies the default timeout of waiting * `$SYSTEMD_NETLINK_DEFAULT_TIMEOUT` — specifies the default timeout of waiting
replies for netlink messages from the kernel. Defaults to 25 seconds. replies for netlink messages from the kernel. Defaults to 25 seconds.
* `$SYSTEMD_VERITY_SHARING=0`if set, sharing dm-verity devices by * `$SYSTEMD_VERITY_SHARING=`takes a boolean. If set, overrides whether
using a stable `<ROOTHASH>-verity` device mapper name will be disabled. dm-verity devices shall be shared between multiple components by using a
stable `<ROOTHASH>-verity` device mapper name. The default for this depends
on the subsystem in question. Usually,
RootImage=/ExtensionImages=/MountImages= in unit files default to enabled,
while other uses default to disabled for this.
`systemctl`: `systemctl`:

View File

@@ -2523,7 +2523,8 @@ int setup_namespace(const NamespaceParameters *p, char **reterr_path) {
DISSECT_IMAGE_GROWFS | DISSECT_IMAGE_GROWFS |
DISSECT_IMAGE_ADD_PARTITION_DEVICES | DISSECT_IMAGE_ADD_PARTITION_DEVICES |
DISSECT_IMAGE_PIN_PARTITION_DEVICES | DISSECT_IMAGE_PIN_PARTITION_DEVICES |
DISSECT_IMAGE_ALLOW_USERSPACE_VERITY; DISSECT_IMAGE_ALLOW_USERSPACE_VERITY |
DISSECT_IMAGE_VERITY_SHARE;
int r; int r;
assert(p); assert(p);

View File

@@ -3064,8 +3064,8 @@ int dissected_image_decrypt(
#if HAVE_LIBCRYPTSETUP #if HAVE_LIBCRYPTSETUP
_cleanup_(decrypted_image_unrefp) DecryptedImage *d = NULL; _cleanup_(decrypted_image_unrefp) DecryptedImage *d = NULL;
int r;
#endif #endif
int r;
assert(m); assert(m);
assert(!verity || verity->root_hash || verity->root_hash_size == 0); assert(!verity || verity->root_hash || verity->root_hash_size == 0);
@@ -3085,6 +3085,10 @@ int dissected_image_decrypt(
if (!m->encrypted && !m->verity_ready) if (!m->encrypted && !m->verity_ready)
return 0; return 0;
r = secure_getenv_bool("SYSTEMD_VERITY_SHARING");
if (r >= 0)
SET_FLAG(flags, DISSECT_IMAGE_VERITY_SHARE, r);
#if HAVE_LIBCRYPTSETUP #if HAVE_LIBCRYPTSETUP
r = decrypted_image_new(&d); r = decrypted_image_new(&d);
if (r < 0) if (r < 0)
@@ -3103,8 +3107,6 @@ int dissected_image_decrypt(
k = partition_verity_hash_of(i); k = partition_verity_hash_of(i);
if (k >= 0) { if (k >= 0) {
flags |= getenv_bool("SYSTEMD_VERITY_SHARING") != 0 ? DISSECT_IMAGE_VERITY_SHARE : 0;
r = verity_partition(i, p, m->partitions + k, verity, flags, d); r = verity_partition(i, p, m->partitions + k, verity, flags, d);
if (r < 0) if (r < 0)
return r; return r;
@@ -4379,7 +4381,8 @@ int verity_dissect_and_mount(
(relax_extension_release_check ? DISSECT_IMAGE_RELAX_EXTENSION_CHECK : 0) | (relax_extension_release_check ? DISSECT_IMAGE_RELAX_EXTENSION_CHECK : 0) |
DISSECT_IMAGE_ADD_PARTITION_DEVICES | DISSECT_IMAGE_ADD_PARTITION_DEVICES |
DISSECT_IMAGE_PIN_PARTITION_DEVICES | DISSECT_IMAGE_PIN_PARTITION_DEVICES |
DISSECT_IMAGE_ALLOW_USERSPACE_VERITY; DISSECT_IMAGE_ALLOW_USERSPACE_VERITY |
DISSECT_IMAGE_VERITY_SHARE;
/* Note that we don't use loop_device_make here, as the FD is most likely O_PATH which would not be /* Note that we don't use loop_device_make here, as the FD is most likely O_PATH which would not be
* accepted by LOOP_CONFIGURE, so just let loop_device_make_by_path reopen it as a regular FD. */ * accepted by LOOP_CONFIGURE, so just let loop_device_make_by_path reopen it as a regular FD. */

View File

@@ -69,12 +69,12 @@ mv "$MINIMAL_IMAGE.fooverity" "$MINIMAL_IMAGE.verity"
mv "$MINIMAL_IMAGE.foohash" "$MINIMAL_IMAGE.roothash" mv "$MINIMAL_IMAGE.foohash" "$MINIMAL_IMAGE.roothash"
mkdir -p "$IMAGE_DIR/mount" "$IMAGE_DIR/mount2" mkdir -p "$IMAGE_DIR/mount" "$IMAGE_DIR/mount2"
systemd-dissect --mount "$MINIMAL_IMAGE.raw" "$IMAGE_DIR/mount" SYSTEMD_VERITY_SHARING=1 systemd-dissect --mount "$MINIMAL_IMAGE.raw" "$IMAGE_DIR/mount"
grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/usr/lib/os-release" grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/usr/lib/os-release"
grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/etc/os-release" grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/etc/os-release"
grep -q -F "MARKER=1" "$IMAGE_DIR/mount/usr/lib/os-release" grep -q -F "MARKER=1" "$IMAGE_DIR/mount/usr/lib/os-release"
# Verity volume should be shared (opened only once) # Verity volume should be shared (opened only once)
systemd-dissect --mount "$MINIMAL_IMAGE.raw" "$IMAGE_DIR/mount2" SYSTEMD_VERITY_SHARING=1 systemd-dissect --mount "$MINIMAL_IMAGE.raw" "$IMAGE_DIR/mount2"
verity_count=$(find /dev/mapper/ -name "*verity*" | wc -l) verity_count=$(find /dev/mapper/ -name "*verity*" | wc -l)
# In theory we should check that count is exactly one. In practice, libdevmapper # In theory we should check that count is exactly one. In practice, libdevmapper
# randomly and unpredictably fails with an unhelpful EINVAL when a device is open # randomly and unpredictably fails with an unhelpful EINVAL when a device is open