Merge tag 'usercopy-v4.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees...
[linux-2.6-block.git] / net / sctp / socket.c
index 039fcb618c34985f5b2a337d6a0876bca24b28da..ebb8cb9eb0bd8fe7d62dffe64237b2d6b5af6689 100644 (file)
@@ -201,6 +201,22 @@ static void sctp_for_each_tx_datachunk(struct sctp_association *asoc,
                cb(chunk);
 }
 
+static void sctp_for_each_rx_skb(struct sctp_association *asoc, struct sock *sk,
+                                void (*cb)(struct sk_buff *, struct sock *))
+
+{
+       struct sk_buff *skb, *tmp;
+
+       sctp_skb_for_each(skb, &asoc->ulpq.lobby, tmp)
+               cb(skb, sk);
+
+       sctp_skb_for_each(skb, &asoc->ulpq.reasm, tmp)
+               cb(skb, sk);
+
+       sctp_skb_for_each(skb, &asoc->ulpq.reasm_uo, tmp)
+               cb(skb, sk);
+}
+
 /* Verify that this is a valid address. */
 static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
                                   int len)
@@ -968,13 +984,6 @@ int sctp_asconf_mgmt(struct sctp_sock *sp, struct sctp_sockaddr_entry *addrw)
  * This is used for tunneling the sctp_bindx() request through sctp_setsockopt()
  * from userspace.
  *
- * We don't use copy_from_user() for optimization: we first do the
- * sanity checks (buffer size -fast- and access check-healthy
- * pointer); if all of those succeed, then we can alloc the memory
- * (expensive operation) needed to copy the data to kernel. Then we do
- * the copying without checking the user space area
- * (__copy_from_user()).
- *
  * On exit there is no need to do sockfd_put(), sys_setsockopt() does
  * it.
  *
@@ -1004,25 +1013,15 @@ static int sctp_setsockopt_bindx(struct sock *sk,
        if (unlikely(addrs_size <= 0))
                return -EINVAL;
 
-       /* Check the user passed a healthy pointer.  */
-       if (unlikely(!access_ok(VERIFY_READ, addrs, addrs_size)))
-               return -EFAULT;
-
-       /* Alloc space for the address array in kernel memory.  */
-       kaddrs = kmalloc(addrs_size, GFP_USER | __GFP_NOWARN);
-       if (unlikely(!kaddrs))
-               return -ENOMEM;
-
-       if (__copy_from_user(kaddrs, addrs, addrs_size)) {
-               kfree(kaddrs);
-               return -EFAULT;
-       }
+       kaddrs = vmemdup_user(addrs, addrs_size);
+       if (unlikely(IS_ERR(kaddrs)))
+               return PTR_ERR(kaddrs);
 
        /* Walk through the addrs buffer and count the number of addresses. */
        addr_buf = kaddrs;
        while (walk_size < addrs_size) {
                if (walk_size + sizeof(sa_family_t) > addrs_size) {
-                       kfree(kaddrs);
+                       kvfree(kaddrs);
                        return -EINVAL;
                }
 
@@ -1033,7 +1032,7 @@ static int sctp_setsockopt_bindx(struct sock *sk,
                 * causes the address buffer to overflow return EINVAL.
                 */
                if (!af || (walk_size + af->sockaddr_len) > addrs_size) {
-                       kfree(kaddrs);
+                       kvfree(kaddrs);
                        return -EINVAL;
                }
                addrcnt++;
@@ -1063,7 +1062,7 @@ static int sctp_setsockopt_bindx(struct sock *sk,
        }
 
 out:
-       kfree(kaddrs);
+       kvfree(kaddrs);
 
        return err;
 }
@@ -1321,13 +1320,6 @@ out_free:
  * land and invoking either sctp_connectx(). This is used for tunneling
  * the sctp_connectx() request through sctp_setsockopt() from userspace.
  *
- * We don't use copy_from_user() for optimization: we first do the
- * sanity checks (buffer size -fast- and access check-healthy
- * pointer); if all of those succeed, then we can alloc the memory
- * (expensive operation) needed to copy the data to kernel. Then we do
- * the copying without checking the user space area
- * (__copy_from_user()).
- *
  * On exit there is no need to do sockfd_put(), sys_setsockopt() does
  * it.
  *
@@ -1343,7 +1335,6 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
                                      sctp_assoc_t *assoc_id)
 {
        struct sockaddr *kaddrs;
-       gfp_t gfp = GFP_KERNEL;
        int err = 0;
 
        pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n",
@@ -1352,24 +1343,12 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
        if (unlikely(addrs_size <= 0))
                return -EINVAL;
 
-       /* Check the user passed a healthy pointer.  */
-       if (unlikely(!access_ok(VERIFY_READ, addrs, addrs_size)))
-               return -EFAULT;
-
-       /* Alloc space for the address array in kernel memory.  */
-       if (sk->sk_socket->file)
-               gfp = GFP_USER | __GFP_NOWARN;
-       kaddrs = kmalloc(addrs_size, gfp);
-       if (unlikely(!kaddrs))
-               return -ENOMEM;
-
-       if (__copy_from_user(kaddrs, addrs, addrs_size)) {
-               err = -EFAULT;
-       } else {
-               err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id);
-       }
+       kaddrs = vmemdup_user(addrs, addrs_size);
+       if (unlikely(IS_ERR(kaddrs)))
+               return PTR_ERR(kaddrs);
 
-       kfree(kaddrs);
+       err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id);
+       kvfree(kaddrs);
 
        return err;
 }
