]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/bootspec.c
bootspec: if unprivileged validate partition data with udev rather than blkid directly
[thirdparty/systemd.git] / src / shared / bootspec.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <stdio.h>
4 #include <linux/magic.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 "bootspec.h"
12 #include "conf-files.h"
13 #include "def.h"
14 #include "device-nodes.h"
15 #include "efivars.h"
16 #include "env-util.h"
17 #include "fd-util.h"
18 #include "fileio.h"
19 #include "parse-util.h"
20 #include "path-util.h"
21 #include "stat-util.h"
22 #include "string-util.h"
23 #include "strv.h"
24 #include "virt.h"
25
26 static void boot_entry_free(BootEntry *entry) {
27 assert(entry);
28
29 free(entry->id);
30 free(entry->path);
31 free(entry->root);
32 free(entry->title);
33 free(entry->show_title);
34 free(entry->version);
35 free(entry->machine_id);
36 free(entry->architecture);
37 strv_free(entry->options);
38 free(entry->kernel);
39 free(entry->efi);
40 strv_free(entry->initrd);
41 free(entry->device_tree);
42 }
43
44 static int boot_entry_load(
45 const char *root,
46 const char *path,
47 BootEntry *entry) {
48
49 _cleanup_(boot_entry_free) BootEntry tmp = {};
50 _cleanup_fclose_ FILE *f = NULL;
51 unsigned line = 1;
52 char *b, *c;
53 int r;
54
55 assert(root);
56 assert(path);
57 assert(entry);
58
59 c = endswith_no_case(path, ".conf");
60 if (!c)
61 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry filename: %s", path);
62
63 b = basename(path);
64 tmp.id = strndup(b, c - b);
65 if (!tmp.id)
66 return log_oom();
67
68 tmp.path = strdup(path);
69 if (!tmp.path)
70 return log_oom();
71
72 tmp.root = strdup(root);
73 if (!tmp.root)
74 return log_oom();
75
76 f = fopen(path, "re");
77 if (!f)
78 return log_error_errno(errno, "Failed to open \"%s\": %m", path);
79
80 for (;;) {
81 _cleanup_free_ char *buf = NULL, *field = NULL;
82 const char *p;
83
84 r = read_line(f, LONG_LINE_MAX, &buf);
85 if (r == 0)
86 break;
87 if (r == -ENOBUFS)
88 return log_error_errno(r, "%s:%u: Line too long", path, line);
89 if (r < 0)
90 return log_error_errno(r, "%s:%u: Error while reading: %m", path, line);
91
92 line++;
93
94 if (IN_SET(*strstrip(buf), '#', '\0'))
95 continue;
96
97 p = buf;
98 r = extract_first_word(&p, &field, " \t", 0);
99 if (r < 0) {
100 log_error_errno(r, "Failed to parse config file %s line %u: %m", path, line);
101 continue;
102 }
103 if (r == 0) {
104 log_warning("%s:%u: Bad syntax", path, line);
105 continue;
106 }
107
108 if (streq(field, "title"))
109 r = free_and_strdup(&tmp.title, p);
110 else if (streq(field, "version"))
111 r = free_and_strdup(&tmp.version, p);
112 else if (streq(field, "machine-id"))
113 r = free_and_strdup(&tmp.machine_id, p);
114 else if (streq(field, "architecture"))
115 r = free_and_strdup(&tmp.architecture, p);
116 else if (streq(field, "options"))
117 r = strv_extend(&tmp.options, p);
118 else if (streq(field, "linux"))
119 r = free_and_strdup(&tmp.kernel, p);
120 else if (streq(field, "efi"))
121 r = free_and_strdup(&tmp.efi, p);
122 else if (streq(field, "initrd"))
123 r = strv_extend(&tmp.initrd, p);
124 else if (streq(field, "devicetree"))
125 r = free_and_strdup(&tmp.device_tree, p);
126 else {
127 log_notice("%s:%u: Unknown line \"%s\", ignoring.", path, line, field);
128 continue;
129 }
130 if (r < 0)
131 return log_error_errno(r, "%s:%u: Error while reading: %m", path, line);
132 }
133
134 *entry = tmp;
135 tmp = (BootEntry) {};
136 return 0;
137 }
138
139 void boot_config_free(BootConfig *config) {
140 size_t i;
141
142 assert(config);
143
144 free(config->default_pattern);
145 free(config->timeout);
146 free(config->editor);
147 free(config->auto_entries);
148 free(config->auto_firmware);
149
150 free(config->entry_oneshot);
151 free(config->entry_default);
152
153 for (i = 0; i < config->n_entries; i++)
154 boot_entry_free(config->entries + i);
155 free(config->entries);
156 }
157
158 static int boot_loader_read_conf(const char *path, BootConfig *config) {
159 _cleanup_fclose_ FILE *f = NULL;
160 unsigned line = 1;
161 int r;
162
163 assert(path);
164 assert(config);
165
166 f = fopen(path, "re");
167 if (!f) {
168 if (errno == ENOENT)
169 return 0;
170
171 return log_error_errno(errno, "Failed to open \"%s\": %m", path);
172 }
173
174 for (;;) {
175 _cleanup_free_ char *buf = NULL, *field = NULL;
176 const char *p;
177
178 r = read_line(f, LONG_LINE_MAX, &buf);
179 if (r == 0)
180 break;
181 if (r == -ENOBUFS)
182 return log_error_errno(r, "%s:%u: Line too long", path, line);
183 if (r < 0)
184 return log_error_errno(r, "%s:%u: Error while reading: %m", path, line);
185
186 line++;
187
188 if (IN_SET(*strstrip(buf), '#', '\0'))
189 continue;
190
191 p = buf;
192 r = extract_first_word(&p, &field, " \t", 0);
193 if (r < 0) {
194 log_error_errno(r, "Failed to parse config file %s line %u: %m", path, line);
195 continue;
196 }
197 if (r == 0) {
198 log_warning("%s:%u: Bad syntax", path, line);
199 continue;
200 }
201
202 if (streq(field, "default"))
203 r = free_and_strdup(&config->default_pattern, p);
204 else if (streq(field, "timeout"))
205 r = free_and_strdup(&config->timeout, p);
206 else if (streq(field, "editor"))
207 r = free_and_strdup(&config->editor, p);
208 else if (streq(field, "auto-entries"))
209 r = free_and_strdup(&config->auto_entries, p);
210 else if (streq(field, "auto-firmware"))
211 r = free_and_strdup(&config->auto_firmware, p);
212 else if (streq(field, "console-mode"))
213 r = free_and_strdup(&config->console_mode, p);
214 else {
215 log_notice("%s:%u: Unknown line \"%s\", ignoring.", path, line, field);
216 continue;
217 }
218 if (r < 0)
219 return log_error_errno(r, "%s:%u: Error while reading: %m", path, line);
220 }
221
222 return 1;
223 }
224
225 static int boot_entry_compare(const BootEntry *a, const BootEntry *b) {
226 return str_verscmp(a->id, b->id);
227 }
228
229 static int boot_entries_find(
230 const char *root,
231 const char *dir,
232 BootEntry **entries,
233 size_t *n_entries) {
234
235 _cleanup_strv_free_ char **files = NULL;
236 size_t n_allocated = *n_entries;
237 bool added = false;
238 char **f;
239 int r;
240
241 assert(root);
242 assert(dir);
243 assert(entries);
244 assert(n_entries);
245
246 r = conf_files_list(&files, ".conf", NULL, 0, dir, NULL);
247 if (r < 0)
248 return log_error_errno(r, "Failed to list files in \"%s\": %m", dir);
249
250 STRV_FOREACH(f, files) {
251 if (!GREEDY_REALLOC0(*entries, n_allocated, *n_entries + 1))
252 return log_oom();
253
254 r = boot_entry_load(root, *f, *entries + *n_entries);
255 if (r < 0)
256 continue;
257
258 (*n_entries) ++;
259 added = true;
260 }
261
262 if (added)
263 typesafe_qsort(*entries, *n_entries, boot_entry_compare);
264
265 return 0;
266 }
267
268 static bool find_nonunique(BootEntry *entries, size_t n_entries, bool *arr) {
269 size_t i, j;
270 bool non_unique = false;
271
272 assert(entries || n_entries == 0);
273 assert(arr || n_entries == 0);
274
275 for (i = 0; i < n_entries; i++)
276 arr[i] = false;
277
278 for (i = 0; i < n_entries; i++)
279 for (j = 0; j < n_entries; j++)
280 if (i != j && streq(boot_entry_title(entries + i),
281 boot_entry_title(entries + j)))
282 non_unique = arr[i] = arr[j] = true;
283
284 return non_unique;
285 }
286
287 static int boot_entries_uniquify(BootEntry *entries, size_t n_entries) {
288 char *s;
289 size_t i;
290 int r;
291 bool arr[n_entries];
292
293 assert(entries || n_entries == 0);
294
295 /* Find _all_ non-unique titles */
296 if (!find_nonunique(entries, n_entries, arr))
297 return 0;
298
299 /* Add version to non-unique titles */
300 for (i = 0; i < n_entries; i++)
301 if (arr[i] && entries[i].version) {
302 r = asprintf(&s, "%s (%s)", boot_entry_title(entries + i), entries[i].version);
303 if (r < 0)
304 return -ENOMEM;
305
306 free_and_replace(entries[i].show_title, s);
307 }
308
309 if (!find_nonunique(entries, n_entries, arr))
310 return 0;
311
312 /* Add machine-id to non-unique titles */
313 for (i = 0; i < n_entries; i++)
314 if (arr[i] && entries[i].machine_id) {
315 r = asprintf(&s, "%s (%s)", boot_entry_title(entries + i), entries[i].machine_id);
316 if (r < 0)
317 return -ENOMEM;
318
319 free_and_replace(entries[i].show_title, s);
320 }
321
322 if (!find_nonunique(entries, n_entries, arr))
323 return 0;
324
325 /* Add file name to non-unique titles */
326 for (i = 0; i < n_entries; i++)
327 if (arr[i]) {
328 r = asprintf(&s, "%s (%s)", boot_entry_title(entries + i), entries[i].id);
329 if (r < 0)
330 return -ENOMEM;
331
332 free_and_replace(entries[i].show_title, s);
333 }
334
335 return 0;
336 }
337
338 static int boot_entries_select_default(const BootConfig *config) {
339 int i;
340
341 assert(config);
342
343 if (config->entry_oneshot)
344 for (i = config->n_entries - 1; i >= 0; i--)
345 if (streq(config->entry_oneshot, config->entries[i].id)) {
346 log_debug("Found default: id \"%s\" is matched by LoaderEntryOneShot",
347 config->entries[i].id);
348 return i;
349 }
350
351 if (config->entry_default)
352 for (i = config->n_entries - 1; i >= 0; i--)
353 if (streq(config->entry_default, config->entries[i].id)) {
354 log_debug("Found default: id \"%s\" is matched by LoaderEntryDefault",
355 config->entries[i].id);
356 return i;
357 }
358
359 if (config->default_pattern)
360 for (i = config->n_entries - 1; i >= 0; i--)
361 if (fnmatch(config->default_pattern, config->entries[i].id, FNM_CASEFOLD) == 0) {
362 log_debug("Found default: id \"%s\" is matched by pattern \"%s\"",
363 config->entries[i].id, config->default_pattern);
364 return i;
365 }
366
367 if (config->n_entries > 0)
368 log_debug("Found default: last entry \"%s\"", config->entries[config->n_entries - 1].id);
369 else
370 log_debug("Found no default boot entry :(");
371
372 return config->n_entries - 1; /* -1 means "no default" */
373 }
374
375 int boot_entries_load_config(
376 const char *esp_path,
377 const char *xbootldr_path,
378 BootConfig *config) {
379
380 const char *p;
381 int r;
382
383 assert(config);
384
385 if (esp_path) {
386 p = strjoina(esp_path, "/loader/loader.conf");
387 r = boot_loader_read_conf(p, config);
388 if (r < 0)
389 return r;
390
391 p = strjoina(esp_path, "/loader/entries");
392 r = boot_entries_find(esp_path, p, &config->entries, &config->n_entries);
393 if (r < 0)
394 return r;
395 }
396
397 if (xbootldr_path) {
398 p = strjoina(xbootldr_path, "/loader/entries");
399 r = boot_entries_find(xbootldr_path, p, &config->entries, &config->n_entries);
400 if (r < 0)
401 return r;
402 }
403
404 r = boot_entries_uniquify(config->entries, config->n_entries);
405 if (r < 0)
406 return log_error_errno(r, "Failed to uniquify boot entries: %m");
407
408 if (is_efi_boot()) {
409 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntryOneShot", &config->entry_oneshot);
410 if (r < 0 && r != -ENOENT)
411 return log_error_errno(r, "Failed to read EFI var \"LoaderEntryOneShot\": %m");
412
413 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntryDefault", &config->entry_default);
414 if (r < 0 && r != -ENOENT)
415 return log_error_errno(r, "Failed to read EFI var \"LoaderEntryDefault\": %m");
416 }
417
418 config->default_entry = boot_entries_select_default(config);
419 return 0;
420 }
421
422 /********************************************************************************/
423
424 static int verify_esp_blkid(
425 dev_t devid,
426 bool searching,
427 uint32_t *ret_part,
428 uint64_t *ret_pstart,
429 uint64_t *ret_psize,
430 sd_id128_t *ret_uuid) {
431
432 sd_id128_t uuid = SD_ID128_NULL;
433 uint64_t pstart = 0, psize = 0;
434 uint32_t part = 0;
435
436 #if HAVE_BLKID
437 _cleanup_(blkid_free_probep) blkid_probe b = NULL;
438 _cleanup_free_ char *node = NULL;
439 const char *v;
440 int r;
441
442 r = device_path_make_major_minor(S_IFBLK, devid, &node);
443 if (r < 0)
444 return log_error_errno(r, "Failed to format major/minor device path: %m");
445
446 errno = 0;
447 b = blkid_new_probe_from_filename(node);
448 if (!b)
449 return log_error_errno(errno ?: SYNTHETIC_ERRNO(ENOMEM), "Failed to open file system \"%s\": %m", node);
450
451 blkid_probe_enable_superblocks(b, 1);
452 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
453 blkid_probe_enable_partitions(b, 1);
454 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
455
456 errno = 0;
457 r = blkid_do_safeprobe(b);
458 if (r == -2)
459 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" is ambiguous.", node);
460 else if (r == 1)
461 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" does not contain a label.", node);
462 else if (r != 0)
463 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system \"%s\": %m", node);
464
465 errno = 0;
466 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
467 if (r != 0)
468 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system type of \"%s\": %m", node);
469 if (!streq(v, "vfat"))
470 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
471 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
472 "File system \"%s\" is not FAT.", node);
473
474 errno = 0;
475 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
476 if (r != 0)
477 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition scheme of \"%s\": %m", node);
478 if (!streq(v, "gpt"))
479 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
480 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
481 "File system \"%s\" is not on a GPT partition table.", node);
482
483 errno = 0;
484 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
485 if (r != 0)
486 return log_error_errno(errno ?: EIO, "Failed to probe partition type UUID of \"%s\": %m", node);
487 if (!streq(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"))
488 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
489 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
490 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
491
492 errno = 0;
493 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
494 if (r != 0)
495 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition entry UUID of \"%s\": %m", node);
496 r = sd_id128_from_string(v, &uuid);
497 if (r < 0)
498 return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
499
500 errno = 0;
501 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
502 if (r != 0)
503 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition number of \"%s\": m", node);
504 r = safe_atou32(v, &part);
505 if (r < 0)
506 return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
507
508 errno = 0;
509 r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL);
510 if (r != 0)
511 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition offset of \"%s\": %m", node);
512 r = safe_atou64(v, &pstart);
513 if (r < 0)
514 return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field.");
515
516 errno = 0;
517 r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL);
518 if (r != 0)
519 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition size of \"%s\": %m", node);
520 r = safe_atou64(v, &psize);
521 if (r < 0)
522 return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field.");
523 #endif
524
525 if (ret_part)
526 *ret_part = part;
527 if (ret_pstart)
528 *ret_pstart = pstart;
529 if (ret_psize)
530 *ret_psize = psize;
531 if (ret_uuid)
532 *ret_uuid = uuid;
533
534 return 0;
535 }
536
537 static int verify_esp_udev(
538 dev_t devid,
539 bool searching,
540 uint32_t *ret_part,
541 uint64_t *ret_pstart,
542 uint64_t *ret_psize,
543 sd_id128_t *ret_uuid) {
544
545 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
546 _cleanup_free_ char *node = NULL;
547 sd_id128_t uuid = SD_ID128_NULL;
548 uint64_t pstart = 0, psize = 0;
549 uint32_t part = 0;
550 const char *v;
551 int r;
552
553 r = device_path_make_major_minor(S_IFBLK, devid, &node);
554 if (r < 0)
555 return log_error_errno(r, "Failed to format major/minor device path: %m");
556
557 r = sd_device_new_from_devnum(&d, 'b', devid);
558 if (r < 0)
559 return log_error_errno(r, "Failed to get device from device number: %m");
560
561 r = sd_device_get_property_value(d, "ID_FS_TYPE", &v);
562 if (r < 0)
563 return log_error_errno(r, "Failed to get device property: %m");
564 if (!streq(v, "vfat"))
565 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
566 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
567 "File system \"%s\" is not FAT.", node );
568
569 r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &v);
570 if (r < 0)
571 return log_error_errno(r, "Failed to get device property: %m");
572 if (!streq(v, "gpt"))
573 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
574 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
575 "File system \"%s\" is not on a GPT partition table.", node);
576
577 r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
578 if (r < 0)
579 return log_error_errno(r, "Failed to get device property: %m");
580 if (!streq(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"))
581 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
582 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
583 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
584
585 r = sd_device_get_property_value(d, "ID_PART_ENTRY_UUID", &v);
586 if (r < 0)
587 return log_error_errno(r, "Failed to get device property: %m");
588 r = sd_id128_from_string(v, &uuid);
589 if (r < 0)
590 return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
591
592 r = sd_device_get_property_value(d, "ID_PART_ENTRY_NUMBER", &v);
593 if (r < 0)
594 return log_error_errno(r, "Failed to get device property: %m");
595 r = safe_atou32(v, &part);
596 if (r < 0)
597 return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
598
599 r = sd_device_get_property_value(d, "ID_PART_ENTRY_OFFSET", &v);
600 if (r < 0)
601 return log_error_errno(r, "Failed to get device property: %m");
602 r = safe_atou64(v, &pstart);
603 if (r < 0)
604 return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field.");
605
606 r = sd_device_get_property_value(d, "ID_PART_ENTRY_SIZE", &v);
607 if (r < 0)
608 return log_error_errno(r, "Failed to get device property: %m");
609 r = safe_atou64(v, &psize);
610 if (r < 0)
611 return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field.");
612
613 if (ret_part)
614 *ret_part = part;
615 if (ret_pstart)
616 *ret_pstart = pstart;
617 if (ret_psize)
618 *ret_psize = psize;
619 if (ret_uuid)
620 *ret_uuid = uuid;
621
622 return 0;
623 }
624
625 static int verify_esp(
626 const char *p,
627 bool searching,
628 bool unprivileged_mode,
629 uint32_t *ret_part,
630 uint64_t *ret_pstart,
631 uint64_t *ret_psize,
632 sd_id128_t *ret_uuid) {
633
634 struct stat st, st2;
635 struct statfs sfs;
636 bool relax_checks;
637 const char *t2;
638 int r;
639
640 assert(p);
641
642 /* This logs about all errors, except:
643 *
644 * -ENOENT → if 'searching' is set, and the dir doesn't exist
645 * -EADDRNOTAVAIL → if 'searching' is set, and the dir doesn't look like an ESP
646 * -EACESS → if 'unprivileged_mode' is set, and we have trouble acessing the thing
647 */
648
649 relax_checks = getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0;
650
651 /* Non-root user can only check the status, so if an error occured in the following, it does not cause any
652 * issues. Let's also, silence the error messages. */
653
654 if (!relax_checks) {
655 if (statfs(p, &sfs) < 0)
656 /* If we are searching for the mount point, don't generate a log message if we can't find the path */
657 return log_full_errno((searching && errno == ENOENT) ||
658 (unprivileged_mode && errno == EACCES) ? LOG_DEBUG : LOG_ERR, errno,
659 "Failed to check file system type of \"%s\": %m", p);
660
661 if (!F_TYPE_EQUAL(sfs.f_type, MSDOS_SUPER_MAGIC))
662 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
663 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
664 "File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p);
665 }
666
667 if (stat(p, &st) < 0)
668 return log_full_errno((searching && errno == ENOENT) ||
669 (unprivileged_mode && errno == EACCES) ? LOG_DEBUG : LOG_ERR, errno,
670 "Failed to determine block device node of \"%s\": %m", p);
671
672 if (major(st.st_dev) == 0)
673 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
674 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
675 "Block device node of \"%s\" is invalid.", p);
676
677 t2 = strjoina(p, "/..");
678 r = stat(t2, &st2);
679 if (r < 0)
680 return log_full_errno(unprivileged_mode && errno == EACCES ? LOG_DEBUG : LOG_ERR, errno,
681 "Failed to determine block device node of parent of \"%s\": %m", p);
682
683 if (st.st_dev == st2.st_dev)
684 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
685 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
686 "Directory \"%s\" is not the root of the EFI System Partition (ESP) file system.", p);
687
688 /* In a container we don't have access to block devices, skip this part of the verification, we trust
689 * the container manager set everything up correctly on its own. */
690 if (detect_container() > 0 || relax_checks)
691 goto finish;
692
693 /* If we are unprivileged we ask udev for the metadata about the partition. If we are privileged we
694 * use blkid instead. Why? Because this code is called from 'bootctl' which is pretty much an
695 * emergency recovery tool that should also work when udev isn't up (i.e. from the emergency shell),
696 * however blkid can't work if we have no privileges to access block devices directly, which is why
697 * we use udev in that case. */
698 if (unprivileged_mode)
699 return verify_esp_udev(st.st_dev, searching, ret_part, ret_pstart, ret_psize, ret_uuid);
700 else
701 return verify_esp_blkid(st.st_dev, searching, ret_part, ret_pstart, ret_psize, ret_uuid);
702
703 finish:
704 if (ret_part)
705 *ret_part = 0;
706 if (ret_pstart)
707 *ret_pstart = 0;
708 if (ret_psize)
709 *ret_psize = 0;
710 if (ret_uuid)
711 *ret_uuid = SD_ID128_NULL;
712
713 return 0;
714 }
715
716 int find_esp_and_warn(
717 const char *path,
718 bool unprivileged_mode,
719 char **ret_path,
720 uint32_t *ret_part,
721 uint64_t *ret_pstart,
722 uint64_t *ret_psize,
723 sd_id128_t *ret_uuid) {
724
725 int r;
726
727 /* This logs about all errors except:
728 *
729 * -ENOKEY → when we can't find the partition
730 * -EACCESS → when unprivileged_mode is true, and we can't access something
731 */
732
733 if (path) {
734 r = verify_esp(path, false, unprivileged_mode, ret_part, ret_pstart, ret_psize, ret_uuid);
735 if (r < 0)
736 return r;
737
738 goto found;
739 }
740
741 path = getenv("SYSTEMD_ESP_PATH");
742 if (path) {
743 if (!path_is_valid(path) || !path_is_absolute(path))
744 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
745 "$SYSTEMD_ESP_PATH does not refer to absolute path, refusing to use it: %s",
746 path);
747
748 /* Note: when the user explicitly configured things with an env var we won't validate the mount
749 * point. After all we want this to be useful for testing. */
750 goto found;
751 }
752
753 FOREACH_STRING(path, "/efi", "/boot", "/boot/efi") {
754
755 r = verify_esp(path, true, unprivileged_mode, ret_part, ret_pstart, ret_psize, ret_uuid);
756 if (r >= 0)
757 goto found;
758 if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */
759 return r;
760 }
761
762 /* No logging here */
763 return -ENOKEY;
764
765 found:
766 if (ret_path) {
767 char *c;
768
769 c = strdup(path);
770 if (!c)
771 return log_oom();
772
773 *ret_path = c;
774 }
775
776 return 0;
777 }
778
779 static int verify_xbootldr_blkid(
780 dev_t devid,
781 bool searching,
782 sd_id128_t *ret_uuid) {
783
784 sd_id128_t uuid = SD_ID128_NULL;
785
786 #if HAVE_BLKID
787 _cleanup_(blkid_free_probep) blkid_probe b = NULL;
788 _cleanup_free_ char *node = NULL;
789 const char *v;
790 int r;
791
792 r = device_path_make_major_minor(S_IFBLK, devid, &node);
793 if (r < 0)
794 return log_error_errno(r, "Failed to format major/minor device path: %m");
795 errno = 0;
796 b = blkid_new_probe_from_filename(node);
797 if (!b)
798 return log_error_errno(errno ?: SYNTHETIC_ERRNO(ENOMEM), "Failed to open file system \"%s\": %m", node);
799
800 blkid_probe_enable_partitions(b, 1);
801 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
802
803 errno = 0;
804 r = blkid_do_safeprobe(b);
805 if (r == -2)
806 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" is ambiguous.", node);
807 else if (r == 1)
808 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" does not contain a label.", node);
809 else if (r != 0)
810 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system \"%s\": %m", node);
811
812 errno = 0;
813 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
814 if (r != 0)
815 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition scheme of \"%s\": %m", node);
816 if (streq(v, "gpt")) {
817
818 errno = 0;
819 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
820 if (r != 0)
821 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition type UUID of \"%s\": %m", node);
822 if (!streq(v, "bc13c2ff-59e6-4262-a352-b275fd6f7172"))
823 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
824 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
825 "File system \"%s\" has wrong type for extended boot loader partition.", node);
826
827 errno = 0;
828 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
829 if (r != 0)
830 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition entry UUID of \"%s\": %m", node);
831 r = sd_id128_from_string(v, &uuid);
832 if (r < 0)
833 return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
834
835 } else if (streq(v, "dos")) {
836
837 errno = 0;
838 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
839 if (r != 0)
840 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition type UUID of \"%s\": %m", node);
841 if (!streq(v, "0xea"))
842 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
843 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
844 "File system \"%s\" has wrong type for extended boot loader partition.", node);
845
846 } else
847 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
848 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
849 "File system \"%s\" is not on a GPT or DOS partition table.", node);
850 #endif
851
852 if (ret_uuid)
853 *ret_uuid = uuid;
854
855 return 0;
856 }
857
858 static int verify_xbootldr(
859 const char *p,
860 bool searching,
861 bool unprivileged_mode,
862 sd_id128_t *ret_uuid) {
863
864 struct stat st, st2;
865 bool relax_checks;
866 const char *t2;
867 int r;
868
869 assert(p);
870
871 relax_checks = getenv_bool("SYSTEMD_RELAX_XBOOTLDR_CHECKS") > 0;
872
873 if (stat(p, &st) < 0)
874 return log_full_errno((searching && errno == ENOENT) ||
875 (unprivileged_mode && errno == EACCES) ? LOG_DEBUG : LOG_ERR, errno,
876 "Failed to determine block device node of \"%s\": %m", p);
877
878 if (major(st.st_dev) == 0)
879 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
880 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
881 "Block device node of \"%s\" is invalid.", p);
882
883 t2 = strjoina(p, "/..");
884 r = stat(t2, &st2);
885 if (r < 0)
886 return log_full_errno(unprivileged_mode && errno == EACCES ? LOG_DEBUG : LOG_ERR, errno,
887 "Failed to determine block device node of parent of \"%s\": %m", p);
888
889 if (st.st_dev == st2.st_dev)
890 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
891 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
892 "Directory \"%s\" is not the root of the XBOOTLDR file system.", p);
893
894 /* In a container we don't have access to block devices, skip this part of the verification, we trust
895 * the container manager set everything up correctly on its own. Also skip the following verification
896 * for non-root user. */
897 if (detect_container() > 0 || unprivileged_mode || relax_checks)
898 goto finish;
899
900 return verify_xbootldr_blkid(st.st_dev, searching, ret_uuid);
901
902 finish:
903 if (ret_uuid)
904 *ret_uuid = SD_ID128_NULL;
905
906 return 0;
907 }
908
909 int find_xbootldr_and_warn(
910 const char *path,
911 bool unprivileged_mode,
912 char **ret_path,
913 sd_id128_t *ret_uuid) {
914
915 int r;
916
917 /* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */
918
919 if (path) {
920 r = verify_xbootldr(path, false, unprivileged_mode, ret_uuid);
921 if (r < 0)
922 return r;
923
924 goto found;
925 }
926
927 path = getenv("SYSTEMD_XBOOTLDR_PATH");
928 if (path) {
929 if (!path_is_valid(path) || !path_is_absolute(path))
930 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
931 "$SYSTEMD_XBOOTLDR_PATH does not refer to absolute path, refusing to use it: %s",
932 path);
933
934 goto found;
935 }
936
937 r = verify_xbootldr("/boot", true, unprivileged_mode, ret_uuid);
938 if (r >= 0) {
939 path = "/boot";
940 goto found;
941 }
942 if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */
943 return r;
944
945 return -ENOKEY;
946
947 found:
948 if (ret_path) {
949 char *c;
950
951 c = strdup(path);
952 if (!c)
953 return log_oom();
954
955 *ret_path = c;
956 }
957
958 return 0;
959 }
960
961 int find_default_boot_entry(
962 const char *esp_path,
963 const char *xbootldr_path,
964 BootConfig *config,
965 const BootEntry **e) {
966
967 _cleanup_free_ char *esp_where = NULL, *xbootldr_where = NULL;
968 int r;
969
970 assert(config);
971 assert(e);
972
973 r = find_esp_and_warn(esp_path, false, &esp_where, NULL, NULL, NULL, NULL);
974 if (r < 0)
975 return r;
976
977 r = find_xbootldr_and_warn(xbootldr_path, false, &xbootldr_where, NULL);
978 if (r < 0 && r != -ENOKEY)
979 return r;
980
981 r = boot_entries_load_config(esp_where, xbootldr_where, config);
982 if (r < 0)
983 return log_error_errno(r, "Failed to load boot loader entries: %m");
984
985 if (config->default_entry < 0)
986 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
987 "No boot loader entry suitable as default, refusing to guess.");
988
989 *e = &config->entries[config->default_entry];
990 log_debug("Found default boot loader entry in file \"%s\"", (*e)->path);
991
992 return 0;
993 }