This chooses the largest contiguous RAM region for the KASLR offset
to live in.

Signed-off-by: Kees Cook <keesc...@chromium.org>
---
v2:
 - make sure to exclude e820 regions outside the 32-bit memory range.
---
 arch/x86/boot/compressed/aslr.c |   47 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 41 insertions(+), 6 deletions(-)

diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
index 4647e3f..3d3789e 100644
--- a/arch/x86/boot/compressed/aslr.c
+++ b/arch/x86/boot/compressed/aslr.c
@@ -2,6 +2,7 @@
 
 #ifdef CONFIG_RANDOMIZE_BASE
 #include <asm/msr.h>
+#include <asm/e820.h>
 
 #include <asm/archrandom.h>
 static inline int rdrand(unsigned long *v)
@@ -48,28 +49,62 @@ static unsigned long get_random_long(void)
        return 0;
 }
 
+int largest_ram_region(unsigned long *start, unsigned long *size)
+{
+       int i, rc = 0;
+
+       *size = 0;
+       for (i = 0; i < real_mode->e820_entries; i++) {
+               struct e820entry *entry = &real_mode->e820_map[i];
+
+               if (entry->type != E820_RAM)
+                       continue;
+
+               /* XXX: Handle arbitrary physical location. */
+               if (entry->addr > UINT_MAX)
+                       continue;
+
+               if (entry->size > *size) {
+                       *size = entry->size;
+                       *start = entry->addr;
+                       rc = 1;
+               }
+       }
+       return rc;
+}
+
 unsigned char *choose_kernel_location(unsigned char *hint, unsigned long size)
 {
        unsigned char *choice = hint;
        unsigned long random, mask;
+       unsigned long addr, length;
 
        if (cmdline_find_option_bool("noaslr")) {
                debug_putstr("KASLR disabled...\n");
                goto out;
        }
 
+       /* Find an appropriate E820 entry. */
+       if (!largest_ram_region(&addr, &length)) {
+               debug_putstr("KASLR could not find suitable E820 region...\n");
+               goto out;
+       }
+
        random = get_random_long();
 
-       /* Clip off top of the range. */
+       /* XXX: Rework page tables to handle arbitrary physical location. */
        mask = CONFIG_RANDOMIZE_BASE_MAX_OFFSET - 1;
        random &= mask;
 
-       /* XXX: Find an appropriate E820 hole, instead of adding hint. */
-       random += (unsigned long)hint;
+       /* Clip to E820 entry size. */
+       while (random > length)
+               random >>= 1;
+
+       /* Offset the target. */
+       random += addr;
 
-       /* XXX: Clip to E820 hole, instead of just using hint. */
-       mask = (unsigned long)hint + CONFIG_RANDOMIZE_BASE_MAX_OFFSET;
-       while (random + size > mask)
+       /* Clip end to E820 entry size. */
+       while (random + size > addr + length)
                random >>= 1;
 
        /* Clip off bottom of range (via alignment). */
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to