@@ -1526,7 +1505,7 @@ static void sctp_close(struct sock *sk, long timeout)
 
        lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
        sk->sk_shutdown = SHUTDOWN_MASK;
-       sk->sk_state = SCTP_SS_CLOSING;
+       inet_sk_set_state(sk, SCTP_SS_CLOSING);
 
        ep = sctp_sk(sk)->ep;
 
@@ -1552,6 +1531,7 @@ static void sctp_close(struct sock *sk, long timeout)
 
                if (data_was_unread || !skb_queue_empty(&asoc->ulpq.lobby) ||
                    !skb_queue_empty(&asoc->ulpq.reasm) ||
+                   !skb_queue_empty(&asoc->ulpq.reasm_uo) ||
                    (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) {
                        struct sctp_chunk *chunk;
 
@@ -2006,7 +1986,20 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
                if (err < 0)
                        goto out_free;
 
-               wait_connect = true;
+               /* If stream interleave is enabled, wait_connect has to be
+                * done earlier than data enqueue, as it needs to make data
+                * or idata according to asoc->intl_enable which is set
+                * after connection is done.
+                */
+               if (sctp_sk(asoc->base.sk)->strm_interleave) {
+                       timeo = sock_sndtimeo(sk, 0);
+                       err = sctp_wait_for_connect(asoc, &timeo);
+                       if (err)
+                               goto out_unlock;
+               } else {
+                       wait_connect = true;
+               }
+
                pr_debug("%s: we associated primitively\n", __func__);
        }
 
@@ -2285,7 +2278,7 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
                        if (!event)
                                return -ENOMEM;
 
-                       sctp_ulpq_tail_event(&asoc->ulpq, event);
+                       asoc->stream.si->enqueue_event(&asoc->ulpq, event);
                }
        }
 
@@ -3184,7 +3177,7 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
                if (val == 0) {
                        val = asoc->pathmtu - sp->pf->af->net_header_len;
                        val -= sizeof(struct sctphdr) +
-                              sizeof(struct sctp_data_chunk);
+                              sctp_datachk_len(&asoc->stream);
                }
                asoc->user_frag = val;
                asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu);
@@ -3354,7 +3347,10 @@ static int sctp_setsockopt_fragment_interleave(struct sock *sk,
        if (get_user(val, (int __user *)optval))
                return -EFAULT;
 
-       sctp_sk(sk)->frag_interleave = (val == 0) ? 0 : 1;
+       sctp_sk(sk)->frag_interleave = !!val;
+
+       if (!sctp_sk(sk)->frag_interleave)
+               sctp_sk(sk)->strm_interleave = 0;
 
        return 0;
 }
@@ -4037,6 +4033,40 @@ out:
        return retval;
 }
 
