net: heap overflow in __audit_sockaddr()
authorDan Carpenter <dan.carpenter@oracle.com>
Wed, 2 Oct 2013 21:27:20 +0000 (00:27 +0300)
committerDavid S. Miller <davem@davemloft.net>
Thu, 3 Oct 2013 20:05:14 +0000 (16:05 -0400)
We need to cap ->msg_namelen or it leads to a buffer overflow when we
to the memcpy() in __audit_sockaddr().  It requires CAP_AUDIT_CONTROL to
exploit this bug.

The call tree is:
___sys_recvmsg()
  move_addr_to_user()
    audit_sockaddr()
      __audit_sockaddr()

Reported-by: Jüri Aedla <juri.aedla@gmail.com>
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/compat.c
net/socket.c

index f0a1ba6..8903258 100644 (file)
@@ -71,6 +71,8 @@ int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg)
            __get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
            __get_user(kmsg->msg_flags, &umsg->msg_flags))
                return -EFAULT;
+       if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
+               return -EINVAL;
        kmsg->msg_name = compat_ptr(tmp1);
        kmsg->msg_iov = compat_ptr(tmp2);
        kmsg->msg_control = compat_ptr(tmp3);
index ebed4b6..c226ace 100644 (file)
@@ -1964,6 +1964,16 @@ struct used_address {
        unsigned int name_len;
 };
 
+static int copy_msghdr_from_user(struct msghdr *kmsg,
+                                struct msghdr __user *umsg)
+{
+       if (copy_from_user(kmsg, umsg, sizeof(struct msghdr)))
+               return -EFAULT;
+       if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
+               return -EINVAL;
+       return 0;
+}
+
 static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
                         struct msghdr *msg_sys, unsigned int flags,
                         struct used_address *used_address)
@@ -1982,8 +1992,11 @@ static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
        if (MSG_CMSG_COMPAT & flags) {
                if (get_compat_msghdr(msg_sys, msg_compat))
                        return -EFAULT;
-       } else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
-               return -EFAULT;
+       } else {
+               err = copy_msghdr_from_user(msg_sys, msg);
+               if (err)
+                       return err;
+       }
 
        if (msg_sys->msg_iovlen > UIO_FASTIOV) {
                err = -EMSGSIZE;
@@ -2191,8 +2204,11 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
        if (MSG_CMSG_COMPAT & flags) {
                if (get_compat_msghdr(msg_sys, msg_compat))
                        return -EFAULT;
-       } else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
-               return -EFAULT;
+       } else {
+               err = copy_msghdr_from_user(msg_sys, msg);
+               if (err)
+                       return err;
+       }
 
        if (msg_sys->msg_iovlen > UIO_FASTIOV) {
                err = -EMSGSIZE;