|
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
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.