Bug Summary

File:build-scan/../src/shared/dissect-image.c
Warning:line 370, column 33
Potential leak of memory pointed to by 'generic_node'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name dissect-image.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I src/shared/libsystemd-shared-239.a.p -I src/shared -I ../src/shared -I src/basic -I ../src/basic -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I . -I .. -I /usr/include/blkid -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility default -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/shared/dissect-image.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <sys/mount.h>
4#include <sys/prctl.h>
5#include <sys/wait.h>
6
7#include "sd-id128.h"
8
9#include "architecture.h"
10#include "ask-password-api.h"
11#include "blkid-util.h"
12#include "blockdev-util.h"
13#include "copy.h"
14#include "crypt-util.h"
15#include "def.h"
16#include "device-nodes.h"
17#include "dissect-image.h"
18#include "fd-util.h"
19#include "fileio.h"
20#include "fs-util.h"
21#include "gpt.h"
22#include "hexdecoct.h"
23#include "hostname-util.h"
24#include "id128-util.h"
25#include "linux-3.13/dm-ioctl.h"
26#include "missing.h"
27#include "mount-util.h"
28#include "os-util.h"
29#include "path-util.h"
30#include "process-util.h"
31#include "raw-clone.h"
32#include "signal-util.h"
33#include "stat-util.h"
34#include "stdio-util.h"
35#include "string-table.h"
36#include "string-util.h"
37#include "strv.h"
38#include "udev-util.h"
39#include "user-util.h"
40#include "xattr-util.h"
41
42int probe_filesystem(const char *node, char **ret_fstype) {
43 /* Try to find device content type and return it in *ret_fstype. If nothing is found,
44 * 0/NULL will be returned. -EUCLEAN will be returned for ambigous results, and an
45 * different error otherwise. */
46
47#if HAVE_BLKID1
48 _cleanup_(blkid_free_probep)__attribute__((cleanup(blkid_free_probep))) blkid_probe b = NULL((void*)0);
49 const char *fstype;
50 int r;
51
52 errno(*__errno_location ()) = 0;
53 b = blkid_new_probe_from_filename(node);
54 if (!b)
55 return -errno(*__errno_location ()) ?: -ENOMEM12;
56
57 blkid_probe_enable_superblocks(b, 1);
58 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE(1 << 5));
59
60 errno(*__errno_location ()) = 0;
61 r = blkid_do_safeprobe(b);
62 if (r == 1) {
63 log_debug("No type detected on partition %s", node)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 63, __func__, "No type detected on partition %s"
, node) : -abs(_e); })
;
64 goto not_found;
65 }
66 if (r == -2) {
67 log_debug("Results ambiguous for partition %s", node)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 67, __func__, "Results ambiguous for partition %s"
, node) : -abs(_e); })
;
68 return -EUCLEAN117;
69 }
70 if (r != 0)
71 return -errno(*__errno_location ()) ?: -EIO5;
72
73 (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL((void*)0));
74
75 if (fstype) {
76 char *t;
77
78 t = strdup(fstype);
79 if (!t)
80 return -ENOMEM12;
81
82 *ret_fstype = t;
83 return 1;
84 }
85
86not_found:
87 *ret_fstype = NULL((void*)0);
88 return 0;
89#else
90 return -EOPNOTSUPP95;
91#endif
92}
93
94#if HAVE_BLKID1
95/* Detect RPMB and Boot partitions, which are not listed by blkid.
96 * See https://github.com/systemd/systemd/issues/5806. */
97static bool_Bool device_is_mmc_special_partition(struct udev_device *d) {
98 const char *sysname;
99
100 sysname = udev_device_get_sysname(d);
101 return sysname && startswith(sysname, "mmcblk") &&
102 (endswith(sysname, "rpmb") || endswith(sysname, "boot0") || endswith(sysname, "boot1"));
103}
104
105static bool_Bool device_is_block(struct udev_device *d) {
106 const char *ss;
107
108 ss = udev_device_get_subsystem(d);
109 if (!ss)
110 return false0;
111
112 return streq(ss, "block")(strcmp((ss),("block")) == 0);
113}
114#endif
115
116int dissect_image(
117 int fd,
118 const void *root_hash,
119 size_t root_hash_size,
120 DissectImageFlags flags,
121 DissectedImage **ret) {
122
123#if HAVE_BLKID1
124 sd_id128_t root_uuid = SD_ID128_NULL((const sd_id128_t) { .qwords = { 0, 0 }}), verity_uuid = SD_ID128_NULL((const sd_id128_t) { .qwords = { 0, 0 }});
125 _cleanup_(udev_enumerate_unrefp)__attribute__((cleanup(udev_enumerate_unrefp))) struct udev_enumerate *e = NULL((void*)0);
126 bool_Bool is_gpt, is_mbr, generic_rw, multiple_generic = false0;
127 _cleanup_(udev_device_unrefp)__attribute__((cleanup(udev_device_unrefp))) struct udev_device *d = NULL((void*)0);
128 _cleanup_(dissected_image_unrefp)__attribute__((cleanup(dissected_image_unrefp))) DissectedImage *m = NULL((void*)0);
129 _cleanup_(blkid_free_probep)__attribute__((cleanup(blkid_free_probep))) blkid_probe b = NULL((void*)0);
130 _cleanup_(udev_unrefp)__attribute__((cleanup(udev_unrefp))) struct udev *udev = NULL((void*)0);
131 _cleanup_free___attribute__((cleanup(freep))) char *generic_node = NULL((void*)0);
132 sd_id128_t generic_uuid = SD_ID128_NULL((const sd_id128_t) { .qwords = { 0, 0 }});
133 const char *pttype = NULL((void*)0);
134 struct udev_list_entry *first, *item;
135 blkid_partlist pl;
136 int r, generic_nr;
137 struct stat st;
138 unsigned i;
139
140 assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/shared/dissect-image.c"
, 140, __PRETTY_FUNCTION__); } while (0)
;
1
Assuming 'fd' is >= 0
2
Taking false branch
3
Loop condition is false. Exiting loop
141 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/shared/dissect-image.c",
141, __PRETTY_FUNCTION__); } while (0)
;
4
Assuming 'ret' is non-null
5
Taking false branch
6
Loop condition is false. Exiting loop
142 assert(root_hash || root_hash_size == 0)do { if ((__builtin_expect(!!(!(root_hash || root_hash_size ==
0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("root_hash || root_hash_size == 0"
), "../src/shared/dissect-image.c", 142, __PRETTY_FUNCTION__)
; } while (0)
;
7
Assuming 'root_hash' is null
8
Assuming 'root_hash_size' is equal to 0
9
Taking false branch
10
Loop condition is false. Exiting loop
143
144 /* Probes a disk image, and returns information about what it found in *ret.
145 *
146 * Returns -ENOPKG if no suitable partition table or file system could be found.
147 * Returns -EADDRNOTAVAIL if a root hash was specified but no matching root/verity partitions found. */
148
149 if (root_hash
10.1
'root_hash' is null
) {
11
Taking false branch
150 /* If a root hash is supplied, then we use the root partition that has a UUID that match the first
151 * 128bit of the root hash. And we use the verity partition that has a UUID that match the final
152 * 128bit. */
153
154 if (root_hash_size < sizeof(sd_id128_t))
155 return -EINVAL22;
156
157 memcpy(&root_uuid, root_hash, sizeof(sd_id128_t));
158 memcpy(&verity_uuid, (const uint8_t*) root_hash + root_hash_size - sizeof(sd_id128_t), sizeof(sd_id128_t));
159
160 if (sd_id128_is_null(root_uuid))
161 return -EINVAL22;
162 if (sd_id128_is_null(verity_uuid))
163 return -EINVAL22;
164 }
165
166 if (fstat(fd, &st) < 0)
12
Assuming the condition is false
13
Taking false branch
167 return -errno(*__errno_location ());
168
169 if (!S_ISBLK(st.st_mode)((((st.st_mode)) & 0170000) == (0060000)))
14
Assuming the condition is true
15
Taking false branch
170 return -ENOTBLK15;
171
172 b = blkid_new_probe();
173 if (!b)
16
Assuming 'b' is non-null
17
Taking false branch
174 return -ENOMEM12;
175
176 errno(*__errno_location ()) = 0;
177 r = blkid_probe_set_device(b, fd, 0, 0);
178 if (r != 0)
18
Assuming 'r' is equal to 0
19
Taking false branch
179 return -errno(*__errno_location ()) ?: -ENOMEM12;
180
181 if ((flags & DISSECT_IMAGE_GPT_ONLY) == 0) {
20
Assuming the condition is false
21
Taking false branch
182 /* Look for file system superblocks, unless we only shall look for GPT partition tables */
183 blkid_probe_enable_superblocks(b, 1);
184 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE(1 << 5)|BLKID_SUBLKS_USAGE(1 << 7));
185 }
186
187 blkid_probe_enable_partitions(b, 1);
188 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS(1 << 2));
189
190 errno(*__errno_location ()) = 0;
191 r = blkid_do_safeprobe(b);
192 if (IN_SET(r, -2, 1)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){-2, 1})/sizeof(int)]; switch(r) { case -
2: case 1: _found = 1; break; default: break; } _found; })
) {
22
Control jumps to the 'default' case at line 192
23
Execution continues on line 192
24
Taking false branch
193 log_debug("Failed to identify any partition table.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 193, __func__, "Failed to identify any partition table."
) : -abs(_e); })
;
194 return -ENOPKG65;
195 }
196 if (r != 0)
25
Assuming 'r' is equal to 0
26
Taking false branch
197 return -errno(*__errno_location ()) ?: -EIO5;
198
199 m = new0(DissectedImage, 1)((DissectedImage*) calloc((1), sizeof(DissectedImage)));
200 if (!m)
27
Assuming 'm' is non-null
28
Taking false branch
201 return -ENOMEM12;
202
203 if (!(flags & DISSECT_IMAGE_GPT_ONLY) &&
204 (flags & DISSECT_IMAGE_REQUIRE_ROOT)) {
205 const char *usage = NULL((void*)0);
206
207 (void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL((void*)0));
208 if (STRPTR_IN_SET(usage, "filesystem", "crypto")({ const char* _x = (usage); _x && (!!strv_find((((char
**) ((const char*[]) { "filesystem", "crypto", ((void*)0) }))
), (_x))); })
) {
209 _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0), *n = NULL((void*)0);
210 const char *fstype = NULL((void*)0);
211
212 /* OK, we have found a file system, that's our root partition then. */
213 (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL((void*)0));
214
215 if (fstype) {
216 t = strdup(fstype);
217 if (!t)
218 return -ENOMEM12;
219 }
220
221 if (asprintf(&n, "/dev/block/%u:%u", major(st.st_rdev)gnu_dev_major (st.st_rdev), minor(st.st_rdev)gnu_dev_minor (st.st_rdev)) < 0)
222 return -ENOMEM12;
223
224 m->partitions[PARTITION_ROOT] = (DissectedPartition) {
225 .found = true1,
226 .rw = true1,
227 .partno = -1,
228 .architecture = _ARCHITECTURE_INVALID,
229 .fstype = TAKE_PTR(t)({ typeof(t) _ptr_ = (t); (t) = ((void*)0); _ptr_; }),
230 .node = TAKE_PTR(n)({ typeof(n) _ptr_ = (n); (n) = ((void*)0); _ptr_; }),
231 };
232
233 m->encrypted = streq_ptr(fstype, "crypto_LUKS");
234
235 *ret = TAKE_PTR(m)({ typeof(m) _ptr_ = (m); (m) = ((void*)0); _ptr_; });
236
237 return 0;
238 }
239 }
240
241 (void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL((void*)0));
242 if (!pttype)
29
Assuming 'pttype' is non-null
30
Taking false branch
243 return -ENOPKG65;
244
245 is_gpt = streq_ptr(pttype, "gpt");
246 is_mbr = streq_ptr(pttype, "dos");
247
248 if (!is_gpt
30.1
'is_gpt' is true
&& ((flags & DISSECT_IMAGE_GPT_ONLY) || !is_mbr))
249 return -ENOPKG65;
250
251 errno(*__errno_location ()) = 0;
252 pl = blkid_probe_get_partitions(b);
253 if (!pl)
31
Assuming 'pl' is non-null
32
Taking false branch
254 return -errno(*__errno_location ()) ?: -ENOMEM12;
255
256 udev = udev_new();
257 if (!udev)
33
Assuming 'udev' is non-null
34
Taking false branch
258 return -errno(*__errno_location ());
259
260 d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
261 if (!d)
35
Assuming 'd' is non-null
36
Taking false branch
262 return -ENOMEM12;
263
264 for (i = 0;; i++) {
37
Loop condition is true. Entering loop body
265 int n, z;
266
267 if (i
37.1
'i' is < 10
>= 10) {
38
Taking false branch
268 log_debug("Kernel partitions never appeared.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 268, __func__, "Kernel partitions never appeared."
) : -abs(_e); })
;
269 return -ENXIO6;
270 }
271
272 e = udev_enumerate_new(udev);
273 if (!e)
39
Assuming 'e' is non-null
40
Taking false branch
274 return -errno(*__errno_location ());
275
276 r = udev_enumerate_add_match_parent(e, d);
277 if (r < 0)
41
Assuming 'r' is >= 0
42
Taking false branch
278 return r;
279
280 r = udev_enumerate_scan_devices(e);
281 if (r < 0)
43
Assuming 'r' is >= 0
44
Taking false branch
282 return r;
283
284 /* Count the partitions enumerated by the kernel */
285 n = 0;
286 first = udev_enumerate_get_list_entry(e);
287 udev_list_entry_foreach(item, first)for (item = first; item != ((void*)0); item = udev_list_entry_get_next
(item))
{
45
Assuming 'item' is equal to null
46
Loop condition is false. Execution continues on line 308
288 _cleanup_(udev_device_unrefp)__attribute__((cleanup(udev_device_unrefp))) struct udev_device *q;
289 dev_t qn;
290
291 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
292 if (!q)
293 return -errno(*__errno_location ());
294
295 qn = udev_device_get_devnum(q);
296 if (major(qn)gnu_dev_major (qn) == 0)
297 continue;
298
299 if (!device_is_block(q))
300 continue;
301
302 if (device_is_mmc_special_partition(q))
303 continue;
304 n++;
305 }
306
307 /* Count the partitions enumerated by blkid */
308 z = blkid_partlist_numof_partitions(pl);
309 if (n == z + 1)
47
Assuming the condition is true
48
Taking true branch
310 break;
49
Execution continues on line 359
311 if (n > z + 1) {
312 log_debug("blkid and kernel partition list do not match.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 312, __func__, "blkid and kernel partition list do not match."
) : -abs(_e); })
;
313 return -EIO5;
314 }
315 if (n < z + 1) {
316 unsigned j = 0;
317
318 /* The kernel has probed fewer partitions than blkid? Maybe the kernel prober is still running
319 * or it got EBUSY because udev already opened the device. Let's reprobe the device, which is a
320 * synchronous call that waits until probing is complete. */
321
322 for (;;) {
323 if (j++ > 20)
324 return -EBUSY16;
325
326 if (ioctl(fd, BLKRRPART(((0U) << (((0 +8)+8)+14)) | (((0x12)) << (0 +8))
| (((95)) << 0) | ((0) << ((0 +8)+8)))
, 0) < 0) {
327 r = -errno(*__errno_location ());
328
329 if (r == -EINVAL22) {
330 struct loop_info64 info;
331
332 /* If we are running on a loop device that has partition scanning off,
333 * return an explicit recognizable error about this, so that callers
334 * can generate a proper message explaining the situation. */
335
336 if (ioctl(fd, LOOP_GET_STATUS640x4C05, &info) >= 0 && (info.lo_flags & LO_FLAGS_PARTSCAN) == 0) {
337 log_debug("Device is loop device and partition scanning is off!")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 337, __func__, "Device is loop device and partition scanning is off!"
) : -abs(_e); })
;
338 return -EPROTONOSUPPORT93;
339 }
340 }
341 if (r != -EBUSY16)
342 return r;
343 } else
344 break;
345
346 /* If something else has the device open, such as an udev rule, the ioctl will return
347 * EBUSY. Since there's no way to wait until it isn't busy anymore, let's just wait a
348 * bit, and try again.
349 *
350 * This is really something they should fix in the kernel! */
351
352 (void) usleep(50 * USEC_PER_MSEC((usec_t) 1000ULL));
353 }
354 }
355
356 e = udev_enumerate_unref(e);
357 }
358
359 first = udev_enumerate_get_list_entry(e);
360 udev_list_entry_foreach(item, first)for (item = first; item != ((void*)0); item = udev_list_entry_get_next
(item))
{
50
Assuming 'item' is not equal to null
51
Loop condition is true. Entering loop body
92
Assuming 'item' is not equal to null
93
Loop condition is true. Entering loop body
361 _cleanup_(udev_device_unrefp)__attribute__((cleanup(udev_device_unrefp))) struct udev_device *q;
362 unsigned long long pflags;
363 blkid_partition pp;
364 const char *node;
365 dev_t qn;
366 int nr;
367
368 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
369 if (!q)
52
Assuming 'q' is non-null
53
Taking false branch
94
Assuming 'q' is null
95
Taking true branch
370 return -errno(*__errno_location ());
96
Potential leak of memory pointed to by 'generic_node'
371
372 qn = udev_device_get_devnum(q);
373 if (major(qn)gnu_dev_major (qn) == 0)
54
Assuming the condition is false
55
Taking false branch
374 continue;
375
376 if (st.st_rdev == qn)
56
Assuming 'qn' is not equal to field 'st_rdev'
57
Taking false branch
377 continue;
378
379 if (!device_is_block(q))
58
Taking false branch
380 continue;
381
382 if (device_is_mmc_special_partition(q))
59
Taking false branch
383 continue;
384
385 node = udev_device_get_devnode(q);
386 if (!node)
60
Assuming 'node' is non-null
61
Taking false branch
387 continue;
388
389 pp = blkid_partlist_devno_to_partition(pl, qn);
390 if (!pp)
62
Assuming 'pp' is non-null
63
Taking false branch
391 continue;
392
393 pflags = blkid_partition_get_flags(pp);
394
395 nr = blkid_partition_get_partno(pp);
396 if (nr < 0)
64
Assuming 'nr' is >= 0
65
Taking false branch
397 continue;
398
399 if (is_gpt
65.1
'is_gpt' is true
) {
66
Taking true branch
400 int designator = _PARTITION_DESIGNATOR_INVALID, architecture = _ARCHITECTURE_INVALID;
401 const char *stype, *sid, *fstype = NULL((void*)0);
402 sd_id128_t type_id, id;
403 bool_Bool rw = true1;
404
405 sid = blkid_partition_get_uuid(pp);
406 if (!sid)
67
Assuming 'sid' is non-null
68
Taking false branch
407 continue;
408 if (sd_id128_from_string(sid, &id) < 0)
69
Assuming the condition is false
70
Taking false branch
409 continue;
410
411 stype = blkid_partition_get_type_string(pp);
412 if (!stype)
71
Assuming 'stype' is non-null
72
Taking false branch
413 continue;
414 if (sd_id128_from_string(stype, &type_id) < 0)
73
Assuming the condition is false
74
Taking false branch
415 continue;
416
417 if (sd_id128_equal(type_id, GPT_HOME((const sd_id128_t) { .bytes = { 0x93, 0x3a, 0xc7, 0xe1, 0x2e
, 0xb4, 0x4f, 0x13, 0xb8, 0x44, 0x0e, 0x14, 0xe2, 0xae, 0xf9,
0x15 }})
)) {
75
Taking false branch
418
419 if (pflags & GPT_FLAG_NO_AUTO(1ULL << 63))
420 continue;
421
422 designator = PARTITION_HOME;
423 rw = !(pflags & GPT_FLAG_READ_ONLY(1ULL << 60));
424 } else if (sd_id128_equal(type_id, GPT_SRV((const sd_id128_t) { .bytes = { 0x3b, 0x8f, 0x84, 0x25, 0x20
, 0xe0, 0x4f, 0x3b, 0x90, 0x7f, 0x1a, 0x25, 0xa7, 0x6f, 0x98,
0xe8 }})
)) {
76
Taking false branch
425
426 if (pflags & GPT_FLAG_NO_AUTO(1ULL << 63))
427 continue;
428
429 designator = PARTITION_SRV;
430 rw = !(pflags & GPT_FLAG_READ_ONLY(1ULL << 60));
431 } else if (sd_id128_equal(type_id, GPT_ESP((const sd_id128_t) { .bytes = { 0xc1, 0x2a, 0x73, 0x28, 0xf8
, 0x1f, 0x11, 0xd2, 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9,
0x3b }})
)) {
77
Taking false branch
432
433 /* Note that we don't check the GPT_FLAG_NO_AUTO flag for the ESP, as it is not defined
434 * there. We instead check the GPT_FLAG_NO_BLOCK_IO_PROTOCOL, as recommended by the
435 * UEFI spec (See "12.3.3 Number and Location of System Partitions"). */
436
437 if (pflags & GPT_FLAG_NO_BLOCK_IO_PROTOCOL(1ULL << 1))
438 continue;
439
440 designator = PARTITION_ESP;
441 fstype = "vfat";
442 }
443#ifdef GPT_ROOT_NATIVE((const sd_id128_t) { .bytes = { 0x4f, 0x68, 0xbc, 0xe3, 0xe8
, 0xcd, 0x4d, 0xb1, 0x96, 0xe7, 0xfb, 0xca, 0xf9, 0x84, 0xb7,
0x09 }})
444 else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE((const sd_id128_t) { .bytes = { 0x4f, 0x68, 0xbc, 0xe3, 0xe8
, 0xcd, 0x4d, 0xb1, 0x96, 0xe7, 0xfb, 0xca, 0xf9, 0x84, 0xb7,
0x09 }})
)) {
78
Taking false branch
445
446 if (pflags & GPT_FLAG_NO_AUTO(1ULL << 63))
447 continue;
448
449 /* If a root ID is specified, ignore everything but the root id */
450 if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id))
451 continue;
452
453 designator = PARTITION_ROOT;
454 architecture = native_architecture()ARCHITECTURE_X86_64;
455 rw = !(pflags & GPT_FLAG_READ_ONLY(1ULL << 60));
456 } else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY((const sd_id128_t) { .bytes = { 0x2c, 0x73, 0x57, 0xed, 0xeb
, 0xd2, 0x46, 0xd9, 0xae, 0xc1, 0x23, 0xd4, 0x37, 0xec, 0x2b,
0xf5 }})
)) {
79
Taking false branch
457
458 if (pflags & GPT_FLAG_NO_AUTO(1ULL << 63))
459 continue;
460
461 m->can_verity = true1;
462
463 /* Ignore verity unless a root hash is specified */
464 if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id))
465 continue;
466
467 designator = PARTITION_ROOT_VERITY;
468 fstype = "DM_verity_hash";
469 architecture = native_architecture()ARCHITECTURE_X86_64;
470 rw = false0;
471 }
472#endif
473#ifdef GPT_ROOT_SECONDARY((const sd_id128_t) { .bytes = { 0x44, 0x47, 0x95, 0x40, 0xf2
, 0x97, 0x41, 0xb2, 0x9a, 0xf7, 0xd1, 0x31, 0xd5, 0xf0, 0x45,
0x8a }})
474 else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY((const sd_id128_t) { .bytes = { 0x44, 0x47, 0x95, 0x40, 0xf2
, 0x97, 0x41, 0xb2, 0x9a, 0xf7, 0xd1, 0x31, 0xd5, 0xf0, 0x45,
0x8a }})
)) {
80
Taking false branch
475
476 if (pflags & GPT_FLAG_NO_AUTO(1ULL << 63))
477 continue;
478
479 /* If a root ID is specified, ignore everything but the root id */
480 if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id))
481 continue;
482
483 designator = PARTITION_ROOT_SECONDARY;
484 architecture = SECONDARY_ARCHITECTUREARCHITECTURE_X86;
485 rw = !(pflags & GPT_FLAG_READ_ONLY(1ULL << 60));
486 } else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY((const sd_id128_t) { .bytes = { 0xd1, 0x3c, 0x5d, 0x3b, 0xb5
, 0xd1, 0x42, 0x2a, 0xb2, 0x9f, 0x94, 0x54, 0xfd, 0xc8, 0x9d,
0x76 }})
)) {
81
Taking false branch
487
488 if (pflags & GPT_FLAG_NO_AUTO(1ULL << 63))
489 continue;
490
491 m->can_verity = true1;
492
493 /* Ignore verity unless root has is specified */
494 if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id))
495 continue;
496
497 designator = PARTITION_ROOT_SECONDARY_VERITY;
498 fstype = "DM_verity_hash";
499 architecture = SECONDARY_ARCHITECTUREARCHITECTURE_X86;
500 rw = false0;
501 }
502#endif
503 else if (sd_id128_equal(type_id, GPT_SWAP((const sd_id128_t) { .bytes = { 0x06, 0x57, 0xfd, 0x6d, 0xa4
, 0xab, 0x43, 0xc4, 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f,
0x4f }})
)) {
82
Taking false branch
504
505 if (pflags & GPT_FLAG_NO_AUTO(1ULL << 63))
506 continue;
507
508 designator = PARTITION_SWAP;
509 fstype = "swap";
510 } else if (sd_id128_equal(type_id, GPT_LINUX_GENERIC((const sd_id128_t) { .bytes = { 0x0f, 0xc6, 0x3d, 0xaf, 0x84
, 0x83, 0x47, 0x72, 0x8e, 0x79, 0x3d, 0x69, 0xd8, 0x47, 0x7d,
0xe4 }})
)) {
83
Taking true branch
511
512 if (pflags & GPT_FLAG_NO_AUTO(1ULL << 63))
84
Assuming the condition is false
85
Taking false branch
513 continue;
514
515 if (generic_node
85.1
'generic_node' is null
)
86
Taking false branch
516 multiple_generic = true1;
517 else {
518 generic_nr = nr;
519 generic_rw = !(pflags & GPT_FLAG_READ_ONLY(1ULL << 60));
87
Assuming the condition is false
520 generic_uuid = id;
521 generic_node = strdup(node);
88
Memory is allocated
522 if (!generic_node)
89
Assuming 'generic_node' is non-null
90
Taking false branch
523 return -ENOMEM12;
524 }
525 }
526
527 if (designator
90.1
'designator' is equal to _PARTITION_DESIGNATOR_INVALID
!= _PARTITION_DESIGNATOR_INVALID) {
91
Taking false branch
528 _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0), *n = NULL((void*)0);
529
530 /* First one wins */
531 if (m->partitions[designator].found)
532 continue;
533
534 if (fstype) {
535 t = strdup(fstype);
536 if (!t)
537 return -ENOMEM12;
538 }
539
540 n = strdup(node);
541 if (!n)
542 return -ENOMEM12;
543
544 m->partitions[designator] = (DissectedPartition) {
545 .found = true1,
546 .partno = nr,
547 .rw = rw,
548 .architecture = architecture,
549 .node = TAKE_PTR(n)({ typeof(n) _ptr_ = (n); (n) = ((void*)0); _ptr_; }),
550 .fstype = TAKE_PTR(t)({ typeof(t) _ptr_ = (t); (t) = ((void*)0); _ptr_; }),
551 .uuid = id,
552 };
553 }
554
555 } else if (is_mbr) {
556
557 if (pflags != 0x80) /* Bootable flag */
558 continue;
559
560 if (blkid_partition_get_type(pp) != 0x83) /* Linux partition */
561 continue;
562
563 if (generic_node)
564 multiple_generic = true1;
565 else {
566 generic_nr = nr;
567 generic_rw = true1;
568 generic_node = strdup(node);
569 if (!generic_node)
570 return -ENOMEM12;
571 }
572 }
573 }
574
575 if (!m->partitions[PARTITION_ROOT].found) {
576 /* No root partition found? Then let's see if ther's one for the secondary architecture. And if not
577 * either, then check if there's a single generic one, and use that. */
578
579 if (m->partitions[PARTITION_ROOT_VERITY].found)
580 return -EADDRNOTAVAIL99;
581
582 if (m->partitions[PARTITION_ROOT_SECONDARY].found) {
583 m->partitions[PARTITION_ROOT] = m->partitions[PARTITION_ROOT_SECONDARY];
584 zero(m->partitions[PARTITION_ROOT_SECONDARY])(({ size_t _l_ = (sizeof(m->partitions[PARTITION_ROOT_SECONDARY
])); void *_x_ = (&(m->partitions[PARTITION_ROOT_SECONDARY
])); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); }))
;
585
586 m->partitions[PARTITION_ROOT_VERITY] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY];
587 zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY])(({ size_t _l_ = (sizeof(m->partitions[PARTITION_ROOT_SECONDARY_VERITY
])); void *_x_ = (&(m->partitions[PARTITION_ROOT_SECONDARY_VERITY
])); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); }))
;
588
589 } else if (flags & DISSECT_IMAGE_REQUIRE_ROOT) {
590
591 /* If the root has was set, then we won't fallback to a generic node, because the root hash
592 * decides */
593 if (root_hash)
594 return -EADDRNOTAVAIL99;
595
596 /* If we didn't find a generic node, then we can't fix this up either */
597 if (!generic_node)
598 return -ENXIO6;
599
600 /* If we didn't find a properly marked root partition, but we did find a single suitable
601 * generic Linux partition, then use this as root partition, if the caller asked for it. */
602 if (multiple_generic)
603 return -ENOTUNIQ76;
604
605 m->partitions[PARTITION_ROOT] = (DissectedPartition) {
606 .found = true1,
607 .rw = generic_rw,
608 .partno = generic_nr,
609 .architecture = _ARCHITECTURE_INVALID,
610 .node = TAKE_PTR(generic_node)({ typeof(generic_node) _ptr_ = (generic_node); (generic_node
) = ((void*)0); _ptr_; })
,
611 .uuid = generic_uuid,
612 };
613 }
614 }
615
616 if (root_hash) {
617 if (!m->partitions[PARTITION_ROOT_VERITY].found || !m->partitions[PARTITION_ROOT].found)
618 return -EADDRNOTAVAIL99;
619
620 /* If we found the primary root with the hash, then we definitely want to suppress any secondary root
621 * (which would be weird, after all the root hash should only be assigned to one pair of
622 * partitions... */
623 m->partitions[PARTITION_ROOT_SECONDARY].found = false0;
624 m->partitions[PARTITION_ROOT_SECONDARY_VERITY].found = false0;
625
626 /* If we found a verity setup, then the root partition is necessarily read-only. */
627 m->partitions[PARTITION_ROOT].rw = false0;
628
629 m->verity = true1;
630 }
631
632 blkid_free_probe(b);
633 b = NULL((void*)0);
634
635 /* Fill in file system types if we don't know them yet. */
636 for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
637 DissectedPartition *p = m->partitions + i;
638
639 if (!p->found)
640 continue;
641
642 if (!p->fstype && p->node) {
643 r = probe_filesystem(p->node, &p->fstype);
644 if (r < 0 && r != -EUCLEAN117)
645 return r;
646 }
647
648 if (streq_ptr(p->fstype, "crypto_LUKS"))
649 m->encrypted = true1;
650
651 if (p->fstype && fstype_is_ro(p->fstype))
652 p->rw = false0;
653 }
654
655 *ret = TAKE_PTR(m)({ typeof(m) _ptr_ = (m); (m) = ((void*)0); _ptr_; });
656
657 return 0;
658#else
659 return -EOPNOTSUPP95;
660#endif
661}
662
663DissectedImage* dissected_image_unref(DissectedImage *m) {
664 unsigned i;
665
666 if (!m)
667 return NULL((void*)0);
668
669 for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
670 free(m->partitions[i].fstype);
671 free(m->partitions[i].node);
672 free(m->partitions[i].decrypted_fstype);
673 free(m->partitions[i].decrypted_node);
674 }
675
676 free(m->hostname);
677 strv_free(m->machine_info);
678 strv_free(m->os_release);
679
680 return mfree(m);
681}
682
683static int is_loop_device(const char *path) {
684 char s[SYS_BLOCK_PATH_MAX("/../loop/")((sizeof("""/sys/dev/block/""") - 1) + (2+(sizeof(dev_t) <=
1 ? 3 : sizeof(dev_t) <= 2 ? 5 : sizeof(dev_t) <= 4 ? 10
: sizeof(dev_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(dev_t) >
8)]))) + 1 + (2+(sizeof(dev_t) <= 1 ? 3 : sizeof(dev_t) <=
2 ? 5 : sizeof(dev_t) <= 4 ? 10 : sizeof(dev_t) <= 8 ?
20 : sizeof(int[-2*(sizeof(dev_t) > 8)]))) + strlen_ptr("/../loop/"
))
];
685 struct stat st;
686
687 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/shared/dissect-image.c"
, 687, __PRETTY_FUNCTION__); } while (0)
;
688
689 if (stat(path, &st) < 0)
690 return -errno(*__errno_location ());
691
692 if (!S_ISBLK(st.st_mode)((((st.st_mode)) & 0170000) == (0060000)))
693 return -ENOTBLK15;
694
695 xsprintf_sys_block_path(s, "/loop/", st.st_dev)do { if ((__builtin_expect(!!(!(((size_t) snprintf(s, __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(s), typeof(&*(s))), sizeof(s)/sizeof((s)[0]), ((void)0))
), "/sys/dev/block/%u:%u%s", gnu_dev_major (st.st_dev), gnu_dev_minor
(st.st_dev), strempty("/loop/")) < (__extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(s), typeof(&*(s)))
, sizeof(s)/sizeof((s)[0]), ((void)0))))))),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("xsprintf: " "s" "[] must be big enough"
), "../src/shared/dissect-image.c", 695, __PRETTY_FUNCTION__)
; } while (0)
;
696 if (access(s, F_OK0) < 0) {
697 if (errno(*__errno_location ()) != ENOENT2)
698 return -errno(*__errno_location ());
699
700 /* The device itself isn't a loop device, but maybe it's a partition and its parent is? */
701 xsprintf_sys_block_path(s, "/../loop/", st.st_dev)do { if ((__builtin_expect(!!(!(((size_t) snprintf(s, __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(s), typeof(&*(s))), sizeof(s)/sizeof((s)[0]), ((void)0))
), "/sys/dev/block/%u:%u%s", gnu_dev_major (st.st_dev), gnu_dev_minor
(st.st_dev), strempty("/../loop/")) < (__extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(s), typeof(&*(s)))
, sizeof(s)/sizeof((s)[0]), ((void)0))))))),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("xsprintf: " "s" "[] must be big enough"
), "../src/shared/dissect-image.c", 701, __PRETTY_FUNCTION__)
; } while (0)
;
702 if (access(s, F_OK0) < 0)
703 return errno(*__errno_location ()) == ENOENT2 ? false0 : -errno(*__errno_location ());
704 }
705
706 return true1;
707}
708
709static int mount_partition(
710 DissectedPartition *m,
711 const char *where,
712 const char *directory,
713 uid_t uid_shift,
714 DissectImageFlags flags) {
715
716 _cleanup_free___attribute__((cleanup(freep))) char *chased = NULL((void*)0), *options = NULL((void*)0);
717 const char *p, *node, *fstype;
718 bool_Bool rw;
719 int r;
720
721 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/shared/dissect-image.c", 721
, __PRETTY_FUNCTION__); } while (0)
;
722 assert(where)do { if ((__builtin_expect(!!(!(where)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("where"), "../src/shared/dissect-image.c"
, 722, __PRETTY_FUNCTION__); } while (0)
;
723
724 node = m->decrypted_node ?: m->node;
725 fstype = m->decrypted_fstype ?: m->fstype;
726
727 if (!m->found || !node || !fstype)
728 return 0;
729
730 /* Stacked encryption? Yuck */
731 if (streq_ptr(fstype, "crypto_LUKS"))
732 return -ELOOP40;
733
734 rw = m->rw && !(flags & DISSECT_IMAGE_READ_ONLY);
735
736 if (directory) {
737 r = chase_symlinks(directory, where, CHASE_PREFIX_ROOT, &chased);
738 if (r < 0)
739 return r;
740
741 p = chased;
742 } else
743 p = where;
744
745 /* If requested, turn on discard support. */
746 if (fstype_can_discard(fstype) &&
747 ((flags & DISSECT_IMAGE_DISCARD) ||
748 ((flags & DISSECT_IMAGE_DISCARD_ON_LOOP) && is_loop_device(m->node)))) {
749 options = strdup("discard");
750 if (!options)
751 return -ENOMEM12;
752 }
753
754 if (uid_is_valid(uid_shift) && uid_shift != 0 && fstype_can_uid_gid(fstype)) {
755 _cleanup_free___attribute__((cleanup(freep))) char *uid_option = NULL((void*)0);
756
757 if (asprintf(&uid_option, "uid=" UID_FMT"%" "u" ",gid=" GID_FMT"%" "u", uid_shift, (gid_t) uid_shift) < 0)
758 return -ENOMEM12;
759
760 if (!strextend_with_separator(&options, ",", uid_option, NULL((void*)0)))
761 return -ENOMEM12;
762 }
763
764 return mount_verbose(LOG_DEBUG7, node, p, fstype, MS_NODEVMS_NODEV|(rw ? 0 : MS_RDONLYMS_RDONLY), options);
765}
766
767int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, DissectImageFlags flags) {
768 int r;
769
770 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/shared/dissect-image.c", 770
, __PRETTY_FUNCTION__); } while (0)
;
771 assert(where)do { if ((__builtin_expect(!!(!(where)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("where"), "../src/shared/dissect-image.c"
, 771, __PRETTY_FUNCTION__); } while (0)
;
772
773 if (!m->partitions[PARTITION_ROOT].found)
774 return -ENXIO6;
775
776 if ((flags & DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY) == 0) {
777 r = mount_partition(m->partitions + PARTITION_ROOT, where, NULL((void*)0), uid_shift, flags);
778 if (r < 0)
779 return r;
780
781 if (flags & DISSECT_IMAGE_VALIDATE_OS) {
782 r = path_is_os_tree(where);
783 if (r < 0)
784 return r;
785 if (r == 0)
786 return -EMEDIUMTYPE124;
787 }
788 }
789
790 if ((flags & DISSECT_IMAGE_MOUNT_ROOT_ONLY))
791 return 0;
792
793 r = mount_partition(m->partitions + PARTITION_HOME, where, "/home", uid_shift, flags);
794 if (r < 0)
795 return r;
796
797 r = mount_partition(m->partitions + PARTITION_SRV, where, "/srv", uid_shift, flags);
798 if (r < 0)
799 return r;
800
801 if (m->partitions[PARTITION_ESP].found) {
802 const char *mp;
803
804 /* Mount the ESP to /efi if it exists and is empty. If it doesn't exist, use /boot instead. */
805
806 FOREACH_STRING(mp, "/efi", "/boot")for (char **_l = ({ char **_ll = ((char**) ((const char*[]) {
"/efi", "/boot", ((void*)0) })); mp = _ll ? _ll[0] : ((void*
)0); _ll; }); _l && *_l; mp = ({ _l ++; _l[0]; }))
{
807 _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0);
808
809 r = chase_symlinks(mp, where, CHASE_PREFIX_ROOT, &p);
810 if (r < 0)
811 continue;
812
813 r = dir_is_empty(p);
814 if (r > 0) {
815 r = mount_partition(m->partitions + PARTITION_ESP, where, mp, uid_shift, flags);
816 if (r < 0)
817 return r;
818 }
819 }
820 }
821
822 return 0;
823}
824
825#if HAVE_LIBCRYPTSETUP1
826typedef struct DecryptedPartition {
827 struct crypt_device *device;
828 char *name;
829 bool_Bool relinquished;
830} DecryptedPartition;
831
832struct DecryptedImage {
833 DecryptedPartition *decrypted;
834 size_t n_decrypted;
835 size_t n_allocated;
836};
837#endif
838
839DecryptedImage* decrypted_image_unref(DecryptedImage* d) {
840#if HAVE_LIBCRYPTSETUP1
841 size_t i;
842 int r;
843
844 if (!d)
845 return NULL((void*)0);
846
847 for (i = 0; i < d->n_decrypted; i++) {
848 DecryptedPartition *p = d->decrypted + i;
849
850 if (p->device && p->name && !p->relinquished) {
851 r = crypt_deactivate(p->device, p->name);
852 if (r < 0)
853 log_debug_errno(r, "Failed to deactivate encrypted partition %s", p->name)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 853, __func__, "Failed to deactivate encrypted partition %s"
, p->name) : -abs(_e); })
;
854 }
855
856 if (p->device)
857 crypt_free(p->device);
858 free(p->name);
859 }
860
861 free(d);
862#endif
863 return NULL((void*)0);
864}
865
866#if HAVE_LIBCRYPTSETUP1
867
868static int make_dm_name_and_node(const void *original_node, const char *suffix, char **ret_name, char **ret_node) {
869 _cleanup_free___attribute__((cleanup(freep))) char *name = NULL((void*)0), *node = NULL((void*)0);
870 const char *base;
871
872 assert(original_node)do { if ((__builtin_expect(!!(!(original_node)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("original_node"), "../src/shared/dissect-image.c"
, 872, __PRETTY_FUNCTION__); } while (0)
;
873 assert(suffix)do { if ((__builtin_expect(!!(!(suffix)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("suffix"), "../src/shared/dissect-image.c"
, 873, __PRETTY_FUNCTION__); } while (0)
;
874 assert(ret_name)do { if ((__builtin_expect(!!(!(ret_name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret_name"), "../src/shared/dissect-image.c"
, 874, __PRETTY_FUNCTION__); } while (0)
;
875 assert(ret_node)do { if ((__builtin_expect(!!(!(ret_node)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret_node"), "../src/shared/dissect-image.c"
, 875, __PRETTY_FUNCTION__); } while (0)
;
876
877 base = strrchr(original_node, '/');
878 if (!base)
879 return -EINVAL22;
880 base++;
881 if (isempty(base))
882 return -EINVAL22;
883
884 name = strjoin(base, suffix)strjoin_real((base), suffix, ((void*)0));
885 if (!name)
886 return -ENOMEM12;
887 if (!filename_is_valid(name))
888 return -EINVAL22;
889
890 node = strjoin(crypt_get_dir(), "/", name)strjoin_real((crypt_get_dir()), "/", name, ((void*)0));
891 if (!node)
892 return -ENOMEM12;
893
894 *ret_name = TAKE_PTR(name)({ typeof(name) _ptr_ = (name); (name) = ((void*)0); _ptr_; }
)
;
895 *ret_node = TAKE_PTR(node)({ typeof(node) _ptr_ = (node); (node) = ((void*)0); _ptr_; }
)
;
896
897 return 0;
898}
899
900static int decrypt_partition(
901 DissectedPartition *m,
902 const char *passphrase,
903 DissectImageFlags flags,
904 DecryptedImage *d) {
905
906 _cleanup_free___attribute__((cleanup(freep))) char *node = NULL((void*)0), *name = NULL((void*)0);
907 _cleanup_(crypt_freep)__attribute__((cleanup(crypt_freep))) struct crypt_device *cd = NULL((void*)0);
908 int r;
909
910 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/shared/dissect-image.c", 910
, __PRETTY_FUNCTION__); } while (0)
;
911 assert(d)do { if ((__builtin_expect(!!(!(d)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("d"), "../src/shared/dissect-image.c", 911
, __PRETTY_FUNCTION__); } while (0)
;
912
913 if (!m->found || !m->node || !m->fstype)
914 return 0;
915
916 if (!streq(m->fstype, "crypto_LUKS")(strcmp((m->fstype),("crypto_LUKS")) == 0))
917 return 0;
918
919 if (!passphrase)
920 return -ENOKEY126;
921
922 r = make_dm_name_and_node(m->node, "-decrypted", &name, &node);
923 if (r < 0)
924 return r;
925
926 if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1)greedy_realloc0((void**) &(d->decrypted), &(d->
n_allocated), (d->n_decrypted + 1), sizeof((d->decrypted
)[0]))
)
927 return -ENOMEM12;
928
929 r = crypt_init(&cd, m->node);
930 if (r < 0)
931 return log_debug_errno(r, "Failed to initialize dm-crypt: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 931, __func__, "Failed to initialize dm-crypt: %m"
) : -abs(_e); })
;
932
933 r = crypt_load(cd, CRYPT_LUKS((void*)0), NULL((void*)0));
934 if (r < 0)
935 return log_debug_errno(r, "Failed to load LUKS metadata: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 935, __func__, "Failed to load LUKS metadata: %m"
) : -abs(_e); })
;
936
937 r = crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT-1, passphrase, strlen(passphrase),
938 ((flags & DISSECT_IMAGE_READ_ONLY) ? CRYPT_ACTIVATE_READONLY(1 << 0) : 0) |
939 ((flags & DISSECT_IMAGE_DISCARD_ON_CRYPTO) ? CRYPT_ACTIVATE_ALLOW_DISCARDS(1 << 3) : 0));
940 if (r < 0) {
941 log_debug_errno(r, "Failed to activate LUKS device: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 941, __func__, "Failed to activate LUKS device: %m"
) : -abs(_e); })
;
942 return r == -EPERM1 ? -EKEYREJECTED129 : r;
943 }
944
945 d->decrypted[d->n_decrypted].name = TAKE_PTR(name)({ typeof(name) _ptr_ = (name); (name) = ((void*)0); _ptr_; }
)
;
946 d->decrypted[d->n_decrypted].device = TAKE_PTR(cd)({ typeof(cd) _ptr_ = (cd); (cd) = ((void*)0); _ptr_; });
947 d->n_decrypted++;
948
949 m->decrypted_node = TAKE_PTR(node)({ typeof(node) _ptr_ = (node); (node) = ((void*)0); _ptr_; }
)
;
950
951 return 0;
952}
953
954static int verity_partition(
955 DissectedPartition *m,
956 DissectedPartition *v,
957 const void *root_hash,
958 size_t root_hash_size,
959 DissectImageFlags flags,
960 DecryptedImage *d) {
961
962 _cleanup_free___attribute__((cleanup(freep))) char *node = NULL((void*)0), *name = NULL((void*)0);
963 _cleanup_(crypt_freep)__attribute__((cleanup(crypt_freep))) struct crypt_device *cd = NULL((void*)0);
964 int r;
965
966 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/shared/dissect-image.c", 966
, __PRETTY_FUNCTION__); } while (0)
;
967 assert(v)do { if ((__builtin_expect(!!(!(v)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("v"), "../src/shared/dissect-image.c", 967
, __PRETTY_FUNCTION__); } while (0)
;
968
969 if (!root_hash)
970 return 0;
971
972 if (!m->found || !m->node || !m->fstype)
973 return 0;
974 if (!v->found || !v->node || !v->fstype)
975 return 0;
976
977 if (!streq(v->fstype, "DM_verity_hash")(strcmp((v->fstype),("DM_verity_hash")) == 0))
978 return 0;
979
980 r = make_dm_name_and_node(m->node, "-verity", &name, &node);
981 if (r < 0)
982 return r;
983
984 if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1)greedy_realloc0((void**) &(d->decrypted), &(d->
n_allocated), (d->n_decrypted + 1), sizeof((d->decrypted
)[0]))
)
985 return -ENOMEM12;
986
987 r = crypt_init(&cd, v->node);
988 if (r < 0)
989 return r;
990
991 r = crypt_load(cd, CRYPT_VERITY"VERITY", NULL((void*)0));
992 if (r < 0)
993 return r;
994
995 r = crypt_set_data_device(cd, m->node);
996 if (r < 0)
997 return r;
998
999 r = crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY(1 << 0));
1000 if (r < 0)
1001 return r;
1002
1003 d->decrypted[d->n_decrypted].name = TAKE_PTR(name)({ typeof(name) _ptr_ = (name); (name) = ((void*)0); _ptr_; }
)
;
1004 d->decrypted[d->n_decrypted].device = TAKE_PTR(cd)({ typeof(cd) _ptr_ = (cd); (cd) = ((void*)0); _ptr_; });
1005 d->n_decrypted++;
1006
1007 m->decrypted_node = TAKE_PTR(node)({ typeof(node) _ptr_ = (node); (node) = ((void*)0); _ptr_; }
)
;
1008
1009 return 0;
1010}
1011#endif
1012
1013int dissected_image_decrypt(
1014 DissectedImage *m,
1015 const char *passphrase,
1016 const void *root_hash,
1017 size_t root_hash_size,
1018 DissectImageFlags flags,
1019 DecryptedImage **ret) {
1020
1021#if HAVE_LIBCRYPTSETUP1
1022 _cleanup_(decrypted_image_unrefp)__attribute__((cleanup(decrypted_image_unrefp))) DecryptedImage *d = NULL((void*)0);
1023 unsigned i;
1024 int r;
1025#endif
1026
1027 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/shared/dissect-image.c", 1027
, __PRETTY_FUNCTION__); } while (0)
;
1028 assert(root_hash || root_hash_size == 0)do { if ((__builtin_expect(!!(!(root_hash || root_hash_size ==
0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("root_hash || root_hash_size == 0"
), "../src/shared/dissect-image.c", 1028, __PRETTY_FUNCTION__
); } while (0)
;
1029
1030 /* Returns:
1031 *
1032 * = 0 → There was nothing to decrypt
1033 * > 0 → Decrypted successfully
1034 * -ENOKEY → There's something to decrypt but no key was supplied
1035 * -EKEYREJECTED → Passed key was not correct
1036 */
1037
1038 if (root_hash && root_hash_size < sizeof(sd_id128_t))
1039 return -EINVAL22;
1040
1041 if (!m->encrypted && !m->verity) {
1042 *ret = NULL((void*)0);
1043 return 0;
1044 }
1045
1046#if HAVE_LIBCRYPTSETUP1
1047 d = new0(DecryptedImage, 1)((DecryptedImage*) calloc((1), sizeof(DecryptedImage)));
1048 if (!d)
1049 return -ENOMEM12;
1050
1051 for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
1052 DissectedPartition *p = m->partitions + i;
1053 int k;
1054
1055 if (!p->found)
1056 continue;
1057
1058 r = decrypt_partition(p, passphrase, flags, d);
1059 if (r < 0)
1060 return r;
1061
1062 k = PARTITION_VERITY_OF(i);
1063 if (k >= 0) {
1064 r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, flags, d);
1065 if (r < 0)
1066 return r;
1067 }
1068
1069 if (!p->decrypted_fstype && p->decrypted_node) {
1070 r = probe_filesystem(p->decrypted_node, &p->decrypted_fstype);
1071 if (r < 0 && r != -EUCLEAN117)
1072 return r;
1073 }
1074 }
1075
1076 *ret = TAKE_PTR(d)({ typeof(d) _ptr_ = (d); (d) = ((void*)0); _ptr_; });
1077
1078 return 1;
1079#else
1080 return -EOPNOTSUPP95;
1081#endif
1082}
1083
1084int dissected_image_decrypt_interactively(
1085 DissectedImage *m,
1086 const char *passphrase,
1087 const void *root_hash,
1088 size_t root_hash_size,
1089 DissectImageFlags flags,
1090 DecryptedImage **ret) {
1091
1092 _cleanup_strv_free_erase___attribute__((cleanup(strv_free_erasep))) char **z = NULL((void*)0);
1093 int n = 3, r;
1094
1095 if (passphrase)
1096 n--;
1097
1098 for (;;) {
1099 r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, flags, ret);
1100 if (r >= 0)
1101 return r;
1102 if (r == -EKEYREJECTED129)
1103 log_error_errno(r, "Incorrect passphrase, try again!")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1103, __func__, "Incorrect passphrase, try again!"
) : -abs(_e); })
;
1104 else if (r != -ENOKEY126) {
1105 log_error_errno(r, "Failed to decrypt image: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1105, __func__, "Failed to decrypt image: %m"
) : -abs(_e); })
;
1106 return r;
1107 }
1108
1109 if (--n < 0) {
1110 log_error("Too many retries.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1110, __func__, "Too many retries."
) : -abs(_e); })
;
1111 return -EKEYREJECTED129;
1112 }
1113
1114 z = strv_free(z);
1115
1116 r = ask_password_auto("Please enter image passphrase!", NULL((void*)0), "dissect", "dissect", USEC_INFINITY((usec_t) -1), 0, &z);
1117 if (r < 0)
1118 return log_error_errno(r, "Failed to query for passphrase: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1118, __func__, "Failed to query for passphrase: %m"
) : -abs(_e); })
;
1119
1120 passphrase = z[0];
1121 }
1122}
1123
1124#if HAVE_LIBCRYPTSETUP1
1125static int deferred_remove(DecryptedPartition *p) {
1126
1127 struct dm_ioctl dm = {
1128 .version = {
1129 DM_VERSION_MAJOR4,
1130 DM_VERSION_MINOR27,
1131 DM_VERSION_PATCHLEVEL0
1132 },
1133 .data_size = sizeof(dm),
1134 .flags = DM_DEFERRED_REMOVE(1 << 17),
1135 };
1136
1137 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
1138
1139 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/shared/dissect-image.c", 1139
, __PRETTY_FUNCTION__); } while (0)
;
1140
1141 /* Unfortunately, libcryptsetup doesn't provide a proper API for this, hence call the ioctl() directly. */
1142
1143 fd = open("/dev/mapper/control", O_RDWR02|O_CLOEXEC02000000);
1144 if (fd < 0)
1145 return -errno(*__errno_location ());
1146
1147 strncpy(dm.name, p->name, sizeof(dm.name));
1148
1149 if (ioctl(fd, DM_DEV_REMOVE(((2U|1U) << (((0 +8)+8)+14)) | (((0xfd)) << (0 +
8)) | (((DM_DEV_REMOVE_CMD)) << 0) | ((((sizeof(struct dm_ioctl
)))) << ((0 +8)+8)))
, &dm))
1150 return -errno(*__errno_location ());
1151
1152 return 0;
1153}
1154#endif
1155
1156int decrypted_image_relinquish(DecryptedImage *d) {
1157
1158#if HAVE_LIBCRYPTSETUP1
1159 size_t i;
1160 int r;
1161#endif
1162
1163 assert(d)do { if ((__builtin_expect(!!(!(d)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("d"), "../src/shared/dissect-image.c", 1163
, __PRETTY_FUNCTION__); } while (0)
;
1164
1165 /* Turns on automatic removal after the last use ended for all DM devices of this image, and sets a boolean so
1166 * that we don't clean it up ourselves either anymore */
1167
1168#if HAVE_LIBCRYPTSETUP1
1169 for (i = 0; i < d->n_decrypted; i++) {
1170 DecryptedPartition *p = d->decrypted + i;
1171
1172 if (p->relinquished)
1173 continue;
1174
1175 r = deferred_remove(p);
1176 if (r < 0)
1177 return log_debug_errno(r, "Failed to mark %s for auto-removal: %m", p->name)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1177, __func__, "Failed to mark %s for auto-removal: %m"
, p->name) : -abs(_e); })
;
1178
1179 p->relinquished = true1;
1180 }
1181#endif
1182
1183 return 0;
1184}
1185
1186int root_hash_load(const char *image, void **ret, size_t *ret_size) {
1187 _cleanup_free___attribute__((cleanup(freep))) char *text = NULL((void*)0);
1188 _cleanup_free___attribute__((cleanup(freep))) void *k = NULL((void*)0);
1189 size_t l;
1190 int r;
1191
1192 assert(image)do { if ((__builtin_expect(!!(!(image)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("image"), "../src/shared/dissect-image.c"
, 1192, __PRETTY_FUNCTION__); } while (0)
;
1193 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/shared/dissect-image.c",
1193, __PRETTY_FUNCTION__); } while (0)
;
1194 assert(ret_size)do { if ((__builtin_expect(!!(!(ret_size)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret_size"), "../src/shared/dissect-image.c"
, 1194, __PRETTY_FUNCTION__); } while (0)
;
1195
1196 if (is_device_path(image)) {
1197 /* If we are asked to load the root hash for a device node, exit early */
1198 *ret = NULL((void*)0);
1199 *ret_size = 0;
1200 return 0;
1201 }
1202
1203 r = getxattr_malloc(image, "user.verity.roothash", &text, true1);
1204 if (r < 0) {
1205 char *fn, *e, *n;
1206
1207 if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){-61, -95, -2})/sizeof(int)]; switch(r) {
case -61: case -95: case -2: _found = 1; break; default: break
; } _found; })
)
1208 return r;
1209
1210 fn = newa(char, strlen(image) + STRLEN(".roothash") + 1)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(char), strlen(image) + (sizeof(""".roothash""") - 1) + 1))),
0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(char), strlen(image) + (sizeof(\"\"\".roothash\"\"\") - 1) + 1)"
), "../src/shared/dissect-image.c", 1210, __PRETTY_FUNCTION__
); } while (0); (char*) __builtin_alloca (sizeof(char)*(strlen
(image) + (sizeof(""".roothash""") - 1) + 1)); })
;
1211 n = stpcpy(fn, image);
1212 e = endswith(fn, ".raw");
1213 if (e)
1214 n = e;
1215
1216 strcpy(n, ".roothash");
1217
1218 r = read_one_line_file(fn, &text);
1219 if (r == -ENOENT2) {
1220 *ret = NULL((void*)0);
1221 *ret_size = 0;
1222 return 0;
1223 }
1224 if (r < 0)
1225 return r;
1226 }
1227
1228 r = unhexmem(text, strlen(text), &k, &l);
1229 if (r < 0)
1230 return r;
1231 if (l < sizeof(sd_id128_t))
1232 return -EINVAL22;
1233
1234 *ret = TAKE_PTR(k)({ typeof(k) _ptr_ = (k); (k) = ((void*)0); _ptr_; });
1235 *ret_size = l;
1236
1237 return 1;
1238}
1239
1240int dissected_image_acquire_metadata(DissectedImage *m) {
1241
1242 enum {
1243 META_HOSTNAME,
1244 META_MACHINE_ID,
1245 META_MACHINE_INFO,
1246 META_OS_RELEASE,
1247 _META_MAX,
1248 };
1249
1250 static const char *const paths[_META_MAX] = {
1251 [META_HOSTNAME] = "/etc/hostname\0",
1252 [META_MACHINE_ID] = "/etc/machine-id\0",
1253 [META_MACHINE_INFO] = "/etc/machine-info\0",
1254 [META_OS_RELEASE] = "/etc/os-release\0/usr/lib/os-release\0",
1255 };
1256
1257 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **machine_info = NULL((void*)0), **os_release = NULL((void*)0);
1258 _cleanup_(rmdir_and_freep)__attribute__((cleanup(rmdir_and_freep))) char *t = NULL((void*)0);
1259 _cleanup_(sigkill_waitp)__attribute__((cleanup(sigkill_waitp))) pid_t child = 0;
1260 sd_id128_t machine_id = SD_ID128_NULL((const sd_id128_t) { .qwords = { 0, 0 }});
1261 _cleanup_free___attribute__((cleanup(freep))) char *hostname = NULL((void*)0);
1262 unsigned n_meta_initialized = 0, k;
1263 int fds[2 * _META_MAX], r;
1264
1265 BLOCK_SIGNALS(SIGCHLD)__attribute__((cleanup(block_signals_reset))) __attribute__ (
(unused)) sigset_t _saved_sigset = ({ sigset_t _t; do { if ((
__builtin_expect(!!(!(sigprocmask_many(0, &_t, 17, -1) >=
0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("sigprocmask_many(SIG_BLOCK, &_t, 17, -1) >= 0"
), "../src/shared/dissect-image.c", 1265, __PRETTY_FUNCTION__
); } while (0); _t; })
;
1266
1267 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/shared/dissect-image.c", 1267
, __PRETTY_FUNCTION__); } while (0)
;
1268
1269 for (; n_meta_initialized < _META_MAX; n_meta_initialized ++)
1270 if (pipe2(fds + 2*n_meta_initialized, O_CLOEXEC02000000) < 0) {
1271 r = -errno(*__errno_location ());
1272 goto finish;
1273 }
1274
1275 r = mkdtemp_malloc("/tmp/dissect-XXXXXX", &t);
1276 if (r < 0)
1277 goto finish;
1278
1279 r = safe_fork("(sd-dissect)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE, &child);
1280 if (r < 0)
1281 goto finish;
1282 if (r == 0) {
1283 r = dissected_image_mount(m, t, UID_INVALID((uid_t) -1), DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_MOUNT_ROOT_ONLY|DISSECT_IMAGE_VALIDATE_OS);
1284 if (r < 0) {
1285 log_debug_errno(r, "Failed to mount dissected image: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1285, __func__, "Failed to mount dissected image: %m"
) : -abs(_e); })
;
1286 _exit(EXIT_FAILURE1);
1287 }
1288
1289 for (k = 0; k < _META_MAX; k++) {
1290 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
1291 const char *p;
1292
1293 fds[2*k] = safe_close(fds[2*k]);
1294
1295 NULSTR_FOREACH(p, paths[k])for ((p) = (paths[k]); (p) && *(p); (p) = strchr((p),
0)+1)
{
1296 fd = chase_symlinks_and_open(p, t, CHASE_PREFIX_ROOT, O_RDONLY00|O_CLOEXEC02000000|O_NOCTTY0400, NULL((void*)0));
1297 if (fd >= 0)
1298 break;
1299 }
1300 if (fd < 0) {
1301 log_debug_errno(fd, "Failed to read %s file of image, ignoring: %m", paths[k])({ int _level = ((7)), _e = ((fd)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1301, __func__, "Failed to read %s file of image, ignoring: %m"
, paths[k]) : -abs(_e); })
;
1302 continue;
1303 }
1304
1305 r = copy_bytes(fd, fds[2*k+1], (uint64_t) -1, 0);
1306 if (r < 0)
1307 _exit(EXIT_FAILURE1);
1308
1309 fds[2*k+1] = safe_close(fds[2*k+1]);
1310 }
1311
1312 _exit(EXIT_SUCCESS0);
1313 }
1314
1315 for (k = 0; k < _META_MAX; k++) {
1316 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0);
1317
1318 fds[2*k+1] = safe_close(fds[2*k+1]);
1319
1320 f = fdopen(fds[2*k], "re");
1321 if (!f) {
1322 r = -errno(*__errno_location ());
1323 goto finish;
1324 }
1325
1326 fds[2*k] = -1;
1327
1328 switch (k) {
1329
1330 case META_HOSTNAME:
1331 r = read_etc_hostname_stream(f, &hostname);
1332 if (r < 0)
1333 log_debug_errno(r, "Failed to read /etc/hostname: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1333, __func__, "Failed to read /etc/hostname: %m"
) : -abs(_e); })
;
1334
1335 break;
1336
1337 case META_MACHINE_ID: {
1338 _cleanup_free___attribute__((cleanup(freep))) char *line = NULL((void*)0);
1339
1340 r = read_line(f, LONG_LINE_MAX(1U*1024U*1024U), &line);
1341 if (r < 0)
1342 log_debug_errno(r, "Failed to read /etc/machine-id: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1342, __func__, "Failed to read /etc/machine-id: %m"
) : -abs(_e); })
;
1343 else if (r == 33) {
1344 r = sd_id128_from_string(line, &machine_id);
1345 if (r < 0)
1346 log_debug_errno(r, "Image contains invalid /etc/machine-id: %s", line)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1346, __func__, "Image contains invalid /etc/machine-id: %s"
, line) : -abs(_e); })
;
1347 } else if (r == 0)
1348 log_debug("/etc/machine-id file is empty.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1348, __func__, "/etc/machine-id file is empty."
) : -abs(_e); })
;
1349 else
1350 log_debug("/etc/machine-id has unexpected length %i.", r)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1350, __func__, "/etc/machine-id has unexpected length %i."
, r) : -abs(_e); })
;
1351
1352 break;
1353 }
1354
1355 case META_MACHINE_INFO:
1356 r = load_env_file_pairs(f, "machine-info", NULL((void*)0), &machine_info);
1357 if (r < 0)
1358 log_debug_errno(r, "Failed to read /etc/machine-info: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1358, __func__, "Failed to read /etc/machine-info: %m"
) : -abs(_e); })
;
1359
1360 break;
1361
1362 case META_OS_RELEASE:
1363 r = load_env_file_pairs(f, "os-release", NULL((void*)0), &os_release);
1364 if (r < 0)
1365 log_debug_errno(r, "Failed to read OS release file: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1365, __func__, "Failed to read OS release file: %m"
) : -abs(_e); })
;
1366
1367 break;
1368 }
1369 }
1370
1371 r = wait_for_terminate_and_check("(sd-dissect)", child, 0);
1372 child = 0;
1373 if (r < 0)
1374 goto finish;
1375 if (r != EXIT_SUCCESS0)
1376 return -EPROTO71;
1377
1378 free_and_replace(m->hostname, hostname)({ free(m->hostname); (m->hostname) = (hostname); (hostname
) = ((void*)0); 0; })
;
1379 m->machine_id = machine_id;
1380 strv_free_and_replace(m->machine_info, machine_info)({ strv_free(m->machine_info); (m->machine_info) = (machine_info
); (machine_info) = ((void*)0); 0; })
;
1381 strv_free_and_replace(m->os_release, os_release)({ strv_free(m->os_release); (m->os_release) = (os_release
); (os_release) = ((void*)0); 0; })
;
1382
1383finish:
1384 for (k = 0; k < n_meta_initialized; k++)
1385 safe_close_pair(fds + 2*k);
1386
1387 return r;
1388}
1389
1390int dissect_image_and_warn(
1391 int fd,
1392 const char *name,
1393 const void *root_hash,
1394 size_t root_hash_size,
1395 DissectImageFlags flags,
1396 DissectedImage **ret) {
1397
1398 _cleanup_free___attribute__((cleanup(freep))) char *buffer = NULL((void*)0);
1399 int r;
1400
1401 if (!name) {
1402 r = fd_get_path(fd, &buffer);
1403 if (r < 0)
1404 return r;
1405
1406 name = buffer;
1407 }
1408
1409 r = dissect_image(fd, root_hash, root_hash_size, flags, ret);
1410
1411 switch (r) {
1412
1413 case -EOPNOTSUPP95:
1414 return log_error_errno(r, "Dissecting images is not supported, compiled without blkid support.")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1414, __func__, "Dissecting images is not supported, compiled without blkid support."
) : -abs(_e); })
;
1415
1416 case -ENOPKG65:
1417 return log_error_errno(r, "Couldn't identify a suitable partition table or file system in '%s'.", name)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1417, __func__, "Couldn't identify a suitable partition table or file system in '%s'."
, name) : -abs(_e); })
;
1418
1419 case -EADDRNOTAVAIL99:
1420 return log_error_errno(r, "No root partition for specified root hash found in '%s'.", name)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1420, __func__, "No root partition for specified root hash found in '%s'."
, name) : -abs(_e); })
;
1421
1422 case -ENOTUNIQ76:
1423 return log_error_errno(r, "Multiple suitable root partitions found in image '%s'.", name)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1423, __func__, "Multiple suitable root partitions found in image '%s'."
, name) : -abs(_e); })
;
1424
1425 case -ENXIO6:
1426 return log_error_errno(r, "No suitable root partition found in image '%s'.", name)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1426, __func__, "No suitable root partition found in image '%s'."
, name) : -abs(_e); })
;
1427
1428 case -EPROTONOSUPPORT93:
1429 return log_error_errno(r, "Device '%s' is loopback block device with partition scanning turned off, please turn it on.", name)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1429, __func__, "Device '%s' is loopback block device with partition scanning turned off, please turn it on."
, name) : -abs(_e); })
;
1430
1431 default:
1432 if (r < 0)
1433 return log_error_errno(r, "Failed to dissect image '%s': %m", name)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/dissect-image.c", 1433, __func__, "Failed to dissect image '%s': %m"
, name) : -abs(_e); })
;
1434
1435 return r;
1436 }
1437}
1438
1439static const char *const partition_designator_table[] = {
1440 [PARTITION_ROOT] = "root",
1441 [PARTITION_ROOT_SECONDARY] = "root-secondary",
1442 [PARTITION_HOME] = "home",
1443 [PARTITION_SRV] = "srv",
1444 [PARTITION_ESP] = "esp",
1445 [PARTITION_SWAP] = "swap",
1446 [PARTITION_ROOT_VERITY] = "root-verity",
1447 [PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity",
1448};
1449
1450DEFINE_STRING_TABLE_LOOKUP(partition_designator, int)const char *partition_designator_to_string(int i) { if (i <
0 || i >= (int) __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(partition_designator_table), typeof(&*(partition_designator_table
))), sizeof(partition_designator_table)/sizeof((partition_designator_table
)[0]), ((void)0)))) return ((void*)0); return partition_designator_table
[i]; } int partition_designator_from_string(const char *s) { return
(int) string_table_lookup(partition_designator_table, __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(partition_designator_table), typeof(&*(partition_designator_table
))), sizeof(partition_designator_table)/sizeof((partition_designator_table
)[0]), ((void)0))), s); }
;