Patchwork x86: enforce DPL checking on task gate switches invoked through IDT

login
register
mail settings
Submitter Alex Zuepke
Date Aug. 17, 2012, 9:14 a.m.
Message ID <502E0B72.3030701@sysgo.com>
Download mbox | patch
Permalink /patch/178396/
State New
Headers show

Comments

Alex Zuepke - Aug. 17, 2012, 9:14 a.m.
Hi,

x86 software emulation (non-KVM mode) does not check privilege levels on
task gate switches ... so one can invoke a kernel's double fault handler
from user space -- very bad.

Expected behaviour (testcase works with any linux distribution + gcc):
  $ cat test.c
    int main(void)
    {
      __asm__ volatile ("int $8");
    }
  $ gcc test.c
  $ ./a.out
  Segmentation fault
  $
... and not a kernel panic (double fault)

Forgive me for sending this patch as attachment, I'm not used to git.

Best Regards,
Alex

Patch

 x86 software emulation (non-KVM mode) does not check privilege
 levels on task gate switches ... so one can invoke a kernel's
 double fault handler from user space.
 
 Signed-off-by: Alex Zuepke <azu@sysgo.de>
diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
index 5fff8d5..23c5542 100644
--- a/target-i386/seg_helper.c
+++ b/target-i386/seg_helper.c
@@ -578,12 +578,17 @@  static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
     e2 = cpu_ldl_kernel(env, ptr + 4);
     /* check gate type */
     type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    cpl = env->hflags & HF_CPL_MASK;
     switch (type) {
     case 5: /* task gate */
         /* must do that check here to return the correct error code */
         if (!(e2 & DESC_P_MASK)) {
             raise_exception_err(env, EXCP0B_NOSEG, intno * 8 + 2);
         }
+        /* check privilege if software int */
+        if (is_int && dpl < cpl)
+            raise_exception_err(env, EXCP0D_GPF, intno * 8 + 2);
         switch_tss(env, intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
         if (has_error_code) {
             int type;
@@ -616,8 +621,6 @@  static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
         raise_exception_err(env, EXCP0D_GPF, intno * 8 + 2);
         break;
     }
-    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
-    cpl = env->hflags & HF_CPL_MASK;
     /* check privilege if software int */
     if (is_int && dpl < cpl) {
         raise_exception_err(env, EXCP0D_GPF, intno * 8 + 2);