diff --git a/man/systemd-measure.xml b/man/systemd-measure.xml index 8ea667426e..931b62c12e 100644 --- a/man/systemd-measure.xml +++ b/man/systemd-measure.xml @@ -17,7 +17,7 @@ systemd-measure - Pre-calculate and sign expected TPM2 PCR values for booted unified kernel images + Pre-calculate and sign expected TPM2 PCR 11 values for booted unified kernel images @@ -62,7 +62,7 @@ status This is the default command if none is specified. This queries the local system's - TPM2 PCR 11+12+13 values and displays them. The data is written in a similar format as the + TPM2 PCR 11 values and displays them. The data is written in a similar format as the calculate command below, and may be used to quickly compare expectation with reality. @@ -76,9 +76,9 @@ kernel image consisting of the components specified with , , , , , , , - , , see below. - Only is mandatory. (Alternatively, specify to use the current values of PCR - register 11 instead.) + , , see below. Only + is mandatory. (Alternatively, specify to use the + current values of PCR register 11 instead.) diff --git a/man/ukify.xml b/man/ukify.xml index bf6f328536..68c72b0ba1 100644 --- a/man/ukify.xml +++ b/man/ukify.xml @@ -292,6 +292,29 @@ + + OSRelease=TEXT|@PATH + + + The os-release description (the .osrel section). The argument + may be a literal string, or @ followed by a path name. If not specified, the + os-release5 file + will be picked up from the host system. + + + + + + Cmdline=TEXT|@PATH + + + The kernel command line (the .cmdline section). The argument may + be a literal string, or @ followed by a path name. If not specified, no command + line will be embedded. + + + + Initrd=INITRD... @@ -314,24 +337,12 @@ - Cmdline=TEXT|@PATH - + Splash=PATH + - The kernel command line (the .cmdline section). The argument may - be a literal string, or @ followed by a path name. If not specified, no command - line will be embedded. - - - - - - OSRelease=TEXT|@PATH - - - The os-release description (the .osrel section). The argument - may be a literal string, or @ followed by a path name. If not specified, the - os-release5 file - will be picked up from the host system. + A picture to display during boot (the .splash section). The + argument is a path to a BMP file. If not specified, the section will not be present. + @@ -348,16 +359,35 @@ - Splash=PATH - + Uname=VERSION + - A picture to display during boot (the .splash section). The - argument is a path to a BMP file. If not specified, the section will not be present. - + Specify the kernel version (as in uname -r, the + .uname section). If not specified, an attempt will be made to extract the + version string from the kernel image. It is recommended to pass this explicitly if known, because + the extraction is based on heuristics and not very reliable. If not specified and extraction fails, + the section will not be present. + + SBAT=TEXT|@PATH + + + SBAT metadata associated with the UKI or addon. SBAT policies are useful to revoke + whole groups of UKIs or addons with a single, static policy update that does not take space in + DBX/MOKX. If not specified manually, a default metadata entry consisting of + uki,1,UKI,uki,1,https://uapi-group.org/specifications/specs/unified_kernel_image/ + for UKIs and + uki-addon,1,UKI Addon,addon,1,https://www.freedesktop.org/software/systemd/man/latest/systemd-stub.html + for addons will be used, to ensure it is always possible to revoke them. For more information on + SBAT see Shim documentation. + + + + + PCRPKey=PATH @@ -370,19 +400,6 @@ - - Uname=VERSION - - - Specify the kernel version (as in uname -r, the - .uname section). If not specified, an attempt will be made to extract the - version string from the kernel image. It is recommended to pass this explicitly if known, because - the extraction is based on heuristics and not very reliable. If not specified and extraction fails, - the section will not be present. - - - - PCRBanks=PATH @@ -488,23 +505,6 @@ - - - SBAT=TEXT|@PATH - - - SBAT metadata associated with the UKI or addon. SBAT policies are useful to revoke - whole groups of UKIs or addons with a single, static policy update that does not take space in - DBX/MOKX. If not specified manually, a default metadata entry consisting of - uki,1,UKI,uki,1,https://uapi-group.org/specifications/specs/unified_kernel_image/ - for UKIs and - uki-addon,1,UKI Addon,addon,1,https://www.freedesktop.org/software/systemd/man/latest/systemd-stub.html - for addons will be used, to ensure it is always possible to revoke them. For more information on - SBAT see Shim documentation. - - - - diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index b3d9329926..6333cdade6 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -620,16 +620,21 @@ static void print_status(Config *config, char16_t *loaded_image_path) { } static EFI_STATUS set_reboot_into_firmware(void) { - uint64_t osind = 0; EFI_STATUS err; + uint64_t osind = 0; (void) efivar_get_uint64_le(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE), u"OsIndications", &osind); + + if (FLAGS_SET(osind, EFI_OS_INDICATIONS_BOOT_TO_FW_UI)) + return EFI_SUCCESS; + osind |= EFI_OS_INDICATIONS_BOOT_TO_FW_UI; err = efivar_set_uint64_le(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE), u"OsIndications", osind, EFI_VARIABLE_NON_VOLATILE); if (err != EFI_SUCCESS) - log_error_status(err, "Error setting OsIndications: %m"); - return err; + return log_error_status(err, "Error setting OsIndications, ignoring: %m"); + + return EFI_SUCCESS; } _noreturn_ static EFI_STATUS poweroff_system(void) { @@ -881,6 +886,7 @@ static bool menu_run( switch (key) { case KEYPRESS(0, SCAN_UP, 0): + case KEYPRESS(0, SCAN_VOLUME_UP, 0): /* Handle phones/tablets that only have a volume up/down rocker + power key (and otherwise just touchscreen input) */ case KEYPRESS(0, 0, 'k'): case KEYPRESS(0, 0, 'K'): if (idx_highlight > 0) @@ -888,6 +894,7 @@ static bool menu_run( break; case KEYPRESS(0, SCAN_DOWN, 0): + case KEYPRESS(0, SCAN_VOLUME_DOWN, 0): case KEYPRESS(0, 0, 'j'): case KEYPRESS(0, 0, 'J'): if (idx_highlight < config->n_entries-1) @@ -925,9 +932,10 @@ static bool menu_run( case KEYPRESS(0, 0, '\n'): case KEYPRESS(0, 0, '\r'): - case KEYPRESS(0, SCAN_F3, 0): /* EZpad Mini 4s firmware sends malformed events */ - case KEYPRESS(0, SCAN_F3, '\r'): /* Teclast X98+ II firmware sends malformed events */ + case KEYPRESS(0, SCAN_F3, 0): /* EZpad Mini 4s firmware sends malformed events */ + case KEYPRESS(0, SCAN_F3, '\r'): /* Teclast X98+ II firmware sends malformed events */ case KEYPRESS(0, SCAN_RIGHT, 0): + case KEYPRESS(0, SCAN_SUSPEND, 0): /* Handle phones/tablets with only a power key + volume up/down rocker (and otherwise just touchscreen input) */ action = ACTION_RUN; break; @@ -1658,15 +1666,21 @@ static void config_load_type1_entries( continue; if (FLAGS_SET(f->Attribute, EFI_FILE_DIRECTORY)) continue; - if (!endswith_no_case(f->FileName, u".conf")) continue; - if (startswith(f->FileName, u"auto-")) + if (startswith_no_case(f->FileName, u"auto-")) continue; - err = file_read(entries_dir, f->FileName, 0, 0, &content, NULL); - if (err == EFI_SUCCESS) - boot_entry_add_type1(config, device, root_dir, u"\\loader\\entries", f->FileName, content, loaded_image_path); + err = file_read(entries_dir, + f->FileName, + /* offset= */ 0, + /* size= */ 0, + &content, + /* ret_size= */ NULL); + if (err != EFI_SUCCESS) + continue; + + boot_entry_add_type1(config, device, root_dir, u"\\loader\\entries", f->FileName, content, loaded_image_path); } } @@ -2081,6 +2095,139 @@ static void config_add_entry_windows(Config *config, EFI_HANDLE *device, EFI_FIL #endif } +static void boot_entry_add_type2( + Config *config, + EFI_HANDLE *device, + EFI_FILE *dir, + const uint16_t *filename) { + + enum { + SECTION_CMDLINE, + SECTION_OSREL, + _SECTION_MAX, + }; + static const char * const section_names[_SECTION_MAX + 1] = { + [SECTION_CMDLINE] = ".cmdline", + [SECTION_OSREL] = ".osrel", + NULL, + }; + + EFI_STATUS err; + + assert(config); + assert(device); + assert(dir); + assert(filename); + + /* Look for .osrel and .cmdline sections in the .efi binary */ + PeSectionVector sections[_SECTION_MAX] = {}; + err = pe_file_locate_sections(dir, filename, section_names, sections); + if (err != EFI_SUCCESS || !PE_SECTION_VECTOR_IS_SET(sections + SECTION_OSREL)) + return; + + _cleanup_free_ char *content = NULL; + err = file_read(dir, + filename, + sections[SECTION_OSREL].file_offset, + sections[SECTION_OSREL].size, + &content, + /* ret_size= */ NULL); + if (err != EFI_SUCCESS) + return; + + _cleanup_free_ char16_t *os_pretty_name = NULL, *os_image_id = NULL, *os_name = NULL, *os_id = NULL, + *os_image_version = NULL, *os_version = NULL, *os_version_id = NULL, *os_build_id = NULL; + char *line, *key, *value; + size_t pos = 0; + + /* read properties from the embedded os-release file */ + while ((line = line_get_key_value(content, "=", &pos, &key, &value))) + if (streq8(key, "PRETTY_NAME")) { + free(os_pretty_name); + os_pretty_name = xstr8_to_16(value); + + } else if (streq8(key, "IMAGE_ID")) { + free(os_image_id); + os_image_id = xstr8_to_16(value); + + } else if (streq8(key, "NAME")) { + free(os_name); + os_name = xstr8_to_16(value); + + } else if (streq8(key, "ID")) { + free(os_id); + os_id = xstr8_to_16(value); + + } else if (streq8(key, "IMAGE_VERSION")) { + free(os_image_version); + os_image_version = xstr8_to_16(value); + + } else if (streq8(key, "VERSION")) { + free(os_version); + os_version = xstr8_to_16(value); + + } else if (streq8(key, "VERSION_ID")) { + free(os_version_id); + os_version_id = xstr8_to_16(value); + + } else if (streq8(key, "BUILD_ID")) { + free(os_build_id); + os_build_id = xstr8_to_16(value); + } + + const char16_t *good_name, *good_version, *good_sort_key; + if (!bootspec_pick_name_version_sort_key( + os_pretty_name, + os_image_id, + os_name, + os_id, + os_image_version, + os_version, + os_version_id, + os_build_id, + &good_name, + &good_version, + &good_sort_key)) + return; + + BootEntry *entry = xnew(BootEntry, 1); + *entry = (BootEntry) { + .id = xstrdup16(filename), + .type = LOADER_UNIFIED_LINUX, + .title = xstrdup16(good_name), + .version = xstrdup16(good_version), + .device = device, + .loader = xasprintf("\\EFI\\Linux\\%ls", filename), + .sort_key = xstrdup16(good_sort_key), + .key = 'l', + .tries_done = -1, + .tries_left = -1, + }; + + strtolower16(entry->id); + config_add_entry(config, entry); + boot_entry_parse_tries(entry, u"\\EFI\\Linux", filename, u".efi"); + + if (!PE_SECTION_VECTOR_IS_SET(sections + SECTION_CMDLINE)) + return; + + content = mfree(content); + + /* read the embedded cmdline file */ + size_t cmdline_len; + err = file_read(dir, + filename, + sections[SECTION_CMDLINE].file_offset, + sections[SECTION_CMDLINE].size, + &content, + &cmdline_len); + if (err == EFI_SUCCESS) { + entry->options = xstrn8_to_16(content, cmdline_len); + mangle_stub_cmdline(entry->options); + entry->options_implied = true; + } +} + static void config_load_type2_entries( Config *config, EFI_HANDLE *device, @@ -2102,26 +2249,6 @@ static void config_load_type2_entries( return; for (;;) { - enum { - SECTION_CMDLINE, - SECTION_OSREL, - _SECTION_MAX, - }; - - static const char * const section_names[_SECTION_MAX + 1] = { - [SECTION_CMDLINE] = ".cmdline", - [SECTION_OSREL] = ".osrel", - NULL, - }; - - _cleanup_free_ char16_t *os_pretty_name = NULL, *os_image_id = NULL, *os_name = NULL, *os_id = NULL, - *os_image_version = NULL, *os_version = NULL, *os_version_id = NULL, *os_build_id = NULL; - const char16_t *good_name, *good_version, *good_sort_key; - _cleanup_free_ char *content = NULL; - PeSectionVector sections[_SECTION_MAX] = {}; - char *line, *key, *value; - size_t pos = 0; - err = readdir(linux_dir, &f, &f_size); if (err != EFI_SUCCESS || !f) break; @@ -2132,108 +2259,10 @@ static void config_load_type2_entries( continue; if (!endswith_no_case(f->FileName, u".efi")) continue; - if (startswith(f->FileName, u"auto-")) + if (startswith_no_case(f->FileName, u"auto-")) continue; - /* look for .osrel and .cmdline sections in the .efi binary */ - err = pe_file_locate_sections(linux_dir, f->FileName, section_names, sections); - if (err != EFI_SUCCESS || !PE_SECTION_VECTOR_IS_SET(sections + SECTION_OSREL)) - continue; - - err = file_read(linux_dir, - f->FileName, - sections[SECTION_OSREL].file_offset, - sections[SECTION_OSREL].size, - &content, - NULL); - if (err != EFI_SUCCESS) - continue; - - /* read properties from the embedded os-release file */ - while ((line = line_get_key_value(content, "=", &pos, &key, &value))) - if (streq8(key, "PRETTY_NAME")) { - free(os_pretty_name); - os_pretty_name = xstr8_to_16(value); - - } else if (streq8(key, "IMAGE_ID")) { - free(os_image_id); - os_image_id = xstr8_to_16(value); - - } else if (streq8(key, "NAME")) { - free(os_name); - os_name = xstr8_to_16(value); - - } else if (streq8(key, "ID")) { - free(os_id); - os_id = xstr8_to_16(value); - - } else if (streq8(key, "IMAGE_VERSION")) { - free(os_image_version); - os_image_version = xstr8_to_16(value); - - } else if (streq8(key, "VERSION")) { - free(os_version); - os_version = xstr8_to_16(value); - - } else if (streq8(key, "VERSION_ID")) { - free(os_version_id); - os_version_id = xstr8_to_16(value); - - } else if (streq8(key, "BUILD_ID")) { - free(os_build_id); - os_build_id = xstr8_to_16(value); - } - - if (!bootspec_pick_name_version_sort_key( - os_pretty_name, - os_image_id, - os_name, - os_id, - os_image_version, - os_version, - os_version_id, - os_build_id, - &good_name, - &good_version, - &good_sort_key)) - continue; - - BootEntry *entry = xnew(BootEntry, 1); - *entry = (BootEntry) { - .id = xstrdup16(f->FileName), - .type = LOADER_UNIFIED_LINUX, - .title = xstrdup16(good_name), - .version = xstrdup16(good_version), - .device = device, - .loader = xasprintf("\\EFI\\Linux\\%ls", f->FileName), - .sort_key = xstrdup16(good_sort_key), - .key = 'l', - .tries_done = -1, - .tries_left = -1, - }; - - strtolower16(entry->id); - config_add_entry(config, entry); - boot_entry_parse_tries(entry, u"\\EFI\\Linux", f->FileName, u".efi"); - - if (!PE_SECTION_VECTOR_IS_SET(sections + SECTION_CMDLINE)) - continue; - - content = mfree(content); - - /* read the embedded cmdline file */ - size_t cmdline_len; - err = file_read(linux_dir, - f->FileName, - sections[SECTION_CMDLINE].file_offset, - sections[SECTION_CMDLINE].size, - &content, - &cmdline_len); - if (err == EFI_SUCCESS) { - entry->options = xstrn8_to_16(content, cmdline_len); - mangle_stub_cmdline(entry->options); - entry->options_implied = true; - } + boot_entry_add_type2(config, device, linux_dir, f->FileName); } } diff --git a/src/boot/efi/pe.c b/src/boot/efi/pe.c index 587e3ef7b1..587960e321 100644 --- a/src/boot/efi/pe.c +++ b/src/boot/efi/pe.c @@ -178,22 +178,22 @@ static bool pe_section_name_equal(const char *a, const char *b) { static void pe_locate_sections( const PeSectionHeader section_table[], size_t n_section_table, - const char * const sections[], + const char *const section_names[], size_t validate_base, - PeSectionVector *ret_sections) { + PeSectionVector sections[]) { assert(section_table || n_section_table == 0); + assert(section_names); assert(sections); - assert(ret_sections); /* Searches for the sections listed in 'sections[]' within the section table. Validates the resulted * data. If 'validate_base' is non-zero also takes base offset when loaded into memory into account for * qchecking for overflows. */ - for (size_t i = 0; sections[i]; i++) + for (size_t i = 0; section_names[i]; i++) FOREACH_ARRAY(j, section_table, n_section_table) { - if (!pe_section_name_equal((const char*) j->Name, sections[i])) + if (!pe_section_name_equal((const char*) j->Name, section_names[i])) continue; /* Overflow check: ignore sections that are impossibly large, relative to the file @@ -220,7 +220,7 @@ static void pe_locate_sections( } /* At this time, the sizes and offsets have been validated. Store them away */ - ret_sections[i] = (PeSectionVector) { + sections[i] = (PeSectionVector) { .size = j->VirtualSize, .file_offset = j->PointerToRawData, .memory_offset = j->VirtualAddress, @@ -232,17 +232,19 @@ static void pe_locate_sections( } static uint32_t get_compatibility_entry_address(const DosFileHeader *dos, const PeFileHeader *pe) { - static const char *sections[] = { ".compat", NULL }; - PeSectionVector vector = {}; - /* The kernel may provide alternative PE entry points for different PE architectures. This allows * booting a 64-bit kernel on 32-bit EFI that is otherwise running on a 64-bit CPU. The locations of any * such compat entry points are located in a special PE section. */ + assert(dos); + assert(pe); + + static const char *const section_names[] = { ".compat", NULL }; + PeSectionVector vector = {}; pe_locate_sections( (const PeSectionHeader *) ((const uint8_t *) dos + section_table_offset(dos, pe)), pe->FileHeader.NumberOfSections, - sections, + section_names, PTR_TO_SIZE(dos), &vector); @@ -259,7 +261,7 @@ static uint32_t get_compatibility_entry_address(const DosFileHeader *dos, const size_t addr = vector.memory_offset, size = vector.size; while (size >= sizeof(LinuxPeCompat1) && addr % alignof(LinuxPeCompat1) == 0) { - LinuxPeCompat1 *compat = (LinuxPeCompat1 *) ((uint8_t *) dos + addr); + const LinuxPeCompat1 *compat = (const LinuxPeCompat1 *) ((const uint8_t *) dos + addr); if (compat->type == 0 || compat->size == 0 || compat->size > size) break; @@ -308,16 +310,16 @@ EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address) { EFI_STATUS pe_memory_locate_sections( const void *base, - const char* const sections[], - PeSectionVector *ret_sections) { + const char *const section_names[], + PeSectionVector sections[]) { const DosFileHeader *dos; const PeFileHeader *pe; size_t offset; assert(base); + assert(section_names); assert(sections); - assert(ret_sections); dos = (const DosFileHeader *) base; if (!verify_dos(dos)) @@ -331,9 +333,9 @@ EFI_STATUS pe_memory_locate_sections( pe_locate_sections( (const PeSectionHeader *) ((const uint8_t *) base + offset), pe->FileHeader.NumberOfSections, - sections, + section_names, PTR_TO_SIZE(base), - ret_sections); + sections); return EFI_SUCCESS; } @@ -341,8 +343,8 @@ EFI_STATUS pe_memory_locate_sections( EFI_STATUS pe_file_locate_sections( EFI_FILE *dir, const char16_t *path, - const char * const sections[], - PeSectionVector *ret_sections) { + const char *const section_names[], + PeSectionVector sections[]) { _cleanup_free_ PeSectionHeader *section_table = NULL; _cleanup_(file_closep) EFI_FILE *handle = NULL; DosFileHeader dos; @@ -352,8 +354,8 @@ EFI_STATUS pe_file_locate_sections( assert(dir); assert(path); + assert(section_names); assert(sections); - assert(ret_sections); err = dir->Open(dir, &handle, (char16_t *) path, EFI_FILE_MODE_READ, 0ULL); if (err != EFI_SUCCESS) @@ -402,9 +404,9 @@ EFI_STATUS pe_file_locate_sections( pe_locate_sections( section_table, pe.FileHeader.NumberOfSections, - sections, + section_names, /* validate_base= */ 0, /* don't validate base */ - ret_sections); + sections); return EFI_SUCCESS; } diff --git a/src/boot/efi/pe.h b/src/boot/efi/pe.h index bc6d74beeb..e55ac5daa9 100644 --- a/src/boot/efi/pe.h +++ b/src/boot/efi/pe.h @@ -17,13 +17,13 @@ static inline bool PE_SECTION_VECTOR_IS_SET(const PeSectionVector *v) { EFI_STATUS pe_memory_locate_sections( const void *base, - const char * const sections[], - PeSectionVector *ret_sections); + const char *const section_names[], + PeSectionVector sections[]); EFI_STATUS pe_file_locate_sections( EFI_FILE *dir, const char16_t *path, - const char * const sections[], - PeSectionVector *ret_sections); + const char *const section_names[], + PeSectionVector sections[]); EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address); diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c index 6ceb032fa1..aafaf06e98 100644 --- a/src/boot/efi/util.c +++ b/src/boot/efi/util.c @@ -9,6 +9,9 @@ #include "version.h" #include "efivars.h" +/* Never try to read more than 16G into memory (and on 32bit 1G) */ +#define FILE_READ_MAX MIN(SIZE_MAX/4, UINT64_C(16)*1024U*1024U*1024U) + void convert_efi_path(char16_t *path) { assert(path); @@ -39,19 +42,17 @@ static bool shall_be_whitespace(char16_t c) { } char16_t* mangle_stub_cmdline(char16_t *cmdline) { - char16_t *p, *q, *e; - if (!cmdline) return cmdline; - p = q = cmdline; - /* Skip initial whitespace */ - while (shall_be_whitespace(*p)) + const char16_t *p = cmdline; + while (*p != 0 && shall_be_whitespace(*p)) p++; /* Turn inner control characters into proper spaces */ - for (e = p; *p != 0; p++) { + char16_t *e = cmdline; + for (char16_t *q = cmdline; *p != 0; p++) { if (shall_be_whitespace(*p)) { *(q++) = ' '; continue; @@ -107,7 +108,7 @@ EFI_STATUS chunked_read(EFI_FILE *file, size_t *size, void *buf) { EFI_STATUS file_read( EFI_FILE *dir, const char16_t *name, - uint64_t off, + uint64_t offset, size_t size, char **ret, size_t *ret_size) { @@ -131,14 +132,17 @@ EFI_STATUS file_read( if (err != EFI_SUCCESS) return err; - if (info->FileSize > SIZE_MAX) + if (info->FileSize > SIZE_MAX) /* overflow check */ return EFI_BAD_BUFFER_SIZE; size = info->FileSize; } - if (off > 0) { - err = handle->SetPosition(handle, off); + if (size > FILE_READ_MAX) /* make sure we don't read unbounded data into RAM */ + return EFI_BAD_BUFFER_SIZE; + + if (offset > 0) { + err = handle->SetPosition(handle, offset); if (err != EFI_SUCCESS) return err; } diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h index 3a26bc5c92..dc16f3fb76 100644 --- a/src/boot/efi/util.h +++ b/src/boot/efi/util.h @@ -86,7 +86,7 @@ char16_t *xstr8_to_path(const char *stra); char16_t *mangle_stub_cmdline(char16_t *cmdline); EFI_STATUS chunked_read(EFI_FILE *file, size_t *size, void *buf); -EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, uint64_t off, size_t size, char **content, size_t *content_size); +EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, uint64_t offset, size_t size, char **content, size_t *content_size); static inline void file_closep(EFI_FILE **handle) { if (!*handle) diff --git a/src/boot/measure.c b/src/boot/measure.c index 9fdc37dfb5..81f1a9fbd2 100644 --- a/src/boot/measure.c +++ b/src/boot/measure.c @@ -1017,14 +1017,6 @@ static int validate_stub(void) { if (r < 0) return r; - r = compare_reported_pcr_nr(TPM2_PCR_KERNEL_CONFIG, EFI_LOADER_VARIABLE(StubPcrKernelParameters), "kernel parameters"); - if (r < 0) - return r; - - r = compare_reported_pcr_nr(TPM2_PCR_SYSEXTS, EFI_LOADER_VARIABLE(StubPcrInitRDSysExts), "initrd system extension images"); - if (r < 0) - return r; - STRV_FOREACH(bank, arg_banks) { _cleanup_free_ char *b = NULL, *p = NULL; @@ -1049,12 +1041,6 @@ static int validate_stub(void) { } static int verb_status(int argc, char *argv[], void *userdata) { - static const uint32_t relevant_pcrs[] = { - TPM2_PCR_KERNEL_BOOT, - TPM2_PCR_KERNEL_CONFIG, - TPM2_PCR_SYSEXTS, - }; - _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; int r; @@ -1062,72 +1048,69 @@ static int verb_status(int argc, char *argv[], void *userdata) { if (r < 0) return r; - for (size_t i = 0; i < ELEMENTSOF(relevant_pcrs); i++) { + STRV_FOREACH(bank, arg_banks) { + _cleanup_free_ char *b = NULL, *p = NULL, *s = NULL; + _cleanup_free_ void *h = NULL; + size_t l; - STRV_FOREACH(bank, arg_banks) { - _cleanup_free_ char *b = NULL, *p = NULL, *s = NULL; - _cleanup_free_ void *h = NULL; - size_t l; + b = strdup(*bank); + if (!b) + return log_oom(); - b = strdup(*bank); - if (!b) + if (asprintf(&p, "/sys/class/tpm/tpm0/pcr-%s/%" PRIu32, ascii_strlower(b), (uint32_t) TPM2_PCR_KERNEL_BOOT) < 0) + return log_oom(); + + r = read_virtual_file(p, 4096, &s, NULL); + if (r == -ENOENT) + continue; + if (r < 0) + return log_error_errno(r, "Failed to read '%s': %m", p); + + r = unhexmem(strstrip(s), &h, &l); + if (r < 0) + return log_error_errno(r, "Failed to decode PCR value '%s': %m", s); + + if (arg_json_format_flags & SD_JSON_FORMAT_OFF) { + _cleanup_free_ char *f = NULL; + + f = hexmem(h, l); + if (!h) return log_oom(); - if (asprintf(&p, "/sys/class/tpm/tpm0/pcr-%s/%" PRIu32, ascii_strlower(b), relevant_pcrs[i]) < 0) - return log_oom(); - - r = read_virtual_file(p, 4096, &s, NULL); - if (r == -ENOENT) - continue; - if (r < 0) - return log_error_errno(r, "Failed to read '%s': %m", p); - - r = unhexmem(strstrip(s), &h, &l); - if (r < 0) - return log_error_errno(r, "Failed to decode PCR value '%s': %m", s); - - if (arg_json_format_flags & SD_JSON_FORMAT_OFF) { - _cleanup_free_ char *f = NULL; - - f = hexmem(h, l); - if (!h) - return log_oom(); - - if (bank == arg_banks) { - /* before the first line for each PCR, write a short descriptive text to - * stderr, and leave the primary content on stdout */ - fflush(stdout); - fprintf(stderr, "%s# PCR[%" PRIu32 "] %s%s%s\n", - ansi_grey(), - relevant_pcrs[i], - tpm2_pcr_index_to_string(relevant_pcrs[i]), - memeqzero(h, l) ? " (NOT SET!)" : "", - ansi_normal()); - fflush(stderr); - } - - printf("%" PRIu32 ":%s=%s\n", relevant_pcrs[i], b, f); - - } else { - _cleanup_(sd_json_variant_unrefp) sd_json_variant *bv = NULL, *a = NULL; - - r = sd_json_buildo( - &bv, - SD_JSON_BUILD_PAIR("pcr", SD_JSON_BUILD_INTEGER(relevant_pcrs[i])), - SD_JSON_BUILD_PAIR("hash", SD_JSON_BUILD_HEX(h, l))); - if (r < 0) - return log_error_errno(r, "Failed to build JSON object: %m"); - - a = sd_json_variant_ref(sd_json_variant_by_key(v, b)); - - r = sd_json_variant_append_array(&a, bv); - if (r < 0) - return log_error_errno(r, "Failed to append PCR entry to JSON array: %m"); - - r = sd_json_variant_set_field(&v, b, a); - if (r < 0) - return log_error_errno(r, "Failed to add bank info to object: %m"); + if (bank == arg_banks) { + /* before the first line for each PCR, write a short descriptive text to + * stderr, and leave the primary content on stdout */ + fflush(stdout); + fprintf(stderr, "%s# PCR[%" PRIu32 "] %s%s%s\n", + ansi_grey(), + (uint32_t) TPM2_PCR_KERNEL_BOOT, + tpm2_pcr_index_to_string(TPM2_PCR_KERNEL_BOOT), + memeqzero(h, l) ? " (NOT SET!)" : "", + ansi_normal()); + fflush(stderr); } + + printf("%" PRIu32 ":%s=%s\n", (uint32_t) TPM2_PCR_KERNEL_BOOT, b, f); + + } else { + _cleanup_(sd_json_variant_unrefp) sd_json_variant *bv = NULL, *a = NULL; + + r = sd_json_buildo( + &bv, + SD_JSON_BUILD_PAIR("pcr", SD_JSON_BUILD_INTEGER(TPM2_PCR_KERNEL_BOOT)), + SD_JSON_BUILD_PAIR("hash", SD_JSON_BUILD_HEX(h, l))); + if (r < 0) + return log_error_errno(r, "Failed to build JSON object: %m"); + + a = sd_json_variant_ref(sd_json_variant_by_key(v, b)); + + r = sd_json_variant_append_array(&a, bv); + if (r < 0) + return log_error_errno(r, "Failed to append PCR entry to JSON array: %m"); + + r = sd_json_variant_set_field(&v, b, a); + if (r < 0) + return log_error_errno(r, "Failed to add bank info to object: %m"); } } diff --git a/src/ukify/ukify.py b/src/ukify/ukify.py index f1db9ba578..5a36ce06ee 100755 --- a/src/ukify/ukify.py +++ b/src/ukify/ukify.py @@ -1264,6 +1264,13 @@ CONFIG_ITEMS = [ action = 'store_true', ), + ConfigItem( + ('--config', '-c'), + metavar = 'PATH', + type = pathlib.Path, + help = 'configuration file', + ), + ConfigItem( '--linux', type = pathlib.Path, @@ -1271,6 +1278,20 @@ CONFIG_ITEMS = [ config_key = 'UKI/Linux', ), + ConfigItem( + '--os-release', + metavar = 'TEXT|@PATH', + help = 'path to os-release file [.osrel section]', + config_key = 'UKI/OSRelease', + ), + + ConfigItem( + '--cmdline', + metavar = 'TEXT|@PATH', + help = 'kernel command line [.cmdline section]', + config_key = 'UKI/Cmdline', + ), + ConfigItem( '--initrd', metavar = 'INITRD', @@ -1290,24 +1311,11 @@ CONFIG_ITEMS = [ ), ConfigItem( - ('--config', '-c'), - metavar = 'PATH', + '--splash', + metavar = 'BMP', type = pathlib.Path, - help = 'configuration file', - ), - - ConfigItem( - '--cmdline', - metavar = 'TEXT|@PATH', - help = 'kernel command line [.cmdline section]', - config_key = 'UKI/Cmdline', - ), - - ConfigItem( - '--os-release', - metavar = 'TEXT|@PATH', - help = 'path to os-release file [.osrel section]', - config_key = 'UKI/OSRelease', + help = 'splash image bitmap file [.splash section]', + config_key = 'UKI/Splash', ), ConfigItem( @@ -1317,13 +1325,23 @@ CONFIG_ITEMS = [ help = 'Device Tree file [.dtb section]', config_key = 'UKI/DeviceTree', ), + ConfigItem( - '--splash', - metavar = 'BMP', - type = pathlib.Path, - help = 'splash image bitmap file [.splash section]', - config_key = 'UKI/Splash', + '--uname', + metavar='VERSION', + help='"uname -r" information [.uname section]', + config_key = 'UKI/Uname', ), + + ConfigItem( + '--sbat', + metavar = 'TEXT|@PATH', + help = 'SBAT policy [.sbat section]', + default = [], + action = 'append', + config_key = 'UKI/SBAT', + ), + ConfigItem( '--pcrpkey', metavar = 'KEY', @@ -1331,11 +1349,14 @@ CONFIG_ITEMS = [ help = 'embedded public key to seal secrets to [.pcrpkey section]', config_key = 'UKI/PCRPKey', ), + ConfigItem( - '--uname', - metavar='VERSION', - help='"uname -r" information [.uname section]', - config_key = 'UKI/Uname', + '--section', + dest = 'sections', + metavar = 'NAME:TEXT|@PATH', + action = 'append', + default = [], + help = 'section as name and contents [NAME section] or section to print', ), ConfigItem( @@ -1353,24 +1374,6 @@ CONFIG_ITEMS = [ config_key = 'UKI/Stub', ), - ConfigItem( - '--sbat', - metavar = 'TEXT|@PATH', - help = 'SBAT policy [.sbat section]', - default = [], - action = 'append', - config_key = 'UKI/SBAT', - ), - - ConfigItem( - '--section', - dest = 'sections', - metavar = 'NAME:TEXT|@PATH', - action = 'append', - default = [], - help = 'section as name and contents [NAME section] or section to print', - ), - ConfigItem( '--pcr-banks', metavar = 'BANK…', @@ -1636,7 +1639,7 @@ def finalize_options(opts): elif len(opts.positional) == 1 and opts.positional[0] in VERBS: opts.verb = opts.positional[0] elif opts.linux or opts.initrd: - raise ValueError('--linux/--initrd options cannot be used with positional arguments') + raise ValueError('--linux=/--initrd= options cannot be used with positional arguments') else: print("Assuming obsolete command line syntax with no verb. Please use 'build'.") if opts.positional: