]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - net/sctp/socket.c
netfilter: nf_flow_table_offload: Correct memcpy size for flow_overload_mangle()
[linux.git] / net / sctp / socket.c
index ffd3262b7a41eac2e3d825c3f0665066f376ea3c..0b485952a71c15f9503437e5d0b0769fb4053b2d 100644 (file)
@@ -384,7 +384,7 @@ static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
                }
        }
 
-       if (snum && snum < inet_prot_sock(net) &&
+       if (snum && inet_port_requires_bind_service(net, snum) &&
            !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE))
                return -EACCES;
 
@@ -1061,7 +1061,7 @@ static int sctp_connect_new_asoc(struct sctp_endpoint *ep,
                if (sctp_autobind(sk))
                        return -EAGAIN;
        } else {
-               if (ep->base.bind_addr.port < inet_prot_sock(net) &&
+               if (inet_port_requires_bind_service(net, ep->base.bind_addr.port) &&
                    !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE))
                        return -EACCES;
        }
@@ -3943,18 +3943,22 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
  */
 static int sctp_setsockopt_paddr_thresholds(struct sock *sk,
                                            char __user *optval,
-                                           unsigned int optlen)
+                                           unsigned int optlen, bool v2)
 {
-       struct sctp_paddrthlds val;
+       struct sctp_paddrthlds_v2 val;
        struct sctp_transport *trans;
        struct sctp_association *asoc;
+       int len;
 
-       if (optlen < sizeof(struct sctp_paddrthlds))
+       len = v2 ? sizeof(val) : sizeof(struct sctp_paddrthlds);
+       if (optlen < len)
                return -EINVAL;
-       if (copy_from_user(&val, (struct sctp_paddrthlds __user *)optval,
-                          sizeof(struct sctp_paddrthlds)))
+       if (copy_from_user(&val, optval, len))
                return -EFAULT;
 
+       if (v2 && val.spt_pathpfthld > val.spt_pathcpthld)
+               return -EINVAL;
+
        if (!sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) {
                trans = sctp_addr_id2transport(sk, &val.spt_address,
                                               val.spt_assoc_id);
@@ -3963,6 +3967,8 @@ static int sctp_setsockopt_paddr_thresholds(struct sock *sk,
 
                if (val.spt_pathmaxrxt)
                        trans->pathmaxrxt = val.spt_pathmaxrxt;
+               if (v2)
+                       trans->ps_retrans = val.spt_pathcpthld;
                trans->pf_retrans = val.spt_pathpfthld;
 
                return 0;
@@ -3978,17 +3984,23 @@ static int sctp_setsockopt_paddr_thresholds(struct sock *sk,
                                    transports) {
                        if (val.spt_pathmaxrxt)
                                trans->pathmaxrxt = val.spt_pathmaxrxt;
+                       if (v2)
+                               trans->ps_retrans = val.spt_pathcpthld;
                        trans->pf_retrans = val.spt_pathpfthld;
                }
 
                if (val.spt_pathmaxrxt)
                        asoc->pathmaxrxt = val.spt_pathmaxrxt;
+               if (v2)
+                       asoc->ps_retrans = val.spt_pathcpthld;
                asoc->pf_retrans = val.spt_pathpfthld;
        } else {
                struct sctp_sock *sp = sctp_sk(sk);
 
                if (val.spt_pathmaxrxt)
                        sp->pathmaxrxt = val.spt_pathmaxrxt;
+               if (v2)
+                       sp->ps_retrans = val.spt_pathcpthld;
                sp->pf_retrans = val.spt_pathpfthld;
        }
 
@@ -4589,6 +4601,40 @@ static int sctp_setsockopt_ecn_supported(struct sock *sk,
        return retval;
 }
 
+static int sctp_setsockopt_pf_expose(struct sock *sk,
+                                    char __user *optval,
+                                    unsigned int optlen)
+{
+       struct sctp_assoc_value params;
+       struct sctp_association *asoc;
+       int retval = -EINVAL;
+
+       if (optlen != sizeof(params))
+               goto out;
+
+       if (copy_from_user(&params, optval, optlen)) {
+               retval = -EFAULT;
+               goto out;
+       }
+
+       if (params.assoc_value > SCTP_PF_EXPOSE_MAX)
+               goto out;
+
+       asoc = sctp_id2assoc(sk, params.assoc_id);
+       if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
+           sctp_style(sk, UDP))
+               goto out;
+
+       if (asoc)
+               asoc->pf_expose = params.assoc_value;
+       else
+               sctp_sk(sk)->pf_expose = params.assoc_value;
+       retval = 0;
+
+out:
+       return retval;
+}
+
 /* API 6.2 setsockopt(), getsockopt()
  *
  * Applications use setsockopt() and getsockopt() to set or retrieve
@@ -4744,7 +4790,12 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
                retval = sctp_setsockopt_auto_asconf(sk, optval, optlen);
                break;
        case SCTP_PEER_ADDR_THLDS:
-               retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen);
+               retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen,
+                                                         false);
+               break;
+       case SCTP_PEER_ADDR_THLDS_V2:
+               retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen,
+                                                         true);
                break;
        case SCTP_RECVRCVINFO:
                retval = sctp_setsockopt_recvrcvinfo(sk, optval, optlen);
@@ -4798,6 +4849,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
        case SCTP_ECN_SUPPORTED:
                retval = sctp_setsockopt_ecn_supported(sk, optval, optlen);
                break;
+       case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE:
+               retval = sctp_setsockopt_pf_expose(sk, optval, optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;
@@ -5041,6 +5095,8 @@ static int sctp_init_sock(struct sock *sk)
        sp->hbinterval  = net->sctp.hb_interval;
        sp->pathmaxrxt  = net->sctp.max_retrans_path;
        sp->pf_retrans  = net->sctp.pf_retrans;
+       sp->ps_retrans  = net->sctp.ps_retrans;
+       sp->pf_expose   = net->sctp.pf_expose;
        sp->pathmtu     = 0; /* allow default discovery */
        sp->sackdelay   = net->sctp.sack_timeout;
        sp->sackfreq    = 2;
@@ -5521,8 +5577,16 @@ static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len,
 
        transport = sctp_addr_id2transport(sk, &pinfo.spinfo_address,
                                           pinfo.spinfo_assoc_id);
-       if (!transport)
-               return -EINVAL;
+       if (!transport) {
+               retval = -EINVAL;
+               goto out;
+       }
+
+       if (transport->state == SCTP_PF &&
+           transport->asoc->pf_expose == SCTP_PF_EXPOSE_DISABLE) {
+               retval = -EACCES;
+               goto out;
+       }
 
        pinfo.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
        pinfo.spinfo_state = transport->state;
@@ -7170,18 +7234,19 @@ static int sctp_getsockopt_assoc_ids(struct sock *sk, int len,
  * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt
  */
 static int sctp_getsockopt_paddr_thresholds(struct sock *sk,
-                                           char __user *optval,
-                                           int len,
-                                           int __user *optlen)
+                                           char __user *optval, int len,
+                                           int __user *optlen, bool v2)
 {
-       struct sctp_paddrthlds val;
+       struct sctp_paddrthlds_v2 val;
        struct sctp_transport *trans;
        struct sctp_association *asoc;
+       int min;
 
-       if (len < sizeof(struct sctp_paddrthlds))
+       min = v2 ? sizeof(val) : sizeof(struct sctp_paddrthlds);
+       if (len < min)
                return -EINVAL;
-       len = sizeof(struct sctp_paddrthlds);
-       if (copy_from_user(&val, (struct sctp_paddrthlds __user *)optval, len))
+       len = min;
+       if (copy_from_user(&val, optval, len))
                return -EFAULT;
 
        if (!sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) {
@@ -7192,6 +7257,7 @@ static int sctp_getsockopt_paddr_thresholds(struct sock *sk,
 
                val.spt_pathmaxrxt = trans->pathmaxrxt;
                val.spt_pathpfthld = trans->pf_retrans;
+               val.spt_pathcpthld = trans->ps_retrans;
 
                goto out;
        }
@@ -7204,11 +7270,13 @@ static int sctp_getsockopt_paddr_thresholds(struct sock *sk,
        if (asoc) {
                val.spt_pathpfthld = asoc->pf_retrans;
                val.spt_pathmaxrxt = asoc->pathmaxrxt;
+               val.spt_pathcpthld = asoc->ps_retrans;
        } else {
                struct sctp_sock *sp = sctp_sk(sk);
 
                val.spt_pathpfthld = sp->pf_retrans;
                val.spt_pathmaxrxt = sp->pathmaxrxt;
+               val.spt_pathcpthld = sp->ps_retrans;
        }
 
 out:
@@ -7900,6 +7968,45 @@ static int sctp_getsockopt_ecn_supported(struct sock *sk, int len,
        return retval;
 }
 
+static int sctp_getsockopt_pf_expose(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_id != SCTP_FUTURE_ASSOC &&
+           sctp_style(sk, UDP)) {
+               retval = -EINVAL;
+               goto out;
+       }
+
+       params.assoc_value = asoc ? asoc->pf_expose
+                                 : sctp_sk(sk)->pf_expose;
+
+       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)
 {
@@ -8049,7 +8156,12 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
                retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen);
                break;
        case SCTP_PEER_ADDR_THLDS:
-               retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen);
+               retval = sctp_getsockopt_paddr_thresholds(sk, optval, len,
+                                                         optlen, false);
+               break;
+       case SCTP_PEER_ADDR_THLDS_V2:
+               retval = sctp_getsockopt_paddr_thresholds(sk, optval, len,
+                                                         optlen, true);
                break;
        case SCTP_GET_ASSOC_STATS:
                retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen);
@@ -8112,6 +8224,9 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
        case SCTP_ECN_SUPPORTED:
                retval = sctp_getsockopt_ecn_supported(sk, len, optval, optlen);
                break;
+       case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE:
+               retval = sctp_getsockopt_pf_expose(sk, len, optval, optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;
@@ -8152,6 +8267,7 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
        struct sctp_sock *sp = sctp_sk(sk);
        bool reuse = (sk->sk_reuse || sp->reuse);
        struct sctp_bind_hashbucket *head; /* hash list */
+       struct net *net = sock_net(sk);
        kuid_t uid = sock_i_uid(sk);
        struct sctp_bind_bucket *pp;
        unsigned short snum;
@@ -8167,7 +8283,6 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
                /* Search for an available port. */
                int low, high, remaining, index;
                unsigned int rover;
-               struct net *net = sock_net(sk);
 
                inet_get_local_port_range(net, &low, &high);
                remaining = (high - low) + 1;
@@ -8179,12 +8294,12 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
                                rover = low;
                        if (inet_is_local_reserved_port(net, rover))
                                continue;
-                       index = sctp_phashfn(sock_net(sk), rover);
+                       index = sctp_phashfn(net, rover);
                        head = &sctp_port_hashtable[index];
                        spin_lock(&head->lock);
                        sctp_for_each_hentry(pp, &head->chain)
                                if ((pp->port == rover) &&
-                                   net_eq(sock_net(sk), pp->net))
+                                   net_eq(net, pp->net))
                                        goto next;
                        break;
                next:
@@ -8208,10 +8323,10 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
                 * to the port number (snum) - we detect that with the
                 * port iterator, pp being NULL.
                 */
-               head = &sctp_port_hashtable[sctp_phashfn(sock_net(sk), snum)];
+               head = &sctp_port_hashtable[sctp_phashfn(net, snum)];
                spin_lock(&head->lock);
                sctp_for_each_hentry(pp, &head->chain) {
-                       if ((pp->port == snum) && net_eq(pp->net, sock_net(sk)))
+                       if ((pp->port == snum) && net_eq(pp->net, net))
                                goto pp_found;
                }
        }
@@ -8267,7 +8382,7 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
 pp_not_found:
        /* If there was a hash table miss, create a new port.  */
        ret = 1;
-       if (!pp && !(pp = sctp_bucket_create(head, sock_net(sk), snum)))
+       if (!pp && !(pp = sctp_bucket_create(head, net, snum)))
                goto fail_unlock;
 
        /* In either case (hit or miss), make sure fastreuse is 1 only
@@ -8376,7 +8491,7 @@ static int sctp_listen_start(struct sock *sk, int backlog)
                }
        }
 
-       sk->sk_max_ack_backlog = backlog;
+       WRITE_ONCE(sk->sk_max_ack_backlog, backlog);
        return sctp_hash_endpoint(ep);
 }
 
@@ -8430,7 +8545,7 @@ int sctp_inet_listen(struct socket *sock, int backlog)
 
        /* If we are already listening, just update the backlog */
        if (sctp_sstate(sk, LISTENING))
-               sk->sk_max_ack_backlog = backlog;
+               WRITE_ONCE(sk->sk_max_ack_backlog, backlog);
        else {
                err = sctp_listen_start(sk, backlog);
                if (err)