diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2013-04-22 00:40:37 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2013-04-22 02:01:34 -0400 |
commit | 68a644d734e61f38b686cb755bd2a3f43d9372f4 (patch) | |
tree | ea2e4f575463a080cbd426338f3666852ea8919d | |
parent | 406a590ba105bfb7b67952f0a5f948e0d374e03e (diff) |
lguest: check vaddr not pgd for Switcher protection.
We currently assume that the Switcher the top pgd; we want to remove
this assumption, so check that vaddr is OK, rather then checking pgd
index.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r-- | drivers/lguest/page_tables.c | 37 |
1 files changed, 16 insertions, 21 deletions
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index 3b62be160a6e..a2454a24a10c 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c | |||
@@ -95,13 +95,6 @@ static pgd_t *spgd_addr(struct lg_cpu *cpu, u32 i, unsigned long vaddr) | |||
95 | { | 95 | { |
96 | unsigned int index = pgd_index(vaddr); | 96 | unsigned int index = pgd_index(vaddr); |
97 | 97 | ||
98 | #ifndef CONFIG_X86_PAE | ||
99 | /* We kill any Guest trying to touch the Switcher addresses. */ | ||
100 | if (index >= SWITCHER_PGD_INDEX) { | ||
101 | kill_guest(cpu, "attempt to access switcher pages"); | ||
102 | index = 0; | ||
103 | } | ||
104 | #endif | ||
105 | /* Return a pointer index'th pgd entry for the i'th page table. */ | 98 | /* Return a pointer index'th pgd entry for the i'th page table. */ |
106 | return &cpu->lg->pgdirs[i].pgdir[index]; | 99 | return &cpu->lg->pgdirs[i].pgdir[index]; |
107 | } | 100 | } |
@@ -117,13 +110,6 @@ static pmd_t *spmd_addr(struct lg_cpu *cpu, pgd_t spgd, unsigned long vaddr) | |||
117 | unsigned int index = pmd_index(vaddr); | 110 | unsigned int index = pmd_index(vaddr); |
118 | pmd_t *page; | 111 | pmd_t *page; |
119 | 112 | ||
120 | /* We kill any Guest trying to touch the Switcher addresses. */ | ||
121 | if (pgd_index(vaddr) == SWITCHER_PGD_INDEX && | ||
122 | index >= SWITCHER_PMD_INDEX) { | ||
123 | kill_guest(cpu, "attempt to access switcher pages"); | ||
124 | index = 0; | ||
125 | } | ||
126 | |||
127 | /* You should never call this if the PGD entry wasn't valid */ | 113 | /* You should never call this if the PGD entry wasn't valid */ |
128 | BUG_ON(!(pgd_flags(spgd) & _PAGE_PRESENT)); | 114 | BUG_ON(!(pgd_flags(spgd) & _PAGE_PRESENT)); |
129 | page = __va(pgd_pfn(spgd) << PAGE_SHIFT); | 115 | page = __va(pgd_pfn(spgd) << PAGE_SHIFT); |
@@ -323,6 +309,10 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode) | |||
323 | pmd_t gpmd; | 309 | pmd_t gpmd; |
324 | #endif | 310 | #endif |
325 | 311 | ||
312 | /* We never demand page the Switcher, so trying is a mistake. */ | ||
313 | if (vaddr >= switcher_addr) | ||
314 | return false; | ||
315 | |||
326 | /* First step: get the top-level Guest page table entry. */ | 316 | /* First step: get the top-level Guest page table entry. */ |
327 | if (unlikely(cpu->linear_pages)) { | 317 | if (unlikely(cpu->linear_pages)) { |
328 | /* Faking up a linear mapping. */ | 318 | /* Faking up a linear mapping. */ |
@@ -495,10 +485,14 @@ static bool page_writable(struct lg_cpu *cpu, unsigned long vaddr) | |||
495 | { | 485 | { |
496 | pgd_t *spgd; | 486 | pgd_t *spgd; |
497 | unsigned long flags; | 487 | unsigned long flags; |
498 | |||
499 | #ifdef CONFIG_X86_PAE | 488 | #ifdef CONFIG_X86_PAE |
500 | pmd_t *spmd; | 489 | pmd_t *spmd; |
501 | #endif | 490 | #endif |
491 | |||
492 | /* You can't put your stack in the Switcher! */ | ||
493 | if (vaddr >= switcher_addr) | ||
494 | return false; | ||
495 | |||
502 | /* Look at the current top level entry: is it present? */ | 496 | /* Look at the current top level entry: is it present? */ |
503 | spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr); | 497 | spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr); |
504 | if (!(pgd_flags(*spgd) & _PAGE_PRESENT)) | 498 | if (!(pgd_flags(*spgd) & _PAGE_PRESENT)) |
@@ -897,6 +891,12 @@ static void do_set_pte(struct lg_cpu *cpu, int idx, | |||
897 | void guest_set_pte(struct lg_cpu *cpu, | 891 | void guest_set_pte(struct lg_cpu *cpu, |
898 | unsigned long gpgdir, unsigned long vaddr, pte_t gpte) | 892 | unsigned long gpgdir, unsigned long vaddr, pte_t gpte) |
899 | { | 893 | { |
894 | /* We don't let you remap the Switcher; we need it to get back! */ | ||
895 | if (vaddr >= switcher_addr) { | ||
896 | kill_guest(cpu, "attempt to set pte into Switcher pages"); | ||
897 | return; | ||
898 | } | ||
899 | |||
900 | /* | 900 | /* |
901 | * Kernel mappings must be changed on all top levels. Slow, but doesn't | 901 | * Kernel mappings must be changed on all top levels. Slow, but doesn't |
902 | * happen often. | 902 | * happen often. |
@@ -995,12 +995,7 @@ void page_table_guest_data_init(struct lg_cpu *cpu) | |||
995 | * "pgd_index(lg->kernel_address)". This assumes it won't hit the | 995 | * "pgd_index(lg->kernel_address)". This assumes it won't hit the |
996 | * Switcher mappings, so check that now. | 996 | * Switcher mappings, so check that now. |
997 | */ | 997 | */ |
998 | #ifdef CONFIG_X86_PAE | 998 | if (cpu->lg->kernel_address >= switcher_addr) |
999 | if (pgd_index(cpu->lg->kernel_address) == SWITCHER_PGD_INDEX && | ||
1000 | pmd_index(cpu->lg->kernel_address) == SWITCHER_PMD_INDEX) | ||
1001 | #else | ||
1002 | if (pgd_index(cpu->lg->kernel_address) >= SWITCHER_PGD_INDEX) | ||
1003 | #endif | ||
1004 | kill_guest(cpu, "bad kernel address %#lx", | 999 | kill_guest(cpu, "bad kernel address %#lx", |
1005 | cpu->lg->kernel_address); | 1000 | cpu->lg->kernel_address); |
1006 | } | 1001 | } |