summaryrefslogtreecommitdiffstats
path: root/src/boot
diff options
context:
space:
mode:
Diffstat (limited to 'src/boot')
-rw-r--r--src/boot/efi/boot.c2
-rw-r--r--src/boot/efi/efi-string.c2
-rw-r--r--src/boot/efi/linux.c6
-rw-r--r--src/boot/efi/linux.h3
-rw-r--r--src/boot/efi/linux_x86.c21
-rw-r--r--src/boot/efi/pe.c7
-rw-r--r--src/boot/efi/pe.h2
-rw-r--r--src/boot/efi/vmm.c9
8 files changed, 37 insertions, 15 deletions
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index e1f0817..93e1236 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -2405,7 +2405,7 @@ static EFI_STATUS image_start(
if (err == EFI_UNSUPPORTED && entry->type == LOADER_LINUX) {
uint32_t compat_address;
- err = pe_kernel_info(loaded_image->ImageBase, &compat_address);
+ err = pe_kernel_info(loaded_image->ImageBase, &compat_address, /* ret_size_in_memory= */ NULL);
if (err != EFI_SUCCESS) {
if (err != EFI_UNSUPPORTED)
return log_error_status(err, "Error finding kernel compat entry address: %m");
diff --git a/src/boot/efi/efi-string.c b/src/boot/efi/efi-string.c
index 3bdb802..db00890 100644
--- a/src/boot/efi/efi-string.c
+++ b/src/boot/efi/efi-string.c
@@ -481,7 +481,7 @@ char *line_get_key_value(char *s, const char *sep, size_t *pos, char **ret_key,
}
char16_t *hexdump(const void *data, size_t size) {
- static const char hex[16] = "0123456789abcdef";
+ static const char hex[] = "0123456789abcdef";
const uint8_t *d = data;
assert(data || size == 0);
diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c
index 65bc176..c8e5951 100644
--- a/src/boot/efi/linux.c
+++ b/src/boot/efi/linux.c
@@ -98,6 +98,7 @@ EFI_STATUS linux_exec(
const void *initrd_buffer,
size_t initrd_length) {
+ size_t kernel_size_in_memory = 0;
uint32_t compat_address;
EFI_STATUS err;
@@ -105,7 +106,7 @@ EFI_STATUS linux_exec(
assert(linux_buffer && linux_length > 0);
assert(initrd_buffer || initrd_length == 0);
- err = pe_kernel_info(linux_buffer, &compat_address);
+ err = pe_kernel_info(linux_buffer, &compat_address, &kernel_size_in_memory);
#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
@@ -116,7 +117,8 @@ EFI_STATUS linux_exec(
linux_buffer,
linux_length,
initrd_buffer,
- initrd_length);
+ initrd_length,
+ kernel_size_in_memory);
#endif
if (err != EFI_SUCCESS)
return log_error_status(err, "Bad kernel image: %m");
diff --git a/src/boot/efi/linux.h b/src/boot/efi/linux.h
index 46b5f4f..0d74c6a 100644
--- a/src/boot/efi/linux.h
+++ b/src/boot/efi/linux.h
@@ -16,4 +16,5 @@ EFI_STATUS linux_exec_efi_handover(
const void *linux_buffer,
size_t linux_length,
const void *initrd_buffer,
- size_t initrd_length);
+ size_t initrd_length,
+ size_t kernel_size_in_memory);
diff --git a/src/boot/efi/linux_x86.c b/src/boot/efi/linux_x86.c
index 757902d..58b1b3c 100644
--- a/src/boot/efi/linux_x86.c
+++ b/src/boot/efi/linux_x86.c
@@ -7,12 +7,13 @@
* this x86 specific linux_exec function passes the initrd by setting the
* corresponding fields in the setup_header struct.
*
- * see https://docs.kernel.org/x86/boot.html
+ * see https://docs.kernel.org/arch/x86/boot.html
*/
#include "initrd.h"
#include "linux.h"
#include "macro-fundamental.h"
+#include "memory-util-fundamental.h"
#include "util.h"
#define KERNEL_SECTOR_SIZE 512u
@@ -126,7 +127,8 @@ EFI_STATUS linux_exec_efi_handover(
const void *linux_buffer,
size_t linux_length,
const void *initrd_buffer,
- size_t initrd_length) {
+ size_t initrd_length,
+ size_t kernel_size_in_memory) {
assert(parent);
assert(linux_buffer);
@@ -153,13 +155,22 @@ EFI_STATUS linux_exec_efi_handover(
FLAGS_SET(image_params->hdr.xloadflags, XLF_CAN_BE_LOADED_ABOVE_4G);
/* 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. */
+ * just fine, but older kernels will fail even if they otherwise have above 4G boot support.
+ * A PE image's memory footprint can be larger than its file size, due to unallocated virtual
+ * memory sections. While normally all PE headers should be taken into account, this case only
+ * involves x86 Linux bzImage kernel images, for which unallocated areas are only part of the last
+ * header, so parsing SizeOfImage and zeroeing the buffer past the image size is enough. */
_cleanup_pages_ Pages linux_relocated = {};
- if (POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + linux_length > UINT32_MAX) {
+ if (POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + linux_length > UINT32_MAX || kernel_size_in_memory > linux_length) {
linux_relocated = xmalloc_pages(
- AllocateMaxAddress, EfiLoaderCode, EFI_SIZE_TO_PAGES(linux_length), UINT32_MAX);
+ AllocateMaxAddress,
+ EfiLoaderCode,
+ EFI_SIZE_TO_PAGES(kernel_size_in_memory > linux_length ? kernel_size_in_memory : linux_length),
+ UINT32_MAX);
linux_buffer = memcpy(
PHYSICAL_ADDRESS_TO_POINTER(linux_relocated.addr), linux_buffer, linux_length);
+ if (kernel_size_in_memory > linux_length)
+ memzero((uint8_t *) linux_buffer + linux_length, kernel_size_in_memory - linux_length);
}
_cleanup_pages_ Pages initrd_relocated = {};
diff --git a/src/boot/efi/pe.c b/src/boot/efi/pe.c
index 829266b..fdca0c9 100644
--- a/src/boot/efi/pe.c
+++ b/src/boot/efi/pe.c
@@ -209,7 +209,7 @@ static uint32_t get_compatibility_entry_address(const DosFileHeader *dos, const
return 0;
}
-EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address) {
+EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address, size_t *ret_size_in_memory) {
assert(base);
assert(ret_compat_address);
@@ -221,6 +221,11 @@ EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address) {
if (!verify_pe(pe, /* allow_compatibility= */ true))
return EFI_LOAD_ERROR;
+ /* When allocating we need to also consider the virtual/uninitialized data sections, so parse it out
+ * of the SizeOfImage field in the PE header and return it */
+ if (ret_size_in_memory)
+ *ret_size_in_memory = pe->OptionalHeader.SizeOfImage;
+
/* Support for LINUX_INITRD_MEDIA_GUID was added in kernel stub 1.0. */
if (pe->OptionalHeader.MajorImageVersion < 1)
return EFI_UNSUPPORTED;
diff --git a/src/boot/efi/pe.h b/src/boot/efi/pe.h
index 7e2258f..860cfe5 100644
--- a/src/boot/efi/pe.h
+++ b/src/boot/efi/pe.h
@@ -16,4 +16,4 @@ EFI_STATUS pe_file_locate_sections(
size_t *offsets,
size_t *sizes);
-EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address);
+EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address, size_t *ret_size_in_memory);
diff --git a/src/boot/efi/vmm.c b/src/boot/efi/vmm.c
index bfc7acc..ed654f6 100644
--- a/src/boot/efi/vmm.c
+++ b/src/boot/efi/vmm.c
@@ -346,7 +346,7 @@ static uint64_t msr(uint32_t index) {
return val;
}
-static bool detect_hyperv_sev(void) {
+static bool detect_hyperv_cvm(uint32_t isoltype) {
uint32_t eax, ebx, ecx, edx, feat;
char sig[13] = {};
@@ -363,7 +363,7 @@ static bool detect_hyperv_sev(void) {
if (ebx & CPUID_HYPERV_ISOLATION && !(ebx & CPUID_HYPERV_CPU_MANAGEMENT)) {
__cpuid(CPUID_HYPERV_ISOLATION_CONFIG, eax, ebx, ecx, edx);
- if ((ebx & CPUID_HYPERV_ISOLATION_TYPE_MASK) == CPUID_HYPERV_ISOLATION_TYPE_SNP)
+ if ((ebx & CPUID_HYPERV_ISOLATION_TYPE_MASK) == isoltype)
return true;
}
@@ -388,7 +388,7 @@ static bool detect_sev(void) {
* specific CPUID checks.
*/
if (!(eax & EAX_SEV))
- return detect_hyperv_sev();
+ return detect_hyperv_cvm(CPUID_HYPERV_ISOLATION_TYPE_SNP);
msrval = msr(MSR_AMD64_SEV);
@@ -412,6 +412,9 @@ static bool detect_tdx(void) {
if (memcmp(sig, CPUID_SIG_INTEL_TDX, sizeof(sig)) == 0)
return true;
+ if (detect_hyperv_cvm(CPUID_HYPERV_ISOLATION_TYPE_TDX))
+ return true;
+
return false;
}
#endif /* ! __i386__ && ! __x86_64__ */