lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20251106173019.1224443-2-ardb+git@google.com>
Date: Thu,  6 Nov 2025 18:30:20 +0100
From: Ard Biesheuvel <ardb+git@...gle.com>
To: linux-kernel@...r.kernel.org
Cc: x86@...nel.org, kees@...nel.org, Ard Biesheuvel <ardb@...nel.org>, 
	Michal Clapinski <mclapinski@...gle.com>, Chris Li <chrisl@...nel.org>
Subject: [RFC PATCH] x86/boot/compressed: Disable physical KASLR when memmap= appears

From: Ard Biesheuvel <ardb@...nel.org>

The decompressor physical KASLR randomization logic is rather intricate,
as it attempts to reconcile various kernel command line parameters such
as mem=, memmap= and hugepages=, in order to create a coherent picture
of which parts of physical RAM may be used to load the kernel.

The memmap= command line option is especially interesting, as it can
appear an unlimited number of times, and each occurrence can describe a
number of memory regions in a number of different ways (see below), with
no guarantees that those occurrences are mutually consistent.

Given that the current logic appears to be flawed, let's not bother and
just disable physical KASLR when memmap= appears at all.

  memmap=exactmap [KNL,X86,EARLY] Enable setting of an exact
  		E820 memory map, as specified by the user.
  		Such memmap=exactmap lines can be constructed based on
  		BIOS output or other requirements. See the memmap=nn@ss
  		option description.

  memmap=nn[KMG]@ss[KMG]
  		[KNL, X86,MIPS,XTENSA,EARLY] Force usage of a specific region of memory.
  		Region of memory to be used is from ss to ss+nn.
  		If @ss[KMG] is omitted, it is equivalent to mem=nn[KMG],
  		which limits max address to nn[KMG].
  		Multiple different regions can be specified,
  		comma delimited.
  		Example:
  			memmap=100M@2G,100M#3G,1G!1024G

  memmap=nn[KMG]#ss[KMG]
  		[KNL,ACPI,EARLY] Mark specific memory as ACPI data.
  		Region of memory to be marked is from ss to ss+nn.

  memmap=nn[KMG]$ss[KMG]
  		[KNL,ACPI,EARLY] Mark specific memory as reserved.
  		Region of memory to be reserved is from ss to ss+nn.
  		Example: Exclude memory from 0x18690000-0x1869ffff
  			 memmap=64K$0x18690000
  			 or
  			 memmap=0x10000$0x18690000
  		Some bootloaders may need an escape character before '$',
  		like Grub2, otherwise '$' and the following number
  		will be eaten.

  memmap=nn[KMG]!ss[KMG,EARLY]
  		[KNL,X86] Mark specific memory as protected.
  		Region of memory to be used, from ss to ss+nn.
  		The memory region may be marked as e820 type 12 (0xc)
  		and is NVDIMM or ADR memory.

  memmap=<size>%<offset>-<oldtype>+<newtype>
  		[KNL,ACPI,EARLY] Convert memory within the specified region
  		from <oldtype> to <newtype>. If "-<oldtype>" is left
  		out, the whole region will be marked as <newtype>,
  		even if previously unavailable. If "+<newtype>" is left
  		out, matching memory will be removed. Types are
  		specified as e820 types, e.g., 1 = RAM, 2 = reserved,
  		3 = ACPI, 12 = PRAM.

Reported-by: Michal Clapinski <mclapinski@...gle.com>
Reported-by: Chris Li <chrisl@...nel.org>
Signed-off-by: Ard Biesheuvel <ardb@...nel.org>
---
 arch/x86/boot/compressed/kaslr.c | 100 ++-----------------------------
 1 file changed, 6 insertions(+), 94 deletions(-)

diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c
index 3b0948ad449f..96805d6c10a4 100644
--- a/arch/x86/boot/compressed/kaslr.c
+++ b/arch/x86/boot/compressed/kaslr.c
@@ -67,16 +67,11 @@ static unsigned long get_boot_seed(void)
 #define KASLR_COMPRESSED_BOOT
 #include "../../lib/kaslr.c"
 
