[Lguest] INT 3 generates GPF in user mode under lguest

ron minnich rminnich at gmail.com
Sun Jul 13 14:28:40 EST 2008


Beautiful. I have debug in Plan 9 now!

Thanks!

ron

On Sat, Jul 12, 2008 at 1:10 AM, Rusty Russell <rusty at rustcorp.com.au> wrote:
> On Saturday 12 July 2008 07:57:43 ron minnich wrote:
>> and here I thought I knew sometning about the x86.
>>
>> anybody know why an INT 3 would generate a gpf? Verified under both
>> Plan 9 and Linux. I'm flummoxed.
>
> Hmm, good q.  Tracked it down here.
>
> OK, because it's not a direct trap (it's an interrupt gate), we don't copy the
> ring level across: the result is that we use the default entry, and that's RPL
> 1 only.
>
> How's this?
> Rusty.
>
> lguest: Guest int3 fix
>
> Ron Minnich noticed that guest userspace gets a GPF when it tries to int3:
> we need to copy the privilege level from the guest-supplied IDT to the real
> IDT.  int3 is the only common case where guest userspace expects to invoke
> an interrupt, so that's the symptom of failing to do this.
>
> Signed-off-by: Rusty Russell <rusty at rustcorp.com.au>
>
> diff -r aacc459aba83 drivers/lguest/interrupts_and_traps.c
> --- a/drivers/lguest/interrupts_and_traps.c     Sat Jul 12 16:22:02 2008 +1000
> +++ b/drivers/lguest/interrupts_and_traps.c     Sat Jul 12 17:43:59 2008 +1000
> @@ -406,7 +406,8 @@ void load_guest_idt_entry(struct lg_cpu
>  * deliver_trap() to bounce it back into the Guest. */
>  static void default_idt_entry(struct desc_struct *idt,
>                              int trap,
> -                             const unsigned long handler)
> +                             const unsigned long handler,
> +                             const struct desc_struct *base)
>  {
>        /* A present interrupt gate. */
>        u32 flags = 0x8e00;
> @@ -415,6 +416,10 @@ static void default_idt_entry(struct des
>         * the Guest to use the "int" instruction to trigger it. */
>        if (trap == LGUEST_TRAP_ENTRY)
>                flags |= (GUEST_PL << 13);
> +       else if (base)
> +               /* Copy priv. level from what Guest asked for.  This allows
> +                * debug (int 3) traps from Guest userspace, for example. */
> +               flags |= (base->b & 0x6000);
>
>        /* Now pack it into the IDT entry in its weird format. */
>        idt->a = (LGUEST_CS<<16) | (handler&0x0000FFFF);
> @@ -428,7 +433,7 @@ void setup_default_idt_entries(struct lg
>        unsigned int i;
>
>        for (i = 0; i < ARRAY_SIZE(state->guest_idt); i++)
> -               default_idt_entry(&state->guest_idt[i], i, def[i]);
> +               default_idt_entry(&state->guest_idt[i], i, def[i], NULL);
>  }
>
>  /*H:240 We don't use the IDT entries in the "struct lguest" directly, instead
> @@ -442,6 +447,8 @@ void copy_traps(const struct lg_cpu *cpu
>        /* We can simply copy the direct traps, otherwise we use the default
>         * ones in the Switcher: they will return to the Host. */
>        for (i = 0; i < ARRAY_SIZE(cpu->arch.idt); i++) {
> +               const struct desc_struct *gidt = &cpu->arch.idt[i];
> +
>                /* If no Guest can ever override this trap, leave it alone. */
>                if (!direct_trap(i))
>                        continue;
> @@ -449,12 +456,15 @@ void copy_traps(const struct lg_cpu *cpu
>                /* Only trap gates (type 15) can go direct to the Guest.
>                 * Interrupt gates (type 14) disable interrupts as they are
>                 * entered, which we never let the Guest do.  Not present
> -                * entries (type 0x0) also can't go direct, of course. */
> -               if (idt_type(cpu->arch.idt[i].a, cpu->arch.idt[i].b) == 0xF)
> -                       idt[i] = cpu->arch.idt[i];
> +                * entries (type 0x0) also can't go direct, of course.
> +                *
> +                * If it can't go direct, we still need to copy the priv. level:
> +                * they might want to give userspace access to a software
> +                * interrupt. */
> +               if (idt_type(gidt->a, gidt->b) == 0xF)
> +                       idt[i] = *gidt;
>                else
> -                       /* Reset it to the default. */
> -                       default_idt_entry(&idt[i], i, def[i]);
> +                       default_idt_entry(&idt[i], i, def[i], gidt);
>        }
>  }
>
>



More information about the Lguest mailing list