Commit 15aa8fb8 authored by Ard Biesheuvel's avatar Ard Biesheuvel

x86/efistub: Omit physical KASLR when memory reservations exist

The legacy decompressor has elaborate logic to ensure that the
randomized physical placement of the decompressed kernel image does not
conflict with any memory reservations, including ones specified on the
command line using mem=, memmap=, efi_fake_mem= or hugepages=, which are
taken into account by the kernel proper at a later stage.

When booting in EFI mode, it is the firmware's job to ensure that the
chosen range does not conflict with any memory reservations that it
knows about, and this is trivially achieved by using the firmware's
memory allocation APIs.

That leaves reservations specified on the command line, though, which
the firmware knows nothing about, as these regions have no other special
significance to the platform. Since commit

  a1b87d54 ("x86/efistub: Avoid legacy decompressor when doing EFI boot")

these reservations are not taken into account when randomizing the
physical placement, which may result in conflicts where the memory
cannot be reserved by the kernel proper because its own executable image
resides there.

To avoid having to duplicate or reuse the existing complicated logic,
disable physical KASLR entirely when such overrides are specified. These
are mostly diagnostic tools or niche features, and physical KASLR (as
opposed to virtual KASLR, which is much more important as it affects the
memory addresses observed by code executing in the kernel) is something
we can live without.

Closes: https://lkml.kernel.org/r/FA5F6719-8824-4B04-803E-82990E65E627%40akamai.comReported-by: default avatarBen Chaney <bchaney@akamai.com>
Fixes: a1b87d54 ("x86/efistub: Avoid legacy decompressor when doing EFI boot")
Cc:  <stable@vger.kernel.org> # v6.1+
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
parent 4b2543f7
...@@ -775,6 +775,26 @@ static void error(char *str) ...@@ -775,6 +775,26 @@ static void error(char *str)
efi_warn("Decompression failed: %s\n", str); efi_warn("Decompression failed: %s\n", str);
} }
static const char *cmdline_memmap_override;
static efi_status_t parse_options(const char *cmdline)
{
static const char opts[][14] = {
"mem=", "memmap=", "efi_fake_mem=", "hugepages="
};
for (int i = 0; i < ARRAY_SIZE(opts); i++) {
const char *p = strstr(cmdline, opts[i]);
if (p == cmdline || (p > cmdline && isspace(p[-1]))) {
cmdline_memmap_override = opts[i];
break;
}
}
return efi_parse_options(cmdline);
}
static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry) static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry)
{ {
unsigned long virt_addr = LOAD_PHYSICAL_ADDR; unsigned long virt_addr = LOAD_PHYSICAL_ADDR;
...@@ -806,6 +826,10 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry) ...@@ -806,6 +826,10 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry)
!memcmp(efistub_fw_vendor(), ami, sizeof(ami))) { !memcmp(efistub_fw_vendor(), ami, sizeof(ami))) {
efi_debug("AMI firmware v2.0 or older detected - disabling physical KASLR\n"); efi_debug("AMI firmware v2.0 or older detected - disabling physical KASLR\n");
seed[0] = 0; seed[0] = 0;
} else if (cmdline_memmap_override) {
efi_info("%s detected on the kernel command line - disabling physical KASLR\n",
cmdline_memmap_override);
seed[0] = 0;
} }
boot_params_ptr->hdr.loadflags |= KASLR_FLAG; boot_params_ptr->hdr.loadflags |= KASLR_FLAG;
...@@ -882,7 +906,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle, ...@@ -882,7 +906,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
} }
#ifdef CONFIG_CMDLINE_BOOL #ifdef CONFIG_CMDLINE_BOOL
status = efi_parse_options(CONFIG_CMDLINE); status = parse_options(CONFIG_CMDLINE);
if (status != EFI_SUCCESS) { if (status != EFI_SUCCESS) {
efi_err("Failed to parse options\n"); efi_err("Failed to parse options\n");
goto fail; goto fail;
...@@ -891,7 +915,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle, ...@@ -891,7 +915,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
if (!IS_ENABLED(CONFIG_CMDLINE_OVERRIDE)) { if (!IS_ENABLED(CONFIG_CMDLINE_OVERRIDE)) {
unsigned long cmdline_paddr = ((u64)hdr->cmd_line_ptr | unsigned long cmdline_paddr = ((u64)hdr->cmd_line_ptr |
((u64)boot_params->ext_cmd_line_ptr << 32)); ((u64)boot_params->ext_cmd_line_ptr << 32));
status = efi_parse_options((char *)cmdline_paddr); status = parse_options((char *)cmdline_paddr);
if (status != EFI_SUCCESS) { if (status != EFI_SUCCESS) {
efi_err("Failed to parse options\n"); efi_err("Failed to parse options\n");
goto fail; goto fail;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment