]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/x25/af_x25.c
x25: Patch to fix bug 15678 - x25 accesses fields beyond end of packet.
[net-next-2.6.git] / net / x25 / af_x25.c
index e3219e4cd0445195ecda74030191f03a49438fde..fe26c01ef3e60c377e18268d5796d88b29988002 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/notifier.h>
 #include <linux/init.h>
 #include <linux/compat.h>
+#include <linux/ctype.h>
 
 #include <net/x25.h>
 #include <net/compat.h>
@@ -81,6 +82,41 @@ struct compat_x25_subscrip_struct {
 };
 #endif
 
+
+int x25_parse_address_block(struct sk_buff *skb,
+               struct x25_address *called_addr,
+               struct x25_address *calling_addr)
+{
+       unsigned char len;
+       int needed;
+       int rc;
+
+       if (skb->len < 1) {
+               /* packet has no address block */
+               rc = 0;
+               goto empty;
+       }
+
+       len = *skb->data;
+       needed = 1 + (len >> 4) + (len & 0x0f);
+
+       if (skb->len < needed) {
+               /* packet is too short to hold the addresses it claims
+                  to hold */
+               rc = -1;
+               goto empty;
+       }
+
+       return x25_addr_ntoa(skb->data, called_addr, calling_addr);
+
+empty:
+       *called_addr->x25_addr = 0;
+       *calling_addr->x25_addr = 0;
+
+       return rc;
+}
+
+
 int x25_addr_ntoa(unsigned char *p, struct x25_address *called_addr,
                  struct x25_address *calling_addr)
 {
@@ -512,15 +548,20 @@ static int x25_create(struct net *net, struct socket *sock, int protocol,
 {
        struct sock *sk;
        struct x25_sock *x25;
-       int rc = -ESOCKTNOSUPPORT;
+       int rc = -EAFNOSUPPORT;
 
        if (!net_eq(net, &init_net))
-               return -EAFNOSUPPORT;
+               goto out;
 
-       if (sock->type != SOCK_SEQPACKET || protocol)
+       rc = -ESOCKTNOSUPPORT;
+       if (sock->type != SOCK_SEQPACKET)
                goto out;
 
-       rc = -ENOMEM;
+       rc = -EINVAL;
+       if (protocol)
+               goto out;
+
+       rc = -ENOBUFS;
        if ((sk = x25_alloc_socket(net)) == NULL)
                goto out;
 
@@ -643,7 +684,7 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
        struct sock *sk = sock->sk;
        struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
-       int rc = 0;
+       int len, i, rc = 0;
 
        lock_kernel();
        if (!sock_flag(sk, SOCK_ZAPPED) ||
@@ -653,6 +694,14 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                goto out;
        }
 
+       len = strlen(addr->sx25_addr.x25_addr);
+       for (i = 0; i < len; i++) {
+               if (!isdigit(addr->sx25_addr.x25_addr[i])) {
+                       rc = -EINVAL;
+                       goto out;
+               }
+       }
+
        x25_sk(sk)->source_addr = addr->sx25_addr;
        x25_insert_socket(sk);
        sock_reset_flag(sk, SOCK_ZAPPED);
@@ -907,16 +956,26 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
        /*
         *      Extract the X.25 addresses and convert them to ASCII strings,
         *      and remove them.
+        *
+        *      Address block is mandatory in call request packets
         */
-       addr_len = x25_addr_ntoa(skb->data, &source_addr, &dest_addr);
+       addr_len = x25_parse_address_block(skb, &source_addr, &dest_addr);
+       if (addr_len <= 0)
+               goto out_clear_request;
        skb_pull(skb, addr_len);
 
        /*
         *      Get the length of the facilities, skip past them for the moment
         *      get the call user data because this is needed to determine
         *      the correct listener
+        *
+        *      Facilities length is mandatory in call request packets
         */
+       if (skb->len < 1)
+               goto out_clear_request;
        len = skb->data[0] + 1;
+       if (skb->len < len)
+               goto out_clear_request;
        skb_pull(skb,len);
 
        /*