lkml.org 
[lkml]   [2011]   [May]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[110/143] econet: fix CVE-2010-3848
    2.6.32-longterm review patch.  If anyone has any objections, please let us know.

    ------------------

    From: Phil Blundell <philb@gnu.org>

    commit a27e13d370415add3487949c60810e36069a23a6 upstream.

    Don't declare variable sized array of iovecs on the stack since this
    could cause stack overflow if msg->msgiovlen is large. Instead, coalesce
    the user-supplied data into a new buffer and use a single iovec for it.

    Signed-off-by: Phil Blundell <philb@gnu.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    [Adjusted to apply to 2.6.32 by dann frazier <dannf@debian.org>]
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
    ---
    net/econet/af_econet.c | 62 ++++++++++++++++++++++++-------------------------
    1 file changed, 31 insertions(+), 31 deletions(-)

    --- a/net/econet/af_econet.c
    +++ b/net/econet/af_econet.c
    @@ -30,6 +30,7 @@
    #include <linux/wireless.h>
    #include <linux/skbuff.h>
    #include <linux/udp.h>
    +#include <linux/vmalloc.h>
    #include <net/sock.h>
    #include <net/inet_common.h>
    #include <linux/stat.h>
    @@ -275,12 +276,12 @@ static int econet_sendmsg(struct kiocb *
    #endif
    #ifdef CONFIG_ECONET_AUNUDP
    struct msghdr udpmsg;
    - struct iovec iov[msg->msg_iovlen+1];
    + struct iovec iov[2];
    struct aunhdr ah;
    struct sockaddr_in udpdest;
    __kernel_size_t size;
    - int i;
    mm_segment_t oldfs;
    + char *userbuf;
    #endif

    /*
    @@ -318,17 +319,17 @@ static int econet_sendmsg(struct kiocb *
    }
    }

    - if (len + 15 > dev->mtu) {
    - mutex_unlock(&econet_mutex);
    - return -EMSGSIZE;
    - }
    -
    if (dev->type == ARPHRD_ECONET) {
    /* Real hardware Econet. We're not worthy etc. */
    #ifdef CONFIG_ECONET_NATIVE
    unsigned short proto = 0;
    int res;

    + if (len + 15 > dev->mtu) {
    + mutex_unlock(&econet_mutex);
    + return -EMSGSIZE;
    + }
    +
    dev_hold(dev);

    skb = sock_alloc_send_skb(sk, len+LL_ALLOCATED_SPACE(dev),
    @@ -404,6 +405,11 @@ static int econet_sendmsg(struct kiocb *
    return -ENETDOWN; /* No socket - can't send */
    }

    + if (len > 32768) {
    + err = -E2BIG;
    + goto error;
    + }
    +
    /* Make up a UDP datagram and hand it off to some higher intellect. */

    memset(&udpdest, 0, sizeof(udpdest));
    @@ -435,36 +441,26 @@ static int econet_sendmsg(struct kiocb *

    /* tack our header on the front of the iovec */
    size = sizeof(struct aunhdr);
    - /*
    - * XXX: that is b0rken. We can't mix userland and kernel pointers
    - * in iovec, since on a lot of platforms copy_from_user() will
    - * *not* work with the kernel and userland ones at the same time,
    - * regardless of what we do with set_fs(). And we are talking about
    - * econet-over-ethernet here, so "it's only ARM anyway" doesn't
    - * apply. Any suggestions on fixing that code? -- AV
    - */
    iov[0].iov_base = (void *)&ah;
    iov[0].iov_len = size;
    - for (i = 0; i < msg->msg_iovlen; i++) {
    - void __user *base = msg->msg_iov[i].iov_base;
    - size_t iov_len = msg->msg_iov[i].iov_len;
    - /* Check it now since we switch to KERNEL_DS later. */
    - if (!access_ok(VERIFY_READ, base, iov_len)) {
    - mutex_unlock(&econet_mutex);
    - return -EFAULT;
    - }
    - iov[i+1].iov_base = base;
    - iov[i+1].iov_len = iov_len;
    - size += iov_len;
    +
    + userbuf = vmalloc(len);
    + if (userbuf == NULL) {
    + err = -ENOMEM;
    + goto error;
    }

    + iov[1].iov_base = userbuf;
    + iov[1].iov_len = len;
    + err = memcpy_fromiovec(userbuf, msg->msg_iov, len);
    + if (err)
    + goto error_free_buf;
    +
    /* Get a skbuff (no data, just holds our cb information) */
    if ((skb = sock_alloc_send_skb(sk, 0,
    msg->msg_flags & MSG_DONTWAIT,
    - &err)) == NULL) {
    - mutex_unlock(&econet_mutex);
    - return err;
    - }
    + &err)) == NULL)
    + goto error_free_buf;

    eb = (struct ec_cb *)&skb->cb;

    @@ -480,7 +476,7 @@ static int econet_sendmsg(struct kiocb *
    udpmsg.msg_name = (void *)&udpdest;
    udpmsg.msg_namelen = sizeof(udpdest);
    udpmsg.msg_iov = &iov[0];
    - udpmsg.msg_iovlen = msg->msg_iovlen + 1;
    + udpmsg.msg_iovlen = 2;
    udpmsg.msg_control = NULL;
    udpmsg.msg_controllen = 0;
    udpmsg.msg_flags=0;
    @@ -488,9 +484,13 @@ static int econet_sendmsg(struct kiocb *
    oldfs = get_fs(); set_fs(KERNEL_DS); /* More privs :-) */
    err = sock_sendmsg(udpsock, &udpmsg, size);
    set_fs(oldfs);
    +
    +error_free_buf:
    + vfree(userbuf);
    #else
    err = -EPROTOTYPE;
    #endif
    + error:
    mutex_unlock(&econet_mutex);

    return err;



    \
     
     \ /
      Last update: 2011-05-06 02:45    [W:0.025 / U:92.584 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site