Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933635AbbGGU0n (ORCPT ); Tue, 7 Jul 2015 16:26:43 -0400 Received: from aserp1040.oracle.com ([141.146.126.69]:51173 "EHLO aserp1040.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932472AbbGGUU6 (ORCPT ); Tue, 7 Jul 2015 16:20:58 -0400 From: Yinghai Lu To: Kees Cook , "H. Peter Anvin" , Baoquan He Cc: linux-kernel@vger.kernel.org Subject: [PATCH 17/42] x86, kaslr: Add support of kernel physical address randomization above 4G Date: Tue, 7 Jul 2015 13:20:03 -0700 Message-Id: <1436300428-21163-18-git-send-email-yinghai@kernel.org> X-Mailer: git-send-email 1.8.4.5 In-Reply-To: <1436300428-21163-1-git-send-email-yinghai@kernel.org> References: <1436300428-21163-1-git-send-email-yinghai@kernel.org> X-Source-IP: userv0021.oracle.com [156.151.31.71] Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4622 Lines: 147 From: Baoquan He In kaslr implementation mechanism, mainly process_e820_entry and slots_fetch_random do the job. process_e820_entry is responsible for storing the slot information. slots_fetch_random takes care of fetching slot information. In this patch, for adding support of kernel physical address randomization above 4G, both of these two functions are changed based on the new slot_area data structure. Now kernel can be reloaded and decompressed anywhere of the whole physical memory, even near 64T at most. Signed-off-by: Baoquan He --- arch/x86/boot/compressed/aslr.c | 68 ++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c index 554b637..9158882 100644 --- a/arch/x86/boot/compressed/aslr.c +++ b/arch/x86/boot/compressed/aslr.c @@ -293,27 +293,40 @@ 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() % slot_max]; + random = get_random_long() % 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("Something wrong happened in slots_fetch_random()...\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 >= CONFIG_RANDOMIZE_BASE_MAX_OFFSET) - return; - /* Ignore entries entirely below our minimum. */ if (entry->addr + entry->size < minimum) return; @@ -321,10 +334,17 @@ static void process_e820_entry(struct e820entry *entry, region.start = entry->addr; region.size = entry->size; +repeat: + start_orig = region.start; + /* Potentially raise address to minimum location. */ if (region.start < minimum) region.start = minimum; + /* Return if slot area array is full */ + if (slot_area_index == MAX_SLOT_AREA) + return; + /* Potentially raise address to meet alignment requirements. */ region.start = ALIGN(region.start, CONFIG_PHYSICAL_ALIGN); @@ -333,20 +353,30 @@ static void process_e820_entry(struct e820entry *entry, return; /* Reduce size by any delta from the original address. */ - region.size -= region.start - entry->addr; + region.size -= region.start - start_orig; - /* Reduce maximum size to fit end of image within maximum limit. */ - if (region.start + region.size > CONFIG_RANDOMIZE_BASE_MAX_OFFSET) - region.size = CONFIG_RANDOMIZE_BASE_MAX_OFFSET - region.start; + /* Return if region can't contain decompressed kernel */ + if (region.size < image_size) + return; - /* 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); + if (!mem_avoid_overlap(®ion)) { + store_slot_info(®ion, image_size); + return; } + + min = mem_min_overlap(®ion, &out); + + 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); + } + + region.size -= out.start - region.start + out.size; + region.start = out.start + out.size; + goto repeat; } static unsigned long find_random_phy_addr(unsigned long minimum, @@ -361,6 +391,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("Stop processing e820 since slot_areas is full...\n"); + break; + } } return slots_fetch_random(); -- 1.8.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/