Skip to content

Commit ed9f007

Browse files
keesIngo Molnar
authored andcommitted
x86/KASLR: Extend kernel image physical address randomization to addresses larger than 4G
We want the physical address to be randomized anywhere between 16MB and the top of physical memory (up to 64TB). 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. Finally, since the slots[] array and its associated functions are not needed any more, so they are removed. Based on earlier patches by Baoquan He. Originally-from: Baoquan He <bhe@redhat.com> Signed-off-by: Kees Cook <keescook@chromium.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andrey Ryabinin <aryabinin@virtuozzo.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Baoquan He <bhe@redhat.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: H.J. Lu <hjl.tools@gmail.com> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Yinghai Lu <yinghai@kernel.org> Link: http://lkml.kernel.org/r/1464216334-17200-5-git-send-email-keescook@chromium.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent 8391c73 commit ed9f007

File tree

2 files changed

+85
-57
lines changed

2 files changed

+85
-57
lines changed

arch/x86/Kconfig

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1934,21 +1934,26 @@ config RANDOMIZE_BASE
19341934
attempts relying on knowledge of the location of kernel
19351935
code internals.
19361936

1937-
The kernel physical and virtual address can be randomized
1938-
from 16MB up to 1GB on 64-bit and 512MB on 32-bit. (Note that
1939-
using RANDOMIZE_BASE reduces the memory space available to
1940-
kernel modules from 1.5GB to 1GB.)
1937+
On 64-bit, the kernel physical and virtual addresses are
1938+
randomized separately. The physical address will be anywhere
1939+
between 16MB and the top of physical memory (up to 64TB). The
1940+
virtual address will be randomized from 16MB up to 1GB (9 bits
1941+
of entropy). Note that this also reduces the memory space
1942+
available to kernel modules from 1.5GB to 1GB.
1943+
1944+
On 32-bit, the kernel physical and virtual addresses are
1945+
randomized together. They will be randomized from 16MB up to
1946+
512MB (8 bits of entropy).
19411947

19421948
Entropy is generated using the RDRAND instruction if it is
19431949
supported. If RDTSC is supported, its value is mixed into
19441950
the entropy pool as well. If neither RDRAND nor RDTSC are
1945-
supported, then entropy is read from the i8254 timer.
1946-
1947-
Since the kernel is built using 2GB addressing, and
1948-
PHYSICAL_ALIGN must be at a minimum of 2MB, only 10 bits of
1949-
entropy is theoretically possible. Currently, with the
1950-
default value for PHYSICAL_ALIGN and due to page table
1951-
layouts, 64-bit uses 9 bits of entropy and 32-bit uses 8 bits.
1951+
supported, then entropy is read from the i8254 timer. The
1952+
usable entropy is limited by the kernel being built using
1953+
2GB addressing, and that PHYSICAL_ALIGN must be at a
1954+
minimum of 2MB. As a result, only 10 bits of entropy are
1955+
theoretically possible, but the implementations are further
1956+
limited due to memory layouts.
19521957

19531958
If CONFIG_HIBERNATE is also enabled, KASLR is disabled at boot
19541959
time. To enable it, boot with "kaslr" on the kernel command

arch/x86/boot/compressed/kaslr.c

