]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/find-esp.c
6b460a27cb9c0d1c56f43df1953cb92e96caf791
[thirdparty/systemd.git] / src / shared / find-esp.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <linux/magic.h>
4 #include <sys/vfs.h>
5
6 #include "sd-device.h"
7 #include "sd-id128.h"
8
9 #include "alloc-util.h"
10 #include "blkid-util.h"
11 #include "btrfs-util.h"
12 #include "chase.h"
13 #include "device-util.h"
14 #include "devnum-util.h"
15 #include "env-util.h"
16 #include "errno-util.h"
17 #include "fd-util.h"
18 #include "find-esp.h"
19 #include "gpt.h"
20 #include "parse-util.h"
21 #include "path-util.h"
22 #include "stat-util.h"
23 #include "string-util.h"
24 #include "virt.h"
25
26 typedef enum VerifyESPFlags {
27 VERIFY_ESP_SEARCHING = 1 << 0, /* Downgrade various "not found" logs to debug level */
28 VERIFY_ESP_UNPRIVILEGED_MODE = 1 << 1, /* Call into udev rather than blkid */
29 VERIFY_ESP_RELAX_CHECKS = 1 << 2, /* Do not validate ESP partition */
30 } VerifyESPFlags;
31
32 static int verify_esp_blkid(
33 dev_t devid,
34 VerifyESPFlags flags,
35 uint32_t *ret_part,
36 uint64_t *ret_pstart,
37 uint64_t *ret_psize,
38 sd_id128_t *ret_uuid) {
39
40 sd_id128_t uuid = SD_ID128_NULL;
41 uint64_t pstart = 0, psize = 0;
42 uint32_t part = 0;
43
44 #if HAVE_BLKID
45 _cleanup_(blkid_free_probep) blkid_probe b = NULL;
46 _cleanup_free_ char *node = NULL;
47 bool searching = FLAGS_SET(flags, VERIFY_ESP_SEARCHING);
48 const char *v;
49 int r;
50
51 r = devname_from_devnum(S_IFBLK, devid, &node);
52 if (r < 0)
53 return log_error_errno(r, "Failed to get device path for " DEVNUM_FORMAT_STR ": %m", DEVNUM_FORMAT_VAL(devid));
54
55 errno = 0;
56 b = blkid_new_probe_from_filename(node);
57 if (!b)
58 return log_error_errno(errno ?: SYNTHETIC_ERRNO(ENOMEM), "Failed to open file system \"%s\": %m", node);
59
60 blkid_probe_enable_superblocks(b, 1);
61 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
62 blkid_probe_enable_partitions(b, 1);
63 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
64
65 errno = 0;
66 r = blkid_do_safeprobe(b);
67 if (r == -2)
68 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" is ambiguous.", node);
69 if (r == 1)
70 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" does not contain a label.", node);
71 if (r != 0)
72 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system \"%s\": %m", node);
73
74 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
75 if (r != 0)
76 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
77 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
78 "No filesystem found on \"%s\": %m", node);
79 if (!streq(v, "vfat"))
80 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
81 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
82 "File system \"%s\" is not FAT.", node);
83
84 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
85 if (r != 0)
86 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
87 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
88 "File system \"%s\" is not located on a partitioned block device.", node);
89 if (!streq(v, "gpt"))
90 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
91 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
92 "File system \"%s\" is not on a GPT partition table.", node);
93
94 errno = 0;
95 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
96 if (r != 0)
97 return log_error_errno(errno ?: EIO, "Failed to probe partition type UUID of \"%s\": %m", node);
98 if (sd_id128_string_equal(v, SD_GPT_ESP) <= 0)
99 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
100 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
101 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
102
103 errno = 0;
104 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
105 if (r != 0)
106 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition entry UUID of \"%s\": %m", node);
107 r = sd_id128_from_string(v, &uuid);
108 if (r < 0)
109 return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
110
111 errno = 0;
112 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
113 if (r != 0)
114 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition number of \"%s\": %m", node);
115 r = safe_atou32(v, &part);
116 if (r < 0)
117 return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
118
119 errno = 0;
120 r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL);
121 if (r != 0)
122 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition offset of \"%s\": %m", node);
123 r = safe_atou64(v, &pstart);
124 if (r < 0)
125 return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field.");
126
127 errno = 0;
128 r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL);
129 if (r != 0)
130 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition size of \"%s\": %m", node);
131 r = safe_atou64(v, &psize);
132 if (r < 0)
133 return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field.");
134 #endif
135
136 if (ret_part)
137 *ret_part = part;
138 if (ret_pstart)
139 *ret_pstart = pstart;
140 if (ret_psize)
141 *ret_psize = psize;
142 if (ret_uuid)
143 *ret_uuid = uuid;
144
145 return 0;
146 }
147
148 static int verify_esp_udev(
149 dev_t devid,
150 VerifyESPFlags flags,
151 uint32_t *ret_part,
152 uint64_t *ret_pstart,
153 uint64_t *ret_psize,
154 sd_id128_t *ret_uuid) {
155
156 bool searching = FLAGS_SET(flags, VERIFY_ESP_SEARCHING);
157 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
158 sd_id128_t uuid = SD_ID128_NULL;
159 uint64_t pstart = 0, psize = 0;
160 uint32_t part = 0;
161 const char *node, *v;
162 int r;
163
164 r = sd_device_new_from_devnum(&d, 'b', devid);
165 if (r < 0)
166 return log_error_errno(r, "Failed to get device from device number: %m");
167
168 r = sd_device_get_devname(d, &node);
169 if (r < 0)
170 return log_device_error_errno(d, r, "Failed to get device node: %m");
171
172 r = sd_device_get_property_value(d, "ID_FS_TYPE", &v);
173 if (r < 0)
174 return log_device_error_errno(d, r, "Failed to get device property: %m");
175 if (!streq(v, "vfat"))
176 return log_device_full_errno(d,
177 searching ? LOG_DEBUG : LOG_ERR,
178 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
179 "File system \"%s\" is not FAT.", node );
180
181 r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &v);
182 if (r < 0)
183 return log_device_full_errno(d,
184 searching && r == -ENOENT ? LOG_DEBUG : LOG_ERR,
185 searching && r == -ENOENT ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : r,
186 "Failed to get device property: %m");
187 if (!streq(v, "gpt"))
188 return log_device_full_errno(d,
189 searching ? LOG_DEBUG : LOG_ERR,
190 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
191 "File system \"%s\" is not on a GPT partition table.", node);
192
193 r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
194 if (r < 0)
195 return log_device_error_errno(d, r, "Failed to get device property: %m");
196 if (sd_id128_string_equal(v, SD_GPT_ESP) <= 0)
197 return log_device_full_errno(d,
198 searching ? LOG_DEBUG : LOG_ERR,
199 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
200 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
201
202 r = sd_device_get_property_value(d, "ID_PART_ENTRY_UUID", &v);
203 if (r < 0)
204 return log_device_error_errno(d, r, "Failed to get device property: %m");
205 r = sd_id128_from_string(v, &uuid);
206 if (r < 0)
207 return log_device_error_errno(d, r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
208
209 r = sd_device_get_property_value(d, "ID_PART_ENTRY_NUMBER", &v);
210 if (r < 0)
211 return log_device_error_errno(d, r, "Failed to get device property: %m");
212 r = safe_atou32(v, &part);
213 if (r < 0)
214 return log_device_error_errno(d, r, "Failed to parse PART_ENTRY_NUMBER field.");
215
216 r = sd_device_get_property_value(d, "ID_PART_ENTRY_OFFSET", &v);
217 if (r < 0)
218 return log_device_error_errno(d, r, "Failed to get device property: %m");
219 r = safe_atou64(v, &pstart);
220 if (r < 0)
221 return log_device_error_errno(d, r, "Failed to parse PART_ENTRY_OFFSET field.");
222
223 r = sd_device_get_property_value(d, "ID_PART_ENTRY_SIZE", &v);
224 if (r < 0)
225 return log_device_error_errno(d, r, "Failed to get device property: %m");
226 r = safe_atou64(v, &psize);
227 if (r < 0)
228 return log_device_error_errno(d, r, "Failed to parse PART_ENTRY_SIZE field.");
229
230 if (ret_part)
231 *ret_part = part;
232 if (ret_pstart)
233 *ret_pstart = pstart;
234 if (ret_psize)
235 *ret_psize = psize;
236 if (ret_uuid)
237 *ret_uuid = uuid;
238
239 return 0;
240 }
241
242 static int verify_fsroot_dir(
243 int dir_fd,
244 const char *path,
245 VerifyESPFlags flags,
246 dev_t *ret_dev) {
247
248 bool searching = FLAGS_SET(flags, VERIFY_ESP_SEARCHING),
249 unprivileged_mode = FLAGS_SET(flags, VERIFY_ESP_UNPRIVILEGED_MODE);
250 _cleanup_free_ char *f = NULL;
251 STRUCT_NEW_STATX_DEFINE(sxa);
252 STRUCT_NEW_STATX_DEFINE(sxb);
253 int r;
254
255 /* Checks if the specified directory is at the root of its file system, and returns device
256 * major/minor of the device, if it is. */
257
258 assert(dir_fd >= 0);
259 assert(path);
260
261 /* We pass the full path from the root directory file descriptor so we can use it for logging, but
262 * dir_fd points to the parent directory of the final component of the given path, so we extract the
263 * filename and operate on that. */
264
265 r = path_extract_filename(path, &f);
266 if (r < 0 && r != -EADDRNOTAVAIL)
267 return log_error_errno(r, "Failed to extract filename of %s: %m", path);
268
269 r = statx_fallback(dir_fd, strempty(f), AT_SYMLINK_NOFOLLOW|(isempty(f) ? AT_EMPTY_PATH : 0),
270 STATX_TYPE|STATX_INO|STATX_MNT_ID, &sxa.sx);
271 if (r < 0)
272 return log_full_errno((searching && r == -ENOENT) ||
273 (unprivileged_mode && ERRNO_IS_PRIVILEGE(r)) ? LOG_DEBUG : LOG_ERR, r,
274 "Failed to determine block device node of \"%s\": %m", path);
275
276 assert(S_ISDIR(sxa.sx.stx_mode)); /* We used O_DIRECTORY above, when opening, so this must hold */
277
278 if (FLAGS_SET(sxa.sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) {
279
280 /* If we have STATX_ATTR_MOUNT_ROOT, we are happy, that's all we need. We operate under the
281 * assumption that a top of a mount point is also the top of the file system. (Which of
282 * course is strictly speaking not always true...) */
283
284 if (!FLAGS_SET(sxa.sx.stx_attributes, STATX_ATTR_MOUNT_ROOT))
285 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
286 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
287 "Directory \"%s\" is not the root of the file system.", path);
288
289 goto success;
290 }
291
292 /* Now let's look at the parent */
293 r = statx_fallback(dir_fd, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sxb.sx);
294 if (r < 0)
295 return log_full_errno(unprivileged_mode && ERRNO_IS_PRIVILEGE(r) ? LOG_DEBUG : LOG_ERR, r,
296 "Failed to determine block device node of parent of \"%s\": %m", path);
297
298 if (statx_inode_same(&sxa.sx, &sxb.sx)) /* for the root dir inode nr for both inodes will be the same */
299 goto success;
300
301 if (statx_mount_same(&sxa.nsx, &sxb.nsx))
302 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
303 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
304 "Directory \"%s\" is not the root of the file system.", path);
305
306 success:
307 if (!ret_dev)
308 return 0;
309
310 if (sxa.sx.stx_dev_major == 0) /* Hmm, maybe a btrfs device, and the caller asked for the backing device? Then let's try to get it. */
311 return btrfs_get_block_device_at(dir_fd, strempty(f), ret_dev);
312
313 *ret_dev = makedev(sxa.sx.stx_dev_major, sxa.sx.stx_dev_minor);
314 return 0;
315 }
316
317 static int verify_esp(
318 int rfd,
319 const char *path,
320 char **ret_path,
321 uint32_t *ret_part,
322 uint64_t *ret_pstart,
323 uint64_t *ret_psize,
324 sd_id128_t *ret_uuid,
325 dev_t *ret_devid,
326 VerifyESPFlags flags) {
327
328 bool relax_checks, searching = FLAGS_SET(flags, VERIFY_ESP_SEARCHING),
329 unprivileged_mode = FLAGS_SET(flags, VERIFY_ESP_UNPRIVILEGED_MODE);
330 _cleanup_free_ char *p = NULL;
331 _cleanup_close_ int pfd = -EBADF;
332 dev_t devid = 0;
333 int r;
334
335 assert(rfd >= 0 || rfd == AT_FDCWD);
336 assert(path);
337
338 /* This logs about all errors, except:
339 *
340 * -ENOENT → if 'searching' is set, and the dir doesn't exist
341 * -EADDRNOTAVAIL → if 'searching' is set, and the dir doesn't look like an ESP
342 * -EACESS → if 'unprivileged_mode' is set, and we have trouble accessing the thing
343 */
344
345 relax_checks =
346 getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0 ||
347 FLAGS_SET(flags, VERIFY_ESP_RELAX_CHECKS);
348
349 /* Non-root user can only check the status, so if an error occurred in the following, it does not cause any
350 * issues. Let's also, silence the error messages. */
351
352 r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT, &p, &pfd);
353 if (r < 0)
354 return log_full_errno((searching && r == -ENOENT) ||
355 (unprivileged_mode && ERRNO_IS_PRIVILEGE(r)) ? LOG_DEBUG : LOG_ERR,
356 r, "Failed to open parent directory of \"%s\": %m", path);
357
358 if (!relax_checks) {
359 _cleanup_free_ char *f = NULL;
360 struct statfs sfs;
361
362 r = path_extract_filename(p, &f);
363 if (r < 0 && r != -EADDRNOTAVAIL)
364 return log_error_errno(r, "Failed to extract filename of %s: %m", p);
365
366 r = xstatfsat(pfd, strempty(f), &sfs);
367 if (r < 0)
368 /* If we are searching for the mount point, don't generate a log message if we can't find the path */
369 return log_full_errno((searching && r == -ENOENT) ||
370 (unprivileged_mode && r == -EACCES) ? LOG_DEBUG : LOG_ERR, r,
371 "Failed to check file system type of \"%s\": %m", p);
372
373 if (!F_TYPE_EQUAL(sfs.f_type, MSDOS_SUPER_MAGIC))
374 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
375 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
376 "File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p);
377 }
378
379 relax_checks =
380 relax_checks ||
381 detect_container() > 0;
382
383 r = verify_fsroot_dir(pfd, p, flags, relax_checks ? NULL : &devid);
384 if (r < 0)
385 return r;
386
387 /* In a container we don't have access to block devices, skip this part of the verification, we trust
388 * the container manager set everything up correctly on its own. */
389 if (relax_checks)
390 goto finish;
391
392 /* If we are unprivileged we ask udev for the metadata about the partition. If we are privileged we
393 * use blkid instead. Why? Because this code is called from 'bootctl' which is pretty much an
394 * emergency recovery tool that should also work when udev isn't up (i.e. from the emergency shell),
395 * however blkid can't work if we have no privileges to access block devices directly, which is why
396 * we use udev in that case. */
397 if (unprivileged_mode)
398 r = verify_esp_udev(devid, flags, ret_part, ret_pstart, ret_psize, ret_uuid);
399 else
400 r = verify_esp_blkid(devid, flags, ret_part, ret_pstart, ret_psize, ret_uuid);
401 if (r < 0)
402 return r;
403
404 if (ret_path)
405 *ret_path = TAKE_PTR(p);
406 if (ret_devid)
407 *ret_devid = devid;
408
409 return 0;
410
411 finish:
412 if (ret_path)
413 *ret_path = TAKE_PTR(p);
414 if (ret_part)
415 *ret_part = 0;
416 if (ret_pstart)
417 *ret_pstart = 0;
418 if (ret_psize)
419 *ret_psize = 0;
420 if (ret_uuid)
421 *ret_uuid = SD_ID128_NULL;
422 if (ret_devid)
423 *ret_devid = 0;
424
425 return 0;
426 }
427
428 int find_esp_and_warn_at(
429 int rfd,
430 const char *path,
431 int unprivileged_mode,
432 char **ret_path,
433 uint32_t *ret_part,
434 uint64_t *ret_pstart,
435 uint64_t *ret_psize,
436 sd_id128_t *ret_uuid,
437 dev_t *ret_devid) {
438
439 VerifyESPFlags flags;
440 int r;
441
442 /* This logs about all errors except:
443 *
444 * -ENOKEY → when we can't find the partition
445 * -EACCESS → when unprivileged_mode is true, and we can't access something
446 */
447
448 assert(rfd >= 0 || rfd == AT_FDCWD);
449
450 if (unprivileged_mode < 0)
451 unprivileged_mode = geteuid() != 0;
452 flags = unprivileged_mode > 0 ? VERIFY_ESP_UNPRIVILEGED_MODE : 0;
453
454 r = dir_fd_is_root_or_cwd(rfd);
455 if (r < 0)
456 return log_error_errno(r, "Failed to check if directory file descriptor is root: %m");
457 if (r == 0)
458 flags |= VERIFY_ESP_RELAX_CHECKS;
459
460 if (path)
461 return verify_esp(rfd, path, ret_path, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid, flags);
462
463 path = getenv("SYSTEMD_ESP_PATH");
464 if (path) {
465 _cleanup_free_ char *p = NULL;
466 _cleanup_close_ int fd = -EBADF;
467 struct stat st;
468
469 if (!path_is_valid(path) || !path_is_absolute(path))
470 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
471 "$SYSTEMD_ESP_PATH does not refer to an absolute path, refusing to use it: %s",
472 path);
473
474 r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT, &p, &fd);
475 if (r < 0)
476 return log_error_errno(r, "Failed to resolve path %s: %m", path);
477
478 /* Note: when the user explicitly configured things with an env var we won't validate the
479 * path beyond checking it refers to a directory. After all we want this to be useful for
480 * testing. */
481
482 if (fstat(fd, &st) < 0)
483 return log_error_errno(errno, "Failed to stat '%s': %m", p);
484 if (!S_ISDIR(st.st_mode))
485 return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR), "ESP path '%s' is not a directory.", p);
486
487 if (ret_path)
488 *ret_path = TAKE_PTR(p);
489 if (ret_part)
490 *ret_part = 0;
491 if (ret_pstart)
492 *ret_pstart = 0;
493 if (ret_psize)
494 *ret_psize = 0;
495 if (ret_uuid)
496 *ret_uuid = SD_ID128_NULL;
497 if (ret_devid)
498 *ret_devid = st.st_dev;
499
500 return 0;
501 }
502
503 FOREACH_STRING(dir, "/efi", "/boot", "/boot/efi") {
504 r = verify_esp(rfd, dir, ret_path, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid,
505 flags | VERIFY_ESP_SEARCHING);
506 if (r >= 0)
507 return 0;
508 if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL, -ENOTDIR, -ENOTTY)) /* This one is not it */
509 return r;
510 }
511
512 /* No logging here */
513 return -ENOKEY;
514 }
515
516 int find_esp_and_warn(
517 const char *root,
518 const char *path,
519 int unprivileged_mode,
520 char **ret_path,
521 uint32_t *ret_part,
522 uint64_t *ret_pstart,
523 uint64_t *ret_psize,
524 sd_id128_t *ret_uuid,
525 dev_t *ret_devid) {
526
527 _cleanup_close_ int rfd = -EBADF;
528 _cleanup_free_ char *p = NULL;
529 uint32_t part;
530 uint64_t pstart, psize;
531 sd_id128_t uuid;
532 dev_t devid;
533 int r;
534
535 rfd = open(empty_to_root(root), O_PATH|O_DIRECTORY|O_CLOEXEC);
536 if (rfd < 0)
537 return -errno;
538
539 r = find_esp_and_warn_at(rfd, path, unprivileged_mode,
540 ret_path ? &p : NULL,
541 ret_part ? &part : NULL,
542 ret_pstart ? &pstart : NULL,
543 ret_psize ? &psize : NULL,
544 ret_uuid ? &uuid : NULL,
545 ret_devid ? &devid : NULL);
546 if (r < 0)
547 return r;
548
549 if (ret_path) {
550 r = chaseat_prefix_root(p, root, ret_path);
551 if (r < 0)
552 return r;
553 }
554 if (ret_part)
555 *ret_part = part;
556 if (ret_pstart)
557 *ret_pstart = pstart;
558 if (ret_psize)
559 *ret_psize = psize;
560 if (ret_uuid)
561 *ret_uuid = uuid;
562 if (ret_devid)
563 *ret_devid = devid;
564
565 return 0;
566 }
567
568 static int verify_xbootldr_blkid(
569 dev_t devid,
570 VerifyESPFlags flags,
571 sd_id128_t *ret_uuid) {
572
573 sd_id128_t uuid = SD_ID128_NULL;
574
575 #if HAVE_BLKID
576 bool searching = FLAGS_SET(flags, VERIFY_ESP_SEARCHING);
577 _cleanup_(blkid_free_probep) blkid_probe b = NULL;
578 _cleanup_free_ char *node = NULL;
579 const char *type, *v;
580 int r;
581
582 r = devname_from_devnum(S_IFBLK, devid, &node);
583 if (r < 0)
584 return log_error_errno(r, "Failed to get block device path for " DEVNUM_FORMAT_STR ": %m",
585 DEVNUM_FORMAT_VAL(devid));
586
587 errno = 0;
588 b = blkid_new_probe_from_filename(node);
589 if (!b)
590 return log_error_errno(errno_or_else(ENOMEM), "%s: Failed to create blkid probe: %m", node);
591
592 blkid_probe_enable_partitions(b, 1);
593 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
594
595 errno = 0;
596 r = blkid_do_safeprobe(b);
597 if (r == _BLKID_SAFEPROBE_AMBIGUOUS)
598 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "%s: File system is ambiguous.", node);
599 if (r == _BLKID_SAFEPROBE_NOT_FOUND)
600 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "%s: File system does not contain a label.", node);
601 if (r == _BLKID_SAFEPROBE_ERROR)
602 return log_error_errno(errno_or_else(EIO), "%s: Failed to probe file system: %m", node);
603
604 assert(r == _BLKID_SAFEPROBE_FOUND);
605
606 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &type, NULL);
607 if (r != 0)
608 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
609 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(EIO),
610 "%s: Failed to probe PART_ENTRY_SCHEME: %m", node);
611 if (streq(type, "gpt")) {
612
613 errno = 0;
614 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
615 if (r != 0)
616 return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
617 if (sd_id128_string_equal(v, SD_GPT_XBOOTLDR) <= 0)
618 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
619 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
620 "%s: Partitition has wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node, v);
621
622 errno = 0;
623 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
624 if (r != 0)
625 return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_UUID: %m", node);
626 r = sd_id128_from_string(v, &uuid);
627 if (r < 0)
628 return log_error_errno(r, "%s: Partition has invalid UUID PART_ENTRY_TYPE=%s: %m", node, v);
629
630 } else if (streq(type, "dos")) {
631
632 errno = 0;
633 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
634 if (r != 0)
635 return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
636 if (!streq(v, "0xea"))
637 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
638 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
639 "%s: Wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node, v);
640
641 } else
642 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
643 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
644 "%s: Not on a GPT or DOS partition table (PART_ENTRY_SCHEME=%s).", node, type);
645 #endif
646
647 if (ret_uuid)
648 *ret_uuid = uuid;
649
650 return 0;
651 }
652
653 static int verify_xbootldr_udev(
654 dev_t devid,
655 VerifyESPFlags flags,
656 sd_id128_t *ret_uuid) {
657
658 bool searching = FLAGS_SET(flags, VERIFY_ESP_SEARCHING);
659 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
660 sd_id128_t uuid = SD_ID128_NULL;
661 const char *node, *type, *v;
662 int r;
663
664 r = sd_device_new_from_devnum(&d, 'b', devid);
665 if (r < 0)
666 return log_error_errno(r, "Failed to get block device for " DEVNUM_FORMAT_STR ": %m", DEVNUM_FORMAT_VAL(devid));
667
668 r = sd_device_get_devname(d, &node);
669 if (r < 0)
670 return log_device_error_errno(d, r, "Failed to get device node: %m");
671
672 r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &type);
673 if (r < 0)
674 return log_device_full_errno(d,
675 searching && r == -ENOENT ? LOG_DEBUG : LOG_ERR,
676 searching && r == -ENOENT ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : r,
677 "Failed to query ID_PART_ENTRY_SCHEME: %m");
678
679 if (streq(type, "gpt")) {
680
681 r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
682 if (r < 0)
683 return log_device_error_errno(d, r, "Failed to query ID_PART_ENTRY_TYPE: %m");
684
685 r = sd_id128_string_equal(v, SD_GPT_XBOOTLDR);
686 if (r < 0)
687 return log_device_error_errno(d, r, "Failed to parse ID_PART_ENTRY_TYPE=%s: %m", v);
688 if (r == 0)
689 return log_device_full_errno(
690 d,
691 searching ? LOG_DEBUG : LOG_ERR,
692 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
693 "Partition has wrong ID_PART_ENTRY_TYPE=%s for XBOOTLDR partition.", v);
694
695 r = sd_device_get_property_value(d, "ID_PART_ENTRY_UUID", &v);
696 if (r < 0)
697 return log_device_error_errno(d, r, "Failed to query ID_PART_ENTRY_UUID: %m");
698 r = sd_id128_from_string(v, &uuid);
699 if (r < 0)
700 return log_device_error_errno(d, r, "Partition has invalid UUID ID_PART_ENTRY_TYPE=%s: %m", v);
701
702 } else if (streq(type, "dos")) {
703
704 r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
705 if (r < 0)
706 return log_device_error_errno(d, r, "Failed to query ID_PART_ENTRY_TYPE: %m");
707 if (!streq(v, "0xea"))
708 return log_device_full_errno(
709 d,
710 searching ? LOG_DEBUG : LOG_ERR,
711 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
712 "Wrong ID_PART_ENTRY_TYPE=%s for XBOOTLDR partition.", v);
713
714 } else
715 return log_device_full_errno(
716 d,
717 searching ? LOG_DEBUG : LOG_ERR,
718 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
719 "Not on a GPT or DOS partition table (ID_PART_ENTRY_SCHEME=%s).", type);
720
721 if (ret_uuid)
722 *ret_uuid = uuid;
723
724 return 0;
725 }
726
727 static int verify_xbootldr(
728 int rfd,
729 const char *path,
730 VerifyESPFlags flags,
731 char **ret_path,
732 sd_id128_t *ret_uuid,
733 dev_t *ret_devid) {
734
735 _cleanup_free_ char *p = NULL;
736 _cleanup_close_ int pfd = -EBADF;
737 bool searching = FLAGS_SET(flags, VERIFY_ESP_SEARCHING),
738 unprivileged_mode = FLAGS_SET(flags, VERIFY_ESP_UNPRIVILEGED_MODE),
739 relax_checks;
740 dev_t devid = 0;
741 int r;
742
743 assert(rfd >= 0 || rfd == AT_FDCWD);
744 assert(path);
745
746 r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT, &p, &pfd);
747 if (r < 0)
748 return log_full_errno((searching && r == -ENOENT) ||
749 (unprivileged_mode && ERRNO_IS_PRIVILEGE(r)) ? LOG_DEBUG : LOG_ERR,
750 r, "Failed to open parent directory of \"%s\": %m", path);
751
752 relax_checks =
753 getenv_bool("SYSTEMD_RELAX_XBOOTLDR_CHECKS") > 0 ||
754 detect_container() > 0;
755
756 r = verify_fsroot_dir(pfd, p, flags, relax_checks ? NULL : &devid);
757 if (r < 0)
758 return r;
759
760 if (relax_checks)
761 goto finish;
762
763 if (unprivileged_mode)
764 r = verify_xbootldr_udev(devid, flags, ret_uuid);
765 else
766 r = verify_xbootldr_blkid(devid, flags, ret_uuid);
767 if (r < 0)
768 return r;
769
770 if (ret_path)
771 *ret_path = TAKE_PTR(p);
772 if (ret_devid)
773 *ret_devid = devid;
774
775 return 0;
776
777 finish:
778 if (ret_path)
779 *ret_path = TAKE_PTR(p);
780 if (ret_uuid)
781 *ret_uuid = SD_ID128_NULL;
782 if (ret_devid)
783 *ret_devid = 0;
784
785 return 0;
786 }
787
788 int find_xbootldr_and_warn_at(
789 int rfd,
790 const char *path,
791 int unprivileged_mode,
792 char **ret_path,
793 sd_id128_t *ret_uuid,
794 dev_t *ret_devid) {
795
796 VerifyESPFlags flags = 0;
797 int r;
798
799 /* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */
800
801 assert(rfd >= 0 || rfd == AT_FDCWD);
802
803 if (unprivileged_mode < 0)
804 unprivileged_mode = geteuid() != 0;
805 if (unprivileged_mode)
806 flags |= VERIFY_ESP_UNPRIVILEGED_MODE;
807
808 if (path)
809 return verify_xbootldr(rfd, path, flags, ret_path, ret_uuid, ret_devid);
810
811 path = getenv("SYSTEMD_XBOOTLDR_PATH");
812 if (path) {
813 _cleanup_free_ char *p = NULL;
814 _cleanup_close_ int fd = -EBADF;
815 struct stat st;
816
817 if (!path_is_valid(path) || !path_is_absolute(path))
818 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
819 "$SYSTEMD_XBOOTLDR_PATH does not refer to an absolute path, refusing to use it: %s",
820 path);
821
822 r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT, &p, &fd);
823 if (r < 0)
824 return log_error_errno(r, "Failed to resolve path %s: %m", p);
825
826 if (fstat(fd, &st) < 0)
827 return log_error_errno(errno, "Failed to stat '%s': %m", p);
828 if (!S_ISDIR(st.st_mode))
829 return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR), "XBOOTLDR path '%s' is not a directory.", p);
830
831 if (ret_path)
832 *ret_path = TAKE_PTR(p);
833 if (ret_uuid)
834 *ret_uuid = SD_ID128_NULL;
835 if (ret_devid)
836 *ret_devid = st.st_dev;
837
838 return 0;
839 }
840
841 r = verify_xbootldr(rfd, "/boot", flags | VERIFY_ESP_SEARCHING, ret_path, ret_uuid, ret_devid);
842 if (r < 0) {
843 if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL, -ENOTDIR, -ENOTTY)) /* This one is not it */
844 return r;
845
846 return -ENOKEY;
847 }
848
849 return 0;
850 }
851
852 int find_xbootldr_and_warn(
853 const char *root,
854 const char *path,
855 int unprivileged_mode,
856 char **ret_path,
857 sd_id128_t *ret_uuid,
858 dev_t *ret_devid) {
859
860 _cleanup_close_ int rfd = -EBADF;
861 _cleanup_free_ char *p = NULL;
862 sd_id128_t uuid;
863 dev_t devid;
864 int r;
865
866 rfd = open(empty_to_root(root), O_PATH|O_DIRECTORY|O_CLOEXEC);
867 if (rfd < 0)
868 return -errno;
869
870 r = find_xbootldr_and_warn_at(rfd, path, unprivileged_mode,
871 ret_path ? &p : NULL,
872 ret_uuid ? &uuid : NULL,
873 ret_devid ? &devid : NULL);
874 if (r < 0)
875 return r;
876
877 if (ret_path) {
878 r = chaseat_prefix_root(p, root, ret_path);
879 if (r < 0)
880 return r;
881 }
882 if (ret_uuid)
883 *ret_uuid = uuid;
884 if (ret_devid)
885 *ret_devid = devid;
886
887 return 0;
888 }