-
-/* Only supporting at most 4 unusable memmap regions with kaslr */
-#define MAX_MEMMAP_REGIONS	4
-
-static bool memmap_too_large;
-
+static bool memmap_found;
 
 /*
  * Store memory limit: MAXMEM on 64-bit and KERNEL_IMAGE_SIZE on 32-bit.
- * It may be reduced by "mem=nn[KMG]" or "memmap=nn[KMG]" command line options.
+ * It may be reduced by "mem=nn[KMG]" command line options.
  */
 static u64 mem_limit;
 
@@ -88,8 +83,6 @@ enum mem_avoid_index {
 	MEM_AVOID_INITRD,
 	MEM_AVOID_CMDLINE,
 	MEM_AVOID_BOOTPARAMS,
-	MEM_AVOID_MEMMAP_BEGIN,
-	MEM_AVOID_MEMMAP_END = MEM_AVOID_MEMMAP_BEGIN + MAX_MEMMAP_REGIONS - 1,
 	MEM_AVOID_MAX,
 };
 
@@ -115,87 +108,6 @@ char *skip_spaces(const char *str)
 #include "../../../../lib/ctype.c"
 #include "../../../../lib/cmdline.c"
 
-static int
-parse_memmap(char *p, u64 *start, u64 *size)
-{
-	char *oldp;
-
-	if (!p)
-		return -EINVAL;
-
-	/* We don't care about this option here */
-	if (!strncmp(p, "exactmap", 8))
-		return -EINVAL;
-
-	oldp = p;
-	*size = memparse(p, &p);
-	if (p == oldp)
-		return -EINVAL;
-
-	switch (*p) {
-	case '#':
-	case '$':
-	case '!':
-		*start = memparse(p + 1, &p);
-		return 0;
-	case '@':
-		/*
-		 * memmap=nn@ss specifies usable region, should
-		 * be skipped
-		 */
-		*size = 0;
-		fallthrough;
-	default:
-		/*
-		 * If w/o offset, only size specified, memmap=nn[KMG] has the
-		 * same behaviour as mem=nn[KMG]. It limits the max address
-		 * system can use. Region above the limit should be avoided.
-		 */
-		*start = 0;
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-static void mem_avoid_memmap(char *str)
-{
-	static int i;
-
-	if (i >= MAX_MEMMAP_REGIONS)
-		return;
-
-	while (str && (i < MAX_MEMMAP_REGIONS)) {
-		int rc;
-		u64 start, size;
-		char *k = strchr(str, ',');
-
-		if (k)
-			*k++ = 0;
-
-		rc = parse_memmap(str, &start, &size);
-		if (rc < 0)
-			break;
-		str = k;
-
-		if (start == 0) {
-			/* Store the specified memory limit if size > 0 */
-			if (size > 0 && size < mem_limit)
-				mem_limit = size;
-
-			continue;
-		}
-
-		mem_avoid[MEM_AVOID_MEMMAP_BEGIN + i].start = start;
-		mem_avoid[MEM_AVOID_MEMMAP_BEGIN + i].size = size;
-		i++;
-	}
-
-	/* More than 4 memmaps, fail kaslr */
-	if ((i >= MAX_MEMMAP_REGIONS) && str)
-		memmap_too_large = true;
-}
-
 /* Store the number of 1GB huge pages which users specified: */
 static unsigned long max_gb_huge_pages;
 
@@ -254,7 +166,7 @@ static void handle_mem_options(void)
 			break;
 
 		if (!strcmp(param, "memmap")) {
-			mem_avoid_memmap(val);
+			memmap_found = true;
 		} else if (IS_ENABLED(CONFIG_X86_64) && strstr(param, "hugepages")) {
 			parse_gb_huge_pages(param, val);
 		} else if (!strcmp(param, "mem")) {
@@ -812,9 +724,9 @@ static unsigned long find_random_phys_addr(unsigned long minimum,
 	if (minimum + image_size > mem_limit)
 		return 0;
 
-	/* Check if we had too many memmaps. */
-	if (memmap_too_large) {
-		debug_putstr("Aborted memory entries scan (more than 4 memmap= args)!\n");
+	/* Check if memmap= appears on the command line */
+	if (memmap_found) {
+		debug_putstr("memmap= found on the command line, disabling physical KASLR\n");
 		return 0;
 	}
 
-- 
2.51.2.1041.gc1ab5b90ca-goog


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