diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2009-04-20 05:14:00 (GMT) |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2009-04-19 13:44:01 (GMT) |
commit | a489f0b555b753f9df8ddc24c7e74f657ef7ee7b (patch) | |
tree | 560bd8c56524b658eb0b46e03ef42e262eb5f9b7 /arch/x86/lguest/boot.c | |
parent | 88df781afb788fa588dbf2e77f205214022a8893 (diff) | |
download | linux-fsl-qoriq-a489f0b555b753f9df8ddc24c7e74f657ef7ee7b.tar.xz |
lguest: fix guest crash on non-linear addresses in gdt pvops
Fixes guest crash 'lguest: bad read address 0x4800000 len 256'
The new per-cpu allocator ends up handing a non-linear address to
write_gdt_entry. We do __pa() on it, and hand it to the host, which
kills us.
I've long wanted to make the hypercall "LOAD_GDT_ENTRY" to match the IDT
code, but had no pressing reason until now.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Cc: lguest@ozlabs.org
Diffstat (limited to 'arch/x86/lguest/boot.c')
-rw-r--r-- | arch/x86/lguest/boot.c | 16 |
1 files changed, 9 insertions, 7 deletions
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index e94a11e..a208536 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -273,15 +273,15 @@ static void lguest_load_idt(const struct desc_ptr *desc) * controls the entire thing and the Guest asks it to make changes using the * LOAD_GDT hypercall. * - * This is the opposite of the IDT code where we have a LOAD_IDT_ENTRY - * hypercall and use that repeatedly to load a new IDT. I don't think it - * really matters, but wouldn't it be nice if they were the same? Wouldn't - * it be even better if you were the one to send the patch to fix it? + * This is the exactly like the IDT code. */ static void lguest_load_gdt(const struct desc_ptr *desc) { - BUG_ON((desc->size + 1) / 8 != GDT_ENTRIES); - kvm_hypercall2(LHCALL_LOAD_GDT, __pa(desc->address), GDT_ENTRIES); + unsigned int i; + struct desc_struct *gdt = (void *)desc->address; + + for (i = 0; i < (desc->size+1)/8; i++) + kvm_hypercall3(LHCALL_LOAD_GDT_ENTRY, i, gdt[i].a, gdt[i].b); } /* For a single GDT entry which changes, we do the lazy thing: alter our GDT, @@ -291,7 +291,9 @@ static void lguest_write_gdt_entry(struct desc_struct *dt, int entrynum, const void *desc, int type) { native_write_gdt_entry(dt, entrynum, desc, type); - kvm_hypercall2(LHCALL_LOAD_GDT, __pa(dt), GDT_ENTRIES); + /* Tell Host about this new entry. */ + kvm_hypercall3(LHCALL_LOAD_GDT_ENTRY, entrynum, + dt[entrynum].a, dt[entrynum].b); } /* OK, I lied. There are three "thread local storage" GDT entries which change |