OSDN Git Service

Merge tag 'selinux-pr-20180403' of git://git.kernel.org/pub/scm/linux/kernel/git...
[uclinux-h8/linux.git] / net / sctp / socket.c
index 7a10ae3..2a2e094 100644 (file)
@@ -1046,6 +1046,12 @@ static int sctp_setsockopt_bindx(struct sock *sk,
        /* Do the work. */
        switch (op) {
        case SCTP_BINDX_ADD_ADDR:
+               /* Allow security module to validate bindx addresses. */
+               err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_BINDX_ADD,
+                                                (struct sockaddr *)kaddrs,
+                                                addrs_size);
+               if (err)
+                       goto out;
                err = sctp_bindx_add(sk, kaddrs, addrcnt);
                if (err)
                        goto out;
@@ -1255,6 +1261,7 @@ static int __sctp_connect(struct sock *sk,
 
        if (assoc_id)
                *assoc_id = asoc->assoc_id;
+
        err = sctp_wait_for_connect(asoc, &timeo);
        /* Note: the asoc may be freed after the return of
         * sctp_wait_for_connect.
@@ -1350,7 +1357,16 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
        if (unlikely(IS_ERR(kaddrs)))
                return PTR_ERR(kaddrs);
 
+       /* Allow security module to validate connectx addresses. */
+       err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_CONNECTX,
+                                        (struct sockaddr *)kaddrs,
+                                         addrs_size);
+       if (err)
+               goto out_free;
+
        err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id);
+
+out_free:
        kvfree(kaddrs);
 
        return err;
@@ -1680,6 +1696,7 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
        struct sctp_association *asoc;
        enum sctp_scope scope;
        struct cmsghdr *cmsg;
+       struct sctp_af *af;
        int err;
 
        *tp = NULL;
@@ -1705,6 +1722,21 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
 
        scope = sctp_scope(daddr);
 
+       /* Label connection socket for first association 1-to-many
+        * style for client sequence socket()->sendmsg(). This
+        * needs to be done before sctp_assoc_add_peer() as that will
+        * set up the initial packet that needs to account for any
+        * security ip options (CIPSO/CALIPSO) added to the packet.
+        */
+       af = sctp_get_af_specific(daddr->sa.sa_family);
+       if (!af)
+               return -EINVAL;
+       err = security_sctp_bind_connect(sk, SCTP_SENDMSG_CONNECT,
+                                        (struct sockaddr *)daddr,
+                                        af->sockaddr_len);
+       if (err < 0)
+               return err;
+
        asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL);
        if (!asoc)
                return -ENOMEM;
@@ -2932,6 +2964,8 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
 {
        struct sctp_prim prim;
        struct sctp_transport *trans;
+       struct sctp_af *af;
+       int err;
 
        if (optlen != sizeof(struct sctp_prim))
                return -EINVAL;
@@ -2939,6 +2973,17 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
        if (copy_from_user(&prim, optval, sizeof(struct sctp_prim)))
                return -EFAULT;
 
+       /* Allow security module to validate address but need address len. */
+       af = sctp_get_af_specific(prim.ssp_addr.ss_family);
+       if (!af)
+               return -EINVAL;
+
+       err = security_sctp_bind_connect(sk, SCTP_PRIMARY_ADDR,
+                                        (struct sockaddr *)&prim.ssp_addr,
+                                        af->sockaddr_len);
+       if (err)
+               return err;
+
        trans = sctp_addr_id2transport(sk, &prim.ssp_addr, prim.ssp_assoc_id);
        if (!trans)
                return -EINVAL;
@@ -3161,6 +3206,7 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsign
 static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen)
 {
        struct sctp_sock *sp = sctp_sk(sk);
+       struct sctp_af *af = sp->pf->af;
        struct sctp_assoc_value params;
        struct sctp_association *asoc;
        int val;
@@ -3185,7 +3231,8 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
        if (val) {
                int min_len, max_len;
 
-               min_len = SCTP_DEFAULT_MINSEGMENT - sp->pf->af->net_header_len;
+               min_len = SCTP_DEFAULT_MINSEGMENT - af->net_header_len;
+               min_len -= af->ip_options_len(sk);
                min_len -= sizeof(struct sctphdr) +
                           sizeof(struct sctp_data_chunk);
 
@@ -3198,7 +3245,8 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
        asoc = sctp_id2assoc(sk, params.assoc_id);
        if (asoc) {
                if (val == 0) {
-                       val = asoc->pathmtu - sp->pf->af->net_header_len;
+                       val = asoc->pathmtu - af->net_header_len;
+                       val -= af->ip_options_len(sk);
                        val -= sizeof(struct sctphdr) +
                               sctp_datachk_len(&asoc->stream);
                }
@@ -3267,6 +3315,13 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
        if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr))
                return -EADDRNOTAVAIL;
 
+       /* Allow security module to validate address. */
+       err = security_sctp_bind_connect(sk, SCTP_SET_PEER_PRIMARY_ADDR,
+                                        (struct sockaddr *)&prim.sspp_addr,
+                                        af->sockaddr_len);
+       if (err)
+               return err;
+
        /* Create an ASCONF chunk with SET_PRIMARY parameter    */
        chunk = sctp_make_asconf_set_prim(asoc,
                                          (union sctp_addr *)&prim.sspp_addr);
@@ -5140,9 +5195,11 @@ int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp)
        sctp_copy_sock(sock->sk, sk, asoc);
 
        /* Make peeled-off sockets more like 1-1 accepted sockets.
-        * Set the daddr and initialize id to something more random
+        * Set the daddr and initialize id to something more random and also
+        * copy over any ip options.
         */
        sp->pf->to_sk_daddr(&asoc->peer.primary_addr, sk);
+       sp->pf->copy_ip_options(sk, sock->sk);
 
        /* Populate the fields of the newsk from the oldsk and migrate the
         * asoc to the newsk.
@@ -8465,6 +8522,8 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
 {
        struct inet_sock *inet = inet_sk(sk);
        struct inet_sock *newinet;
+       struct sctp_sock *sp = sctp_sk(sk);
+       struct sctp_endpoint *ep = sp->ep;
 
        newsk->sk_type = sk->sk_type;
        newsk->sk_bound_dev_if = sk->sk_bound_dev_if;
@@ -8507,7 +8566,10 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
        if (newsk->sk_flags & SK_FLAGS_TIMESTAMP)
                net_enable_timestamp();
 
-       security_sk_clone(sk, newsk);
+       /* Set newsk security attributes from orginal sk and connection
+        * security attribute from ep.
+        */
+       security_sctp_sk_clone(ep, sk, newsk);
 }
 
 static inline void sctp_copy_descendant(struct sock *sk_to,