source: trunk/packages/xen-3.1/xen-3.1/tools/ioemu/patches/ne2000-bounds-checks @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 3.2 KB
Line 
1# HG changeset patch
2# User kaf24@localhost.localdomain
3# Node ID 66fe61db9e69e03e12d0c4086683bebfb4a67780
4# Parent  1940ee13f9d6ab1be2c614a0fbf7769536a056d2
5[QEMU] ne2000: Stop memory access beyond buffer
6
7As a program that runs in dom0 which serves users from guests,
8the qemu drivers need to be vigilant to the input that comes
9from the guests since they may be malicious.
10
11As it is there are multiple ways to get ne2000 to read/write
12memory beyond the 48K buffer that it has allocated for each
13adapter.
14
15This patch checks the addresses and prevents this from occuring.
16
17The boundary is checked each time since it's changed for every
18packet received while the other parameters are only changed
19(by the guest) during setup.
20
21Signed-off: Herbert Xu <herbert@gondor.apana.org.au>
22
23Index: ioemu/hw/ne2000.c
24===================================================================
25--- ioemu.orig/hw/ne2000.c      2006-12-08 18:20:45.000000000 +0000
26+++ ioemu/hw/ne2000.c   2006-12-08 18:20:53.000000000 +0000
27@@ -137,6 +137,7 @@
28     uint8_t curpag;
29     uint8_t mult[8]; /* multicast mask array */
30     int irq;
31+    int tainted;
32     PCIDevice *pci_dev;
33     VLANClientState *vc;
34     uint8_t macaddr[6];
35@@ -226,6 +227,27 @@
36 
37 #define MIN_BUF_SIZE 60
38 
39+static inline int ne2000_valid_ring_addr(NE2000State *s, unsigned int addr)
40+{
41+    addr <<= 8;
42+    return addr < s->stop && addr >= s->start;
43+}
44+
45+static inline int ne2000_check_state(NE2000State *s)
46+{
47+    if (!s->tainted)
48+        return 0;
49+
50+    if (s->start >= s->stop || s->stop > NE2000_MEM_SIZE)
51+        return -EINVAL;
52+
53+    if (!ne2000_valid_ring_addr(s, s->curpag))
54+        return -EINVAL;
55+
56+    s->tainted = 0;
57+    return 0;
58+}
59+
60 static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
61 {
62     NE2000State *s = opaque;
63@@ -239,6 +261,12 @@
64     printf("NE2000: received len=%d\n", size);
65 #endif
66 
67+    if (ne2000_check_state(s))
68+        return;
69+
70+    if (!ne2000_valid_ring_addr(s, s->boundary))
71+        return;
72+
73     if (s->cmd & E8390_STOP || ne2000_buffer_full(s))
74         return;
75     
76@@ -359,9 +387,11 @@
77         switch(offset) {
78         case EN0_STARTPG:
79             s->start = val << 8;
80+            s->tainted = 1;
81             break;
82         case EN0_STOPPG:
83             s->stop = val << 8;
84+            s->tainted = 1;
85             break;
86         case EN0_BOUNDARY:
87             s->boundary = val;
88@@ -406,6 +436,7 @@
89             break;
90         case EN1_CURPAG:
91             s->curpag = val;
92+            s->tainted = 1;
93             break;
94         case EN1_MULT ... EN1_MULT + 7:
95             s->mult[offset - EN1_MULT] = val;
96@@ -509,7 +540,7 @@
97 {
98     addr &= ~1; /* XXX: check exact behaviour if not even */
99     if (addr < 32 ||
100-        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
101+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE - 2)) {
102         cpu_to_le32wu((uint32_t *)(s->mem + addr), val);
103     }
104 }
105@@ -539,7 +570,7 @@
106 {
107     addr &= ~1; /* XXX: check exact behaviour if not even */
108     if (addr < 32 ||
109-        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
110+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE - 2)) {
111         return le32_to_cpupu((uint32_t *)(s->mem + addr));
112     } else {
113         return 0xffffffff;
Note: See TracBrowser for help on using the repository browser.