[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1460672954-32567-20-git-send-email-keescook@chromium.org>
Date: Thu, 14 Apr 2016 15:29:12 -0700
From: Kees Cook <keescook@...omium.org>
To: Ingo Molnar <mingo@...nel.org>
Cc: Kees Cook <keescook@...omium.org>, Baoquan He <bhe@...hat.com>,
Yinghai Lu <yinghai@...nel.org>,
Ard Biesheuvel <ard.biesheuvel@...aro.org>,
Matt Redfearn <matt.redfearn@...tec.com>, x86@...nel.org,
"H. Peter Anvin" <hpa@...or.com>, Ingo Molnar <mingo@...hat.com>,
Borislav Petkov <bp@...en8.de>,
Vivek Goyal <vgoyal@...hat.com>,
Andy Lutomirski <luto@...nel.org>, lasse.collin@...aani.org,
Andrew Morton <akpm@...ux-foundation.org>,
Dave Young <dyoung@...hat.com>,
kernel-hardening@...ts.openwall.com,
LKML <linux-kernel@...r.kernel.org>
Subject: [PATCH v5 19/21] x86, KASLR: Add physical address randomization >4G
From: Baoquan He <bhe@...hat.com>
This patch exchanges the prior slots[] array for the new slot_areas[]
array, and lifts the limitation of KERNEL_IMAGE_SIZE on the physical
address offset for 64-bit. As before, process_e820_entry walks memory and
populates slot_areas[], splitting on any detected mem_avoid collisions.
Signed-off-by: Baoquan He <bhe@...hat.com>
[kees: rewrote changelog, refactored goto into while, limit 32-bit to 1G]
Signed-off-by: Kees Cook <keescook@...omium.org>
---
arch/x86/boot/compressed/aslr.c | 92 ++++++++++++++++++++++++++++++-----------
1 file changed, 68 insertions(+), 24 deletions(-)
diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
index 53ceaa0a08b9..0587eac3e05d 100644
--- a/arch/x86/boot/compressed/aslr.c
+++ b/arch/x86/boot/compressed/aslr.c
@@ -335,25 +335,42 @@ static void slots_append(unsigned long addr)
static unsigned long slots_fetch_random(void)
{
+ unsigned long random;
+ int i;
+
/* Handle case of no slots stored. */
if (slot_max == 0)
return 0;
- return slots[get_random_long("Physical") % slot_max];
+ random = get_random_long("Physical") % slot_max;
+
+ for (i = 0; i < slot_area_index; i++) {
+ if (random >= slot_areas[i].num) {
+ random -= slot_areas[i].num;
+ continue;
+ }
+ return slot_areas[i].addr + random * CONFIG_PHYSICAL_ALIGN;
+ }
+
+ if (i == slot_area_index)
+ debug_putstr("slots_fetch_random() failed!?\n");
+ return 0;
}
static void process_e820_entry(struct e820entry *entry,
unsigned long minimum,
unsigned long image_size)
{
- struct mem_vector region, img;
+ struct mem_vector region, out;
+ struct slot_area slot_area;
+ unsigned long min, start_orig;
/* Skip non-RAM entries. */
if (entry->type != E820_RAM)
return;
- /* Ignore entries entirely above our maximum. */
- if (entry->addr >= KERNEL_IMAGE_SIZE)
+ /* On 32-bit, ignore entries entirely above our maximum. */
+ if (IS_ENABLED(CONFIG_X86_32) && entry->addr >= KERNEL_IMAGE_SIZE)
return;
/* Ignore entries entirely below our minimum. */
@@ -363,31 +380,54 @@ static void process_e820_entry(struct e820entry *entry,
region.start = entry->addr;
region.size = entry->size;
- /* Potentially raise address to minimum location. */
- if (region.start < minimum)
- region.start = minimum;
+ /* Give up if slot area array is full. */
+ while (slot_area_index < MAX_SLOT_AREA) {
+ start_orig = region.start;
- /* Potentially raise address to meet alignment requirements. */
- region.start = ALIGN(region.start, CONFIG_PHYSICAL_ALIGN);
+ /* Potentially raise address to minimum location. */
+ if (region.start < minimum)
+ region.start = minimum;
- /* Did we raise the address above the bounds of this e820 region? */
- if (region.start > entry->addr + entry->size)
- return;
+ /* Potentially raise address to meet alignment needs. */
+ region.start = ALIGN(region.start, CONFIG_PHYSICAL_ALIGN);
- /* Reduce size by any delta from the original address. */
- region.size -= region.start - entry->addr;
+ /* Did we raise the address above this e820 region? */
+ if (region.start > entry->addr + entry->size)
+ return;
- /* Reduce maximum size to fit end of image within maximum limit. */
- if (region.start + region.size > KERNEL_IMAGE_SIZE)
- region.size = KERNEL_IMAGE_SIZE - region.start;
+ /* Reduce size by any delta from the original address. */
+ region.size -= region.start - start_orig;
- /* Walk each aligned slot and check for avoided areas. */
- for (img.start = region.start, img.size = image_size ;
- mem_contains(®ion, &img) ;
- img.start += CONFIG_PHYSICAL_ALIGN) {
- if (mem_avoid_overlap(&img))
- continue;
- slots_append(img.start);
+ /* On 32-bit, reduce region size to fit within max size. */
+ if (IS_ENABLED(CONFIG_X86_32) &&
+ region.start + region.size > KERNEL_IMAGE_SIZE)
+ region.size = KERNEL_IMAGE_SIZE - region.start;
+
+ /* Return if region can't contain decompressed kernel */
+ if (region.size < image_size)
+ return;
+
+ /* If nothing overlaps, store the region and return. */
+ if (!mem_avoid_overlap(®ion)) {
+ store_slot_info(®ion, image_size);
+ return;
+ }
+
+ /* Other wise, find the lowest overlap. */
+ min = mem_min_overlap(®ion, &out);
+
+ /* Store the region if it can hold at least image_size. */
+ if (min > region.start + image_size) {
+ struct mem_vector tmp;
+
+ tmp.start = region.start;
+ tmp.size = min - region.start;
+ store_slot_info(&tmp, image_size);
+ }
+
+ /* Clip off the overlapping region and start over. */
+ region.size -= out.start - region.start + out.size;
+ region.start = out.start + out.size;
}
}
@@ -403,6 +443,10 @@ static unsigned long find_random_phy_addr(unsigned long minimum,
/* Verify potential e820 positions, appending to slots list. */
for (i = 0; i < real_mode->e820_entries; i++) {
process_e820_entry(&real_mode->e820_map[i], minimum, size);
+ if (slot_area_index == MAX_SLOT_AREA) {
+ debug_putstr("Aborted e820 scan (slot_areas full)!\n");
+ break;
+ }
}
return slots_fetch_random();
--
2.6.3
Powered by blists - more mailing lists