Lines changed: 69 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -132,17 +132,6 @@ enum mem_avoid_index {
132132

133133
static struct mem_vector mem_avoid[MEM_AVOID_MAX];
134134

135-
static bool mem_contains(struct mem_vector *region, struct mem_vector *item)
136-
{
137-
/* Item at least partially before region. */
138-
if (item->start < region->start)
139-
return false;
140-
/* Item at least partially after region. */
141-
if (item->start + item->size > region->start + region->size)
142-
return false;
143-
return true;
144-
}
145-
146135
static bool mem_overlaps(struct mem_vector *one, struct mem_vector *two)
147136
{
148137
/* Item one is entirely before item two. */
@@ -319,8 +308,6 @@ static bool mem_avoid_overlap(struct mem_vector *img,
319308
return is_overlapping;
320309
}
321310

322-
static unsigned long slots[KERNEL_IMAGE_SIZE / CONFIG_PHYSICAL_ALIGN];
323-
324311
struct slot_area {
325312
unsigned long addr;
326313
int num;
@@ -351,36 +338,44 @@ static void store_slot_info(struct mem_vector *region, unsigned long image_size)
351338
}
352339
}
353340

354-
static void slots_append(unsigned long addr)
355-
{
356-
/* Overflowing the slots list should be impossible. */
357-
if (slot_max >= KERNEL_IMAGE_SIZE / CONFIG_PHYSICAL_ALIGN)
358-
return;
359-
360-
slots[slot_max++] = addr;
361-
}
362-
363341
static unsigned long slots_fetch_random(void)
364342
{
343+
unsigned long slot;
344+
int i;
345+
365346
/* Handle case of no slots stored. */
366347
if (slot_max == 0)
367348
return 0;
368349

369-
return slots[get_random_long("Physical") % slot_max];
350+
slot = get_random_long("Physical") % slot_max;
351+
352+
for (i = 0; i < slot_area_index; i++) {
353+
if (slot >= slot_areas[i].num) {
354+
slot -= slot_areas[i].num;
355+
continue;
356+
}
357+
return slot_areas[i].addr + slot * CONFIG_PHYSICAL_ALIGN;
358+
}
359+
360+
if (i == slot_area_index)
361+
debug_putstr("slots_fetch_random() failed!?\n");
362+
return 0;
370363
}
371364

372365
static void process_e820_entry(struct e820entry *entry,
373366
unsigned long minimum,
374367
unsigned long image_size)
375368
{
376-
struct mem_vector region, img, overlap;
369+
struct mem_vector region, overlap;
370+
struct slot_area slot_area;
371+
unsigned long start_orig;
377372

378373
/* Skip non-RAM entries. */
379374
if (entry->type != E820_RAM)
380375
return;
381376

382-
/* Ignore entries entirely above our maximum. */
383-
if (entry->addr >= KERNEL_IMAGE_SIZE)
377+
/* On 32-bit, ignore entries entirely above our maximum. */
378+
if (IS_ENABLED(CONFIG_X86_32) && entry->addr >= KERNEL_IMAGE_SIZE)
384379
return;
385380

386381
/* Ignore entries entirely below our minimum. */
@@ -390,31 +385,55 @@ static void process_e820_entry(struct e820entry *entry,
390385
region.start = entry->addr;
391386
region.size = entry->size;
392387

393-
/* Potentially raise address to minimum location. */
394-
if (region.start < minimum)
395-
region.start = minimum;
388+
/* Give up if slot area array is full. */
389+
while (slot_area_index < MAX_SLOT_AREA) {
390+
start_orig = region.start;
396391

397-
/* Potentially raise address to meet alignment requirements. */
398-
region.start = ALIGN(region.start, CONFIG_PHYSICAL_ALIGN);
392+
/* Potentially raise address to minimum location. */
393+
if (region.start < minimum)
394+
region.start = minimum;
399395

400-
/* Did we raise the address above the bounds of this e820 region? */
401-
if (region.start > entry->addr + entry->size)
402-
return;
396+
/* Potentially raise address to meet alignment needs. */
397+
region.start = ALIGN(region.start, CONFIG_PHYSICAL_ALIGN);
403398

404-
/* Reduce size by any delta from the original address. */
405-
region.size -= region.start - entry->addr;
399+
/* Did we raise the address above this e820 region? */
400+
if (region.start > entry->addr + entry->size)
401+
return;
406402

407-
/* Reduce maximum size to fit end of image within maximum limit. */
408-
if (region.start + region.size > KERNEL_IMAGE_SIZE)
409-
region.size = KERNEL_IMAGE_SIZE - region.start;
403+
/* Reduce size by any delta from the original address. */
404+
region.size -= region.start - start_orig;
410405

411-
/* Walk each aligned slot and check for avoided areas. */
412-
for (img.start = region.start, img.size = image_size ;
413-
mem_contains(&region, &img) ;
414-
img.start += CONFIG_PHYSICAL_ALIGN) {
415-
if (mem_avoid_overlap(&img, &overlap))
416-
continue;
417-
slots_append(img.start);
406+
/* On 32-bit, reduce region size to fit within max size. */
407+
if (IS_ENABLED(CONFIG_X86_32) &&
408+
region.start + region.size > KERNEL_IMAGE_SIZE)
409+
region.size = KERNEL_IMAGE_SIZE - region.start;
410+
411+
/* Return if region can't contain decompressed kernel */
412+
if (region.size < image_size)
413+
return;
414+
415+
/* If nothing overlaps, store the region and return. */
416+
if (!mem_avoid_overlap(&region, &overlap)) {
417+
store_slot_info(&region, image_size);
418+
return;
419+
}
420+
421+
/* Store beginning of region if holds at least image_size. */
422+
if (overlap.start > region.start + image_size) {
423+
struct mem_vector beginning;
424+
425+
beginning.start = region.start;
426+
beginning.size = overlap.start - region.start;
427+
store_slot_info(&beginning, image_size);
428+
}
429+
430+
/* Return if overlap extends to or past end of region. */
431+
if (overlap.start + overlap.size >= region.start + region.size)
432+
return;
433+
434+
/* Clip off the overlapping region and start over. */
435+
region.size -= overlap.start - region.start + overlap.size;
436+
region.start = overlap.start + overlap.size;
418437
}
419438
}
420439

@@ -431,6 +450,10 @@ static unsigned long find_random_phys_addr(unsigned long minimum,
431450
for (i = 0; i < boot_params->e820_entries; i++) {
432451
process_e820_entry(&boot_params->e820_map[i], minimum,
433452
image_size);
453+
if (slot_area_index == MAX_SLOT_AREA) {
454+
debug_putstr("Aborted e820 scan (slot_areas full)!\n");
455+
break;
456+
}
434457
}
435458

436459
return slots_fetch_random();

0 commit comments

Comments
 (0)