mirror of
https://github.com/systemd/systemd.git
synced 2025-08-02 04:22:27 +03:00
Merge pull request #20438 from medhefgo/boot
sd-boot: Better self-detection and windows loader title
This commit is contained in:
@ -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")))
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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)
|
||||
|
@ -2,6 +2,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <efi.h>
|
||||
#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,
|
||||
|
@ -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);
|
||||
|
@ -292,6 +292,7 @@ if have_gnu_efi
|
||||
'-j', '.text',
|
||||
'-j', '.sdata',
|
||||
'-j', '.sbat',
|
||||
'-j', '.sdmagic',
|
||||
'-j', '.data',
|
||||
'-j', '.dynamic',
|
||||
'-j', '.dynsym',
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1,9 +1,17 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <efi.h>
|
||||
#include <efidef.h>
|
||||
|
||||
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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)))
|
||||
|
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user