2020-05-29 19:51:20 +03:00
#!/usr/bin/env bash
2021-10-17 19:13:06 +03:00
# SPDX-License-Identifier: LGPL-2.1-or-later
2020-05-29 19:51:20 +03:00
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh
2021-04-09 20:39:41 +03:00
set -eux
2020-05-29 19:51:20 +03:00
set -o pipefail
2020-07-20 18:43:18 +03:00
export SYSTEMD_LOG_LEVEL = debug
2023-05-16 21:55:45 +03:00
# shellcheck disable=SC2317
2022-09-17 15:27:31 +03:00
cleanup( ) { (
set +ex
2020-07-10 12:30:33 +03:00
if [ -z " ${ image_dir } " ] ; then
return
fi
2022-09-17 15:27:31 +03:00
umount " ${ image_dir } /app0 "
umount " ${ image_dir } /app1 "
umount " ${ image_dir } /app-nodistro "
2020-07-10 12:30:33 +03:00
rm -rf " ${ image_dir } "
2022-09-17 15:27:31 +03:00
) }
2020-07-10 12:30:33 +03:00
2022-08-26 18:52:04 +03:00
udevadm control --log-level= debug
2020-05-29 19:51:20 +03:00
cd /tmp
2020-07-10 12:30:33 +03:00
image_dir = " $( mktemp -d -t -p /tmp tmp.XXXXXX) "
if [ -z " ${ image_dir } " ] || [ ! -d " ${ image_dir } " ] ; then
echo "mktemp under /tmp failed"
exit 1
2020-05-29 19:51:20 +03:00
fi
2020-07-10 12:30:33 +03:00
trap cleanup EXIT
2020-08-28 16:17:31 +03:00
cp /usr/share/minimal* " ${ image_dir } / "
image = " ${ image_dir } /minimal_0 "
2021-04-09 20:49:32 +03:00
roothash = " $( cat " ${ image } .roothash " ) "
os_release = " $( test -e /etc/os-release && echo /etc/os-release || echo /usr/lib/os-release) "
systemd-dissect --json= short " ${ image } .raw " | grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"'
systemd-dissect " ${ image } .raw " | grep -q -F "MARKER=1"
systemd-dissect " ${ image } .raw " | grep -q -F -f <( sed 's/"//g' " $os_release " )
2022-11-08 20:17:55 +03:00
systemd-dissect --list " ${ image } .raw " | grep -q '^etc/os-release$'
2023-07-06 12:24:22 +03:00
systemd-dissect --mtree " ${ image } .raw " --mtree-hash yes | grep -qe " ^./usr/bin/cat type=file mode=0755 uid=0 gid=0 size=[0-9]* sha256sum=[a-z0-9]* $"
systemd-dissect --mtree " ${ image } .raw " --mtree-hash no | grep -qe " ^./usr/bin/cat type=file mode=0755 uid=0 gid=0 size=[0-9]* $"
2022-11-08 20:17:55 +03:00
read -r SHA256SUM1 _ < <( systemd-dissect --copy-from " ${ image } .raw " etc/os-release | sha256sum)
test " $SHA256SUM1 " != ""
read -r SHA256SUM2 _ < <( systemd-dissect --read-only --with " ${ image } .raw " sha256sum etc/os-release)
test " $SHA256SUM2 " != ""
test " $SHA256SUM1 " = " $SHA256SUM2 "
2021-04-09 20:49:32 +03:00
mv " ${ image } .verity " " ${ image } .fooverity "
mv " ${ image } .roothash " " ${ image } .foohash "
systemd-dissect --json= short " ${ image } .raw " --root-hash= " ${ roothash } " --verity-data= " ${ image } .fooverity " | grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"'
systemd-dissect " ${ image } .raw " --root-hash= " ${ roothash } " --verity-data= " ${ image } .fooverity " | grep -q -F "MARKER=1"
systemd-dissect " ${ image } .raw " --root-hash= " ${ roothash } " --verity-data= " ${ image } .fooverity " | grep -q -F -f <( sed 's/"//g' " $os_release " )
mv " ${ image } .fooverity " " ${ image } .verity "
mv " ${ image } .foohash " " ${ image } .roothash "
mkdir -p " ${ image_dir } /mount " " ${ image_dir } /mount2 "
systemd-dissect --mount " ${ 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/etc/os-release "
grep -q -F "MARKER=1" " ${ image_dir } /mount/usr/lib/os-release "
2020-07-08 21:57:31 +03:00
# Verity volume should be shared (opened only once)
2021-04-09 20:49:32 +03:00
systemd-dissect --mount " ${ image } .raw " " ${ image_dir } /mount2 "
verity_count = $( find /dev/mapper/ -name "*verity*" | wc -l)
2020-07-08 21:57:31 +03:00
# 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
# (and even mounted and in use), so best-effort is the most we can do for now
2021-04-09 20:49:32 +03:00
if [ " ${ verity_count } " -lt 1 ] ; then
2020-07-08 21:57:31 +03:00
echo " Verity device ${ image } .raw not found in /dev/mapper/ "
exit 1
fi
2022-07-28 02:55:11 +03:00
systemd-dissect --umount " ${ image_dir } /mount "
systemd-dissect --umount " ${ image_dir } /mount2 "
2020-05-29 19:51:20 +03:00
2021-04-23 18:17:26 +03:00
systemd-run -P -p RootImage = " ${ image } .raw " cat /usr/lib/os-release | grep -q -F "MARKER=1"
2021-04-09 20:49:32 +03:00
mv " ${ image } .verity " " ${ image } .fooverity "
mv " ${ image } .roothash " " ${ image } .foohash "
2021-04-23 18:17:26 +03:00
systemd-run -P -p RootImage = " ${ image } .raw " -p RootHash = " ${ image } .foohash " -p RootVerity = " ${ image } .fooverity " cat /usr/lib/os-release | grep -q -F "MARKER=1"
2020-09-22 13:36:38 +03:00
# Let's use the long option name just here as a test
2021-04-23 18:17:26 +03:00
systemd-run -P --property RootImage = " ${ image } .raw " --property RootHash = " ${ roothash } " --property RootVerity = " ${ image } .fooverity " cat /usr/lib/os-release | grep -q -F "MARKER=1"
2021-04-09 20:49:32 +03:00
mv " ${ image } .fooverity " " ${ image } .verity "
mv " ${ image } .foohash " " ${ image } .roothash "
2020-07-15 19:54:12 +03:00
2020-07-10 18:01:15 +03:00
# Make a GPT disk on the fly, with the squashfs as partition 1 and the verity hash tree as partition 2
machine = " $( uname -m) "
if [ " ${ machine } " = "x86_64" ] ; then
root_guid = 4f68bce3-e8cd-4db1-96e7-fbcaf984b709
verity_guid = 2c7357ed-ebd2-46d9-aec1-23d437ec2bf5
2021-09-28 17:49:16 +03:00
signature_guid = 41092b05-9fc8-4523-994f-2def0408b176
2020-10-18 17:41:34 +03:00
architecture = "x86-64"
2020-07-10 18:01:15 +03:00
elif [ " ${ machine } " = "i386" ] || [ " ${ machine } " = "i686" ] || [ " ${ machine } " = "x86" ] ; then
root_guid = 44479540-f297-41b2-9af7-d131d5f0458a
verity_guid = d13c5d3b-b5d1-422a-b29f-9454fdc89d76
2021-09-28 17:49:16 +03:00
signature_guid = 5996fc05-109c-48de-808b-23fa0830b676
2020-10-18 17:41:34 +03:00
architecture = "x86"
2020-07-10 18:01:15 +03:00
elif [ " ${ machine } " = "aarch64" ] || [ " ${ machine } " = "aarch64_be" ] || [ " ${ machine } " = "armv8b" ] || [ " ${ machine } " = "armv8l" ] ; then
root_guid = b921b045-1df0-41c3-af44-4c6f280d3fae
verity_guid = df3300ce-d69f-4c92-978c-9bfb0f38d820
2021-09-28 17:49:16 +03:00
signature_guid = 6db69de6-29f4-4758-a7a5-962190f00ce3
2020-10-18 17:41:34 +03:00
architecture = "arm64"
2020-07-10 18:01:15 +03:00
elif [ " ${ machine } " = "arm" ] ; then
root_guid = 69dad710-2ce4-4e3c-b16c-21a1d49abed3
verity_guid = 7386cdf2-203c-47a9-a498-f2ecce45a2d6
2021-09-28 17:49:16 +03:00
signature_guid = 42b0455f-eb11-491d-98d3-56145ba9d037
2020-10-18 17:41:34 +03:00
architecture = "arm"
2021-04-19 16:03:32 +03:00
elif [ " ${ machine } " = "loongarch64" ] ; then
root_guid = 77055800-792c-4f94-b39a-98c91b762bb6
verity_guid = f3393b22-e9af-4613-a948-9d3bfbd0c535
signature_guid = 5afb67eb-ecc8-4f85-ae8e-ac1e7c50e7d0
architecture = "loongarch64"
2020-07-10 18:01:15 +03:00
elif [ " ${ machine } " = "ia64" ] ; then
root_guid = 993d8d3d-f80e-4225-855a-9daf8ed7ea97
verity_guid = 86ed10d5-b607-45bb-8957-d350f23d0571
2021-09-28 17:49:16 +03:00
signature_guid = e98b36ee-32ba-4882-9b12-0ce14655f46a
2020-10-18 17:41:34 +03:00
architecture = "ia64"
2022-01-13 01:38:04 +03:00
elif [ " ${ machine } " = "s390x" ] ; then
root_guid = 5eead9a9-fe09-4a1e-a1d7-520d00531306
verity_guid = b325bfbe-c7be-4ab8-8357-139e652d2f6b
signature_guid = c80187a5-73a3-491a-901a-017c3fa953e9
architecture = "s390x"
2020-10-18 17:41:34 +03:00
elif [ " ${ machine } " = "ppc64le" ] ; then
2022-01-13 01:38:04 +03:00
root_guid = c31c45e6-3f39-412e-80fb-4809c4980599
verity_guid = 906bd944-4589-4aae-a4e4-dd983917446a
signature_guid = d4a236e7-e873-4c07-bf1d-bf6cf7f1c3c6
architecture = "ppc64-le"
2020-07-20 18:43:18 +03:00
else
echo " Unexpected uname -m: ${ machine } in testsuite-50.sh, please fix me "
exit 1
2020-07-10 18:01:15 +03:00
fi
# du rounds up to block size, which is more helpful for partitioning
2021-04-09 20:49:32 +03:00
root_size = " $( du -k " ${ image } .raw " | cut -f1) "
verity_size = " $( du -k " ${ image } .verity " | cut -f1) "
2021-09-28 17:49:16 +03:00
signature_size = 4
2020-07-10 18:01:15 +03:00
# 4MB seems to be the minimum size blkid will accept, below that probing fails
2021-09-28 17:49:16 +03:00
dd if = /dev/zero of = " ${ image } .gpt " bs = 512 count = $(( 8192 + root_size*2+verity_size*2+signature_size*2))
2020-07-10 18:01:15 +03:00
# sfdisk seems unhappy if the size overflows into the next unit, eg: 1580KiB will be interpreted as 1MiB
# so do some basic rounding up if the minimal image is more than 1 MB
2021-04-09 20:49:32 +03:00
if [ " ${ root_size } " -ge 1024 ] ; then
root_size = " $(( root_size/1024 + 1 )) MiB "
2020-07-10 18:01:15 +03:00
else
root_size = " ${ root_size } KiB "
fi
2021-04-09 20:49:32 +03:00
verity_size = " $(( verity_size * 2 )) KiB "
2021-09-28 17:49:16 +03:00
signature_size = " $(( signature_size * 2 )) KiB "
2021-10-07 02:26:26 +03:00
HAVE_OPENSSL = 0
if systemctl --version | grep -q -- +OPENSSL ; then
2021-12-16 21:18:28 +03:00
# The openssl binary is installed conditionally.
# If we have OpenSSL support enabled and openssl is missing, fail early
# with a proper error message.
if ! command -v openssl >/dev/null 2>& 1; then
echo "openssl missing" >/failed
exit 1
fi
2021-10-07 02:26:26 +03:00
HAVE_OPENSSL = 1
# Unfortunately OpenSSL insists on reading some config file, hence provide one with mostly placeholder contents
2023-02-05 23:41:24 +03:00
cat >>" ${ image } .openssl.cnf " <<EOF
2021-09-28 17:49:16 +03:00
[ req ]
prompt = no
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
C = DE
ST = Test State
L = Test Locality
O = Org Name
OU = Org Unit Name
CN = Common Name
emailAddress = test@email.com
EOF
2021-10-07 02:26:26 +03:00
# Create key pair
openssl req -config " ${ image } .openssl.cnf " -new -x509 -newkey rsa:1024 -keyout " ${ image } .key " -out " ${ image } .crt " -days 365 -nodes
# Sign Verity root hash with it
openssl smime -sign -nocerts -noattr -binary -in " ${ image } .roothash " -inkey " ${ image } .key " -signer " ${ image } .crt " -outform der -out " ${ image } .roothash.p7s "
# Generate signature partition JSON data
2023-02-05 23:41:24 +03:00
echo '{"rootHash":"' " ${ roothash } " '","signature":"' " $( base64 -w 0 <" ${ image } .roothash.p7s " ) " '"}' >" ${ image } .verity-sig "
2021-10-07 02:26:26 +03:00
# Pad it
truncate -s " ${ signature_size } " " ${ image } .verity-sig "
# Register certificate in the (userspace) verity key ring
mkdir -p /run/verity.d
ln -s " ${ image } .crt " /run/verity.d/ok.crt
fi
2021-09-28 17:49:16 +03:00
2021-04-09 20:49:32 +03:00
# Construct a UUID from hash
# input: 11111111222233334444555566667777
# output: 11111111-2222-3333-4444-555566667777
uuid = " $( head -c 32 " ${ image } .roothash " | sed -r 's/(.{8})(.{4})(.{4})(.{4})(.+)/\1-\2-\3-\4-\5/' ) "
echo -e " label: gpt\nsize= ${ root_size } , type= ${ root_guid } , uuid= ${ uuid } " | sfdisk " ${ image } .gpt "
uuid = " $( tail -c 32 " ${ image } .roothash " | sed -r 's/(.{8})(.{4})(.{4})(.{4})(.+)/\1-\2-\3-\4-\5/' ) "
echo -e " size= ${ verity_size } , type= ${ verity_guid } , uuid= ${ uuid } " | sfdisk " ${ image } .gpt " --append
2021-10-07 02:26:26 +03:00
if [ " ${ HAVE_OPENSSL } " -eq 1 ] ; then
echo -e " size= ${ signature_size } , type= ${ signature_guid } " | sfdisk " ${ image } .gpt " --append
fi
2021-04-09 20:49:32 +03:00
sfdisk --part-label " ${ image } .gpt " 1 "Root Partition"
sfdisk --part-label " ${ image } .gpt " 2 "Verity Partition"
2021-10-07 02:26:26 +03:00
if [ " ${ HAVE_OPENSSL } " -eq 1 ] ; then
sfdisk --part-label " ${ image } .gpt " 3 "Signature Partition"
fi
2021-04-09 20:49:32 +03:00
loop = " $( losetup --show -P -f " ${ image } .gpt " ) "
2022-08-27 10:13:27 +03:00
partitions = (
" ${ loop : ? } p1 "
" ${ loop : ? } p2 "
)
2021-10-07 02:26:26 +03:00
if [ " ${ HAVE_OPENSSL } " -eq 1 ] ; then
2022-08-27 10:13:27 +03:00
partitions += ( " ${ loop : ? } p3 " )
fi
# The kernel sometimes(?) does not emit "add" uevent for loop block partition devices.
# Let's not expect the devices to be initialized.
udevadm wait --timeout 60 --settle --initialized= no " ${ partitions [@] } "
udevadm lock --device= " ${ loop } p1 " dd if = " ${ image } .raw " of = " ${ loop } p1 "
udevadm lock --device= " ${ loop } p2 " dd if = " ${ image } .verity " of = " ${ loop } p2 "
if [ " ${ HAVE_OPENSSL } " -eq 1 ] ; then
udevadm lock --device= " ${ loop } p3 " dd if = " ${ image } .verity-sig " of = " ${ loop } p3 "
2021-10-07 02:26:26 +03:00
fi
2021-04-09 20:49:32 +03:00
losetup -d " ${ loop } "
2020-07-10 18:01:15 +03:00
2020-08-12 00:32:19 +03:00
# Derive partition UUIDs from root hash, in UUID syntax
2021-04-09 20:49:32 +03:00
ROOT_UUID = " $( systemd-id128 -u show " $( head -c 32 " ${ image } .roothash " ) " -u | tail -n 1 | cut -b 6-) "
VERITY_UUID = " $( systemd-id128 -u show " $( tail -c 32 " ${ image } .roothash " ) " -u | tail -n 1 | cut -b 6-) "
2020-07-10 18:01:15 +03:00
2022-09-18 16:36:59 +03:00
systemd-dissect --json= short --root-hash " ${ roothash } " " ${ image } .gpt " | grep -q '{"rw":"ro","designator":"root","partition_uuid":"' " $ROOT_UUID " '","partition_label":"Root Partition","fstype":"squashfs","architecture":"' " $architecture " '","verity":"signed",'
2021-04-21 17:35:21 +03:00
systemd-dissect --json= short --root-hash " ${ roothash } " " ${ image } .gpt " | grep -q '{"rw":"ro","designator":"root-verity","partition_uuid":"' " $VERITY_UUID " '","partition_label":"Verity Partition","fstype":"DM_verity_hash","architecture":"' " $architecture " '","verity":null,'
2022-09-18 16:36:59 +03:00
if [ " ${ HAVE_OPENSSL } " -eq 1 ] ; then
systemd-dissect --json= short --root-hash " ${ roothash } " " ${ image } .gpt " | grep -q -E '{"rw":"ro","designator":"root-verity-sig","partition_uuid":"' ".*" '","partition_label":"Signature Partition","fstype":"verity_hash_signature","architecture":"' " $architecture " '","verity":null,'
fi
2021-04-09 20:49:32 +03:00
systemd-dissect --root-hash " ${ roothash } " " ${ image } .gpt " | grep -q -F "MARKER=1"
systemd-dissect --root-hash " ${ roothash } " " ${ image } .gpt " | grep -q -F -f <( sed 's/"//g' " $os_release " )
2020-08-12 00:32:19 +03:00
2022-12-02 19:16:57 +03:00
# Test image policies
systemd-dissect --validate " ${ image } .gpt "
systemd-dissect --validate " ${ image } .gpt " --image-policy= '*'
( ! systemd-dissect --validate " ${ image } .gpt " --image-policy= '~' )
( ! systemd-dissect --validate " ${ image } .gpt " --image-policy= '-' )
( ! systemd-dissect --validate " ${ image } .gpt " --image-policy= root = absent)
( ! systemd-dissect --validate " ${ image } .gpt " --image-policy= swap = unprotected+encrypted+verity)
systemd-dissect --validate " ${ image } .gpt " --image-policy= root = unprotected
systemd-dissect --validate " ${ image } .gpt " --image-policy= root = verity
systemd-dissect --validate " ${ image } .gpt " --image-policy= root = verity:root-verity-sig= unused+absent
systemd-dissect --validate " ${ image } .gpt " --image-policy= root = verity:swap= absent
systemd-dissect --validate " ${ image } .gpt " --image-policy= root = verity:swap= absent+unprotected
( ! systemd-dissect --validate " ${ image } .gpt " --image-policy= root = verity:root-verity= unused+absent)
systemd-dissect --validate " ${ image } .gpt " --image-policy= root = signed
( ! systemd-dissect --validate " ${ image } .gpt " --image-policy= root = signed:root-verity-sig= unused+absent)
( ! systemd-dissect --validate " ${ image } .gpt " --image-policy= root = signed:root-verity= unused+absent)
# Test RootImagePolicy= unit file setting
systemd-run --wait -P -p RootImage = " ${ image } .gpt " -p RootHash = " ${ roothash } " -p MountAPIVFS = yes cat /usr/lib/os-release | grep -q -F "MARKER=1"
systemd-run --wait -P -p RootImage = " ${ image } .gpt " -p RootHash = " ${ roothash } " -p RootImagePolicy = '*' -p MountAPIVFS = yes cat /usr/lib/os-release | grep -q -F "MARKER=1"
( ! systemd-run --wait -P -p RootImage = " ${ image } .gpt " -p RootHash = " ${ roothash } " -p RootImagePolicy = '~' -p MountAPIVFS = yes cat /usr/lib/os-release | grep -q -F "MARKER=1" )
( ! systemd-run --wait -P -p RootImage = " ${ image } .gpt " -p RootHash = " ${ roothash } " -p RootImagePolicy = '-' -p MountAPIVFS = yes cat /usr/lib/os-release | grep -q -F "MARKER=1" )
( ! systemd-run --wait -P -p RootImage = " ${ image } .gpt " -p RootHash = " ${ roothash } " -p RootImagePolicy = 'root=absent' -p MountAPIVFS = yes cat /usr/lib/os-release | grep -q -F "MARKER=1" )
systemd-run --wait -P -p RootImage = " ${ image } .gpt " -p RootHash = " ${ roothash } " -p RootImagePolicy = 'root=verity' -p MountAPIVFS = yes cat /usr/lib/os-release | grep -q -F "MARKER=1"
systemd-run --wait -P -p RootImage = " ${ image } .gpt " -p RootHash = " ${ roothash } " -p RootImagePolicy = 'root=signed' -p MountAPIVFS = yes cat /usr/lib/os-release | grep -q -F "MARKER=1"
( ! systemd-run --wait -P -p RootImage = " ${ image } .gpt " -p RootHash = " ${ roothash } " -p RootImagePolicy = 'root=encrypted' -p MountAPIVFS = yes cat /usr/lib/os-release | grep -q -F "MARKER=1" )
2021-04-09 20:49:32 +03:00
systemd-dissect --root-hash " ${ roothash } " --mount " ${ image } .gpt " " ${ 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/etc/os-release "
grep -q -F "MARKER=1" " ${ image_dir } /mount/usr/lib/os-release "
2022-07-28 02:55:11 +03:00
systemd-dissect --umount " ${ image_dir } /mount "
2020-07-10 18:01:15 +03:00
2022-12-08 14:46:41 +03:00
systemd-dissect --root-hash " ${ roothash } " --mount " ${ image } .gpt " --in-memory " ${ 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/etc/os-release "
grep -q -F "MARKER=1" " ${ image_dir } /mount/usr/lib/os-release "
systemd-dissect --umount " ${ image_dir } /mount "
2020-09-22 13:36:38 +03:00
# add explicit -p MountAPIVFS=yes once to test the parser
2021-04-23 18:17:26 +03:00
systemd-run -P -p RootImage = " ${ image } .gpt " -p RootHash = " ${ roothash } " -p MountAPIVFS = yes cat /usr/lib/os-release | grep -q -F "MARKER=1"
2020-07-15 19:54:12 +03:00
2021-04-23 18:17:26 +03:00
systemd-run -P -p RootImage = " ${ image } .raw " -p RootImageOptions = "root:nosuid,dev home:ro,dev ro,noatime" mount | grep -F "squashfs" | grep -q -F "nosuid"
systemd-run -P -p RootImage = " ${ image } .gpt " -p RootImageOptions = "root:ro,noatime root:ro,dev" mount | grep -F "squashfs" | grep -q -F "noatime"
2020-06-29 15:19:31 +03:00
2021-04-09 20:49:32 +03:00
mkdir -p " ${ image_dir } /result "
2020-09-22 13:36:38 +03:00
cat >/run/systemd/system/testservice-50a.service <<EOF
2020-06-29 15:19:31 +03:00
[ Service]
Type = oneshot
2020-09-22 13:36:38 +03:00
ExecStart = bash -c "mount >/run/result/a"
2020-08-14 20:50:46 +03:00
BindPaths = ${ image_dir } /result:/run/result
TemporaryFileSystem = /run
2020-06-29 15:19:31 +03:00
RootImage = ${ image } .raw
2020-08-14 20:50:46 +03:00
RootImageOptions = root:ro,noatime home:ro,dev relatime,dev
2020-06-29 15:19:31 +03:00
RootImageOptions = nosuid,dev
EOF
systemctl start testservice-50a.service
2021-04-09 20:49:32 +03:00
grep -F "squashfs" " ${ image_dir } /result/a " | grep -q -F "noatime"
grep -F "squashfs" " ${ image_dir } /result/a " | grep -q -F -v "nosuid"
2020-06-29 15:19:31 +03:00
2020-09-22 13:36:38 +03:00
cat >/run/systemd/system/testservice-50b.service <<EOF
2020-06-29 15:19:31 +03:00
[ Service]
Type = oneshot
2020-09-22 13:36:38 +03:00
ExecStart = bash -c "mount >/run/result/b"
2020-08-14 20:50:46 +03:00
BindPaths = ${ image_dir } /result:/run/result
TemporaryFileSystem = /run
2020-06-29 15:19:31 +03:00
RootImage = ${ image } .gpt
2020-08-14 20:50:46 +03:00
RootImageOptions = root:ro,noatime,nosuid home:ro,dev nosuid,dev
RootImageOptions = home:ro,dev nosuid,dev,%%foo
2020-09-22 13:36:38 +03:00
# this is the default, but let's specify once to test the parser
MountAPIVFS = yes
2020-06-29 15:19:31 +03:00
EOF
systemctl start testservice-50b.service
2021-04-09 20:49:32 +03:00
grep -F "squashfs" " ${ image_dir } /result/b " | grep -q -F "noatime"
2020-06-29 15:19:31 +03:00
2020-09-22 13:36:38 +03:00
# Check that specifier escape is applied %%foo → %foo
2020-06-29 15:19:31 +03:00
busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1/unit/testservice_2d50b_2eservice org.freedesktop.systemd1.Service RootImageOptions | grep -F "nosuid,dev,%foo"
2020-07-31 17:06:15 +03:00
# Now do some checks with MountImages, both by itself, with options and in combination with RootImage, and as single FS or GPT image
2021-04-23 18:17:26 +03:00
systemd-run -P -p MountImages = " ${ image } .gpt:/run/img1 ${ image } .raw:/run/img2 " cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1"
systemd-run -P -p MountImages = " ${ image } .gpt:/run/img1 ${ image } .raw:/run/img2 " cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1"
systemd-run -P -p MountImages = " ${ image } .gpt:/run/img1 ${ image } .raw:/run/img2:nosuid,dev " mount | grep -F "squashfs" | grep -q -F "nosuid"
systemd-run -P -p MountImages = " ${ image } .gpt:/run/img1:root:nosuid ${ image } .raw:/run/img2:home:suid " mount | grep -F "squashfs" | grep -q -F "nosuid"
systemd-run -P -p MountImages = " ${ image } .raw:/run/img2\:3 " cat /run/img2:3/usr/lib/os-release | grep -q -F "MARKER=1"
systemd-run -P -p MountImages = " ${ image } .raw:/run/img2\:3:nosuid " mount | grep -F "squashfs" | grep -q -F "nosuid"
systemd-run -P -p TemporaryFileSystem = /run -p RootImage = " ${ image } .raw " -p MountImages = " ${ image } .gpt:/run/img1 ${ image } .raw:/run/img2 " cat /usr/lib/os-release | grep -q -F "MARKER=1"
systemd-run -P -p TemporaryFileSystem = /run -p RootImage = " ${ image } .raw " -p MountImages = " ${ image } .gpt:/run/img1 ${ image } .raw:/run/img2 " cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1"
systemd-run -P -p TemporaryFileSystem = /run -p RootImage = " ${ image } .gpt " -p RootHash = " ${ roothash } " -p MountImages = " ${ image } .gpt:/run/img1 ${ image } .raw:/run/img2 " cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1"
2020-07-31 17:06:15 +03:00
cat >/run/systemd/system/testservice-50c.service <<EOF
2020-07-14 18:18:41 +03:00
[ Service]
2020-07-31 17:06:15 +03:00
MountAPIVFS = yes
2020-07-14 18:18:41 +03:00
TemporaryFileSystem = /run
RootImage = ${ image } .raw
2020-07-31 17:06:15 +03:00
MountImages = ${ image } .gpt:/run/img1:root:noatime:home:relatime
MountImages = ${ image } .raw:/run/img2\: 3:nosuid
2020-09-22 13:36:38 +03:00
ExecStart = bash -c "cat /run/img1/usr/lib/os-release >/run/result/c"
ExecStart = bash -c "cat /run/img2:3/usr/lib/os-release >>/run/result/c"
ExecStart = bash -c "mount >>/run/result/c"
2020-07-31 17:06:15 +03:00
BindPaths = ${ image_dir } /result:/run/result
2020-07-14 18:18:41 +03:00
Type = oneshot
EOF
2020-07-31 17:06:15 +03:00
systemctl start testservice-50c.service
2021-04-09 20:49:32 +03:00
grep -q -F "MARKER=1" " ${ image_dir } /result/c "
grep -F "squashfs" " ${ image_dir } /result/c " | grep -q -F "noatime"
grep -F "squashfs" " ${ image_dir } /result/c " | grep -q -F -v "nosuid"
2020-07-14 18:18:41 +03:00
2021-01-21 21:37:40 +03:00
# Adding a new mounts at runtime works if the unit is in the active state,
# so use Type=notify to make sure there's no race condition in the test
2021-04-08 01:09:55 +03:00
cat >/run/systemd/system/testservice-50d.service <<EOF
2021-01-21 21:37:40 +03:00
[ Service]
RuntimeMaxSec = 300
Type = notify
RemainAfterExit = yes
MountAPIVFS = yes
PrivateTmp = yes
2022-09-11 18:37:01 +03:00
ExecStart = /bin/sh -c ' \\
systemd-notify --ready; \\
while [ [ ! -f /tmp/img/usr/lib/os-release ] ] || ! grep -q -F MARKER /tmp/img/usr/lib/os-release; do \\
sleep 0.1; \\
done ; \\
mount; \\
mount | grep -F "on /tmp/img type squashfs" | grep -q -F "nosuid" ; \\
'
2021-01-21 21:37:40 +03:00
EOF
systemctl start testservice-50d.service
2021-04-09 20:49:32 +03:00
systemctl mount-image --mkdir testservice-50d.service " ${ image } .raw " /tmp/img root:nosuid
2021-01-21 21:37:40 +03:00
while systemctl show -P SubState testservice-50d.service | grep -q running
do
sleep 0.1
done
systemctl is-active testservice-50d.service
2021-02-22 15:20:33 +03:00
# ExtensionImages will set up an overlay
2021-04-23 18:17:26 +03:00
systemd-run -P --property ExtensionImages = /usr/share/app0.raw --property RootImage = " ${ image } .raw " cat /opt/script0.sh | grep -q -F "extension-release.app0"
systemd-run -P --property ExtensionImages = /usr/share/app0.raw --property RootImage = " ${ image } .raw " cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
systemd-run -P --property ExtensionImages = "/usr/share/app0.raw /usr/share/app1.raw" --property RootImage = " ${ image } .raw " cat /opt/script0.sh | grep -q -F "extension-release.app0"
systemd-run -P --property ExtensionImages = "/usr/share/app0.raw /usr/share/app1.raw" --property RootImage = " ${ image } .raw " cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
2021-07-22 22:41:34 +03:00
systemd-run -P --property ExtensionImages = "/usr/share/app0.raw /usr/share/app1.raw" --property RootImage = " ${ image } .raw " cat /opt/script1.sh | grep -q -F "extension-release.app2"
2021-04-23 18:17:26 +03:00
systemd-run -P --property ExtensionImages = "/usr/share/app0.raw /usr/share/app1.raw" --property RootImage = " ${ image } .raw " cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1"
2022-08-09 14:34:18 +03:00
systemd-run -P --property ExtensionImages = /usr/share/app-nodistro.raw --property RootImage = " ${ image } .raw " cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
2022-08-15 18:47:03 +03:00
# Check that using a symlink to NAME-VERSION.raw works as long as the symlink has the correct name NAME.raw
mkdir -p /usr/share/symlink-test/
cp /usr/share/app-nodistro.raw /usr/share/symlink-test/app-nodistro-v1.raw
ln -fs /usr/share/symlink-test/app-nodistro-v1.raw /usr/share/symlink-test/app-nodistro.raw
systemd-run -P --property ExtensionImages = /usr/share/symlink-test/app-nodistro.raw --property RootImage = " ${ image } .raw " cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
2021-02-22 15:20:33 +03:00
cat >/run/systemd/system/testservice-50e.service <<EOF
[ Service]
MountAPIVFS = yes
2022-01-27 17:10:34 +03:00
TemporaryFileSystem = /run /var/lib
StateDirectory = app0
2021-02-22 15:20:33 +03:00
RootImage = ${ image } .raw
ExtensionImages = /usr/share/app0.raw /usr/share/app1.raw:nosuid
2021-03-08 13:28:40 +03:00
# Relevant only for sanitizer runs
UnsetEnvironment = LD_PRELOAD
2021-02-22 15:20:33 +03:00
ExecStart = /bin/bash -c '/opt/script0.sh | grep ID'
ExecStart = /bin/bash -c '/opt/script1.sh | grep ID'
Type = oneshot
RemainAfterExit = yes
EOF
systemctl start testservice-50e.service
systemctl is-active testservice-50e.service
2022-01-17 04:14:14 +03:00
# ExtensionDirectories will set up an overlay
2022-08-09 14:34:18 +03:00
mkdir -p " ${ image_dir } /app0 " " ${ image_dir } /app1 " " ${ image_dir } /app-nodistro "
2023-04-05 16:50:42 +03:00
( ! systemd-run -P --property ExtensionDirectories = " ${ image_dir } /nonexistent " --property RootImage = " ${ image } .raw " cat /opt/script0.sh)
( ! systemd-run -P --property ExtensionDirectories = " ${ image_dir } /app0 " --property RootImage = " ${ image } .raw " cat /opt/script0.sh)
2022-01-17 04:14:14 +03:00
systemd-dissect --mount /usr/share/app0.raw " ${ image_dir } /app0 "
systemd-dissect --mount /usr/share/app1.raw " ${ image_dir } /app1 "
2022-08-09 14:34:18 +03:00
systemd-dissect --mount /usr/share/app-nodistro.raw " ${ image_dir } /app-nodistro "
2022-01-17 04:14:14 +03:00
systemd-run -P --property ExtensionDirectories = " ${ image_dir } /app0 " --property RootImage = " ${ image } .raw " cat /opt/script0.sh | grep -q -F "extension-release.app0"
systemd-run -P --property ExtensionDirectories = " ${ image_dir } /app0 " --property RootImage = " ${ image } .raw " cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
systemd-run -P --property ExtensionDirectories = " ${ image_dir } /app0 ${ image_dir } /app1 " --property RootImage = " ${ image } .raw " cat /opt/script0.sh | grep -q -F "extension-release.app0"
systemd-run -P --property ExtensionDirectories = " ${ image_dir } /app0 ${ image_dir } /app1 " --property RootImage = " ${ image } .raw " cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
systemd-run -P --property ExtensionDirectories = " ${ image_dir } /app0 ${ image_dir } /app1 " --property RootImage = " ${ image } .raw " cat /opt/script1.sh | grep -q -F "extension-release.app2"
systemd-run -P --property ExtensionDirectories = " ${ image_dir } /app0 ${ image_dir } /app1 " --property RootImage = " ${ image } .raw " cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1"
2022-08-09 14:34:18 +03:00
systemd-run -P --property ExtensionDirectories = " ${ image_dir } /app-nodistro " --property RootImage = " ${ image } .raw " cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
2022-01-17 04:14:14 +03:00
cat >/run/systemd/system/testservice-50f.service <<EOF
[ Service]
MountAPIVFS = yes
2022-01-27 17:10:34 +03:00
TemporaryFileSystem = /run /var/lib
StateDirectory = app0
2022-01-17 04:14:14 +03:00
RootImage = ${ image } .raw
ExtensionDirectories = ${ image_dir } /app0 ${ image_dir } /app1
# Relevant only for sanitizer runs
UnsetEnvironment = LD_PRELOAD
ExecStart = /bin/bash -c '/opt/script0.sh | grep ID'
ExecStart = /bin/bash -c '/opt/script1.sh | grep ID'
Type = oneshot
RemainAfterExit = yes
EOF
systemctl start testservice-50f.service
systemctl is-active testservice-50f.service
2022-07-28 02:55:11 +03:00
systemd-dissect --umount " ${ image_dir } /app0 "
systemd-dissect --umount " ${ image_dir } /app1 "
2022-01-17 04:14:14 +03:00
2022-08-16 13:29:12 +03:00
# Test that an extension consisting of an empty directory under /etc/extensions/ takes precedence
mkdir -p /var/lib/extensions/
ln -s /usr/share/app-nodistro.raw /var/lib/extensions/app-nodistro.raw
systemd-sysext merge
grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file
systemd-sysext unmerge
mkdir -p /etc/extensions/app-nodistro
systemd-sysext merge
test ! -e /usr/lib/systemd/system/some_file
systemd-sysext unmerge
rmdir /etc/extensions/app-nodistro
2023-03-29 01:16:20 +03:00
# Check that extensions cannot contain os-release
mkdir -p /run/extensions/app-reject/usr/lib/{ extension-release.d/,systemd/system}
echo "ID=_any" >/run/extensions/app-reject/usr/lib/extension-release.d/extension-release.app-reject
echo "ID=_any" >/run/extensions/app-reject/usr/lib/os-release
touch /run/extensions/app-reject/usr/lib/systemd/system/other_file
2023-04-05 16:50:42 +03:00
( ! systemd-sysext merge)
2023-03-29 01:16:20 +03:00
test ! -e /usr/lib/systemd/system/some_file
test ! -e /usr/lib/systemd/system/other_file
systemd-sysext unmerge
rm -rf /run/extensions/app-reject
2022-08-16 13:29:12 +03:00
rm /var/lib/extensions/app-nodistro.raw
2022-11-29 18:39:06 +03:00
mkdir -p /run/machines /run/portables /run/extensions
touch /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw
2023-02-05 23:41:24 +03:00
systemd-dissect --discover --json= short >/tmp/discover.json
2022-11-29 18:39:06 +03:00
grep -q -F '{"name":"a","type":"raw","class":"machine","ro":false,"path":"/run/machines/a.raw"' /tmp/discover.json
grep -q -F '{"name":"b","type":"raw","class":"portable","ro":false,"path":"/run/portables/b.raw"' /tmp/discover.json
2023-07-14 19:36:50 +03:00
grep -q -F '{"name":"c","type":"raw","class":"sysext","ro":false,"path":"/run/extensions/c.raw"' /tmp/discover.json
2022-11-29 18:39:06 +03:00
rm /tmp/discover.json /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw
2023-03-06 20:27:38 +03:00
# Check that the /sbin/mount.ddi helper works
T = " /tmp/mounthelper. $RANDOM "
mount -t ddi " ${ image } .gpt " " $T " -o ro,X-mount.mkdir,discard
umount -R " $T "
rmdir " $T "
2023-03-06 15:23:48 +03:00
LOOP = " $( systemd-dissect --attach --loop-ref= waldo " ${ image } .raw " ) "
# Wait until the symlinks we want to test are established
udevadm trigger -w " $LOOP "
# Check if the /dev/loop/* symlinks really reference the right device
test /dev/loop/by-ref/waldo -ef " $LOOP "
if [ " $( stat -c '%Hd:%Ld' " ${ image } .raw " ) " != '?d:?d' ] ; then
# Old stat didn't know the %Hd and %Ld specifiers and turned them into ?d
# instead. Let's simply skip the test on such old systems.
test " $( stat -c '/dev/loop/by-inode/%Hd:%Ld-%i' " ${ image } .raw " ) " -ef " $LOOP "
fi
# Detach by loopback device
systemd-dissect --detach " $LOOP "
2023-03-13 17:36:32 +03:00
# Test long reference name.
# Note, sizeof_field(struct loop_info64, lo_file_name) == 64,
# and --loop-ref accepts upto 63 characters, and udev creates symlink
# based on the name when it has upto _62_ characters.
2023-04-07 11:17:15 +03:00
name = " $( for _ in { 1..62} ; do echo -n 'x' ; done ) "
2023-03-13 17:36:32 +03:00
LOOP = " $( systemd-dissect --attach --loop-ref= " $name " " ${ image } .raw " ) "
udevadm trigger -w " $LOOP "
# Check if the /dev/loop/by-ref/$name symlink really references the right device
test " /dev/loop/by-ref/ $name " -ef " $LOOP "
# Detach by the /dev/loop/by-ref symlink
systemd-dissect --detach " /dev/loop/by-ref/ $name "
2023-04-07 11:17:15 +03:00
name = " $( for _ in { 1..63} ; do echo -n 'x' ; done ) "
2023-03-13 17:36:32 +03:00
LOOP = " $( systemd-dissect --attach --loop-ref= " $name " " ${ image } .raw " ) "
udevadm trigger -w " $LOOP "
# Check if the /dev/loop/by-ref/$name symlink does not exist
test ! -e " /dev/loop/by-ref/ $name "
2023-03-06 15:23:48 +03:00
# Detach by backing inode
systemd-dissect --detach " ${ image } .raw "
( ! systemd-dissect --detach " ${ image } .raw " )
2023-02-24 11:35:38 +03:00
# check for confext functionality
mkdir -p /run/confexts/test/etc/extension-release.d
echo "ID=_any" >/run/confexts/test/etc/extension-release.d/extension-release.test
echo "ARCHITECTURE=_any" >>/run/confexts/test/etc/extension-release.d/extension-release.test
echo "MARKER_CONFEXT_123" >/run/confexts/test/etc/testfile
2023-04-05 16:50:42 +03:00
cat <<EOF >/run/confexts/test/etc/testscript
2023-04-06 14:19:22 +03:00
#!/bin/bash
echo "This should not happen"
EOF
chmod +x /run/confexts/test/etc/testscript
2023-02-24 11:35:38 +03:00
systemd-confext merge
grep -q -F "MARKER_CONFEXT_123" /etc/testfile
2023-04-05 16:50:42 +03:00
( ! /etc/testscript)
2023-02-24 11:35:38 +03:00
systemd-confext status
systemd-confext unmerge
rm -rf /run/confexts/
2023-06-20 14:54:07 +03:00
unsquashfs -no-xattrs -d /tmp/img " ${ image } .raw "
systemd-run --unit= test-root-ephemeral \
-p RootDirectory = /tmp/img \
-p RootEphemeral = yes \
-p Type = exec \
bash -c "touch /abc && sleep infinity"
test -n " $( ls -A /var/lib/systemd/ephemeral-trees) "
systemctl stop test-root-ephemeral
# shellcheck disable=SC2016
timeout 10 bash -c 'while ! test -z "$(ls -A /var/lib/systemd/ephemeral-trees)"; do sleep .5; done'
test ! -f /tmp/img/abc
2023-07-06 11:58:44 +03:00
systemd-dissect --mtree /tmp/img
systemd-dissect --list /tmp/img
read -r SHA256SUM1 _ < <( systemd-dissect --copy-from /tmp/img etc/os-release | sha256sum)
test " $SHA256SUM1 " != ""
echo abc > abc
systemd-dissect --copy-to /tmp/img abc /abc
test -f /tmp/img/abc
2023-07-14 01:10:01 +03:00
# Test for dissect tool support with systemd-sysext
mkdir -p /run/extensions/ testkit/usr/lib/extension-release.d/
echo "ID=_any" >testkit/usr/lib/extension-release.d/extension-release.testkit
echo "ARCHITECTURE=_any" >>testkit/usr/lib/extension-release.d/extension-release.testkit
echo "MARKER_SYSEXT_123" >testkit/usr/lib/testfile
mksquashfs testkit/ testkit.raw
cp testkit.raw /run/extensions/
unsquashfs -l /run/extensions/testkit.raw
systemd-dissect --no-pager /run/extensions/testkit.raw | grep -q '✓ sysext extension for portable service'
systemd-dissect --no-pager /run/extensions/testkit.raw | grep -q '✓ sysext extension for system'
systemd-sysext merge
systemd-sysext status
grep -q -F "MARKER_SYSEXT_123" /usr/lib/testfile
systemd-sysext unmerge
rm -rf /run/extensions/ testkit/
# Test for dissect tool support with systemd-confext
mkdir -p /run/confexts/ testjob/etc/extension-release.d/
echo "ID=_any" >testjob/etc/extension-release.d/extension-release.testjob
echo "ARCHITECTURE=_any" >>testjob/etc/extension-release.d/extension-release.testjob
echo "MARKER_CONFEXT_123" >testjob/etc/testfile
mksquashfs testjob/ testjob.raw
cp testjob.raw /run/confexts/
unsquashfs -l /run/confexts/testjob.raw
systemd-dissect --no-pager /run/confexts/testjob.raw | grep -q '✓ confext extension for system'
systemd-dissect --no-pager /run/confexts/testjob.raw | grep -q '✓ confext extension for portable service'
systemd-confext merge
systemd-confext status
grep -q -F "MARKER_CONFEXT_123" /etc/testfile
systemd-confext unmerge
rm -rf /run/confexts/ testjob/
2023-07-12 16:49:55 +03:00
touch /testok