rose: Add length checks to CALL_REQUEST parsing, CVE-2011-1493
[linux-flexiantxendom0-natty.git] / net / rose / af_rose.c
index 92d85c3..9eb767f 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/in.h>
+#include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
@@ -63,7 +64,7 @@ int sysctl_rose_window_size             = ROSE_DEFAULT_WINDOW_SIZE;
 static HLIST_HEAD(rose_list);
 static DEFINE_SPINLOCK(rose_list_lock);
 
-static struct proto_ops rose_proto_ops;
+static const struct proto_ops rose_proto_ops;
 
 ax25_address rose_callsign;
 
@@ -74,27 +75,39 @@ ax25_address rose_callsign;
  * separate class since they always nest.
  */
 static struct lock_class_key rose_netdev_xmit_lock_key;
+static struct lock_class_key rose_netdev_addr_lock_key;
+
+static void rose_set_lockdep_one(struct net_device *dev,
+                                struct netdev_queue *txq,
+                                void *_unused)
+{
+       lockdep_set_class(&txq->_xmit_lock, &rose_netdev_xmit_lock_key);
+}
+
+static void rose_set_lockdep_key(struct net_device *dev)
+{
+       lockdep_set_class(&dev->addr_list_lock, &rose_netdev_addr_lock_key);
+       netdev_for_each_tx_queue(dev, rose_set_lockdep_one, NULL);
+}
 
 /*
  *     Convert a ROSE address into text.
  */
-const char *rose2asc(const rose_address *addr)
+char *rose2asc(char *buf, const rose_address *addr)
 {
-       static char buffer[11];
-
        if (addr->rose_addr[0] == 0x00 && addr->rose_addr[1] == 0x00 &&
            addr->rose_addr[2] == 0x00 && addr->rose_addr[3] == 0x00 &&
            addr->rose_addr[4] == 0x00) {
-               strcpy(buffer, "*");
+               strcpy(buf, "*");
        } else {
-               sprintf(buffer, "%02X%02X%02X%02X%02X", addr->rose_addr[0] & 0xFF,
+               sprintf(buf, "%02X%02X%02X%02X%02X", addr->rose_addr[0] & 0xFF,
                                                addr->rose_addr[1] & 0xFF,
                                                addr->rose_addr[2] & 0xFF,
                                                addr->rose_addr[3] & 0xFF,
                                                addr->rose_addr[4] & 0xFF);
        }
 
-       return buffer;
+       return buf;
 }
 
 /*
@@ -197,7 +210,7 @@ static int rose_device_event(struct notifier_block *this, unsigned long event,
 {
        struct net_device *dev = (struct net_device *)ptr;
 
-       if (dev_net(dev) != &init_net)
+       if (!net_eq(dev_net(dev), &init_net))
                return NOTIFY_DONE;
 
        if (event != NETDEV_DOWN)
@@ -342,8 +355,7 @@ void rose_destroy_socket(struct sock *sk)
                kfree_skb(skb);
        }
 
-       if (atomic_read(&sk->sk_wmem_alloc) ||
-           atomic_read(&sk->sk_rmem_alloc)) {
+       if (sk_has_allocations(sk)) {
                /* Defer: outstanding buffers */
                setup_timer(&sk->sk_timer, rose_destroy_timer,
                                (unsigned long)sk);
@@ -359,7 +371,7 @@ void rose_destroy_socket(struct sock *sk)
  */
 
 static int rose_setsockopt(struct socket *sock, int level, int optname,
-       char __user *optval, int optlen)
+       char __user *optval, unsigned int optlen)
 {
        struct sock *sk = sock->sk;
        struct rose_sock *rose = rose_sk(sk);
@@ -501,12 +513,13 @@ static struct proto rose_proto = {
        .obj_size = sizeof(struct rose_sock),
 };
 
-static int rose_create(struct net *net, struct socket *sock, int protocol)
+static int rose_create(struct net *net, struct socket *sock, int protocol,
+                      int kern)
 {
        struct sock *sk;
        struct rose_sock *rose;
 
-       if (net != &init_net)
+       if (!net_eq(net, &init_net))
                return -EAFNOSUPPORT;
 
        if (sock->type != SOCK_SEQPACKET || protocol != 0)
@@ -566,13 +579,11 @@ static struct sock *rose_make_new(struct sock *osk)
 #endif
 
        sk->sk_type     = osk->sk_type;
-       sk->sk_socket   = osk->sk_socket;
        sk->sk_priority = osk->sk_priority;
        sk->sk_protocol = osk->sk_protocol;
        sk->sk_rcvbuf   = osk->sk_rcvbuf;
        sk->sk_sndbuf   = osk->sk_sndbuf;
        sk->sk_state    = TCP_ESTABLISHED;
-       sk->sk_sleep    = osk->sk_sleep;
        sock_copy_flags(sk, osk);
 
        init_timer(&rose->timer);
@@ -598,17 +609,24 @@ static int rose_release(struct socket *sock)
 
        if (sk == NULL) return 0;
 
+       sock_hold(sk);
+       sock_orphan(sk);
+       lock_sock(sk);
        rose = rose_sk(sk);
 
        switch (rose->state) {
        case ROSE_STATE_0:
+               release_sock(sk);
                rose_disconnect(sk, 0, -1, -1);
+               lock_sock(sk);
                rose_destroy_socket(sk);
                break;
 
        case ROSE_STATE_2:
                rose->neighbour->use--;
+               release_sock(sk);
                rose_disconnect(sk, 0, -1, -1);
+               lock_sock(sk);
                rose_destroy_socket(sk);
                break;
 
@@ -633,6 +651,8 @@ static int rose_release(struct socket *sock)
        }
 
        sock->sk = NULL;
+       release_sock(sk);
+       sock_put(sk);
 
        return 0;
 }
@@ -659,7 +679,7 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1)
                return -EINVAL;
 
