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>
This commit is contained in:
parent
406a590ba1
commit
68a644d734
@ -95,13 +95,6 @@ static pgd_t *spgd_addr(struct lg_cpu *cpu, u32 i, unsigned long vaddr)
|
|||||||
{
|
{
|
||||||
unsigned int index = pgd_index(vaddr);
|
unsigned int index = pgd_index(vaddr);
|
||||||
|
|
||||||
#ifndef CONFIG_X86_PAE
|
|
||||||
/* We kill any Guest trying to touch the Switcher addresses. */
|
|
||||||
if (index >= SWITCHER_PGD_INDEX) {
|
|
||||||
kill_guest(cpu, "attempt to access switcher pages");
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/* Return a pointer index'th pgd entry for the i'th page table. */
|
/* Return a pointer index'th pgd entry for the i'th page table. */
|
||||||
return &cpu->lg->pgdirs[i].pgdir[index];
|
return &cpu->lg->pgdirs[i].pgdir[index];
|
||||||
}
|
}
|
||||||
@ -117,13 +110,6 @@ static pmd_t *spmd_addr(struct lg_cpu *cpu, pgd_t spgd, unsigned long vaddr)
|
|||||||
unsigned int index = pmd_index(vaddr);
|
unsigned int index = pmd_index(vaddr);
|
||||||
pmd_t *page;
|
pmd_t *page;
|
||||||
|
|
||||||
/* We kill any Guest trying to touch the Switcher addresses. */
|
|
||||||
if (pgd_index(vaddr) == SWITCHER_PGD_INDEX &&
|
|
||||||
index >= SWITCHER_PMD_INDEX) {
|
|
||||||
kill_guest(cpu, "attempt to access switcher pages");
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* You should never call this if the PGD entry wasn't valid */
|
/* You should never call this if the PGD entry wasn't valid */
|
||||||
BUG_ON(!(pgd_flags(spgd) & _PAGE_PRESENT));
|
BUG_ON(!(pgd_flags(spgd) & _PAGE_PRESENT));
|
||||||
page = __va(pgd_pfn(spgd) << PAGE_SHIFT);
|
page = __va(pgd_pfn(spgd) << PAGE_SHIFT);
|
||||||
@ -323,6 +309,10 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
|
|||||||
pmd_t gpmd;
|
pmd_t gpmd;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* We never demand page the Switcher, so trying is a mistake. */
|
||||||
|
if (vaddr >= switcher_addr)
|
||||||
|
return false;
|
||||||
|
|
||||||
/* First step: get the top-level Guest page table entry. */
|
/* First step: get the top-level Guest page table entry. */
|
||||||
if (unlikely(cpu->linear_pages)) {
|
if (unlikely(cpu->linear_pages)) {
|
||||||
/* Faking up a linear mapping. */
|
/* Faking up a linear mapping. */
|
||||||
@ -495,10 +485,14 @@ static bool page_writable(struct lg_cpu *cpu, unsigned long vaddr)
|
|||||||
{
|
{
|
||||||
pgd_t *spgd;
|
pgd_t *spgd;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
#ifdef CONFIG_X86_PAE
|
#ifdef CONFIG_X86_PAE
|
||||||
pmd_t *spmd;
|
pmd_t *spmd;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* You can't put your stack in the Switcher! */
|
||||||
|
if (vaddr >= switcher_addr)
|
||||||
|
return false;
|
||||||
|
|
||||||
/* Look at the current top level entry: is it present? */
|
/* Look at the current top level entry: is it present? */
|
||||||
spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr);
|
spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr);
|
||||||
if (!(pgd_flags(*spgd) & _PAGE_PRESENT))
|
if (!(pgd_flags(*spgd) & _PAGE_PRESENT))
|
||||||
@ -897,6 +891,12 @@ static void do_set_pte(struct lg_cpu *cpu, int idx,
|
|||||||
void guest_set_pte(struct lg_cpu *cpu,
|
void guest_set_pte(struct lg_cpu *cpu,
|
||||||
unsigned long gpgdir, unsigned long vaddr, pte_t gpte)
|
unsigned long gpgdir, unsigned long vaddr, pte_t gpte)
|
||||||
{
|
{
|
||||||
|
/* We don't let you remap the Switcher; we need it to get back! */
|
||||||
|
if (vaddr >= switcher_addr) {
|
||||||
|
kill_guest(cpu, "attempt to set pte into Switcher pages");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Kernel mappings must be changed on all top levels. Slow, but doesn't
|
* Kernel mappings must be changed on all top levels. Slow, but doesn't
|
||||||
* happen often.
|
* happen often.
|
||||||
@ -995,12 +995,7 @@ void page_table_guest_data_init(struct lg_cpu *cpu)
|
|||||||
* "pgd_index(lg->kernel_address)". This assumes it won't hit the
|
* "pgd_index(lg->kernel_address)". This assumes it won't hit the
|
||||||
* Switcher mappings, so check that now.
|
* Switcher mappings, so check that now.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_X86_PAE
|
if (cpu->lg->kernel_address >= switcher_addr)
|
||||||
if (pgd_index(cpu->lg->kernel_address) == SWITCHER_PGD_INDEX &&
|
|
||||||
pmd_index(cpu->lg->kernel_address) == SWITCHER_PMD_INDEX)
|
|
||||||
#else
|
|
||||||
if (pgd_index(cpu->lg->kernel_address) >= SWITCHER_PGD_INDEX)
|
|
||||||
#endif
|
|
||||||
kill_guest(cpu, "bad kernel address %#lx",
|
kill_guest(cpu, "bad kernel address %#lx",
|
||||||
cpu->lg->kernel_address);
|
cpu->lg->kernel_address);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user