+static int sctp_setsockopt_interleaving_supported(struct sock *sk,
+                                                 char __user *optval,
+                                                 unsigned int optlen)
+{
+       struct sctp_sock *sp = sctp_sk(sk);
+       struct net *net = sock_net(sk);
+       struct sctp_assoc_value params;
+       int retval = -EINVAL;
+
+       if (optlen < sizeof(params))
+               goto out;
+
+       optlen = sizeof(params);
+       if (copy_from_user(&params, optval, optlen)) {
+               retval = -EFAULT;
+               goto out;
+       }
+
+       if (params.assoc_id)
+               goto out;
+
+       if (!net->sctp.intl_enable || !sp->frag_interleave) {
+               retval = -EPERM;
+               goto out;
+       }
+
+       sp->strm_interleave = !!params.assoc_value;
+
+       retval = 0;
+
+out:
+       return retval;
+}
+
 /* API 6.2 setsockopt(), getsockopt()
  *
  * Applications use setsockopt() and getsockopt() to set or retrieve
@@ -4224,6 +4254,10 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
        case SCTP_STREAM_SCHEDULER_VALUE:
                retval = sctp_setsockopt_scheduler_value(sk, optval, optlen);
                break;
+       case SCTP_INTERLEAVING_SUPPORTED:
+               retval = sctp_setsockopt_interleaving_supported(sk, optval,
+                                                               optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;
@@ -4600,7 +4634,7 @@ static void sctp_shutdown(struct sock *sk, int how)
        if (how & SEND_SHUTDOWN && !list_empty(&ep->asocs)) {
                struct sctp_association *asoc;
 
-               sk->sk_state = SCTP_SS_CLOSING;
+               inet_sk_set_state(sk, SCTP_SS_CLOSING);
                asoc = list_entry(ep->asocs.next,
                                  struct sctp_association, asocs);
                sctp_primitive_SHUTDOWN(net, asoc, NULL);
@@ -4694,20 +4728,11 @@ int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc,
 EXPORT_SYMBOL_GPL(sctp_get_sctp_info);
 
 /* use callback to avoid exporting the core structure */
-int sctp_transport_walk_start(struct rhashtable_iter *iter)
+void sctp_transport_walk_start(struct rhashtable_iter *iter)
 {
-       int err;
-
        rhltable_walk_enter(&sctp_transport_hashtable, iter);
 
-       err = rhashtable_walk_start(iter);
-       if (err && err != -EAGAIN) {
-               rhashtable_walk_stop(iter);
-               rhashtable_walk_exit(iter);
-               return err;
-       }
-
-       return 0;
+       rhashtable_walk_start(iter);
 }
 
 void sctp_transport_walk_stop(struct rhashtable_iter *iter)
@@ -4801,9 +4826,8 @@ int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *),
        int ret;
 
 again:
-       ret = sctp_transport_walk_start(&hti);
-       if (ret)
-               return ret;
+       ret = 0;
+       sctp_transport_walk_start(&hti);
 
        tsp = sctp_transport_get_idx(net, &hti, *pos + 1);
        for (; !IS_ERR_OR_NULL(tsp); tsp = sctp_transport_get_next(net, &hti)) {
@@ -5029,7 +5053,7 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optv
        len = sizeof(int);
        if (put_user(len, optlen))
                return -EFAULT;
-       if (copy_to_user(optval, &sctp_sk(sk)->autoclose, len))
+       if (put_user(sctp_sk(sk)->autoclose, (int __user *)optval))
                return -EFAULT;
        return 0;
 }
@@ -7002,6 +7026,47 @@ out:
        return retval;
 }
 