-       if (addr->srose_ndigis > ROSE_MAX_DIGIS)
+       if ((unsigned int) addr->srose_ndigis > ROSE_MAX_DIGIS)
                return -EINVAL;
 
        if ((dev = rose_dev_get(&addr->srose_addr)) == NULL) {
@@ -669,7 +689,7 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 
        source = &addr->srose_call;
 
-       user = ax25_findbyuid(current->euid);
+       user = ax25_findbyuid(current_euid());
        if (user) {
                rose->source_call = user->call;
                ax25_uid_put(user);
@@ -719,7 +739,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
        if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1)
                return -EINVAL;
 
-       if (addr->srose_ndigis > ROSE_MAX_DIGIS)
+       if ((unsigned int) addr->srose_ndigis > ROSE_MAX_DIGIS)
                return -EINVAL;
 
        /* Source + Destination digis should not exceed ROSE_MAX_DIGIS */
@@ -750,9 +770,11 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
        sock->state = SS_UNCONNECTED;
 
        rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause,
-                                        &diagnostic);
-       if (!rose->neighbour)
-               return -ENETUNREACH;
+                                        &diagnostic, 0);
+       if (!rose->neighbour) {
+               err = -ENETUNREACH;
+               goto out_release;
+       }
 
        rose->lci = rose_new_lci(rose->neighbour);
        if (!rose->lci) {
@@ -768,7 +790,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
                        goto out_release;
                }
 
