[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Fwd: [PATCH] 1.3.0.0 X86EMU: added blacklist for I/O port in 0-0xFF range



This is one of two patches made against X server 1.3 (should also work
against 1.4) that fix BIOS parsing in x86emu, which should prevent
crashes and freezes seen with some chipset drivers. Could this please
be applied to the 1.3 in Testing via proposed-updates and to 1.4.1 in
Unstable too?  Thanks!

---------- Forwarded message ----------
From: Bart Trojanowski <bart@jukie.net>
Date: Jan 11, 2008 10:49 PM
Subject: [PATCH] 1.3.0.0 X86EMU: added blacklist for I/O port in 0-0xFF range
To: xorg@lists.freedesktop.org, xorg-driver-geode@lists.x.org

This patch adds a test just before x86emu accesses real I/O ports.  The
intent is to prevent access to ports that are know to be under the
kernel's control.  Accessing these from the X process could cause
catastrophic failure of the system.

If such an access is detected, we terminate X "gracefully" by sending a
SIGSEGV signal which is picked up by xf86SigHandler() which dumps the
backtrace and exits gracefully.

Signed-off-by: Bart Trojanowski <bart@jukie.net>
---
 hw/xfree86/int10/helper_exec.c |   80 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 80 insertions(+), 0 deletions(-)

diff --git a/hw/xfree86/int10/helper_exec.c b/hw/xfree86/int10/helper_exec.c
index befc18e..99d5937 100644
--- a/hw/xfree86/int10/helper_exec.c
+++ b/hw/xfree86/int10/helper_exec.c
@@ -19,6 +19,8 @@
 #endif

 #include <unistd.h>
+#include <sys/types.h>
+#include <signal.h>

 #include <X11/Xos.h>
 #include "xf86.h"
@@ -203,6 +205,72 @@ stack_trace(xf86Int10InfoPtr pInt)
        xf86ErrorFVerb(3, "\n");
 }

+enum port_action_e {
+       PORT_ACTION_PERMIT,
+       PORT_ACTION_WARN,
+       PORT_ACTION_BAIL,
+       PORT_ACTION_MAX
+};
+
+static const struct port_range {
+       CARD16 start, end;
+       enum port_action_e access;
+} port_range_table[] = {
+       // NOTE: port ranges are non overlapping and sorted
+       { 0x00, 0x1f, PORT_ACTION_BAIL },       // DMA
+       { 0x20, 0x21, PORT_ACTION_BAIL },       // PIC
+       { 0x40, 0x47, PORT_ACTION_BAIL },       // PIT 1&2
+       { 0x50, 0x53, PORT_ACTION_BAIL },
+       { 0x70, 0x77, PORT_ACTION_BAIL },       // CMOS/RTC
+       { 0x81, 0x8f, PORT_ACTION_BAIL },       // DIAG REGS
+       { 0xa0, 0xa1, PORT_ACTION_BAIL },       // PIC2
+       { 0xc0, 0xdf, PORT_ACTION_BAIL },       // DMA
+};
+#define ARRAY_SIZE(X) (sizeof((X)) / (sizeof(*(X))))
+#define ARRAY_END(X)  (&((X)[ARRAY_SIZE(X)]))
+
+static void assert_port_access_allowed (CARD16 port, CARD16 width)
+{
+       CARD16 access_start, access_end;
+       const struct port_range *pr, *pr_start, *pr_end;
+
+       access_start = port;
+       access_end = port + width - 1;
+
+       // TODO: if the list gets too long we should do a binary search
+       //        or convert the port list to a bitmap representation
+       pr_start = port_range_table;
+       pr_end   = ARRAY_END(port_range_table);
+
+       for (pr = pr_start; pr < pr_end; pr++) {
+               if (access_end < pr->start)
+                       continue;
+               if (access_start > pr->end)
+                       break;
+
+               // we are in the pr range now
+               switch (pr->access) {
+               default:
+                       continue;
+               case PORT_ACTION_BAIL:
+               case PORT_ACTION_WARN:
+                       break;
+               }
+
+               ErrorF("Emulator asked to make a suspect %saccess to "
+                               "port %u (0x%04x)%s\n",
+                               (width == 1) ? "byte " :
+                               (width == 2) ? "word " :
+                               (width == 4) ? "long " : "",
+                               port, port,
+                               (pr->access == PORT_ACTION_BAIL)
+                               ? "; terminating." : "ignoring.");
+
+               if (pr->access == PORT_ACTION_BAIL)
+                       kill(getpid(), SIGSEGV);
+       }
+}
+
 int
 port_rep_inb(xf86Int10InfoPtr pInt,
             CARD16 port, CARD32 base, int d_f, CARD32 count)
@@ -328,6 +396,8 @@ x_inb(CARD16 port)
        }
 #endif /* __NOT_YET__ */
     } else {
+       assert_port_access_allowed (port, sizeof(val));
+
        if (!pciCfg1inb(port, &val))
            val = inb(Int10Current->ioBase + port);
 #ifdef PRINT_PORT
@@ -352,6 +422,8 @@ x_inw(CARD16 port)
        X_GETTIMEOFDAY(&tv);
        val = (CARD16)(tv.tv_usec / 3);
     } else {
+       assert_port_access_allowed (port, sizeof(val));
+
        if (!pciCfg1inw(port, &val))
            val = inw(Int10Current->ioBase + port);
     }
@@ -390,6 +462,8 @@ x_outb(CARD16 port, CARD8 val)
 #ifdef PRINT_PORT
        ErrorF(" outb(%#x, %2.2x)\n", port, val);
 #endif
+       assert_port_access_allowed (port, sizeof(val));
+
        if (!pciCfg1outb(port, val))
            outb(Int10Current->ioBase + port, val);
     }
@@ -402,6 +476,8 @@ x_outw(CARD16 port, CARD16 val)
     ErrorF(" outw(%#x, %4.4x)\n", port, val);
 #endif

+    assert_port_access_allowed (port, sizeof(val));
+
     if (!pciCfg1outw(port, val))
        outw(Int10Current->ioBase + port, val);
 }
@@ -411,6 +487,8 @@ x_inl(CARD16 port)
 {
     CARD32 val;

+    assert_port_access_allowed (port, sizeof(val));
+
     if (!pciCfg1in(port, &val))
        val = inl(Int10Current->ioBase + port);

@@ -427,6 +505,8 @@ x_outl(CARD16 port, CARD32 val)
     ErrorF(" outl(%#x, %8.8x)\n", port, val);
 #endif

+    assert_port_access_allowed (port, sizeof(val));
+
     if (!pciCfg1out(port, val))
        outl(Int10Current->ioBase + port, val);
 }
--
1.5.3.7.1150.g149d432


-- 
Martin-Éric Racine
http://q-funk.iki.fi

Reply to: