Commit e27d90e8 authored by Rusty Russell's avatar Rusty Russell Committed by Ingo Molnar

lguest: Map switcher text R/O

Pavel noted that lguest maps the switcher code executable and
read-write.  This is a bad idea for any kernel text, but
particularly for text mapped at a fixed address.

Create two vmas, one for the text (PAGE_KERNEL_RX) and another
for the stacks (PAGE_KERNEL).  Use VM_NO_GUARD to map them
adjacent (as expected by the rest of the code).
Reported-by: default avatarPavel Machek <pavel@ucw.cz>
Tested-by: default avatarPavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent aa042141
...@@ -12,7 +12,9 @@ ...@@ -12,7 +12,9 @@
#define GUEST_PL 1 #define GUEST_PL 1
/* Page for Switcher text itself, then two pages per cpu */ /* Page for Switcher text itself, then two pages per cpu */
#define TOTAL_SWITCHER_PAGES (1 + 2 * nr_cpu_ids) #define SWITCHER_TEXT_PAGES (1)
#define SWITCHER_STACK_PAGES (2 * nr_cpu_ids)
#define TOTAL_SWITCHER_PAGES (SWITCHER_TEXT_PAGES + SWITCHER_STACK_PAGES)
/* Where we map the Switcher, in both Host and Guest. */ /* Where we map the Switcher, in both Host and Guest. */
extern unsigned long switcher_addr; extern unsigned long switcher_addr;
......
...@@ -22,7 +22,8 @@ ...@@ -22,7 +22,8 @@
unsigned long switcher_addr; unsigned long switcher_addr;
struct page **lg_switcher_pages; struct page **lg_switcher_pages;
static struct vm_struct *switcher_vma; static struct vm_struct *switcher_text_vma;
static struct vm_struct *switcher_stacks_vma;
/* This One Big lock protects all inter-guest data structures. */ /* This One Big lock protects all inter-guest data structures. */
DEFINE_MUTEX(lguest_lock); DEFINE_MUTEX(lguest_lock);
...@@ -82,55 +83,81 @@ static __init int map_switcher(void) ...@@ -82,55 +83,81 @@ static __init int map_switcher(void)
} }
} }
/*
* Copy in the compiled-in Switcher code (from x86/switcher_32.S).
* It goes in the first page, which we map in momentarily.
*/
memcpy(kmap(lg_switcher_pages[0]), start_switcher_text,
end_switcher_text - start_switcher_text);
kunmap(lg_switcher_pages[0]);
/* /*
* We place the Switcher underneath the fixmap area, which is the * We place the Switcher underneath the fixmap area, which is the
* highest virtual address we can get. This is important, since we * highest virtual address we can get. This is important, since we
* tell the Guest it can't access this memory, so we want its ceiling * tell the Guest it can't access this memory, so we want its ceiling
* as high as possible. * as high as possible.
*/ */
switcher_addr = FIXADDR_START - (TOTAL_SWITCHER_PAGES+1)*PAGE_SIZE; switcher_addr = FIXADDR_START - TOTAL_SWITCHER_PAGES*PAGE_SIZE;
/* /*
* Now we reserve the "virtual memory area" we want. We might * Now we reserve the "virtual memory area"s we want. We might
* not get it in theory, but in practice it's worked so far. * not get them in theory, but in practice it's worked so far.
* The end address needs +1 because __get_vm_area allocates an *
* extra guard page, so we need space for that. * We want the switcher text to be read-only and executable, and
* the stacks to be read-write and non-executable.
*/ */
switcher_vma = __get_vm_area(TOTAL_SWITCHER_PAGES * PAGE_SIZE, switcher_text_vma = __get_vm_area(PAGE_SIZE, VM_ALLOC|VM_NO_GUARD,
VM_ALLOC, switcher_addr, switcher_addr switcher_addr,
+ (TOTAL_SWITCHER_PAGES+1) * PAGE_SIZE); switcher_addr + PAGE_SIZE);
if (!switcher_vma) {
if (!switcher_text_vma) {
err = -ENOMEM; err = -ENOMEM;
printk("lguest: could not map switcher pages high\n"); printk("lguest: could not map switcher pages high\n");
goto free_pages; goto free_pages;
} }
switcher_stacks_vma = __get_vm_area(SWITCHER_STACK_PAGES * PAGE_SIZE,
VM_ALLOC|VM_NO_GUARD,
switcher_addr + PAGE_SIZE,
switcher_addr + TOTAL_SWITCHER_PAGES * PAGE_SIZE);
if (!switcher_stacks_vma) {
err = -ENOMEM;
printk("lguest: could not map switcher pages high\n");
goto free_text_vma;
}
/* /*
* This code actually sets up the pages we've allocated to appear at * This code actually sets up the pages we've allocated to appear at
* switcher_addr. map_vm_area() takes the vma we allocated above, the * switcher_addr. map_vm_area() takes the vma we allocated above, the
* kind of pages we're mapping (kernel pages), and a pointer to our * kind of pages we're mapping (kernel text pages and kernel writable
* array of struct pages. * pages respectively), and a pointer to our array of struct pages.
*/ */
err = map_vm_area(switcher_vma, PAGE_KERNEL_EXEC, lg_switcher_pages); err = map_vm_area(switcher_text_vma, PAGE_KERNEL_RX, lg_switcher_pages);
if (err) {
printk("lguest: text map_vm_area failed: %i\n", err);
goto free_vmas;
}
err = map_vm_area(switcher_stacks_vma, PAGE_KERNEL,
lg_switcher_pages + SWITCHER_TEXT_PAGES);
if (err) { if (err) {
printk("lguest: map_vm_area failed: %i\n", err); printk("lguest: stacks map_vm_area failed: %i\n", err);
goto free_vma; goto free_vmas;
} }
/* /*
* Now the Switcher is mapped at the right address, we can't fail! * Now the Switcher is mapped at the right address, we can't fail!
* Copy in the compiled-in Switcher code (from x86/switcher_32.S).
*/ */
memcpy(switcher_vma->addr, start_switcher_text,
end_switcher_text - start_switcher_text);
printk(KERN_INFO "lguest: mapped switcher at %p\n", printk(KERN_INFO "lguest: mapped switcher at %p\n",
switcher_vma->addr); switcher_text_vma->addr);
/* And we succeeded... */ /* And we succeeded... */
return 0; return 0;
free_vma: free_vmas:
vunmap(switcher_vma->addr); /* Undoes map_vm_area and __get_vm_area */
vunmap(switcher_stacks_vma->addr);
free_text_vma:
vunmap(switcher_text_vma->addr);
free_pages: free_pages:
i = TOTAL_SWITCHER_PAGES; i = TOTAL_SWITCHER_PAGES;
free_some_pages: free_some_pages:
...@@ -148,7 +175,8 @@ static void unmap_switcher(void) ...@@ -148,7 +175,8 @@ static void unmap_switcher(void)
unsigned int i; unsigned int i;
/* vunmap() undoes *both* map_vm_area() and __get_vm_area(). */ /* vunmap() undoes *both* map_vm_area() and __get_vm_area(). */
vunmap(switcher_vma->addr); vunmap(switcher_text_vma->addr);
vunmap(switcher_stacks_vma->addr);
/* Now we just need to free the pages we copied the switcher into */ /* Now we just need to free the pages we copied the switcher into */
for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) for (i = 0; i < TOTAL_SWITCHER_PAGES; i++)
__free_pages(lg_switcher_pages[i], 0); __free_pages(lg_switcher_pages[i], 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment