]>
Commit | Line | Data |
---|---|---|
e7cbe5cb | 1 | #!/usr/bin/env bash |
7b3cec95 | 2 | # SPDX-License-Identifier: LGPL-2.1-or-later |
e7cbe5cb LB |
3 | # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- |
4 | # ex: ts=8 sw=4 sts=4 et filetype=sh | |
084575ff | 5 | set -eux |
e7cbe5cb LB |
6 | set -o pipefail |
7 | ||
08de6f94 LB |
8 | export SYSTEMD_LOG_LEVEL=debug |
9 | ||
d3fcb736 YW |
10 | cleanup() {( |
11 | set +ex | |
12 | ||
69398734 LB |
13 | if [ -z "${image_dir}" ]; then |
14 | return | |
15 | fi | |
d3fcb736 YW |
16 | umount "${image_dir}/app0" |
17 | umount "${image_dir}/app1" | |
18 | umount "${image_dir}/app-nodistro" | |
69398734 | 19 | rm -rf "${image_dir}" |
d3fcb736 | 20 | )} |
69398734 | 21 | |
20d4b3cc YW |
22 | udevadm control --log-level=debug |
23 | ||
e7cbe5cb LB |
24 | cd /tmp |
25 | ||
69398734 LB |
26 | image_dir="$(mktemp -d -t -p /tmp tmp.XXXXXX)" |
27 | if [ -z "${image_dir}" ] || [ ! -d "${image_dir}" ]; then | |
28 | echo "mktemp under /tmp failed" | |
29 | exit 1 | |
e7cbe5cb LB |
30 | fi |
31 | ||
69398734 LB |
32 | trap cleanup EXIT |
33 | ||
9785c44d LB |
34 | cp /usr/share/minimal* "${image_dir}/" |
35 | image="${image_dir}/minimal_0" | |
38825267 FS |
36 | roothash="$(cat "${image}.roothash")" |
37 | ||
38 | os_release="$(test -e /etc/os-release && echo /etc/os-release || echo /usr/lib/os-release)" | |
39 | ||
40 | 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"' | |
41 | systemd-dissect "${image}.raw" | grep -q -F "MARKER=1" | |
42 | systemd-dissect "${image}.raw" | grep -q -F -f <(sed 's/"//g' "$os_release") | |
43 | ||
efffde8e | 44 | systemd-dissect --list "${image}.raw" | grep -q '^etc/os-release$' |
baf6c932 | 45 | systemd-dissect --mtree "${image}.raw" | grep -q "./usr/bin/cat type=file mode=0755 uid=0 gid=0" |
efffde8e LP |
46 | |
47 | read -r SHA256SUM1 _ < <(systemd-dissect --copy-from "${image}.raw" etc/os-release | sha256sum) | |
48 | test "$SHA256SUM1" != "" | |
49 | read -r SHA256SUM2 _ < <(systemd-dissect --read-only --with "${image}.raw" sha256sum etc/os-release) | |
50 | test "$SHA256SUM2" != "" | |
51 | test "$SHA256SUM1" = "$SHA256SUM2" | |
52 | ||
38825267 FS |
53 | mv "${image}.verity" "${image}.fooverity" |
54 | mv "${image}.roothash" "${image}.foohash" | |
55 | 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"' | |
56 | systemd-dissect "${image}.raw" --root-hash="${roothash}" --verity-data="${image}.fooverity" | grep -q -F "MARKER=1" | |
57 | systemd-dissect "${image}.raw" --root-hash="${roothash}" --verity-data="${image}.fooverity" | grep -q -F -f <(sed 's/"//g' "$os_release") | |
58 | mv "${image}.fooverity" "${image}.verity" | |
59 | mv "${image}.foohash" "${image}.roothash" | |
60 | ||
61 | mkdir -p "${image_dir}/mount" "${image_dir}/mount2" | |
62 | systemd-dissect --mount "${image}.raw" "${image_dir}/mount" | |
63 | grep -q -F -f "$os_release" "${image_dir}/mount/usr/lib/os-release" | |
64 | grep -q -F -f "$os_release" "${image_dir}/mount/etc/os-release" | |
65 | grep -q -F "MARKER=1" "${image_dir}/mount/usr/lib/os-release" | |
ac1f3ad0 | 66 | # Verity volume should be shared (opened only once) |
38825267 FS |
67 | systemd-dissect --mount "${image}.raw" "${image_dir}/mount2" |
68 | verity_count=$(find /dev/mapper/ -name "*verity*" | wc -l) | |
ac1f3ad0 LB |
69 | # In theory we should check that count is exactly one. In practice, libdevmapper |
70 | # randomly and unpredictably fails with an unhelpful EINVAL when a device is open | |
71 | # (and even mounted and in use), so best-effort is the most we can do for now | |
38825267 | 72 | if [ "${verity_count}" -lt 1 ]; then |
ac1f3ad0 LB |
73 | echo "Verity device ${image}.raw not found in /dev/mapper/" |
74 | exit 1 | |
75 | fi | |
ac1f1adf DDM |
76 | systemd-dissect --umount "${image_dir}/mount" |
77 | systemd-dissect --umount "${image_dir}/mount2" | |
e7cbe5cb | 78 | |
43ed3d29 | 79 | systemd-run -P -p RootImage="${image}.raw" cat /usr/lib/os-release | grep -q -F "MARKER=1" |
38825267 FS |
80 | mv "${image}.verity" "${image}.fooverity" |
81 | mv "${image}.roothash" "${image}.foohash" | |
43ed3d29 | 82 | 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" |
d583cf45 | 83 | # Let's use the long option name just here as a test |
43ed3d29 | 84 | systemd-run -P --property RootImage="${image}.raw" --property RootHash="${roothash}" --property RootVerity="${image}.fooverity" cat /usr/lib/os-release | grep -q -F "MARKER=1" |
38825267 FS |
85 | mv "${image}.fooverity" "${image}.verity" |
86 | mv "${image}.foohash" "${image}.roothash" | |
2bc148ad | 87 | |
a5f1d665 LB |
88 | # Make a GPT disk on the fly, with the squashfs as partition 1 and the verity hash tree as partition 2 |
89 | machine="$(uname -m)" | |
90 | if [ "${machine}" = "x86_64" ]; then | |
91 | root_guid=4f68bce3-e8cd-4db1-96e7-fbcaf984b709 | |
92 | verity_guid=2c7357ed-ebd2-46d9-aec1-23d437ec2bf5 | |
2c424ee0 | 93 | signature_guid=41092b05-9fc8-4523-994f-2def0408b176 |
91987527 | 94 | architecture="x86-64" |
a5f1d665 LB |
95 | elif [ "${machine}" = "i386" ] || [ "${machine}" = "i686" ] || [ "${machine}" = "x86" ]; then |
96 | root_guid=44479540-f297-41b2-9af7-d131d5f0458a | |
97 | verity_guid=d13c5d3b-b5d1-422a-b29f-9454fdc89d76 | |
2c424ee0 | 98 | signature_guid=5996fc05-109c-48de-808b-23fa0830b676 |
91987527 | 99 | architecture="x86" |
a5f1d665 LB |
100 | elif [ "${machine}" = "aarch64" ] || [ "${machine}" = "aarch64_be" ] || [ "${machine}" = "armv8b" ] || [ "${machine}" = "armv8l" ]; then |
101 | root_guid=b921b045-1df0-41c3-af44-4c6f280d3fae | |
102 | verity_guid=df3300ce-d69f-4c92-978c-9bfb0f38d820 | |
2c424ee0 | 103 | signature_guid=6db69de6-29f4-4758-a7a5-962190f00ce3 |
91987527 | 104 | architecture="arm64" |
a5f1d665 LB |
105 | elif [ "${machine}" = "arm" ]; then |
106 | root_guid=69dad710-2ce4-4e3c-b16c-21a1d49abed3 | |
107 | verity_guid=7386cdf2-203c-47a9-a498-f2ecce45a2d6 | |
2c424ee0 | 108 | signature_guid=42b0455f-eb11-491d-98d3-56145ba9d037 |
91987527 | 109 | architecture="arm" |
0444a6e4 XW |
110 | elif [ "${machine}" = "loongarch64" ]; then |
111 | root_guid=77055800-792c-4f94-b39a-98c91b762bb6 | |
112 | verity_guid=f3393b22-e9af-4613-a948-9d3bfbd0c535 | |
113 | signature_guid=5afb67eb-ecc8-4f85-ae8e-ac1e7c50e7d0 | |
114 | architecture="loongarch64" | |
a5f1d665 LB |
115 | elif [ "${machine}" = "ia64" ]; then |
116 | root_guid=993d8d3d-f80e-4225-855a-9daf8ed7ea97 | |
117 | verity_guid=86ed10d5-b607-45bb-8957-d350f23d0571 | |
2c424ee0 | 118 | signature_guid=e98b36ee-32ba-4882-9b12-0ce14655f46a |
91987527 | 119 | architecture="ia64" |
a94b9977 LB |
120 | elif [ "${machine}" = "s390x" ]; then |
121 | root_guid=5eead9a9-fe09-4a1e-a1d7-520d00531306 | |
122 | verity_guid=b325bfbe-c7be-4ab8-8357-139e652d2f6b | |
123 | signature_guid=c80187a5-73a3-491a-901a-017c3fa953e9 | |
124 | architecture="s390x" | |
91987527 | 125 | elif [ "${machine}" = "ppc64le" ]; then |
a94b9977 LB |
126 | root_guid=c31c45e6-3f39-412e-80fb-4809c4980599 |
127 | verity_guid=906bd944-4589-4aae-a4e4-dd983917446a | |
128 | signature_guid=d4a236e7-e873-4c07-bf1d-bf6cf7f1c3c6 | |
129 | architecture="ppc64-le" | |
08de6f94 LB |
130 | else |
131 | echo "Unexpected uname -m: ${machine} in testsuite-50.sh, please fix me" | |
132 | exit 1 | |
a5f1d665 LB |
133 | fi |
134 | # du rounds up to block size, which is more helpful for partitioning | |
38825267 FS |
135 | root_size="$(du -k "${image}.raw" | cut -f1)" |
136 | verity_size="$(du -k "${image}.verity" | cut -f1)" | |
2c424ee0 | 137 | signature_size=4 |
a5f1d665 | 138 | # 4MB seems to be the minimum size blkid will accept, below that probing fails |
2c424ee0 | 139 | dd if=/dev/zero of="${image}.gpt" bs=512 count=$((8192+root_size*2+verity_size*2+signature_size*2)) |
a5f1d665 LB |
140 | # sfdisk seems unhappy if the size overflows into the next unit, eg: 1580KiB will be interpreted as 1MiB |
141 | # so do some basic rounding up if the minimal image is more than 1 MB | |
38825267 FS |
142 | if [ "${root_size}" -ge 1024 ]; then |
143 | root_size="$((root_size/1024 + 1))MiB" | |
a5f1d665 LB |
144 | else |
145 | root_size="${root_size}KiB" | |
146 | fi | |
38825267 | 147 | verity_size="$((verity_size * 2))KiB" |
2c424ee0 LP |
148 | signature_size="$((signature_size * 2))KiB" |
149 | ||
c9d1c37c LB |
150 | HAVE_OPENSSL=0 |
151 | if systemctl --version | grep -q -- +OPENSSL ; then | |
85e3a3a8 MB |
152 | # The openssl binary is installed conditionally. |
153 | # If we have OpenSSL support enabled and openssl is missing, fail early | |
154 | # with a proper error message. | |
155 | if ! command -v openssl >/dev/null 2>&1; then | |
156 | echo "openssl missing" >/failed | |
157 | exit 1 | |
158 | fi | |
c9d1c37c LB |
159 | HAVE_OPENSSL=1 |
160 | # Unfortunately OpenSSL insists on reading some config file, hence provide one with mostly placeholder contents | |
7a17e41d | 161 | cat >>"${image}.openssl.cnf" <<EOF |
2c424ee0 LP |
162 | [ req ] |
163 | prompt = no | |
164 | distinguished_name = req_distinguished_name | |
165 | ||
166 | [ req_distinguished_name ] | |
167 | C = DE | |
168 | ST = Test State | |
169 | L = Test Locality | |
170 | O = Org Name | |
171 | OU = Org Unit Name | |
172 | CN = Common Name | |
173 | emailAddress = test@email.com | |
174 | EOF | |
175 | ||
c9d1c37c LB |
176 | # Create key pair |
177 | openssl req -config "${image}.openssl.cnf" -new -x509 -newkey rsa:1024 -keyout "${image}.key" -out "${image}.crt" -days 365 -nodes | |
178 | # Sign Verity root hash with it | |
179 | openssl smime -sign -nocerts -noattr -binary -in "${image}.roothash" -inkey "${image}.key" -signer "${image}.crt" -outform der -out "${image}.roothash.p7s" | |
180 | # Generate signature partition JSON data | |
7a17e41d | 181 | echo '{"rootHash":"'"${roothash}"'","signature":"'"$(base64 -w 0 <"${image}.roothash.p7s")"'"}' >"${image}.verity-sig" |
c9d1c37c LB |
182 | # Pad it |
183 | truncate -s "${signature_size}" "${image}.verity-sig" | |
184 | # Register certificate in the (userspace) verity key ring | |
185 | mkdir -p /run/verity.d | |
186 | ln -s "${image}.crt" /run/verity.d/ok.crt | |
187 | fi | |
2c424ee0 | 188 | |
38825267 FS |
189 | # Construct a UUID from hash |
190 | # input: 11111111222233334444555566667777 | |
191 | # output: 11111111-2222-3333-4444-555566667777 | |
192 | uuid="$(head -c 32 "${image}.roothash" | sed -r 's/(.{8})(.{4})(.{4})(.{4})(.+)/\1-\2-\3-\4-\5/')" | |
193 | echo -e "label: gpt\nsize=${root_size}, type=${root_guid}, uuid=${uuid}" | sfdisk "${image}.gpt" | |
194 | uuid="$(tail -c 32 "${image}.roothash" | sed -r 's/(.{8})(.{4})(.{4})(.{4})(.+)/\1-\2-\3-\4-\5/')" | |
195 | echo -e "size=${verity_size}, type=${verity_guid}, uuid=${uuid}" | sfdisk "${image}.gpt" --append | |
c9d1c37c LB |
196 | if [ "${HAVE_OPENSSL}" -eq 1 ]; then |
197 | echo -e "size=${signature_size}, type=${signature_guid}" | sfdisk "${image}.gpt" --append | |
198 | fi | |
38825267 FS |
199 | sfdisk --part-label "${image}.gpt" 1 "Root Partition" |
200 | sfdisk --part-label "${image}.gpt" 2 "Verity Partition" | |
c9d1c37c LB |
201 | if [ "${HAVE_OPENSSL}" -eq 1 ]; then |
202 | sfdisk --part-label "${image}.gpt" 3 "Signature Partition" | |
203 | fi | |
38825267 | 204 | loop="$(losetup --show -P -f "${image}.gpt")" |
ba44a5c7 YW |
205 | partitions=( |
206 | "${loop:?}p1" | |
207 | "${loop:?}p2" | |
208 | ) | |
c9d1c37c | 209 | if [ "${HAVE_OPENSSL}" -eq 1 ]; then |
ba44a5c7 YW |
210 | partitions+=( "${loop:?}p3" ) |
211 | fi | |
212 | # The kernel sometimes(?) does not emit "add" uevent for loop block partition devices. | |
213 | # Let's not expect the devices to be initialized. | |
214 | udevadm wait --timeout 60 --settle --initialized=no "${partitions[@]}" | |
215 | udevadm lock --device="${loop}p1" dd if="${image}.raw" of="${loop}p1" | |
216 | udevadm lock --device="${loop}p2" dd if="${image}.verity" of="${loop}p2" | |
217 | if [ "${HAVE_OPENSSL}" -eq 1 ]; then | |
218 | udevadm lock --device="${loop}p3" dd if="${image}.verity-sig" of="${loop}p3" | |
c9d1c37c | 219 | fi |
38825267 | 220 | losetup -d "${loop}" |
a5f1d665 | 221 | |
35afe47a | 222 | # Derive partition UUIDs from root hash, in UUID syntax |
38825267 FS |
223 | ROOT_UUID="$(systemd-id128 -u show "$(head -c 32 "${image}.roothash")" -u | tail -n 1 | cut -b 6-)" |
224 | VERITY_UUID="$(systemd-id128 -u show "$(tail -c 32 "${image}.roothash")" -u | tail -n 1 | cut -b 6-)" | |
a5f1d665 | 225 | |
3dd73ea7 | 226 | 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",' |
ee8e497d | 227 | 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,' |
3dd73ea7 DDM |
228 | if [ "${HAVE_OPENSSL}" -eq 1 ]; then |
229 | 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,' | |
230 | fi | |
38825267 FS |
231 | systemd-dissect --root-hash "${roothash}" "${image}.gpt" | grep -q -F "MARKER=1" |
232 | systemd-dissect --root-hash "${roothash}" "${image}.gpt" | grep -q -F -f <(sed 's/"//g' "$os_release") | |
35afe47a | 233 | |
38825267 FS |
234 | systemd-dissect --root-hash "${roothash}" --mount "${image}.gpt" "${image_dir}/mount" |
235 | grep -q -F -f "$os_release" "${image_dir}/mount/usr/lib/os-release" | |
236 | grep -q -F -f "$os_release" "${image_dir}/mount/etc/os-release" | |
237 | grep -q -F "MARKER=1" "${image_dir}/mount/usr/lib/os-release" | |
ac1f1adf | 238 | systemd-dissect --umount "${image_dir}/mount" |
a5f1d665 | 239 | |
971d83a8 LP |
240 | systemd-dissect --root-hash "${roothash}" --mount "${image}.gpt" --in-memory "${image_dir}/mount" |
241 | grep -q -F -f "$os_release" "${image_dir}/mount/usr/lib/os-release" | |
242 | grep -q -F -f "$os_release" "${image_dir}/mount/etc/os-release" | |
243 | grep -q -F "MARKER=1" "${image_dir}/mount/usr/lib/os-release" | |
244 | systemd-dissect --umount "${image_dir}/mount" | |
245 | ||
d583cf45 | 246 | # add explicit -p MountAPIVFS=yes once to test the parser |
43ed3d29 | 247 | systemd-run -P -p RootImage="${image}.gpt" -p RootHash="${roothash}" -p MountAPIVFS=yes cat /usr/lib/os-release | grep -q -F "MARKER=1" |
2bc148ad | 248 | |
43ed3d29 LP |
249 | 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" |
250 | systemd-run -P -p RootImage="${image}.gpt" -p RootImageOptions="root:ro,noatime root:ro,dev" mount | grep -F "squashfs" | grep -q -F "noatime" | |
18d73705 | 251 | |
38825267 | 252 | mkdir -p "${image_dir}/result" |
d583cf45 | 253 | cat >/run/systemd/system/testservice-50a.service <<EOF |
18d73705 LB |
254 | [Service] |
255 | Type=oneshot | |
d583cf45 | 256 | ExecStart=bash -c "mount >/run/result/a" |
9ece6444 LB |
257 | BindPaths=${image_dir}/result:/run/result |
258 | TemporaryFileSystem=/run | |
18d73705 | 259 | RootImage=${image}.raw |
9ece6444 | 260 | RootImageOptions=root:ro,noatime home:ro,dev relatime,dev |
18d73705 LB |
261 | RootImageOptions=nosuid,dev |
262 | EOF | |
263 | systemctl start testservice-50a.service | |
38825267 FS |
264 | grep -F "squashfs" "${image_dir}/result/a" | grep -q -F "noatime" |
265 | grep -F "squashfs" "${image_dir}/result/a" | grep -q -F -v "nosuid" | |
18d73705 | 266 | |
d583cf45 | 267 | cat >/run/systemd/system/testservice-50b.service <<EOF |
18d73705 LB |
268 | [Service] |
269 | Type=oneshot | |
d583cf45 | 270 | ExecStart=bash -c "mount >/run/result/b" |
9ece6444 LB |
271 | BindPaths=${image_dir}/result:/run/result |
272 | TemporaryFileSystem=/run | |
18d73705 | 273 | RootImage=${image}.gpt |
9ece6444 LB |
274 | RootImageOptions=root:ro,noatime,nosuid home:ro,dev nosuid,dev |
275 | RootImageOptions=home:ro,dev nosuid,dev,%%foo | |
d583cf45 ZJS |
276 | # this is the default, but let's specify once to test the parser |
277 | MountAPIVFS=yes | |
18d73705 LB |
278 | EOF |
279 | systemctl start testservice-50b.service | |
38825267 | 280 | grep -F "squashfs" "${image_dir}/result/b" | grep -q -F "noatime" |
18d73705 | 281 | |
d583cf45 | 282 | # Check that specifier escape is applied %%foo → %foo |
18d73705 LB |
283 | busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1/unit/testservice_2d50b_2eservice org.freedesktop.systemd1.Service RootImageOptions | grep -F "nosuid,dev,%foo" |
284 | ||
427353f6 | 285 | # Now do some checks with MountImages, both by itself, with options and in combination with RootImage, and as single FS or GPT image |
43ed3d29 LP |
286 | 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" |
287 | 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" | |
288 | systemd-run -P -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2:nosuid,dev" mount | grep -F "squashfs" | grep -q -F "nosuid" | |
289 | 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" | |
290 | systemd-run -P -p MountImages="${image}.raw:/run/img2\:3" cat /run/img2:3/usr/lib/os-release | grep -q -F "MARKER=1" | |
291 | systemd-run -P -p MountImages="${image}.raw:/run/img2\:3:nosuid" mount | grep -F "squashfs" | grep -q -F "nosuid" | |
292 | 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" | |
293 | 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" | |
294 | 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" | |
427353f6 | 295 | cat >/run/systemd/system/testservice-50c.service <<EOF |
b3d13314 | 296 | [Service] |
427353f6 | 297 | MountAPIVFS=yes |
b3d13314 LB |
298 | TemporaryFileSystem=/run |
299 | RootImage=${image}.raw | |
427353f6 LB |
300 | MountImages=${image}.gpt:/run/img1:root:noatime:home:relatime |
301 | MountImages=${image}.raw:/run/img2\:3:nosuid | |
d583cf45 ZJS |
302 | ExecStart=bash -c "cat /run/img1/usr/lib/os-release >/run/result/c" |
303 | ExecStart=bash -c "cat /run/img2:3/usr/lib/os-release >>/run/result/c" | |
304 | ExecStart=bash -c "mount >>/run/result/c" | |
427353f6 | 305 | BindPaths=${image_dir}/result:/run/result |
b3d13314 LB |
306 | Type=oneshot |
307 | EOF | |
427353f6 | 308 | systemctl start testservice-50c.service |
38825267 FS |
309 | grep -q -F "MARKER=1" "${image_dir}/result/c" |
310 | grep -F "squashfs" "${image_dir}/result/c" | grep -q -F "noatime" | |
311 | grep -F "squashfs" "${image_dir}/result/c" | grep -q -F -v "nosuid" | |
b3d13314 | 312 | |
6faecbd3 LB |
313 | # Adding a new mounts at runtime works if the unit is in the active state, |
314 | # so use Type=notify to make sure there's no race condition in the test | |
0ee99483 | 315 | cat >/run/systemd/system/testservice-50d.service <<EOF |
6faecbd3 LB |
316 | [Service] |
317 | RuntimeMaxSec=300 | |
318 | Type=notify | |
319 | RemainAfterExit=yes | |
320 | MountAPIVFS=yes | |
321 | PrivateTmp=yes | |
759b4b4a YW |
322 | ExecStart=/bin/sh -c ' \\ |
323 | systemd-notify --ready; \\ | |
324 | while [[ ! -f /tmp/img/usr/lib/os-release ]] || ! grep -q -F MARKER /tmp/img/usr/lib/os-release; do \\ | |
325 | sleep 0.1; \\ | |
326 | done; \\ | |
327 | mount; \\ | |
328 | mount | grep -F "on /tmp/img type squashfs" | grep -q -F "nosuid"; \\ | |
329 | ' | |
6faecbd3 LB |
330 | EOF |
331 | systemctl start testservice-50d.service | |
332 | ||
38825267 | 333 | systemctl mount-image --mkdir testservice-50d.service "${image}.raw" /tmp/img root:nosuid |
6faecbd3 LB |
334 | |
335 | while systemctl show -P SubState testservice-50d.service | grep -q running | |
336 | do | |
337 | sleep 0.1 | |
338 | done | |
339 | ||
340 | systemctl is-active testservice-50d.service | |
341 | ||
93f59701 | 342 | # ExtensionImages will set up an overlay |
43ed3d29 LP |
343 | systemd-run -P --property ExtensionImages=/usr/share/app0.raw --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0" |
344 | 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" | |
345 | 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" | |
346 | 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" | |
9a4b883b | 347 | 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" |
43ed3d29 | 348 | 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" |
ab4d43c5 | 349 | 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" |
e374439f KL |
350 | # Check that using a symlink to NAME-VERSION.raw works as long as the symlink has the correct name NAME.raw |
351 | mkdir -p /usr/share/symlink-test/ | |
352 | cp /usr/share/app-nodistro.raw /usr/share/symlink-test/app-nodistro-v1.raw | |
353 | ln -fs /usr/share/symlink-test/app-nodistro-v1.raw /usr/share/symlink-test/app-nodistro.raw | |
354 | 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" | |
93f59701 LB |
355 | cat >/run/systemd/system/testservice-50e.service <<EOF |
356 | [Service] | |
357 | MountAPIVFS=yes | |
3fa80e5e LB |
358 | TemporaryFileSystem=/run /var/lib |
359 | StateDirectory=app0 | |
93f59701 LB |
360 | RootImage=${image}.raw |
361 | ExtensionImages=/usr/share/app0.raw /usr/share/app1.raw:nosuid | |
c335b7c3 FS |
362 | # Relevant only for sanitizer runs |
363 | UnsetEnvironment=LD_PRELOAD | |
93f59701 LB |
364 | ExecStart=/bin/bash -c '/opt/script0.sh | grep ID' |
365 | ExecStart=/bin/bash -c '/opt/script1.sh | grep ID' | |
366 | Type=oneshot | |
367 | RemainAfterExit=yes | |
368 | EOF | |
369 | systemctl start testservice-50e.service | |
370 | systemctl is-active testservice-50e.service | |
371 | ||
a07b9926 | 372 | # ExtensionDirectories will set up an overlay |
ab4d43c5 | 373 | mkdir -p "${image_dir}/app0" "${image_dir}/app1" "${image_dir}/app-nodistro" |
e6d31fc9 | 374 | systemd-run -P --property ExtensionDirectories="${image_dir}/nonexistent" --property RootImage="${image}.raw" cat /opt/script0.sh && { echo 'unexpected success'; exit 1; } |
a07b9926 LB |
375 | systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /opt/script0.sh && { echo 'unexpected success'; exit 1; } |
376 | systemd-dissect --mount /usr/share/app0.raw "${image_dir}/app0" | |
377 | systemd-dissect --mount /usr/share/app1.raw "${image_dir}/app1" | |
ab4d43c5 | 378 | systemd-dissect --mount /usr/share/app-nodistro.raw "${image_dir}/app-nodistro" |
a07b9926 LB |
379 | systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0" |
380 | systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" | |
381 | 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" | |
382 | 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" | |
383 | 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" | |
384 | 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" | |
ab4d43c5 | 385 | 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" |
a07b9926 LB |
386 | cat >/run/systemd/system/testservice-50f.service <<EOF |
387 | [Service] | |
388 | MountAPIVFS=yes | |
3fa80e5e LB |
389 | TemporaryFileSystem=/run /var/lib |
390 | StateDirectory=app0 | |
a07b9926 LB |
391 | RootImage=${image}.raw |
392 | ExtensionDirectories=${image_dir}/app0 ${image_dir}/app1 | |
393 | # Relevant only for sanitizer runs | |
394 | UnsetEnvironment=LD_PRELOAD | |
395 | ExecStart=/bin/bash -c '/opt/script0.sh | grep ID' | |
396 | ExecStart=/bin/bash -c '/opt/script1.sh | grep ID' | |
397 | Type=oneshot | |
398 | RemainAfterExit=yes | |
399 | EOF | |
400 | systemctl start testservice-50f.service | |
401 | systemctl is-active testservice-50f.service | |
ac1f1adf DDM |
402 | systemd-dissect --umount "${image_dir}/app0" |
403 | systemd-dissect --umount "${image_dir}/app1" | |
a07b9926 | 404 | |
1abe15fe KL |
405 | # Test that an extension consisting of an empty directory under /etc/extensions/ takes precedence |
406 | mkdir -p /var/lib/extensions/ | |
407 | ln -s /usr/share/app-nodistro.raw /var/lib/extensions/app-nodistro.raw | |
408 | systemd-sysext merge | |
409 | grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file | |
410 | systemd-sysext unmerge | |
411 | mkdir -p /etc/extensions/app-nodistro | |
412 | systemd-sysext merge | |
413 | test ! -e /usr/lib/systemd/system/some_file | |
414 | systemd-sysext unmerge | |
415 | rmdir /etc/extensions/app-nodistro | |
416 | rm /var/lib/extensions/app-nodistro.raw | |
417 | ||
0305cf6e LP |
418 | mkdir -p /run/machines /run/portables /run/extensions |
419 | touch /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw | |
420 | ||
7a17e41d | 421 | systemd-dissect --discover --json=short >/tmp/discover.json |
0305cf6e LP |
422 | grep -q -F '{"name":"a","type":"raw","class":"machine","ro":false,"path":"/run/machines/a.raw"' /tmp/discover.json |
423 | grep -q -F '{"name":"b","type":"raw","class":"portable","ro":false,"path":"/run/portables/b.raw"' /tmp/discover.json | |
424 | grep -q -F '{"name":"c","type":"raw","class":"extension","ro":false,"path":"/run/extensions/c.raw"' /tmp/discover.json | |
425 | rm /tmp/discover.json /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw | |
426 | ||
d583cf45 | 427 | echo OK >/testok |
e7cbe5cb LB |
428 | |
429 | exit 0 |