From da16cb67f9ecd004ae4d3e5fbae6d65eecf12dd7 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Tue, 19 Feb 2008 20:44:40 -0500 Subject: [PATCH] X86EMU: added blacklist for I/O port in 0-0xFF range 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, as it had occurred on all Geode systems with the General Software VGA BIOS. If such an access is detected, we terminate X "gracefully" by sending a SIGSEGV signal which is picked up by xf86SigHandler(), it then dumps the backtrace and exits gracefully. Note that exiting here avoids a system corruption or freeze. This patch was based on help from Alan Cox. Thanks to Symbio Technologies for funding my work, and ThinCan for providing hardware :) Signed-off-by: Bart Trojanowski --- 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 e833426..e8bdd53 100644 --- a/hw/xfree86/int10/helper_exec.c +++ b/hw/xfree86/int10/helper_exec.c @@ -21,6 +21,8 @@ #define PRINT_PORT 0 #include +#include +#include #include #include "xf86.h" @@ -211,6 +213,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) @@ -329,6 +397,8 @@ x_inb(CARD16 port) } #endif /* __NOT_YET__ */ } else if (!pciCfg1inb(port, &val)) { + assert_port_access_allowed (port, sizeof(val)); + val = inb(Int10Current->ioBase + port); if (PRINT_PORT && DEBUG_IO_TRACE()) ErrorF(" inb(%#x) = %2.2x\n", port, val); @@ -351,6 +421,8 @@ x_inw(CARD16 port) X_GETTIMEOFDAY(&tv); val = (CARD16)(tv.tv_usec / 3); } else if (!pciCfg1inw(port, &val)) { + assert_port_access_allowed (port, sizeof(val)); + val = inw(Int10Current->ioBase + port); if (PRINT_PORT && DEBUG_IO_TRACE()) ErrorF(" inw(%#x) = %4.4x\n", port, val); @@ -383,6 +455,8 @@ x_outb(CARD16 port, CARD8 val) } #endif /* __NOT_YET__ */ } else if (!pciCfg1outb(port, val)) { + assert_port_access_allowed (port, sizeof(val)); + if (PRINT_PORT && DEBUG_IO_TRACE()) ErrorF(" outb(%#x, %2.2x)\n", port, val); outb(Int10Current->ioBase + port, val); @@ -394,6 +468,8 @@ x_outw(CARD16 port, CARD16 val) { if (!pciCfg1outw(port, val)) { + assert_port_access_allowed (port, sizeof(val)); + if (PRINT_PORT && DEBUG_IO_TRACE()) ErrorF(" outw(%#x, %4.4x)\n", port, val); outw(Int10Current->ioBase + port, val); @@ -406,6 +482,8 @@ x_inl(CARD16 port) CARD32 val; if (!pciCfg1in(port, &val)) { + assert_port_access_allowed (port, sizeof(val)); + val = inl(Int10Current->ioBase + port); if (PRINT_PORT && DEBUG_IO_TRACE()) ErrorF(" inl(%#x) = %8.8x\n", port, val); @@ -417,6 +495,8 @@ void x_outl(CARD16 port, CARD32 val) { if (!pciCfg1out(port, val)) { + assert_port_access_allowed (port, sizeof(val)); + if (PRINT_PORT && DEBUG_IO_TRACE()) ErrorF(" outl(%#x, %8.8x)\n", port, val); outl(Int10Current->ioBase + port, val); -- 1.5.3.7.1150.g149d432