]> xenbits.xensource.com Git - qemu-xen-4.0-testing.git/commitdiff
merge from in xen-unstable tip (17318:b5fea3aeb04b): hw/ne2000: security fixes and...
authorIan Jackson <iwj@mariner.uk.xensource.com>
Wed, 7 May 2008 15:20:46 +0000 (16:20 +0100)
committerIan Jackson <Ian.Jackson@eu.citrix.com>
Mon, 12 May 2008 11:20:11 +0000 (12:20 +0100)
hw/ne2000.c

index 2ae140859dcfcaf80d6a6f8d6e50c92565a6c557..760c1e6916176914bb7b6c92849299f5efd49ebf 100644 (file)
@@ -140,6 +140,7 @@ typedef struct NE2000State {
     uint8_t curpag;
     uint8_t mult[8]; /* multicast mask array */
     qemu_irq irq;
+    int tainted;
     PCIDevice *pci_dev;
     VLANClientState *vc;
     uint8_t macaddr[6];
@@ -223,6 +224,27 @@ static int ne2000_can_receive(void *opaque)
 
 #define MIN_BUF_SIZE 60
 
+static inline int ne2000_valid_ring_addr(NE2000State *s, unsigned int addr)
+{
+    addr <<= 8;
+    return addr < s->stop && addr >= s->start;
+}
+
+static inline int ne2000_check_state(NE2000State *s)
+{
+    if (!s->tainted)
+        return 0;
+
+    if (s->start >= s->stop || s->stop > NE2000_MEM_SIZE)
+        return -EINVAL;
+
+    if (!ne2000_valid_ring_addr(s, s->curpag))
+        return -EINVAL;
+
+    s->tainted = 0;
+    return 0;
+}
+
 static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
 {
     NE2000State *s = opaque;
@@ -236,6 +258,12 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
     printf("NE2000: received len=%d\n", size);
 #endif
 
+    if (ne2000_check_state(s))
+        return;
+
+    if (!ne2000_valid_ring_addr(s, s->boundary))
+        return;
+
     if (s->cmd & E8390_STOP || ne2000_buffer_full(s))
         return;
 
@@ -296,6 +324,7 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
 
     /* write packet data */
     while (size > 0) {
+        /* taviso: this can wrap, so check its okay. */
         if (index <= s->stop)
             avail = s->stop - index;
         else
@@ -359,9 +388,11 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         switch(offset) {
         case EN0_STARTPG:
             s->start = val << 8;
+            s->tainted = 1;
             break;
         case EN0_STOPPG:
             s->stop = val << 8;
+            s->tainted = 1;
             break;
         case EN0_BOUNDARY:
             s->boundary = val;
@@ -406,6 +437,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             break;
         case EN1_CURPAG:
             s->curpag = val;
+            s->tainted = 1;
             break;
         case EN1_MULT ... EN1_MULT + 7:
             s->mult[offset - EN1_MULT] = val;
@@ -508,8 +540,8 @@ static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr,
                                      uint32_t val)
 {
     addr &= ~1; /* XXX: check exact behaviour if not even */
-    if (addr < 32 ||
-        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+    if (addr < 32 || 
+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE - 2)) {
         cpu_to_le32wu((uint32_t *)(s->mem + addr), val);
     }
 }
@@ -538,8 +570,8 @@ static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr)
 static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr)
 {
     addr &= ~1; /* XXX: check exact behaviour if not even */
-    if (addr < 32 ||
-        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+    if (addr < 32 || 
+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE - 2)) {
         return le32_to_cpupu((uint32_t *)(s->mem + addr));
     } else {
         return 0xffffffff;
@@ -752,8 +784,8 @@ void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd)
              s->macaddr[3],
              s->macaddr[4],
              s->macaddr[5]);
-
-    register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s);
+             
+    register_savevm("ne2000", base, 2, ne2000_save, ne2000_load, s);
 }
 
 /***********************************************************/