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 | |
---|
7 | As a program that runs in dom0 which serves users from guests, |
---|
8 | the qemu drivers need to be vigilant to the input that comes |
---|
9 | from the guests since they may be malicious. |
---|
10 | |
---|
11 | As it is there are multiple ways to get ne2000 to read/write |
---|
12 | memory beyond the 48K buffer that it has allocated for each |
---|
13 | adapter. |
---|
14 | |
---|
15 | This patch checks the addresses and prevents this from occuring. |
---|
16 | |
---|
17 | The boundary is checked each time since it's changed for every |
---|
18 | packet received while the other parameters are only changed |
---|
19 | (by the guest) during setup. |
---|
20 | |
---|
21 | Signed-off: Herbert Xu <herbert@gondor.apana.org.au> |
---|
22 | |
---|
23 | Index: 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; |
---|