mirror of
https://github.com/systemd/systemd
synced 2024-09-30 05:15:19 +00:00
Merge pull request #33493 from poettering/stub-refactor
sd-stub: clean-up codebase/refactoring
This commit is contained in:
commit
fbdb7854a5
|
@ -6,6 +6,7 @@
|
|||
#include <sys/uio.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "iovec-util-fundamental.h"
|
||||
#include "macro.h"
|
||||
|
||||
extern const struct iovec iovec_nul_byte; /* Points to a single NUL byte */
|
||||
|
@ -15,13 +16,6 @@ size_t iovec_total_size(const struct iovec *iovec, size_t n);
|
|||
|
||||
bool iovec_increment(struct iovec *iovec, size_t n, size_t k);
|
||||
|
||||
/* This accepts both const and non-const pointers */
|
||||
#define IOVEC_MAKE(base, len) \
|
||||
(struct iovec) { \
|
||||
.iov_base = (void*) (base), \
|
||||
.iov_len = (len), \
|
||||
}
|
||||
|
||||
static inline struct iovec* iovec_make_string(struct iovec *iovec, const char *s) {
|
||||
assert(iovec);
|
||||
/* We don't use strlen_ptr() here, because we don't want to include string-util.h for now */
|
||||
|
@ -38,14 +32,6 @@ static inline struct iovec* iovec_make_string(struct iovec *iovec, const char *s
|
|||
.iov_len = STRLEN(s), \
|
||||
}
|
||||
|
||||
static inline void iovec_done(struct iovec *iovec) {
|
||||
/* A _cleanup_() helper that frees the iov_base in the iovec */
|
||||
assert(iovec);
|
||||
|
||||
iovec->iov_base = mfree(iovec->iov_base);
|
||||
iovec->iov_len = 0;
|
||||
}
|
||||
|
||||
static inline void iovec_done_erase(struct iovec *iovec) {
|
||||
assert(iovec);
|
||||
|
||||
|
@ -53,16 +39,6 @@ static inline void iovec_done_erase(struct iovec *iovec) {
|
|||
iovec->iov_len = 0;
|
||||
}
|
||||
|
||||
static inline bool iovec_is_set(const struct iovec *iovec) {
|
||||
/* Checks if the iovec points to a non-empty chunk of memory */
|
||||
return iovec && iovec->iov_len > 0 && iovec->iov_base;
|
||||
}
|
||||
|
||||
static inline bool iovec_is_valid(const struct iovec *iovec) {
|
||||
/* Checks if the iovec is either NULL, empty or points to a valid bit of memory */
|
||||
return !iovec || (iovec->iov_base || iovec->iov_len == 0);
|
||||
}
|
||||
|
||||
char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value);
|
||||
char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value);
|
||||
|
||||
|
|
|
@ -211,16 +211,10 @@ static inline int __coverity_check_and_return__(int condition) {
|
|||
#define PTR_TO_UINT64(p) ((uint64_t) ((uintptr_t) (p)))
|
||||
#define UINT64_TO_PTR(u) ((void *) ((uintptr_t) (u)))
|
||||
|
||||
#define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p)))
|
||||
#define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u)))
|
||||
|
||||
#define CHAR_TO_STR(x) ((char[2]) { x, 0 })
|
||||
|
||||
#define char_array_0(x) x[sizeof(x)-1] = 0;
|
||||
|
||||
#define sizeof_field(struct_type, member) sizeof(((struct_type *) 0)->member)
|
||||
#define endoffsetof_field(struct_type, member) (offsetof(struct_type, member) + sizeof_field(struct_type, member))
|
||||
|
||||
/* Maximum buffer size needed for formatting an unsigned integer type as hex, including space for '0x'
|
||||
* prefix and trailing NUL suffix. */
|
||||
#define HEXADECIMAL_STR_MAX(type) (2 + sizeof(type) * 2 + 1)
|
||||
|
@ -266,18 +260,6 @@ static inline int __coverity_check_and_return__(int condition) {
|
|||
/* Pointers range from NULL to POINTER_MAX */
|
||||
#define POINTER_MAX ((void*) UINTPTR_MAX)
|
||||
|
||||
#define _FOREACH_ARRAY(i, array, num, m, end) \
|
||||
for (typeof(array[0]) *i = (array), *end = ({ \
|
||||
typeof(num) m = (num); \
|
||||
(i && m > 0) ? i + m : NULL; \
|
||||
}); end && i < end; i++)
|
||||
|
||||
#define FOREACH_ARRAY(i, array, num) \
|
||||
_FOREACH_ARRAY(i, array, num, UNIQ_T(m, UNIQ), UNIQ_T(end, UNIQ))
|
||||
|
||||
#define FOREACH_ELEMENT(i, array) \
|
||||
FOREACH_ARRAY(i, array, ELEMENTSOF(array))
|
||||
|
||||
#define _DEFINE_TRIVIAL_REF_FUNC(type, name, scope) \
|
||||
scope type *name##_ref(type *p) { \
|
||||
if (!p) \
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "devicetree.h"
|
||||
#include "drivers.h"
|
||||
#include "efivars-fundamental.h"
|
||||
#include "export-vars.h"
|
||||
#include "graphics.h"
|
||||
#include "initrd.h"
|
||||
#include "linux.h"
|
||||
|
@ -1855,23 +1856,24 @@ static void generate_boot_entry_titles(Config *config) {
|
|||
}
|
||||
|
||||
static bool is_sd_boot(EFI_FILE *root_dir, const char16_t *loader_path) {
|
||||
EFI_STATUS err;
|
||||
static const char * const sections[] = {
|
||||
".sdmagic",
|
||||
NULL
|
||||
};
|
||||
size_t offset = 0, size = 0, read;
|
||||
_cleanup_free_ char *content = NULL;
|
||||
PeSectionVector vector = {};
|
||||
EFI_STATUS err;
|
||||
size_t read;
|
||||
|
||||
assert(root_dir);
|
||||
assert(loader_path);
|
||||
|
||||
err = pe_file_locate_sections(root_dir, loader_path, sections, &offset, &size);
|
||||
if (err != EFI_SUCCESS || size != sizeof(SD_MAGIC))
|
||||
err = pe_file_locate_sections(root_dir, loader_path, sections, &vector);
|
||||
if (err != EFI_SUCCESS || vector.size != sizeof(SD_MAGIC))
|
||||
return false;
|
||||
|
||||
err = file_read(root_dir, loader_path, offset, size, &content, &read);
|
||||
if (err != EFI_SUCCESS || size != read)
|
||||
err = file_read(root_dir, loader_path, vector.file_offset, vector.size, &content, &read);
|
||||
if (err != EFI_SUCCESS || vector.size != read)
|
||||
return false;
|
||||
|
||||
return memcmp(content, SD_MAGIC, sizeof(SD_MAGIC)) == 0;
|
||||
|
@ -2104,7 +2106,7 @@ static void config_load_type2_entries(
|
|||
_SECTION_MAX,
|
||||
};
|
||||
|
||||
static const char * const sections[_SECTION_MAX + 1] = {
|
||||
static const char * const section_names[_SECTION_MAX + 1] = {
|
||||
[SECTION_CMDLINE] = ".cmdline",
|
||||
[SECTION_OSREL] = ".osrel",
|
||||
NULL,
|
||||
|
@ -2114,8 +2116,9 @@ static void config_load_type2_entries(
|
|||
*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;
|
||||
size_t offs[_SECTION_MAX] = {}, szs[_SECTION_MAX] = {}, pos = 0;
|
||||
PeSectionVector sections[_SECTION_MAX] = {};
|
||||
char *line, *key, *value;
|
||||
size_t pos = 0;
|
||||
|
||||
err = readdir(linux_dir, &f, &f_size);
|
||||
if (err != EFI_SUCCESS || !f)
|
||||
|
@ -2131,11 +2134,16 @@ static void config_load_type2_entries(
|
|||
continue;
|
||||
|
||||
/* look for .osrel and .cmdline sections in the .efi binary */
|
||||
err = pe_file_locate_sections(linux_dir, f->FileName, sections, offs, szs);
|
||||
if (err != EFI_SUCCESS || szs[SECTION_OSREL] == 0)
|
||||
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, offs[SECTION_OSREL], szs[SECTION_OSREL], &content, NULL);
|
||||
err = file_read(linux_dir,
|
||||
f->FileName,
|
||||
sections[SECTION_OSREL].file_offset,
|
||||
sections[SECTION_OSREL].size,
|
||||
&content,
|
||||
NULL);
|
||||
if (err != EFI_SUCCESS)
|
||||
continue;
|
||||
|
||||
|
@ -2206,14 +2214,19 @@ static void config_load_type2_entries(
|
|||
config_add_entry(config, entry);
|
||||
boot_entry_parse_tries(entry, u"\\EFI\\Linux", f->FileName, u".efi");
|
||||
|
||||
if (szs[SECTION_CMDLINE] == 0)
|
||||
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, offs[SECTION_CMDLINE], szs[SECTION_CMDLINE], &content, &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);
|
||||
|
@ -2526,9 +2539,8 @@ static EFI_STATUS secure_boot_discover_keys(Config *config, EFI_FILE *root_dir)
|
|||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static void export_variables(
|
||||
static void export_loader_variables(
|
||||
EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
|
||||
const char16_t *loaded_image_path,
|
||||
uint64_t init_usec) {
|
||||
|
||||
static const uint64_t loader_features =
|
||||
|
@ -2548,28 +2560,11 @@ static void export_variables(
|
|||
EFI_LOADER_FEATURE_MENU_DISABLE |
|
||||
0;
|
||||
|
||||
_cleanup_free_ char16_t *infostr = NULL, *typestr = NULL;
|
||||
|
||||
assert(loaded_image);
|
||||
|
||||
efivar_set_time_usec(MAKE_GUID_PTR(LOADER), u"LoaderTimeInitUSec", init_usec);
|
||||
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderInfo", u"systemd-boot " GIT_VERSION, 0);
|
||||
|
||||
infostr = xasprintf("%ls %u.%02u", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
|
||||
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareInfo", infostr, 0);
|
||||
|
||||
typestr = xasprintf("UEFI %u.%02u", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
|
||||
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareType", typestr, 0);
|
||||
|
||||
(void) efivar_set_time_usec(MAKE_GUID_PTR(LOADER), u"LoaderTimeInitUSec", init_usec);
|
||||
(void) efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderInfo", u"systemd-boot " GIT_VERSION, 0);
|
||||
(void) efivar_set_uint64_le(MAKE_GUID_PTR(LOADER), u"LoaderFeatures", loader_features, 0);
|
||||
|
||||
/* the filesystem path to this image, to prevent adding ourselves to the menu */
|
||||
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderImageIdentifier", loaded_image_path, 0);
|
||||
|
||||
/* export the device path this image is started from */
|
||||
_cleanup_free_ char16_t *uuid = disk_get_part_uuid(loaded_image->DeviceHandle);
|
||||
if (uuid)
|
||||
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", uuid, 0);
|
||||
}
|
||||
|
||||
static void config_load_all_entries(
|
||||
|
@ -2669,7 +2664,6 @@ static EFI_STATUS run(EFI_HANDLE image) {
|
|||
EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
|
||||
_cleanup_(file_closep) EFI_FILE *root_dir = NULL;
|
||||
_cleanup_(config_free) Config config = {};
|
||||
_cleanup_free_ char16_t *loaded_image_path = NULL;
|
||||
EFI_STATUS err;
|
||||
uint64_t init_usec;
|
||||
bool menu = false;
|
||||
|
@ -2684,9 +2678,8 @@ static EFI_STATUS run(EFI_HANDLE image) {
|
|||
if (err != EFI_SUCCESS)
|
||||
return log_error_status(err, "Error getting a LoadedImageProtocol handle: %m");
|
||||
|
||||
(void) device_path_to_str(loaded_image->FilePath, &loaded_image_path);
|
||||
|
||||
export_variables(loaded_image, loaded_image_path, init_usec);
|
||||
export_common_variables(loaded_image);
|
||||
export_loader_variables(loaded_image, init_usec);
|
||||
|
||||
err = discover_root_dir(loaded_image, &root_dir);
|
||||
if (err != EFI_SUCCESS)
|
||||
|
@ -2694,6 +2687,8 @@ static EFI_STATUS run(EFI_HANDLE image) {
|
|||
|
||||
(void) load_drivers(image, loaded_image, root_dir);
|
||||
|
||||
_cleanup_free_ char16_t *loaded_image_path = NULL;
|
||||
(void) device_path_to_str(loaded_image->FilePath, &loaded_image_path);
|
||||
config_load_all_entries(&config, loaded_image, loaded_image_path, root_dir);
|
||||
|
||||
if (config.n_entries == 0)
|
||||
|
|
|
@ -311,8 +311,7 @@ EFI_STATUS pack_cpio(
|
|||
uint32_t access_mode,
|
||||
uint32_t tpm_pcr,
|
||||
const char16_t *tpm_description,
|
||||
void **ret_buffer,
|
||||
size_t *ret_buffer_size,
|
||||
struct iovec *ret_buffer,
|
||||
bool *ret_measured) {
|
||||
|
||||
_cleanup_(file_closep) EFI_FILE *root = NULL, *extra_dir = NULL;
|
||||
|
@ -327,7 +326,6 @@ EFI_STATUS pack_cpio(
|
|||
assert(loaded_image);
|
||||
assert(target_dir_prefix);
|
||||
assert(ret_buffer);
|
||||
assert(ret_buffer_size);
|
||||
|
||||
if (!loaded_image->DeviceHandle)
|
||||
goto nothing;
|
||||
|
@ -439,14 +437,11 @@ EFI_STATUS pack_cpio(
|
|||
tpm_pcr,
|
||||
tpm_description);
|
||||
|
||||
*ret_buffer = TAKE_PTR(buffer);
|
||||
*ret_buffer_size = buffer_size;
|
||||
|
||||
*ret_buffer = IOVEC_MAKE(TAKE_PTR(buffer), buffer_size);
|
||||
return EFI_SUCCESS;
|
||||
|
||||
nothing:
|
||||
*ret_buffer = NULL;
|
||||
*ret_buffer_size = 0;
|
||||
*ret_buffer = (struct iovec) {};
|
||||
|
||||
if (ret_measured)
|
||||
*ret_measured = false;
|
||||
|
@ -463,8 +458,7 @@ EFI_STATUS pack_cpio_literal(
|
|||
uint32_t access_mode,
|
||||
uint32_t tpm_pcr,
|
||||
const char16_t *tpm_description,
|
||||
void **ret_buffer,
|
||||
size_t *ret_buffer_size,
|
||||
struct iovec *ret_buffer,
|
||||
bool *ret_measured) {
|
||||
|
||||
uint32_t inode = 1; /* inode counter, so that each item gets a new inode */
|
||||
|
@ -476,7 +470,6 @@ EFI_STATUS pack_cpio_literal(
|
|||
assert(target_dir_prefix);
|
||||
assert(target_filename);
|
||||
assert(ret_buffer);
|
||||
assert(ret_buffer_size);
|
||||
|
||||
/* Generate the leading directory inodes right before adding the first files, to the
|
||||
* archive. Otherwise the cpio archive cannot be unpacked, since the leading dirs won't exist. */
|
||||
|
@ -508,8 +501,6 @@ EFI_STATUS pack_cpio_literal(
|
|||
tpm_pcr,
|
||||
tpm_description);
|
||||
|
||||
*ret_buffer = TAKE_PTR(buffer);
|
||||
*ret_buffer_size = buffer_size;
|
||||
|
||||
*ret_buffer = IOVEC_MAKE(TAKE_PTR(buffer), buffer_size);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "efi.h"
|
||||
#include "iovec-util-fundamental.h"
|
||||
#include "proto/loaded-image.h"
|
||||
|
||||
EFI_STATUS pack_cpio(
|
||||
|
@ -14,8 +15,7 @@ EFI_STATUS pack_cpio(
|
|||
uint32_t access_mode,
|
||||
uint32_t tpm_pcr,
|
||||
const char16_t *tpm_description,
|
||||
void **ret_buffer,
|
||||
size_t *ret_buffer_size,
|
||||
struct iovec *ret_buffer,
|
||||
bool *ret_measured);
|
||||
|
||||
EFI_STATUS pack_cpio_literal(
|
||||
|
@ -27,6 +27,5 @@ EFI_STATUS pack_cpio_literal(
|
|||
uint32_t access_mode,
|
||||
uint32_t tpm_pcr,
|
||||
const char16_t *tpm_description,
|
||||
void **ret_buffer,
|
||||
size_t *ret_buffer_size,
|
||||
struct iovec *ret_buffer,
|
||||
bool *ret_measured);
|
||||
|
|
44
src/boot/efi/export-vars.c
Normal file
44
src/boot/efi/export-vars.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "device-path-util.h"
|
||||
#include "export-vars.h"
|
||||
#include "part-discovery.h"
|
||||
#include "util.h"
|
||||
|
||||
void export_common_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
|
||||
assert(loaded_image);
|
||||
|
||||
/* Export the device path this image is started from, if it's not set yet */
|
||||
if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", NULL, NULL) != EFI_SUCCESS) {
|
||||
_cleanup_free_ char16_t *uuid = disk_get_part_uuid(loaded_image->DeviceHandle);
|
||||
if (uuid)
|
||||
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", uuid, 0);
|
||||
}
|
||||
|
||||
/* If LoaderImageIdentifier is not set, assume the image with this stub was loaded directly from the
|
||||
* UEFI firmware without any boot loader, and hence set the LoaderImageIdentifier ourselves. Note
|
||||
* that some boot chain loaders neither set LoaderImageIdentifier nor make FilePath available to us,
|
||||
* in which case there's simple nothing to set for us. (The UEFI spec doesn't really say who's wrong
|
||||
* here, i.e. whether FilePath may be NULL or not, hence handle this gracefully and check if FilePath
|
||||
* is non-NULL explicitly.) */
|
||||
if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderImageIdentifier", NULL, NULL) != EFI_SUCCESS &&
|
||||
loaded_image->FilePath) {
|
||||
_cleanup_free_ char16_t *s = NULL;
|
||||
if (device_path_to_str(loaded_image->FilePath, &s) == EFI_SUCCESS)
|
||||
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderImageIdentifier", s, 0);
|
||||
}
|
||||
|
||||
/* if LoaderFirmwareInfo is not set, let's set it */
|
||||
if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareInfo", NULL, NULL) != EFI_SUCCESS) {
|
||||
_cleanup_free_ char16_t *s = NULL;
|
||||
s = xasprintf("%ls %u.%02u", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
|
||||
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareInfo", s, 0);
|
||||
}
|
||||
|
||||
/* ditto for LoaderFirmwareType */
|
||||
if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareType", NULL, NULL) != EFI_SUCCESS) {
|
||||
_cleanup_free_ char16_t *s = NULL;
|
||||
s = xasprintf("UEFI %u.%02u", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
|
||||
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareType", s, 0);
|
||||
}
|
||||
}
|
5
src/boot/efi/export-vars.h
Normal file
5
src/boot/efi/export-vars.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "proto/loaded-image.h"
|
||||
|
||||
void export_common_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image);
|
|
@ -93,19 +93,17 @@ static EFI_STATUS load_image(EFI_HANDLE parent, const void *source, size_t len,
|
|||
EFI_STATUS linux_exec(
|
||||
EFI_HANDLE parent,
|
||||
const char16_t *cmdline,
|
||||
const void *linux_buffer,
|
||||
size_t linux_length,
|
||||
const void *initrd_buffer,
|
||||
size_t initrd_length) {
|
||||
const struct iovec *kernel,
|
||||
const struct iovec *initrd) {
|
||||
|
||||
uint32_t compat_address;
|
||||
EFI_STATUS err;
|
||||
|
||||
assert(parent);
|
||||
assert(linux_buffer && linux_length > 0);
|
||||
assert(initrd_buffer || initrd_length == 0);
|
||||
assert(iovec_is_set(kernel));
|
||||
assert(iovec_is_valid(initrd));
|
||||
|
||||
err = pe_kernel_info(linux_buffer, &compat_address);
|
||||
err = pe_kernel_info(kernel->iov_base, &compat_address);
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
if (err == EFI_UNSUPPORTED)
|
||||
/* Kernel is too old to support LINUX_INITRD_MEDIA_GUID, try the deprecated EFI handover
|
||||
|
@ -113,16 +111,14 @@ EFI_STATUS linux_exec(
|
|||
return linux_exec_efi_handover(
|
||||
parent,
|
||||
cmdline,
|
||||
linux_buffer,
|
||||
linux_length,
|
||||
initrd_buffer,
|
||||
initrd_length);
|
||||
kernel,
|
||||
initrd);
|
||||
#endif
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status(err, "Bad kernel image: %m");
|
||||
|
||||
_cleanup_(unload_imagep) EFI_HANDLE kernel_image = NULL;
|
||||
err = load_image(parent, linux_buffer, linux_length, &kernel_image);
|
||||
err = load_image(parent, kernel->iov_base, kernel->iov_len, &kernel_image);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status(err, "Error loading kernel image: %m");
|
||||
|
||||
|
@ -138,7 +134,7 @@ EFI_STATUS linux_exec(
|
|||
}
|
||||
|
||||
_cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL;
|
||||
err = initrd_register(initrd_buffer, initrd_length, &initrd_handle);
|
||||
err = initrd_register(initrd->iov_base, initrd->iov_len, &initrd_handle);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status(err, "Error registering initrd: %m");
|
||||
|
||||
|
|
|
@ -2,18 +2,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "efi.h"
|
||||
#include "iovec-util-fundamental.h"
|
||||
|
||||
EFI_STATUS linux_exec(
|
||||
EFI_HANDLE parent,
|
||||
const char16_t *cmdline,
|
||||
const void *linux_buffer,
|
||||
size_t linux_length,
|
||||
const void *initrd_buffer,
|
||||
size_t initrd_length);
|
||||
const struct iovec *kernel,
|
||||
const struct iovec *initrd);
|
||||
EFI_STATUS linux_exec_efi_handover(
|
||||
EFI_HANDLE parent,
|
||||
const char16_t *cmdline,
|
||||
const void *linux_buffer,
|
||||
size_t linux_length,
|
||||
const void *initrd_buffer,
|
||||
size_t initrd_length);
|
||||
const struct iovec *kernel,
|
||||
const struct iovec *initrd);
|
||||
|
|
|
@ -123,19 +123,17 @@ static void linux_efi_handover(EFI_HANDLE parent, uintptr_t kernel, BootParams *
|
|||
EFI_STATUS linux_exec_efi_handover(
|
||||
EFI_HANDLE parent,
|
||||
const char16_t *cmdline,
|
||||
const void *linux_buffer,
|
||||
size_t linux_length,
|
||||
const void *initrd_buffer,
|
||||
size_t initrd_length) {
|
||||
const struct iovec *kernel,
|
||||
const struct iovec *initrd) {
|
||||
|
||||
assert(parent);
|
||||
assert(linux_buffer);
|
||||
assert(initrd_buffer || initrd_length == 0);
|
||||
assert(iovec_is_set(kernel));
|
||||
assert(iovec_is_valid(initrd));
|
||||
|
||||
if (linux_length < sizeof(BootParams))
|
||||
if (kernel->iov_len < sizeof(BootParams))
|
||||
return EFI_LOAD_ERROR;
|
||||
|
||||
const BootParams *image_params = (const BootParams *) linux_buffer;
|
||||
const BootParams *image_params = (const BootParams *) kernel->iov_base;
|
||||
if (image_params->hdr.header != SETUP_MAGIC || image_params->hdr.boot_flag != BOOT_FLAG_MAGIC)
|
||||
return log_error_status(EFI_UNSUPPORTED, "Unsupported kernel image.");
|
||||
if (image_params->hdr.version < SETUP_VERSION_2_11)
|
||||
|
@ -155,22 +153,26 @@ EFI_STATUS linux_exec_efi_handover(
|
|||
/* There is no way to pass the high bits of code32_start. Newer kernels seems to handle this
|
||||
* just fine, but older kernels will fail even if they otherwise have above 4G boot support. */
|
||||
_cleanup_pages_ Pages linux_relocated = {};
|
||||
if (POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + linux_length > UINT32_MAX) {
|
||||
const void *linux_buffer;
|
||||
if (POINTER_TO_PHYSICAL_ADDRESS(kernel->iov_base) + kernel->iov_len > UINT32_MAX) {
|
||||
linux_relocated = xmalloc_pages(
|
||||
AllocateMaxAddress, EfiLoaderCode, EFI_SIZE_TO_PAGES(linux_length), UINT32_MAX);
|
||||
AllocateMaxAddress, EfiLoaderCode, EFI_SIZE_TO_PAGES(kernel->iov_len), UINT32_MAX);
|
||||
linux_buffer = memcpy(
|
||||
PHYSICAL_ADDRESS_TO_POINTER(linux_relocated.addr), linux_buffer, linux_length);
|
||||
}
|
||||
PHYSICAL_ADDRESS_TO_POINTER(linux_relocated.addr), kernel->iov_base, kernel->iov_len);
|
||||
} else
|
||||
linux_buffer = kernel->iov_base;
|
||||
|
||||
_cleanup_pages_ Pages initrd_relocated = {};
|
||||
if (!can_4g && POINTER_TO_PHYSICAL_ADDRESS(initrd_buffer) + initrd_length > UINT32_MAX) {
|
||||
const void *initrd_buffer;
|
||||
if (!can_4g && POINTER_TO_PHYSICAL_ADDRESS(initrd->iov_base) + initrd->iov_len > UINT32_MAX) {
|
||||
initrd_relocated = xmalloc_pages(
|
||||
AllocateMaxAddress, EfiLoaderData, EFI_SIZE_TO_PAGES(initrd_length), UINT32_MAX);
|
||||
AllocateMaxAddress, EfiLoaderData, EFI_SIZE_TO_PAGES(initrd->iov_len), UINT32_MAX);
|
||||
initrd_buffer = memcpy(
|
||||
PHYSICAL_ADDRESS_TO_POINTER(initrd_relocated.addr),
|
||||
initrd_buffer,
|
||||
initrd_length);
|
||||
}
|
||||
initrd->iov_base,
|
||||
initrd->iov_len);
|
||||
} else
|
||||
initrd_buffer = initrd->iov_base;
|
||||
|
||||
_cleanup_pages_ Pages boot_params_page = xmalloc_pages(
|
||||
can_4g ? AllocateAnyPages : AllocateMaxAddress,
|
||||
|
@ -215,8 +217,8 @@ EFI_STATUS linux_exec_efi_handover(
|
|||
|
||||
boot_params->hdr.ramdisk_image = (uintptr_t) initrd_buffer;
|
||||
boot_params->ext_ramdisk_image = POINTER_TO_PHYSICAL_ADDRESS(initrd_buffer) >> 32;
|
||||
boot_params->hdr.ramdisk_size = initrd_length;
|
||||
boot_params->ext_ramdisk_size = ((uint64_t) initrd_length) >> 32;
|
||||
boot_params->hdr.ramdisk_size = initrd->iov_len;
|
||||
boot_params->ext_ramdisk_size = ((uint64_t) initrd->iov_len) >> 32;
|
||||
|
||||
log_wait();
|
||||
linux_efi_handover(parent, (uintptr_t) linux_buffer, boot_params);
|
||||
|
|
|
@ -195,12 +195,17 @@ static EFI_STATUS tcg2_log_ipl_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buf
|
|||
assert(ret_measured);
|
||||
|
||||
tpm2 = tcg2_interface_check();
|
||||
if (tpm2)
|
||||
err = tpm2_measure_to_pcr_and_ipl_event_log(tpm2, pcrindex, buffer, buffer_size, description);
|
||||
if (!tpm2) {
|
||||
*ret_measured = false;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
*ret_measured = tpm2 && (err == EFI_SUCCESS);
|
||||
err = tpm2_measure_to_pcr_and_ipl_event_log(tpm2, pcrindex, buffer, buffer_size, description);
|
||||
if (err != EFI_SUCCESS)
|
||||
return err;
|
||||
|
||||
return err;
|
||||
*ret_measured = true;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static EFI_STATUS cc_log_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char16_t *description, bool *ret_measured) {
|
||||
|
@ -210,12 +215,17 @@ static EFI_STATUS cc_log_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, s
|
|||
assert(ret_measured);
|
||||
|
||||
cc = cc_interface_check();
|
||||
if (cc)
|
||||
err = cc_measure_to_mr_and_ipl_event_log(cc, pcrindex, buffer, buffer_size, description);
|
||||
if (!cc) {
|
||||
*ret_measured = false;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
*ret_measured = cc && (err == EFI_SUCCESS);
|
||||
err = cc_measure_to_mr_and_ipl_event_log(cc, pcrindex, buffer, buffer_size, description);
|
||||
if (err != EFI_SUCCESS)
|
||||
return err;
|
||||
|
||||
return err;
|
||||
*ret_measured = true;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS tpm_log_ipl_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char16_t *description, bool *ret_measured) {
|
||||
|
@ -240,10 +250,13 @@ EFI_STATUS tpm_log_ipl_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, siz
|
|||
return err;
|
||||
|
||||
err = tcg2_log_ipl_event(pcrindex, buffer, buffer_size, description, &tpm_ret_measured);
|
||||
if (err == EFI_SUCCESS && ret_measured)
|
||||
if (err != EFI_SUCCESS)
|
||||
return err;
|
||||
|
||||
if (ret_measured)
|
||||
*ret_measured = tpm_ret_measured || cc_ret_measured;
|
||||
|
||||
return err;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS tpm_log_tagged_event(
|
||||
|
@ -272,10 +285,11 @@ EFI_STATUS tpm_log_tagged_event(
|
|||
}
|
||||
|
||||
err = tpm2_measure_to_pcr_and_tagged_event_log(tpm2, pcrindex, buffer, buffer_size, event_id, description);
|
||||
if (err == EFI_SUCCESS && ret_measured)
|
||||
*ret_measured = true;
|
||||
if (!err)
|
||||
return err;
|
||||
|
||||
return err;
|
||||
*ret_measured = true;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS tpm_log_ipl_event_ascii(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char *description, bool *ret_measured) {
|
||||
|
|
|
@ -258,6 +258,7 @@ libefi_sources = files(
|
|||
'devicetree.c',
|
||||
'drivers.c',
|
||||
'efi-string.c',
|
||||
'export-vars.c',
|
||||
'graphics.c',
|
||||
'initrd.c',
|
||||
'log.c',
|
||||
|
|
|
@ -101,7 +101,7 @@ typedef struct PeOptionalHeader {
|
|||
} _packed_ PeOptionalHeader;
|
||||
|
||||
typedef struct PeFileHeader {
|
||||
uint8_t Magic[4];
|
||||
uint8_t Magic[4];
|
||||
CoffFileHeader FileHeader;
|
||||
PeOptionalHeader OptionalHeader;
|
||||
} _packed_ PeFileHeader;
|
||||
|
@ -119,69 +119,134 @@ typedef struct PeSectionHeader {
|
|||
uint32_t Characteristics;
|
||||
} _packed_ PeSectionHeader;
|
||||
|
||||
#define SECTION_TABLE_BYTES_MAX (16U * 1024U * 1024U)
|
||||
|
||||
static bool verify_dos(const DosFileHeader *dos) {
|
||||
assert(dos);
|
||||
return memcmp(dos->Magic, DOS_FILE_MAGIC, STRLEN(DOS_FILE_MAGIC)) == 0;
|
||||
|
||||
DISABLE_WARNING_TYPE_LIMITS;
|
||||
return memcmp(dos->Magic, DOS_FILE_MAGIC, STRLEN(DOS_FILE_MAGIC)) == 0 &&
|
||||
dos->ExeHeader >= sizeof(DosFileHeader) &&
|
||||
(size_t) dos->ExeHeader <= SIZE_MAX - sizeof(PeFileHeader);
|
||||
REENABLE_WARNING;
|
||||
}
|
||||
|
||||
static bool verify_pe(const PeFileHeader *pe, bool allow_compatibility) {
|
||||
static bool verify_pe(
|
||||
const DosFileHeader *dos,
|
||||
const PeFileHeader *pe,
|
||||
bool allow_compatibility) {
|
||||
|
||||
assert(dos);
|
||||
assert(pe);
|
||||
|
||||
return memcmp(pe->Magic, PE_FILE_MAGIC, STRLEN(PE_FILE_MAGIC)) == 0 &&
|
||||
(pe->FileHeader.Machine == TARGET_MACHINE_TYPE ||
|
||||
(allow_compatibility && pe->FileHeader.Machine == TARGET_MACHINE_TYPE_COMPATIBILITY)) &&
|
||||
pe->FileHeader.NumberOfSections > 0 &&
|
||||
pe->FileHeader.NumberOfSections <= MAX_SECTIONS &&
|
||||
IN_SET(pe->OptionalHeader.Magic, OPTHDR32_MAGIC, OPTHDR64_MAGIC);
|
||||
(pe->FileHeader.Machine == TARGET_MACHINE_TYPE ||
|
||||
(allow_compatibility && pe->FileHeader.Machine == TARGET_MACHINE_TYPE_COMPATIBILITY)) &&
|
||||
pe->FileHeader.NumberOfSections > 0 &&
|
||||
pe->FileHeader.NumberOfSections <= MAX_SECTIONS &&
|
||||
IN_SET(pe->OptionalHeader.Magic, OPTHDR32_MAGIC, OPTHDR64_MAGIC) &&
|
||||
pe->FileHeader.SizeOfOptionalHeader < SIZE_MAX - (dos->ExeHeader + offsetof(PeFileHeader, OptionalHeader));
|
||||
}
|
||||
|
||||
static size_t section_table_offset(const DosFileHeader *dos, const PeFileHeader *pe) {
|
||||
assert(dos);
|
||||
assert(pe);
|
||||
|
||||
return dos->ExeHeader + offsetof(PeFileHeader, OptionalHeader) + pe->FileHeader.SizeOfOptionalHeader;
|
||||
}
|
||||
|
||||
static void locate_sections(
|
||||
static bool pe_section_name_equal(const char *a, const char *b) {
|
||||
|
||||
if (a == b)
|
||||
return true;
|
||||
if (!a != !b)
|
||||
return false;
|
||||
|
||||
/* Compares up to 8 characters of a and b i.e. the name size limit in the PE section header */
|
||||
|
||||
for (size_t i = 0; i < sizeof_field(PeSectionHeader, Name); i++) {
|
||||
if (a[i] != b[i])
|
||||
return false;
|
||||
|
||||
if (a[i] == 0) /* Name is shorter than 8 */
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void pe_locate_sections(
|
||||
const PeSectionHeader section_table[],
|
||||
size_t n_table,
|
||||
size_t n_section_table,
|
||||
const char * const sections[],
|
||||
size_t *offsets,
|
||||
size_t *sizes,
|
||||
bool in_memory) {
|
||||
size_t validate_base,
|
||||
PeSectionVector *ret_sections) {
|
||||
|
||||
assert(section_table);
|
||||
assert(section_table || n_section_table == 0);
|
||||
assert(sections);
|
||||
assert(offsets);
|
||||
assert(sizes);
|
||||
assert(ret_sections);
|
||||
|
||||
for (size_t i = 0; i < n_table; i++) {
|
||||
const PeSectionHeader *sect = section_table + i;
|
||||
/* 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 j = 0; sections[j]; j++) {
|
||||
if (memcmp(sect->Name, sections[j], strlen8(sections[j])) != 0)
|
||||
for (size_t i = 0; sections[i]; i++)
|
||||
FOREACH_ARRAY(j, section_table, n_section_table) {
|
||||
|
||||
if (!pe_section_name_equal((const char*) j->Name, sections[i]))
|
||||
continue;
|
||||
|
||||
offsets[j] = in_memory ? sect->VirtualAddress : sect->PointerToRawData;
|
||||
sizes[j] = sect->VirtualSize;
|
||||
/* Overflow check: ignore sections that are impossibly large, relative to the file
|
||||
* address for the section. */
|
||||
size_t size_max = SIZE_MAX - j->PointerToRawData;
|
||||
if ((size_t) j->VirtualSize > size_max)
|
||||
continue;
|
||||
|
||||
/* Overflow check: ignore sections that are impossibly large, given the virtual
|
||||
* address for the section */
|
||||
size_max = SIZE_MAX - j->VirtualAddress;
|
||||
if (j->VirtualSize > size_max)
|
||||
continue;
|
||||
|
||||
/* 2nd overflow check: ignore sections that are impossibly large also taking the
|
||||
* loaded base into account. */
|
||||
if (validate_base != 0) {
|
||||
if (validate_base > size_max)
|
||||
continue;
|
||||
size_max -= validate_base;
|
||||
|
||||
if (j->VirtualAddress > size_max)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* At this time, the sizes and offsets have been validated. Store them away */
|
||||
ret_sections[i] = (PeSectionVector) {
|
||||
.size = j->VirtualSize,
|
||||
.file_offset = j->PointerToRawData,
|
||||
.memory_offset = j->VirtualAddress,
|
||||
};
|
||||
|
||||
/* First matching section wins, ignore the rest */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t get_compatibility_entry_address(const DosFileHeader *dos, const PeFileHeader *pe) {
|
||||
size_t addr = 0, size = 0;
|
||||
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. */
|
||||
|
||||
locate_sections((const PeSectionHeader *) ((const uint8_t *) dos + section_table_offset(dos, pe)),
|
||||
pe_locate_sections(
|
||||
(const PeSectionHeader *) ((const uint8_t *) dos + section_table_offset(dos, pe)),
|
||||
pe->FileHeader.NumberOfSections,
|
||||
sections,
|
||||
&addr,
|
||||
&size,
|
||||
/*in_memory=*/true);
|
||||
PTR_TO_SIZE(dos),
|
||||
&vector);
|
||||
|
||||
if (size == 0)
|
||||
if (vector.size == 0) /* not found */
|
||||
return 0;
|
||||
|
||||
typedef struct {
|
||||
|
@ -191,6 +256,8 @@ static uint32_t get_compatibility_entry_address(const DosFileHeader *dos, const
|
|||
uint32_t entry_point;
|
||||
} _packed_ LinuxPeCompat1;
|
||||
|
||||
size_t addr = vector.memory_offset, size = vector.size;
|
||||
|
||||
while (size >= sizeof(LinuxPeCompat1) && addr % alignof(LinuxPeCompat1) == 0) {
|
||||
LinuxPeCompat1 *compat = (LinuxPeCompat1 *) ((uint8_t *) dos + addr);
|
||||
|
||||
|
@ -218,7 +285,7 @@ EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address) {
|
|||
return EFI_LOAD_ERROR;
|
||||
|
||||
const PeFileHeader *pe = (const PeFileHeader *) ((const uint8_t *) base + dos->ExeHeader);
|
||||
if (!verify_pe(pe, /* allow_compatibility= */ true))
|
||||
if (!verify_pe(dos, pe, /* allow_compatibility= */ true))
|
||||
return EFI_LOAD_ERROR;
|
||||
|
||||
/* Support for LINUX_INITRD_MEDIA_GUID was added in kernel stub 1.0. */
|
||||
|
@ -239,31 +306,34 @@ EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address) {
|
|||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS pe_memory_locate_sections(const void *base, const char * const sections[], size_t *addrs, size_t *sizes) {
|
||||
EFI_STATUS pe_memory_locate_sections(
|
||||
const void *base,
|
||||
const char* const sections[],
|
||||
PeSectionVector *ret_sections) {
|
||||
|
||||
const DosFileHeader *dos;
|
||||
const PeFileHeader *pe;
|
||||
size_t offset;
|
||||
|
||||
assert(base);
|
||||
assert(sections);
|
||||
assert(addrs);
|
||||
assert(sizes);
|
||||
assert(ret_sections);
|
||||
|
||||
dos = (const DosFileHeader *) base;
|
||||
if (!verify_dos(dos))
|
||||
return EFI_LOAD_ERROR;
|
||||
|
||||
pe = (const PeFileHeader *) ((uint8_t *) base + dos->ExeHeader);
|
||||
if (!verify_pe(pe, /* allow_compatibility= */ false))
|
||||
pe = (const PeFileHeader *) ((const uint8_t *) base + dos->ExeHeader);
|
||||
if (!verify_pe(dos, pe, /* allow_compatibility= */ false))
|
||||
return EFI_LOAD_ERROR;
|
||||
|
||||
offset = section_table_offset(dos, pe);
|
||||
locate_sections((PeSectionHeader *) ((uint8_t *) base + offset),
|
||||
pe_locate_sections(
|
||||
(const PeSectionHeader *) ((const uint8_t *) base + offset),
|
||||
pe->FileHeader.NumberOfSections,
|
||||
sections,
|
||||
addrs,
|
||||
sizes,
|
||||
/*in_memory=*/true);
|
||||
PTR_TO_SIZE(base),
|
||||
ret_sections);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
@ -272,8 +342,7 @@ EFI_STATUS pe_file_locate_sections(
|
|||
EFI_FILE *dir,
|
||||
const char16_t *path,
|
||||
const char * const sections[],
|
||||
size_t *offsets,
|
||||
size_t *sizes) {
|
||||
PeSectionVector *ret_sections) {
|
||||
_cleanup_free_ PeSectionHeader *section_table = NULL;
|
||||
_cleanup_(file_closep) EFI_FILE *handle = NULL;
|
||||
DosFileHeader dos;
|
||||
|
@ -284,8 +353,7 @@ EFI_STATUS pe_file_locate_sections(
|
|||
assert(dir);
|
||||
assert(path);
|
||||
assert(sections);
|
||||
assert(offsets);
|
||||
assert(sizes);
|
||||
assert(ret_sections);
|
||||
|
||||
err = dir->Open(dir, &handle, (char16_t *) path, EFI_FILE_MODE_READ, 0ULL);
|
||||
if (err != EFI_SUCCESS)
|
||||
|
@ -306,10 +374,16 @@ EFI_STATUS pe_file_locate_sections(
|
|||
err = handle->Read(handle, &len, &pe);
|
||||
if (err != EFI_SUCCESS)
|
||||
return err;
|
||||
if (len != sizeof(pe) || !verify_pe(&pe, /* allow_compatibility= */ false))
|
||||
if (len != sizeof(pe) || !verify_pe(&dos, &pe, /* allow_compatibility= */ false))
|
||||
return EFI_LOAD_ERROR;
|
||||
|
||||
section_table_len = pe.FileHeader.NumberOfSections * sizeof(PeSectionHeader);
|
||||
DISABLE_WARNING_TYPE_LIMITS;
|
||||
if ((size_t) pe.FileHeader.NumberOfSections > SIZE_MAX / sizeof(PeSectionHeader))
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
REENABLE_WARNING;
|
||||
section_table_len = (size_t) pe.FileHeader.NumberOfSections * sizeof(PeSectionHeader);
|
||||
if (section_table_len > SECTION_TABLE_BYTES_MAX)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
section_table = xmalloc(section_table_len);
|
||||
if (!section_table)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
@ -325,8 +399,12 @@ EFI_STATUS pe_file_locate_sections(
|
|||
if (len != section_table_len)
|
||||
return EFI_LOAD_ERROR;
|
||||
|
||||
locate_sections(section_table, pe.FileHeader.NumberOfSections,
|
||||
sections, offsets, sizes, /*in_memory=*/false);
|
||||
pe_locate_sections(
|
||||
section_table,
|
||||
pe.FileHeader.NumberOfSections,
|
||||
sections,
|
||||
/* validate_base= */ 0, /* don't validate base */
|
||||
ret_sections);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -3,17 +3,27 @@
|
|||
|
||||
#include "efi.h"
|
||||
|
||||
/* This is a subset of the full PE section header structure, with validated values, and without
|
||||
* the noise. */
|
||||
typedef struct PeSectionVector {
|
||||
size_t size;
|
||||
size_t memory_offset; /* Offset in memory, relative to base address */
|
||||
uint64_t file_offset; /* Offset on disk, relative to beginning of file */
|
||||
} PeSectionVector;
|
||||
|
||||
static inline bool PE_SECTION_VECTOR_IS_SET(const PeSectionVector *v) {
|
||||
return v && v->size != 0;
|
||||
}
|
||||
|
||||
EFI_STATUS pe_memory_locate_sections(
|
||||
const void *base,
|
||||
const char * const sections[],
|
||||
size_t *addrs,
|
||||
size_t *sizes);
|
||||
PeSectionVector *ret_sections);
|
||||
|
||||
EFI_STATUS pe_file_locate_sections(
|
||||
EFI_FILE *dir,
|
||||
const char16_t *path,
|
||||
const char * const sections[],
|
||||
size_t *offsets,
|
||||
size_t *sizes);
|
||||
PeSectionVector *ret_sections);
|
||||
|
||||
EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -330,7 +330,14 @@ EFI_STATUS chunked_read(EFI_FILE *file, size_t *size, void *buf) {
|
|||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, size_t off, size_t size, char **ret, size_t *ret_size) {
|
||||
EFI_STATUS file_read(
|
||||
EFI_FILE *dir,
|
||||
const char16_t *name,
|
||||
uint64_t off,
|
||||
size_t size,
|
||||
char **ret,
|
||||
size_t *ret_size) {
|
||||
|
||||
_cleanup_(file_closep) EFI_FILE *handle = NULL;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
EFI_STATUS err;
|
||||
|
@ -350,6 +357,9 @@ EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, size_t off, size_t siz
|
|||
if (err != EFI_SUCCESS)
|
||||
return err;
|
||||
|
||||
if (info->FileSize > SIZE_MAX)
|
||||
return EFI_BAD_BUFFER_SIZE;
|
||||
|
||||
size = info->FileSize;
|
||||
}
|
||||
|
||||
|
|
|
@ -102,7 +102,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, size_t off, size_t size, char **content, size_t *content_size);
|
||||
EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, uint64_t off, size_t size, char **content, size_t *content_size);
|
||||
|
||||
static inline void file_closep(EFI_FILE **handle) {
|
||||
if (!*handle)
|
||||
|
|
37
src/fundamental/iovec-util-fundamental.h
Normal file
37
src/fundamental/iovec-util-fundamental.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#if SD_BOOT
|
||||
/* struct iovec is a POSIX userspace construct. Let's introduce it also in EFI mode, it's just so useful */
|
||||
struct iovec {
|
||||
void *iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
|
||||
static inline void free(void *p);
|
||||
#endif
|
||||
|
||||
/* This accepts both const and non-const pointers */
|
||||
#define IOVEC_MAKE(base, len) \
|
||||
(struct iovec) { \
|
||||
.iov_base = (void*) (base), \
|
||||
.iov_len = (len), \
|
||||
}
|
||||
|
||||
static inline void iovec_done(struct iovec *iovec) {
|
||||
/* A _cleanup_() helper that frees the iov_base in the iovec */
|
||||
assert(iovec);
|
||||
|
||||
iovec->iov_base = mfree(iovec->iov_base);
|
||||
iovec->iov_len = 0;
|
||||
}
|
||||
|
||||
static inline bool iovec_is_set(const struct iovec *iovec) {
|
||||
/* Checks if the iovec points to a non-empty chunk of memory */
|
||||
return iovec && iovec->iov_len > 0 && iovec->iov_base;
|
||||
}
|
||||
|
||||
static inline bool iovec_is_valid(const struct iovec *iovec) {
|
||||
/* Checks if the iovec is either NULL, empty or points to a valid bit of memory */
|
||||
return !iovec || (iovec->iov_base || iovec->iov_len == 0);
|
||||
}
|
|
@ -546,3 +546,21 @@ static inline uint64_t ALIGN_OFFSET_U64(uint64_t l, uint64_t ali) {
|
|||
#else
|
||||
#define DECLARE_SBAT(text)
|
||||
#endif
|
||||
|
||||
#define sizeof_field(struct_type, member) sizeof(((struct_type *) 0)->member)
|
||||
#define endoffsetof_field(struct_type, member) (offsetof(struct_type, member) + sizeof_field(struct_type, member))
|
||||
|
||||
#define _FOREACH_ARRAY(i, array, num, m, end) \
|
||||
for (typeof(array[0]) *i = (array), *end = ({ \
|
||||
typeof(num) m = (num); \
|
||||
(i && m > 0) ? i + m : NULL; \
|
||||
}); end && i < end; i++)
|
||||
|
||||
#define FOREACH_ARRAY(i, array, num) \
|
||||
_FOREACH_ARRAY(i, array, num, UNIQ_T(m, UNIQ), UNIQ_T(end, UNIQ))
|
||||
|
||||
#define FOREACH_ELEMENT(i, array) \
|
||||
FOREACH_ARRAY(i, array, ELEMENTSOF(array))
|
||||
|
||||
#define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p)))
|
||||
#define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u)))
|
||||
|
|
|
@ -5,6 +5,7 @@ fundamental_include = include_directories('.')
|
|||
fundamental_sources = files(
|
||||
'bootspec-fundamental.c',
|
||||
'efivars-fundamental.c',
|
||||
'iovec-util-fundamental.h',
|
||||
'sha256-fundamental.c',
|
||||
'string-util-fundamental.c',
|
||||
'uki.c',
|
||||
|
|
Loading…
Reference in a new issue