diff --git a/src/basic/macro.h b/src/basic/macro.h index 645f93096f..280f302864 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -20,7 +20,6 @@ #define _sentinel_ __attribute__((__sentinel__)) #define _destructor_ __attribute__((__destructor__)) #define _deprecated_ __attribute__((__deprecated__)) -#define _packed_ __attribute__((__packed__)) #define _malloc_ __attribute__((__malloc__)) #define _weak_ __attribute__((__weak__)) #define _public_ __attribute__((__visibility__("default"))) diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 9155e50ba8..5c11adf393 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -189,22 +189,6 @@ static inline void strncpy_exact(char *buf, const char *src, size_t buf_len) { } REENABLE_WARNING; -/* Like startswith(), but operates on arbitrary memory blocks */ -static inline void *memory_startswith(const void *p, size_t sz, const char *token) { - assert(token); - - size_t n = strlen(token); - if (sz < n) - return NULL; - - assert(p); - - if (memcmp(p, token, n) != 0) - return NULL; - - return (uint8_t*) p + n; -} - /* Like startswith_no_case(), but operates on arbitrary memory blocks. * It works only for ASCII strings. */ diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 638070d77a..82da984325 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -22,7 +22,7 @@ #endif /* magic string to find in the binary image */ -static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-boot " GIT_VERSION " ####"; +static const char _used_ _section_(".sdmagic") magic[] = "#### LoaderInfo: systemd-boot " GIT_VERSION " ####"; enum loader_type { LOADER_UNDEFINED, @@ -1792,6 +1792,29 @@ static ConfigEntry *config_entry_add_loader( return entry; } +static BOOLEAN is_sd_boot(EFI_FILE *root_dir, const CHAR16 *loader_path) { + EFI_STATUS err; + const CHAR8 *sections[] = { + (CHAR8 *)".sdmagic", + NULL + }; + UINTN offset = 0, size = 0, read; + _cleanup_freepool_ CHAR8 *content = NULL; + + assert(root_dir); + assert(loader_path); + + err = pe_file_locate_sections(root_dir, loader_path, sections, &offset, &size); + if (EFI_ERROR(err) || size != sizeof(magic)) + return FALSE; + + err = file_read(root_dir, loader_path, offset, size, &content, &read); + if (EFI_ERROR(err) || size != read) + return FALSE; + + return CompareMem(content, magic, sizeof(magic)) == 0; +} + static BOOLEAN config_entry_add_loader_auto( Config *config, EFI_HANDLE *device, @@ -1811,25 +1834,23 @@ static BOOLEAN config_entry_add_loader_auto( assert(root_dir); assert(id); assert(title); - assert(loader); + assert(loader || loaded_image_path); if (!config->auto_entries) return FALSE; - /* do not add an entry for ourselves */ if (loaded_image_path) { - UINTN len; - _cleanup_freepool_ CHAR8 *content = NULL; + loader = L"\\EFI\\BOOT\\BOOT" EFI_MACHINE_TYPE_NAME ".efi"; - if (StriCmp(loader, loaded_image_path) == 0) + /* We are trying to add the default EFI loader here, + * but we do not want to do that if that would be us. + * + * If the default loader is not us, it might be shim. It would + * chainload GRUBX64.EFI in that case, which might be us.*/ + if (StriCmp(loader, loaded_image_path) == 0 || + is_sd_boot(root_dir, loader) || + is_sd_boot(root_dir, L"\\EFI\\BOOT\\GRUB" EFI_MACHINE_TYPE_NAME L".EFI")) return FALSE; - - /* look for systemd-boot magic string */ - err = file_read(root_dir, loader, 0, 100*1024, &content, &len); - if (!EFI_ERROR(err)) - for (CHAR8 *start = content; start <= content + len - sizeof(magic) - 1; start++) - if (start[0] == magic[0] && CompareMem(start, magic, sizeof(magic) - 1) == 0) - return FALSE; } /* check existence */ @@ -1876,6 +1897,55 @@ static VOID config_entry_add_osx(Config *config) { } } +static VOID config_entry_add_windows(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir) { + _cleanup_freepool_ CHAR8 *bcd = NULL; + const CHAR16 *title = NULL; + EFI_STATUS err; + UINTN len; + + assert(config); + assert(device); + assert(root_dir); + + if (!config->auto_entries) + return; + + /* Try to find a better title. */ + err = file_read(root_dir, L"\\EFI\\Microsoft\\Boot\\BCD", 0, 100*1024, &bcd, &len); + if (!EFI_ERROR(err)) { + static const CHAR16 *versions[] = { + L"Windows 11", + L"Windows 10", + L"Windows 8.1", + L"Windows 8", + L"Windows 7", + L"Windows Vista", + }; + + CHAR8 *p = bcd; + while (!title) { + CHAR8 *q = mempmem_safe(p, len, versions[0], STRLEN(L"Windows ")); + if (!q) + break; + + len -= q - p; + p = q; + + /* We found the prefix, now try all the version strings. */ + for (UINTN i = 0; i < ELEMENTSOF(versions); i++) { + if (memory_startswith(p, len, versions[i] + STRLEN("Windows "))) { + title = versions[i]; + break; + } + } + } + } + + config_entry_add_loader_auto(config, device, root_dir, NULL, + L"auto-windows", 'w', title ?: L"Windows Boot Manager", + L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi"); +} + static VOID config_entry_add_linux( Config *config, EFI_HANDLE *device, @@ -1897,14 +1967,13 @@ static VOID config_entry_add_linux( CHAR16 buf[256]; UINTN bufsize = sizeof buf; EFI_FILE_INFO *f; - CHAR8 *sections[] = { + const CHAR8 *sections[] = { (CHAR8 *)".osrel", (CHAR8 *)".cmdline", NULL }; UINTN offs[ELEMENTSOF(sections)-1] = {}; UINTN szs[ELEMENTSOF(sections)-1] = {}; - UINTN addrs[ELEMENTSOF(sections)-1] = {}; CHAR8 *content = NULL; CHAR8 *line; UINTN pos = 0; @@ -1931,7 +2000,7 @@ static VOID config_entry_add_linux( continue; /* look for .osrel and .cmdline sections in the .efi binary */ - err = pe_file_locate_sections(linux_dir, f->FileName, sections, addrs, offs, szs); + err = pe_file_locate_sections(linux_dir, f->FileName, sections, offs, szs); if (EFI_ERROR(err)) continue; @@ -2410,13 +2479,12 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { config_sort_entries(&config); /* if we find some well-known loaders, add them to the end of the list */ - config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, NULL, - L"auto-windows", 'w', L"Windows Boot Manager", L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi"); + config_entry_add_osx(&config); + config_entry_add_windows(&config, loaded_image->DeviceHandle, root_dir); config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, NULL, L"auto-efi-shell", 's', L"EFI Shell", L"\\shell" EFI_MACHINE_TYPE_NAME ".efi"); config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path, - L"auto-efi-default", '\0', L"EFI Default Loader", L"\\EFI\\Boot\\boot" EFI_MACHINE_TYPE_NAME ".efi"); - config_entry_add_osx(&config); + L"auto-efi-default", '\0', L"EFI Default Loader", NULL); if (config.auto_firmware && efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndicationsSupported", &osind) == EFI_SUCCESS) { if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) diff --git a/src/boot/efi/linux.h b/src/boot/efi/linux.h index 09be2de27b..7fdef9990b 100644 --- a/src/boot/efi/linux.h +++ b/src/boot/efi/linux.h @@ -2,6 +2,7 @@ #pragma once #include +#include "macro-fundamental.h" #define SETUP_MAGIC 0x53726448 /* "HdrS" */ @@ -44,7 +45,7 @@ struct setup_header { UINT64 pref_address; UINT32 init_size; UINT32 handover_offset; -} __attribute__((packed)); +} _packed_; /* adapted from linux' bootparam.h */ struct boot_params { @@ -81,7 +82,7 @@ struct boot_params { UINT8 _pad8[48]; UINT8 eddbuf[6*82]; // was: struct edd_info eddbuf[EDDMAXNR] UINT8 _pad9[276]; -} __attribute__((packed)); +} _packed_; EFI_STATUS linux_exec(EFI_HANDLE *image, CHAR8 *cmdline, UINTN cmdline_size, diff --git a/src/boot/efi/measure.c b/src/boot/efi/measure.c index 429e82657b..1d19366f73 100644 --- a/src/boot/efi/measure.c +++ b/src/boot/efi/measure.c @@ -133,13 +133,13 @@ typedef struct { UINT16 HeaderVersion; UINT32 PCRIndex; UINT32 EventType; -} __attribute__((packed)) EFI_TCG2_EVENT_HEADER; +} _packed_ EFI_TCG2_EVENT_HEADER; typedef struct tdEFI_TCG2_EVENT { UINT32 Size; EFI_TCG2_EVENT_HEADER Header; UINT8 Event[1]; -} __attribute__((packed)) EFI_TCG2_EVENT; +} _packed_ EFI_TCG2_EVENT; typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_CAPABILITY) (IN EFI_TCG2_PROTOCOL * This, IN OUT EFI_TCG2_BOOT_SERVICE_CAPABILITY * ProtocolCapability); diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build index c96a16426a..3d16ce84b5 100644 --- a/src/boot/efi/meson.build +++ b/src/boot/efi/meson.build @@ -292,6 +292,7 @@ if have_gnu_efi '-j', '.text', '-j', '.sdata', '-j', '.sbat', + '-j', '.sdmagic', '-j', '.data', '-j', '.dynamic', '-j', '.dynsym', diff --git a/src/boot/efi/missing_efi.h b/src/boot/efi/missing_efi.h index b983931348..37c468f2ab 100644 --- a/src/boot/efi/missing_efi.h +++ b/src/boot/efi/missing_efi.h @@ -120,3 +120,7 @@ typedef struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL { } EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL; #endif + +#ifndef EFI_IMAGE_MACHINE_RISCV64 + #define EFI_IMAGE_MACHINE_RISCV64 0x5064 +#endif diff --git a/src/boot/efi/pe.c b/src/boot/efi/pe.c index 5c20acc9f3..04b4504c2e 100644 --- a/src/boot/efi/pe.c +++ b/src/boot/efi/pe.c @@ -6,6 +6,24 @@ #include "pe.h" #include "util.h" +#define DOS_FILE_MAGIC "MZ" +#define PE_FILE_MAGIC "PE\0\0" +#define MAX_SECTIONS 96 + +#if defined(__i386__) + #define TARGET_MACHINE_TYPE EFI_IMAGE_MACHINE_IA32 +#elif defined(__x86_64__) + #define TARGET_MACHINE_TYPE EFI_IMAGE_MACHINE_X64 +#elif defined(__aarch64__) + #define TARGET_MACHINE_TYPE EFI_IMAGE_MACHINE_AARCH64 +#elif defined(__arm__) + #define TARGET_MACHINE_TYPE EFI_IMAGE_MACHINE_ARMTHUMB_MIXED +#elif defined(__riscv) && __riscv_xlen == 64 + #define TARGET_MACHINE_TYPE EFI_IMAGE_MACHINE_RISCV64 +#else + #error Unknown EFI arch +#endif + struct DosFileHeader { UINT8 Magic[2]; UINT16 LastSize; @@ -26,14 +44,9 @@ struct DosFileHeader { UINT16 OEMInfo; UINT16 reserved2[10]; UINT32 ExeHeader; -} __attribute__((packed)); +} _packed_; -#define PE_HEADER_MACHINE_I386 0x014c -#define PE_HEADER_MACHINE_X64 0x8664 -#define PE_HEADER_MACHINE_ARM64 0xaa64 -#define PE_HEADER_MACHINE_ARM 0x01c2 -#define PE_HEADER_MACHINE_RISCV64 0x5064 -struct PeFileHeader { +struct CoffFileHeader { UINT16 Machine; UINT16 NumberOfSections; UINT32 TimeDateStamp; @@ -41,12 +54,13 @@ struct PeFileHeader { UINT32 NumberOfSymbols; UINT16 SizeOfOptionalHeader; UINT16 Characteristics; -} __attribute__((packed)); +} _packed_; -struct PeHeader { +struct PeFileHeader { UINT8 Magic[4]; - struct PeFileHeader FileHeader; -} __attribute__((packed)); + struct CoffFileHeader FileHeader; + /* OptionalHeader omitted */ +} _packed_; struct PeSectionHeader { UINT8 Name[8]; @@ -59,120 +73,143 @@ struct PeSectionHeader { UINT16 NumberOfRelocations; UINT16 NumberOfLinenumbers; UINT32 Characteristics; -} __attribute__((packed)); +} _packed_; -EFI_STATUS pe_memory_locate_sections(CHAR8 *base, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) { - struct DosFileHeader *dos; - struct PeHeader *pe; - UINTN offset; +static inline BOOLEAN verify_dos(const struct DosFileHeader *dos) { + assert(dos); + return CompareMem(dos->Magic, DOS_FILE_MAGIC, STRLEN(DOS_FILE_MAGIC)) == 0; +} - assert(base); +static inline BOOLEAN verify_pe(const struct PeFileHeader *pe) { + assert(pe); + return CompareMem(pe->Magic, PE_FILE_MAGIC, STRLEN(PE_FILE_MAGIC)) == 0 && + pe->FileHeader.Machine == TARGET_MACHINE_TYPE && + pe->FileHeader.NumberOfSections > 0 && + pe->FileHeader.NumberOfSections <= MAX_SECTIONS; +} + +static inline UINTN section_table_offset(const struct DosFileHeader *dos, const struct PeFileHeader *pe) { + assert(dos); + assert(pe); + return dos->ExeHeader + sizeof(struct PeFileHeader) + pe->FileHeader.SizeOfOptionalHeader; +} + +static VOID locate_sections( + const struct PeSectionHeader section_table[], + UINTN n_table, + const CHAR8 **sections, + UINTN *addrs, + UINTN *offsets, + UINTN *sizes) { + + assert(section_table); assert(sections); + assert(sizes); - dos = (struct DosFileHeader *)base; + for (UINTN i = 0; i < n_table; i++) { + const struct PeSectionHeader *sect = section_table + i; - if (CompareMem(dos->Magic, "MZ", 2) != 0) - return EFI_LOAD_ERROR; - - pe = (struct PeHeader *)&base[dos->ExeHeader]; - if (CompareMem(pe->Magic, "PE\0\0", 4) != 0) - return EFI_LOAD_ERROR; - - /* PE32+ Subsystem type */ - if (pe->FileHeader.Machine != PE_HEADER_MACHINE_X64 && - pe->FileHeader.Machine != PE_HEADER_MACHINE_ARM64 && - pe->FileHeader.Machine != PE_HEADER_MACHINE_I386 && - pe->FileHeader.Machine != PE_HEADER_MACHINE_ARM && - pe->FileHeader.Machine != PE_HEADER_MACHINE_RISCV64) - return EFI_LOAD_ERROR; - - if (pe->FileHeader.NumberOfSections > 96) - return EFI_LOAD_ERROR; - - offset = dos->ExeHeader + sizeof(*pe) + pe->FileHeader.SizeOfOptionalHeader; - - for (UINTN i = 0; i < pe->FileHeader.NumberOfSections; i++) { - struct PeSectionHeader *sect; - - sect = (struct PeSectionHeader *)&base[offset]; for (UINTN j = 0; sections[j]; j++) { if (CompareMem(sect->Name, sections[j], strlena(sections[j])) != 0) continue; if (addrs) - addrs[j] = (UINTN)sect->VirtualAddress; + addrs[j] = sect->VirtualAddress; if (offsets) - offsets[j] = (UINTN)sect->PointerToRawData; - if (sizes) - sizes[j] = (UINTN)sect->VirtualSize; + offsets[j] = sect->PointerToRawData; + sizes[j] = sect->VirtualSize; } - offset += sizeof(*sect); } +} + +EFI_STATUS pe_memory_locate_sections( + const CHAR8 *base, + const CHAR8 **sections, + UINTN *addrs, + UINTN *sizes) { + const struct DosFileHeader *dos; + const struct PeFileHeader *pe; + UINTN offset; + + assert(base); + assert(sections); + assert(addrs); + assert(sizes); + + dos = (const struct DosFileHeader*)base; + if (!verify_dos(dos)) + return EFI_LOAD_ERROR; + + pe = (const struct PeFileHeader*)&base[dos->ExeHeader]; + if (!verify_pe(pe)) + return EFI_LOAD_ERROR; + + offset = section_table_offset(dos, pe); + locate_sections((struct PeSectionHeader*)&base[offset], pe->FileHeader.NumberOfSections, + sections, addrs, NULL, sizes); return EFI_SUCCESS; } -EFI_STATUS pe_file_locate_sections(EFI_FILE *dir, CHAR16 *path, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) { - EFI_FILE_HANDLE handle; +EFI_STATUS pe_file_locate_sections( + EFI_FILE *dir, + const CHAR16 *path, + const CHAR8 **sections, + UINTN *offsets, + UINTN *sizes) { + _cleanup_freepool_ struct PeSectionHeader *section_table = NULL; + _cleanup_(FileHandleClosep) EFI_FILE_HANDLE handle = NULL; struct DosFileHeader dos; - struct PeHeader pe; - UINTN len; - UINTN headerlen; + struct PeFileHeader pe; + UINTN len, section_table_len; EFI_STATUS err; - _cleanup_freepool_ CHAR8 *header = NULL; assert(dir); assert(path); + assert(sections); + assert(offsets); + assert(sizes); - err = uefi_call_wrapper(dir->Open, 5, dir, &handle, path, EFI_FILE_MODE_READ, 0ULL); + err = uefi_call_wrapper(dir->Open, 5, dir, &handle, (CHAR16*)path, EFI_FILE_MODE_READ, 0ULL); if (EFI_ERROR(err)) return err; - /* MS-DOS stub */ len = sizeof(dos); err = uefi_call_wrapper(handle->Read, 3, handle, &len, &dos); if (EFI_ERROR(err)) - goto out; - if (len != sizeof(dos)) { - err = EFI_LOAD_ERROR; - goto out; - } + return err; + if (len != sizeof(dos) || !verify_dos(&dos)) + return EFI_LOAD_ERROR; err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader); if (EFI_ERROR(err)) - goto out; + return err; len = sizeof(pe); err = uefi_call_wrapper(handle->Read, 3, handle, &len, &pe); if (EFI_ERROR(err)) - goto out; - if (len != sizeof(pe)) { - err = EFI_LOAD_ERROR; - goto out; - } + return err; + if (len != sizeof(pe) || !verify_pe(&pe)) + return EFI_LOAD_ERROR; - headerlen = sizeof(dos) + sizeof(pe) + pe.FileHeader.SizeOfOptionalHeader + pe.FileHeader.NumberOfSections * sizeof(struct PeSectionHeader); - header = AllocatePool(headerlen); - if (!header) { - err = EFI_OUT_OF_RESOURCES; - goto out; - } - len = headerlen; - err = uefi_call_wrapper(handle->SetPosition, 2, handle, 0); + section_table_len = pe.FileHeader.NumberOfSections * sizeof(struct PeSectionHeader); + section_table = AllocatePool(section_table_len); + if (!section_table) + return EFI_OUT_OF_RESOURCES; + + err = uefi_call_wrapper(handle->SetPosition, 2, handle, section_table_offset(&dos, &pe)); if (EFI_ERROR(err)) - goto out; + return err; - err = uefi_call_wrapper(handle->Read, 3, handle, &len, header); + len = section_table_len; + err = uefi_call_wrapper(handle->Read, 3, handle, &len, section_table); if (EFI_ERROR(err)) - goto out; + return err; + if (len != section_table_len) + return EFI_LOAD_ERROR; - if (len != headerlen) { - err = EFI_LOAD_ERROR; - goto out; - } + locate_sections(section_table, pe.FileHeader.NumberOfSections, + sections, NULL, offsets, sizes); - err = pe_memory_locate_sections(header, sections, addrs, offsets, sizes); -out: - uefi_call_wrapper(handle->Close, 1, handle); - return err; + return EFI_SUCCESS; } diff --git a/src/boot/efi/pe.h b/src/boot/efi/pe.h index 06a0fcd70c..e355211223 100644 --- a/src/boot/efi/pe.h +++ b/src/boot/efi/pe.h @@ -1,9 +1,17 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include +#include -EFI_STATUS pe_memory_locate_sections(CHAR8 *base, - CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes); -EFI_STATUS pe_file_locate_sections(EFI_FILE *dir, CHAR16 *path, - CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes); +EFI_STATUS pe_memory_locate_sections( + const CHAR8 *base, + const CHAR8 **sections, + UINTN *addrs, + UINTN *sizes); + +EFI_STATUS pe_file_locate_sections( + EFI_FILE *dir, + const CHAR16 *path, + const CHAR8 **sections, + UINTN *offsets, + UINTN *sizes); diff --git a/src/boot/efi/splash.c b/src/boot/efi/splash.c index 920b440825..23627a794e 100644 --- a/src/boot/efi/splash.c +++ b/src/boot/efi/splash.c @@ -12,7 +12,7 @@ struct bmp_file { UINT32 size; UINT16 reserved[2]; UINT32 offset; -} __attribute__((packed)); +} _packed_; /* we require at least BITMAPINFOHEADER, later versions are accepted, but their features ignored */ @@ -28,14 +28,14 @@ struct bmp_dib { INT32 y_pixel_meter; UINT32 colors_used; UINT32 colors_important; -} __attribute__((packed)); +} _packed_; struct bmp_map { UINT8 blue; UINT8 green; UINT8 red; UINT8 reserved; -} __attribute__((packed)); +} _packed_; static EFI_STATUS bmp_parse_header(UINT8 *bmp, UINTN size, struct bmp_dib **ret_dib, struct bmp_map **ret_map, UINT8 **pixmap) { diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index 82da1d3ec4..5758b5cd94 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -17,7 +17,7 @@ static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-stub EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { EFI_LOADED_IMAGE *loaded_image; - CHAR8 *sections[] = { + const CHAR8 *sections[] = { (CHAR8 *)".cmdline", (CHAR8 *)".linux", (CHAR8 *)".initrd", @@ -25,7 +25,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { NULL }; UINTN addrs[ELEMENTSOF(sections)-1] = {}; - UINTN offs[ELEMENTSOF(sections)-1] = {}; UINTN szs[ELEMENTSOF(sections)-1] = {}; CHAR8 *cmdline = NULL; UINTN cmdline_len; @@ -39,7 +38,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { if (EFI_ERROR(err)) return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err); - err = pe_memory_locate_sections(loaded_image->ImageBase, sections, addrs, offs, szs); + err = pe_memory_locate_sections(loaded_image->ImageBase, sections, addrs, szs); if (EFI_ERROR(err)) return log_error_status_stall(err, L"Unable to locate embedded .linux section: %r", err); diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c index 0c28cab246..823689e223 100644 --- a/src/boot/efi/util.c +++ b/src/boot/efi/util.c @@ -501,3 +501,17 @@ EFI_STATUS log_oom(void) { log_error_stall(L"Out of memory."); return EFI_OUT_OF_RESOURCES; } + +VOID *memmem_safe(const VOID *haystack, UINTN haystack_len, const VOID *needle, UINTN needle_len) { + assert(haystack || haystack_len == 0); + assert(needle || needle_len == 0); + + if (needle_len == 0) + return (VOID*)haystack; + + for (const CHAR8 *h = haystack, *n = needle; haystack_len >= needle_len; h++, haystack_len--) + if (*h == *n && CompareMem(h + 1, n + 1, needle_len - 1) == 0) + return (VOID*)h; + + return NULL; +} diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h index d3bf848a95..f620f14212 100644 --- a/src/boot/efi/util.h +++ b/src/boot/efi/util.h @@ -84,3 +84,10 @@ EFI_STATUS log_oom(void); log_error_stall(fmt, ##__VA_ARGS__); \ err; \ }) + +VOID *memmem_safe(const VOID *haystack, UINTN haystack_len, const VOID *needle, UINTN needle_len); + +static inline VOID *mempmem_safe(const VOID *haystack, UINTN haystack_len, const VOID *needle, UINTN needle_len) { + CHAR8 *p = memmem_safe(haystack, haystack_len, needle, needle_len); + return p ? p + needle_len : NULL; +} diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h index 461d37fa9e..20d8dabf29 100644 --- a/src/fundamental/macro-fundamental.h +++ b/src/fundamental/macro-fundamental.h @@ -11,6 +11,7 @@ #define _const_ __attribute__((__const__)) #define _pure_ __attribute__((__pure__)) #define _section_(x) __attribute__((__section__(x))) +#define _packed_ __attribute__((__packed__)) #define _used_ __attribute__((__used__)) #define _unused_ __attribute__((__unused__)) #define _cleanup_(x) __attribute__((__cleanup__(x))) diff --git a/src/fundamental/string-util-fundamental.h b/src/fundamental/string-util-fundamental.h index 407cede48d..7455c05492 100644 --- a/src/fundamental/string-util-fundamental.h +++ b/src/fundamental/string-util-fundamental.h @@ -16,6 +16,7 @@ #define strncmp(a, b, n) StrnCmp((a), (b), (n)) #define strcasecmp(a, b) StriCmp((a), (b)) #define STR_C(str) (L ## str) +#define memcmp(a, b, n) CompareMem(a, b, n) #else #define STR_C(str) (str) #endif @@ -65,3 +66,19 @@ static inline const sd_char *yes_no(sd_bool b) { } sd_int strverscmp_improved(const sd_char *a, const sd_char *b); + +/* Like startswith(), but operates on arbitrary memory blocks */ +static inline void *memory_startswith(const void *p, sd_size_t sz, const sd_char *token) { + assert(token); + + sd_size_t n = strlen(token) * sizeof(sd_char); + if (sz < n) + return NULL; + + assert(p); + + if (memcmp(p, token, n) != 0) + return NULL; + + return (uint8_t*) p + n; +}