[34] | 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; |
---|