[Lguest] Gdb in lguest

Rusty Russell rusty at rustcorp.com.au
Wed Sep 4 15:28:06 EST 2013


Sakari Ailus <sakari.ailus at iki.fi> writes:
> Hi,
>
> I recently tried to run gdb in lguest over an ssh connection which, much 
> to my surprise, brought the whole guest down with a message "lguest: Bad 
> address 0xdb49adac". This is reproducible. I'm running Linux 3.9.2.
>
> I haven't had time to investigate this further yet.

Cool, thanks for the bug report!

I reproduced it, and uncovered three bugs, which is pretty good.  I'd
never run gdb under lguest (we don't support debug registers, so much
isn't available).

You should be able to run gdb after applying these three patches
(actually, the last two are enough).

Cheers,
Rusty.

lguest: fix BUG_ON() in invalid guest page table.

If we discover the entry is invalid, we kill the guest, but we must
avoid calling gpte_addr() on the invalid pmd, otherwise:

	kernel BUG at drivers/lguest/page_tables.c:157!

Signed-off-by: Rusty Russell <rusty at rustcorp.com.au>

diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
index a35d8d1..bfb39bb 100644
--- a/drivers/lguest/page_tables.c
+++ b/drivers/lguest/page_tables.c
@@ -669,8 +669,10 @@ unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
 
 #ifdef CONFIG_X86_PAE
 	gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t);
-	if (!(pmd_flags(gpmd) & _PAGE_PRESENT))
+	if (!(pmd_flags(gpmd) & _PAGE_PRESENT)) {
 		kill_guest(cpu, "Bad address %#lx", vaddr);
+		return -1UL;
+	}
 	gpte = lgread(cpu, gpte_addr(cpu, gpmd, vaddr), pte_t);
 #else
 	gpte = lgread(cpu, gpte_addr(cpu, gpgd, vaddr), pte_t);


lguest: fix guest kernel stack overflow when TF bit set.

The symptoms are that running gdb on a binary causes the guest to
overflow the kernels stack (after some period of time), resulting in
it finally being killed with a "Bad address" message.

Reported-by: Sakari Ailus <sakari.ailus at iki.fi>
Signed-off-by: Rusty Russell <rusty at rustcorp.com.au>

diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
index 28433a1..213d065 100644
--- a/drivers/lguest/interrupts_and_traps.c
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -140,6 +141,16 @@ static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
 	cpu->regs->eip = idt_address(lo, hi);
 
 	/*
+	 * Trapping always clears these flags:
+	 * TF: Trap flag
+	 * VM: Virtual 8086 mode
+	 * RF: Resume
+	 * NT: Nested task.
+	 */
+	cpu->regs->eflags &=
+		~(X86_EFLAGS_TF|X86_EFLAGS_VM|X86_EFLAGS_RF|X86_EFLAGS_NT);
+
+	/*
 	 * There are two kinds of interrupt handlers: 0xE is an "interrupt
 	 * gate" which expects interrupts to be disabled on entry.
 	 */


lguest: fix GPF in guest when using gdb.

Since the Guest is in ring 1, it can't read the debug registers: doing
so gives a number of nasty messages:

(gdb) run
Starting program: /bin/sleep 
[   31.170230] general protection fault: 0000 [#1] SMP 
[   31.170230] Modules linked in:
[   31.170230] CPU: 0 PID: 2678 Comm: sleep Not tainted 3.11.0+ #64
[   31.170230] task: cc5c09b0 ti: cc79c000 task.ti: cc79c000
[   31.170230] EIP: 0061:[<c01333d8>] EFLAGS: 00000097 CPU: 0
[   31.170230] EIP is at native_get_debugreg+0x58/0x70
[   31.170230] EAX: 00000006 EBX: cc79dfb4 ECX: b7fff918 EDX: 00000000
[   31.170230] ESI: cc5c09b0 EDI: 00000000 EBP: cc79df84 ESP: cc79df84
[   31.170230]  DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0069
[   31.170230] CR0: 00000008 CR2: 081ba69a CR3: 0e2f2000 CR4: 00000000

Signed-off-by: Rusty Russell <rusty at rustcorp.com.au>

diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index 7c1fde5..bdf8532 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -1056,6 +1056,12 @@ static void lguest_load_sp0(struct tss_struct *tss,
 }
 
 /* Let's just say, I wouldn't do debugging under a Guest. */
+static unsigned long lguest_get_debugreg(int regno)
+{
+	/* FIXME: Implement */
+	return 0;
+}
+
 static void lguest_set_debugreg(int regno, unsigned long value)
 {
 	/* FIXME: Implement */
@@ -1303,6 +1309,7 @@ __init void lguest_init(void)
 	pv_cpu_ops.load_tr_desc = lguest_load_tr_desc;
 	pv_cpu_ops.set_ldt = lguest_set_ldt;
 	pv_cpu_ops.load_tls = lguest_load_tls;
+	pv_cpu_ops.get_debugreg = lguest_get_debugreg;
 	pv_cpu_ops.set_debugreg = lguest_set_debugreg;
 	pv_cpu_ops.clts = lguest_clts;
 	pv_cpu_ops.read_cr0 = lguest_read_cr0;


More information about the Lguest mailing list