+static int sctp_getsockopt_interleaving_supported(struct sock *sk, int len,
+                                                 char __user *optval,
+                                                 int __user *optlen)
+{
+       struct sctp_assoc_value params;
+       struct sctp_association *asoc;
+       int retval = -EFAULT;
+
+       if (len < sizeof(params)) {
+               retval = -EINVAL;
+               goto out;
+       }
+
+       len = sizeof(params);
+       if (copy_from_user(&params, optval, len))
+               goto out;
+
+       asoc = sctp_id2assoc(sk, params.assoc_id);
+       if (asoc) {
+               params.assoc_value = asoc->intl_enable;
+       } else if (!params.assoc_id) {
+               struct sctp_sock *sp = sctp_sk(sk);
+
+               params.assoc_value = sp->strm_interleave;
+       } else {
+               retval = -EINVAL;
+               goto out;
+       }
+
+       if (put_user(len, optlen))
+               goto out;
+
+       if (copy_to_user(optval, &params, len))
+               goto out;
+
+       retval = 0;
+
+out:
+       return retval;
+}
+
 static int sctp_getsockopt(struct sock *sk, int level, int optname,
                           char __user *optval, int __user *optlen)
 {
@@ -7192,6 +7257,10 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
                retval = sctp_getsockopt_scheduler_value(sk, len, optval,
                                                         optlen);
                break;
+       case SCTP_INTERLEAVING_SUPPORTED:
+               retval = sctp_getsockopt_interleaving_supported(sk, len, optval,
+                                                               optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;
@@ -7426,13 +7495,13 @@ static int sctp_listen_start(struct sock *sk, int backlog)
         * sockets.
         *
         */
-       sk->sk_state = SCTP_SS_LISTENING;
+       inet_sk_set_state(sk, SCTP_SS_LISTENING);
        if (!ep->base.bind_addr.port) {
                if (sctp_autobind(sk))
                        return -EAGAIN;
        } else {
                if (sctp_get_port(sk, inet_sk(sk)->inet_num)) {
-                       sk->sk_state = SCTP_SS_CLOSED;
+                       inet_sk_set_state(sk, SCTP_SS_CLOSED);
                        return -EADDRINUSE;
                }
        }
@@ -7518,11 +7587,11 @@ out:
  * here, again, by modeling the current TCP/UDP code.  We don't have
  * a good way to test with it yet.
  */
-unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
+__poll_t sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
 {
        struct sock *sk = sock->sk;
        struct sctp_sock *sp = sctp_sk(sk);
-       unsigned int mask;
+       __poll_t mask;
 
        poll_wait(file, sk_sleep(sk), wait);
 
@@ -8425,11 +8494,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
 
        }
 
-       sctp_skb_for_each(skb, &assoc->ulpq.reasm, tmp)
-               sctp_skb_set_owner_r_frag(skb, newsk);
-
-       sctp_skb_for_each(skb, &assoc->ulpq.lobby, tmp)
-               sctp_skb_set_owner_r_frag(skb, newsk);
+       sctp_for_each_rx_skb(assoc, newsk, sctp_skb_set_owner_r_frag);
 
        /* Set the type of socket to indicate that it is peeled off from the
         * original UDP-style socket or created with the accept() call on a
@@ -8455,10 +8520,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
         * is called, set RCV_SHUTDOWN flag.
         */
        if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP)) {
-               newsk->sk_state = SCTP_SS_CLOSED;
+               inet_sk_set_state(newsk, SCTP_SS_CLOSED);
                newsk->sk_shutdown |= RCV_SHUTDOWN;
        } else {
-               newsk->sk_state = SCTP_SS_ESTABLISHED;
+               inet_sk_set_state(newsk, SCTP_SS_ESTABLISHED);
        }
 
        release_sock(newsk);
@@ -8487,6 +8552,10 @@ struct proto sctp_prot = {
        .unhash      =  sctp_unhash,
        .get_port    =  sctp_get_port,
        .obj_size    =  sizeof(struct sctp_sock),
+       .useroffset  =  offsetof(struct sctp_sock, subscribe),
+       .usersize    =  offsetof(struct sctp_sock, initmsg) -
+                               offsetof(struct sctp_sock, subscribe) +
+                               sizeof_field(struct sctp_sock, initmsg),
        .sysctl_mem  =  sysctl_sctp_mem,
        .sysctl_rmem =  sysctl_sctp_rmem,
        .sysctl_wmem =  sysctl_sctp_wmem,
@@ -8526,6 +8595,10 @@ struct proto sctpv6_prot = {
        .unhash         = sctp_unhash,
        .get_port       = sctp_get_port,
        .obj_size       = sizeof(struct sctp6_sock),
+       .useroffset     = offsetof(struct sctp6_sock, sctp.subscribe),
+       .usersize       = offsetof(struct sctp6_sock, sctp.initmsg) -
+                               offsetof(struct sctp6_sock, sctp.subscribe) +
+                               sizeof_field(struct sctp6_sock, sctp.initmsg),
        .sysctl_mem     = sysctl_sctp_mem,
        .sysctl_rmem    = sysctl_sctp_rmem,
        .sysctl_wmem    = sysctl_sctp_wmem,