rose: Add length checks to CALL_REQUEST parsing, CVE-2011-1493
[linux-flexiantxendom0-natty.git] / net / rose / rose_route.c
index b4fdaac..f8beb5f 100644 (file)
@@ -857,7 +857,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        unsigned int lci, new_lci;
        unsigned char cause, diagnostic;
        struct net_device *dev;
-       int len, res = 0;
+       int res = 0;
        char buf[11];
 
 #if 0
@@ -865,10 +865,17 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
                return res;
 #endif
 
+       if (skb->len < ROSE_MIN_LEN)
+               return res;
        frametype = skb->data[2];
        lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
-       src_addr  = (rose_address *)(skb->data + 9);
-       dest_addr = (rose_address *)(skb->data + 4);
+       if (frametype == ROSE_CALL_REQUEST &&
+           (skb->len <= ROSE_CALL_REQ_FACILITIES_OFF ||
+            skb->data[ROSE_CALL_REQ_ADDR_LEN_OFF] !=
+            ROSE_CALL_REQ_ADDR_LEN_VAL))
+               return res;
+       src_addr  = (rose_address *)(skb->data + ROSE_CALL_REQ_SRC_ADDR_OFF);
+       dest_addr = (rose_address *)(skb->data + ROSE_CALL_REQ_DEST_ADDR_OFF);
 
        spin_lock_bh(&rose_neigh_list_lock);
        spin_lock_bh(&rose_route_list_lock);
@@ -1006,12 +1013,11 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
                goto out;
        }
 
-       len  = (((skb->data[3] >> 4) & 0x0F) + 1) >> 1;
-       len += (((skb->data[3] >> 0) & 0x0F) + 1) >> 1;
-
        memset(&facilities, 0x00, sizeof(struct rose_facilities_struct));
 
-       if (!rose_parse_facilities(skb->data + len + 4, &facilities)) {
+       if (!rose_parse_facilities(skb->data + ROSE_CALL_REQ_FACILITIES_OFF,
+                                  skb->len - ROSE_CALL_REQ_FACILITIES_OFF,
+                                  &facilities)) {
                rose_transmit_clear_request(rose_neigh, lci, ROSE_INVALID_FACILITY, 76);
                goto out;
        }