-               user = ax25_findbyuid(current->euid);
+               user = ax25_findbyuid(current_euid());
                if (!user) {
                        err = -EINVAL;
                        goto out_release;
@@ -823,7 +845,7 @@ rose_try_next_neigh:
                DEFINE_WAIT(wait);
 
                for (;;) {
-                       prepare_to_wait(sk->sk_sleep, &wait,
+                       prepare_to_wait(sk_sleep(sk), &wait,
                                        TASK_INTERRUPTIBLE);
                        if (sk->sk_state != TCP_SYN_SENT)
                                break;
@@ -836,7 +858,7 @@ rose_try_next_neigh:
                        err = -ERESTARTSYS;
                        break;
                }
-               finish_wait(sk->sk_sleep, &wait);
+               finish_wait(sk_sleep(sk), &wait);
 
                if (err)
                        goto out_release;
@@ -844,7 +866,7 @@ rose_try_next_neigh:
 
        if (sk->sk_state != TCP_ESTABLISHED) {
        /* Try next neighbour */
-               rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic);
+               rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic, 0);
                if (rose->neighbour)
                        goto rose_try_next_neigh;
 
@@ -889,7 +911,7 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
         *      hooked into the SABM we saved
         */
        for (;;) {
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
 
                skb = skb_dequeue(&sk->sk_receive_queue);
                if (skb)
@@ -908,19 +930,17 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
                err = -ERESTARTSYS;
                break;
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        if (err)
                goto out_release;
 
        newsk = skb->sk;
-       newsk->sk_socket = newsock;
-       newsk->sk_sleep = &newsock->wait;
+       sock_graft(newsk, newsock);
 
        /* Now attach up the new socket */
        skb->sk = NULL;
        kfree_skb(skb);
        sk->sk_ack_backlog--;
-       newsock->sk = newsk;
 
 out_release:
        release_sock(sk);
@@ -936,6 +956,7 @@ static int rose_getname(struct socket *sock, struct sockaddr *uaddr,
        struct rose_sock *rose = rose_sk(sk);
        int n;
 
+       memset(srose, 0, sizeof(*srose));
        if (peer != 0) {
                if (sk->sk_state != TCP_ESTABLISHED)
                        return -ENOTCONN;
@@ -964,7 +985,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros
        struct sock *make;
        struct rose_sock *make_rose;
        struct rose_facilities_struct facilities;
-       int n, len;
+       int n;
 
        skb->sk = NULL;         /* Initially we don't know who it's for */
 
@@ -973,9 +994,9 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros
         */
        memset(&facilities, 0x00, sizeof(struct rose_facilities_struct));
 
-       len  = (((skb->data[3] >> 4) & 0x0F) + 1) >> 1;
-       len += (((skb->data[3] >> 0) & 0x0F) + 1) >> 1;
-       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(neigh, lci, ROSE_INVALID_FACILITY, 76);
                return 0;
        }
@@ -1099,6 +1120,10 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock,
 
        /* Build a packet */
        SOCK_DEBUG(sk, "ROSE: sendto: building packet.\n");
+       /* Sanity check the packet size */
+       if (len > 65535)
+               return -EMSGSIZE;
+
        size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN;
 
        if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
@@ -1285,7 +1310,8 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
        switch (cmd) {
        case TIOCOUTQ: {
                long amount;
-               amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+
+               amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
                if (amount < 0)
                        amount = 0;
                return put_user(amount, (unsigned int __user *) argp);
@@ -1379,29 +1405,13 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 static void *rose_info_start(struct seq_file *seq, loff_t *pos)
        __acquires(rose_list_lock)
 {
-       int i;
-       struct sock *s;
-       struct hlist_node *node;
-
        spin_lock_bh(&rose_list_lock);
-       if (*pos == 0)
-               return SEQ_START_TOKEN;
-
-       i = 1;
-       sk_for_each(s, node, &rose_list) {
-               if (i == *pos)
-                       return s;
-               ++i;
-       }
-       return NULL;
+       return seq_hlist_start_head(&rose_list, *pos);
 }
 
 static void *rose_info_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-       ++*pos;
-
-       return (v == SEQ_START_TOKEN) ? sk_head(&rose_list)
-               : sk_next((struct sock *)v);
+       return seq_hlist_next(v, &rose_list, pos);
 }
 
 static void rose_info_stop(struct seq_file *seq, void *v)
@@ -1412,14 +1422,14 @@ static void rose_info_stop(struct seq_file *seq, void *v)
 
 static int rose_info_show(struct seq_file *seq, void *v)
 {
-       char buf[11];
+       char buf[11], rsbuf[11];
 
        if (v == SEQ_START_TOKEN)
                seq_puts(seq,
                         "dest_addr  dest_call src_addr   src_call  dev   lci neigh st vs vr va   t  t1  t2  t3  hb    idle Snd-Q Rcv-Q inode\n");
 
        else {
-               struct sock *s = v;
+               struct sock *s = sk_entry(v);
                struct rose_sock *rose = rose_sk(s);
                const char *devname, *callsign;
                const struct net_device *dev = rose->device;
@@ -1430,8 +1440,8 @@ static int rose_info_show(struct seq_file *seq, void *v)
                        devname = dev->name;
 
                seq_printf(seq, "%-10s %-9s ",
-                       rose2asc(&rose->dest_addr),
-                       ax2asc(buf, &rose->dest_call));
+                          rose2asc(rsbuf, &rose->dest_addr),
+                          ax2asc(buf, &rose->dest_call));
 
                if (ax25cmp(&rose->source_call, &null_ax25_address) == 0)
                        callsign = "??????-?";
@@ -1440,7 +1450,7 @@ static int rose_info_show(struct seq_file *seq, void *v)
 
                seq_printf(seq,
                           "%-10s %-9s %-5s %3.3X %05d  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n",
-                       rose2asc(&rose->source_addr),
+                       rose2asc(rsbuf, &rose->source_addr),
                        callsign,
                        devname,
                        rose->lci & 0x0FFF,
@@ -1456,8 +1466,8 @@ static int rose_info_show(struct seq_file *seq, void *v)
                        rose->hb / HZ,
                        ax25_display_timer(&rose->idletimer) / (60 * HZ),
                        rose->idle / (60 * HZ),
-                       atomic_read(&s->sk_wmem_alloc),
-                       atomic_read(&s->sk_rmem_alloc),
+                       sk_wmem_alloc_get(s),
+                       sk_rmem_alloc_get(s),
                        s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L);
        }
 
@@ -1485,13 +1495,13 @@ static const struct file_operations rose_info_fops = {
 };
 #endif /* CONFIG_PROC_FS */
 
-static struct net_proto_family rose_family_ops = {
+static const struct net_proto_family rose_family_ops = {
        .family         =       PF_ROSE,
        .create         =       rose_create,
        .owner          =       THIS_MODULE,
 };
 
-static struct proto_ops rose_proto_ops = {
+static const struct proto_ops rose_proto_ops = {
        .family         =       PF_ROSE,
        .owner          =       THIS_MODULE,
        .release        =       rose_release,
@@ -1556,8 +1566,7 @@ static int __init rose_proto_init(void)
                char name[IFNAMSIZ];
 
                sprintf(name, "rose%d", i);
-               dev = alloc_netdev(sizeof(struct net_device_stats),
-                                  name, rose_setup);
+               dev = alloc_netdev(0, name, rose_setup);
                if (!dev) {
                        printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate memory\n");
                        rc = -ENOMEM;
@@ -1569,7 +1578,7 @@ static int __init rose_proto_init(void)
                        free_netdev(dev);
                        goto fail;
                }
-               lockdep_set_class(&dev->_xmit_lock, &rose_netdev_xmit_lock_key);
+               rose_set_lockdep_key(dev);
                dev_rose[i] = dev;
        }