Impact: potential bugfix

In theory, the kernel could reuse the same page as pgdir for a new process
while the hypervisor keeps it cached.  This would have undesirable results.

Signed-off-by: Rusty Russell <ru...@rustcorp.com.au>
---
 arch/x86/include/asm/lguest_hcall.h |    1 +
 arch/x86/lguest/boot.c              |    8 ++++++++
 drivers/lguest/hypercalls.c         |    3 +++
 drivers/lguest/lg.h                 |    1 +
 drivers/lguest/page_tables.c        |   16 ++++++++++++++++
 5 files changed, 29 insertions(+)

diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c
index 54d66f0..a160894 100644
--- a/drivers/lguest/hypercalls.c
+++ b/drivers/lguest/hypercalls.c
@@ -92,6 +92,9 @@ static void do_hcall(struct lg_cpu *cpu, struct hcall_args 
*args)
        case LHCALL_NOTIFY:
                cpu->pending_notify = args->arg1;
                break;
+       case LHCALL_INVALIDATE_PGTABLE:
+               invalidate_pagetable(cpu, args->arg1);
+               break;
        default:
                /* It should be an architecture-specific hypercall. */
                if (lguest_arch_do_hcall(cpu, args))
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index 65f0b8a..c3bdf0b 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -540,6 +551,13 @@ static void lguest_flush_tlb_kernel(void)
        lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0);
 }
 
+/* This routine is called when a process exits, and we're throwing away the
+ * page table. */
+static void lguest_pgd_free(struct mm_struct *mm, pgd_t *pgd)
+{
+       lazy_hcall(LHCALL_INVALIDATE_PGTABLE, __pa(pgd), 0, 0);
+}
+
 /*
  * The Unadvanced Programmable Interrupt Controller.
  *
@@ -1018,6 +1046,7 @@ __init void lguest_init(void)
        pv_mmu_ops.lazy_mode.leave = lguest_leave_lazy_mode;
        pv_mmu_ops.pte_update = lguest_pte_update;
        pv_mmu_ops.pte_update_defer = lguest_pte_update;
+       pv_mmu_ops.pgd_free = lguest_pgd_free;
 
 #ifdef CONFIG_X86_LOCAL_APIC
        /* apic read/write intercepts */
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
index 5faefea..363c231 100644
--- a/drivers/lguest/lg.h
+++ b/drivers/lguest/lg.h
@@ -174,6 +174,7 @@ void guest_set_pte(struct lg_cpu *cpu, unsigned long gpgdir,
                   unsigned long vaddr, pte_t val);
 void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages);
 int demand_page(struct lg_cpu *cpu, unsigned long cr2, int errcode);
+void invalidate_pagetable(struct lg_cpu *cpu, unsigned long pgtable);
 void pin_page(struct lg_cpu *cpu, unsigned long vaddr);
 unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr);
 void page_table_guest_data_init(struct lg_cpu *cpu);
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
index 81d0c60..fd3e1f5 100644
--- a/drivers/lguest/page_tables.c
+++ b/drivers/lguest/page_tables.c
@@ -448,6 +571,22 @@ void guest_new_pagetable(struct lg_cpu *cpu, unsigned long 
pgtable)
                pin_stack_pages(cpu);
 }
 
+/* The Guest tells us when a page is no longer being used as a pagetable.
+ * Without this there can be a subtle bug where the same page gets re-used
+ * for a different process, and we think it's the same one as the one we have
+ * in our little pgdir cache. */
+void invalidate_pagetable(struct lg_cpu *cpu, unsigned long pgtable)
+{
+       unsigned int pgdir = find_pgdir(cpu->lg, pgtable);
+
+       if (pgdir != ARRAY_SIZE(cpu->lg->pgdirs)) {
+               if (pgdir == cpu->cpu_pgd)
+                       kill_guest(cpu, "Attempt to invalidate in-use pgdir");
+               /* We set it to an invalid value. */
+               cpu->lg->pgdirs[pgdir].gpgdir = -1UL;
+       }
+}
+
 /*H:470 Finally, a routine which throws away everything: all PGD entries in all
  * the shadow page tables, including the Guest's kernel mappings.  This is used
  * when we destroy the Guest. */
diff --git a/arch/x86/include/asm/lguest_hcall.h 
b/arch/x86/include/asm/lguest_hcall.h
index 8f034ba..3e200ea 100644
--- a/arch/x86/include/asm/lguest_hcall.h
+++ b/arch/x86/include/asm/lguest_hcall.h
@@ -17,6 +17,7 @@
 #define LHCALL_SET_PMD         15
 #define LHCALL_LOAD_TLS                16
 #define LHCALL_NOTIFY          17
+#define LHCALL_INVALIDATE_PGTABLE 18
 
 #define LGUEST_TRAP_ENTRY 0x1F
 

_______________________________________________
Lguest mailing list
Lguest@ozlabs.org
https://ozlabs.org/mailman/listinfo/lguest

Reply via email to