diff options
Diffstat (limited to 'src/boot/efi')
-rw-r--r-- | src/boot/efi/boot.c | 2 | ||||
-rw-r--r-- | src/boot/efi/efi-string.c | 2 | ||||
-rw-r--r-- | src/boot/efi/linux.c | 6 | ||||
-rw-r--r-- | src/boot/efi/linux.h | 3 | ||||
-rw-r--r-- | src/boot/efi/linux_x86.c | 21 | ||||
-rw-r--r-- | src/boot/efi/pe.c | 7 | ||||
-rw-r--r-- | src/boot/efi/pe.h | 2 | ||||
-rw-r--r-- | src/boot/efi/vmm.c | 9 |
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__ */ |