sctp: process sk_reuseport in sctp_get_port_local
authorXin Long <lucien.xin@gmail.com>
Mon, 12 Nov 2018 10:27:17 +0000 (18:27 +0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 12 Nov 2018 17:09:51 +0000 (09:09 -0800)
When socks' sk_reuseport is set, the same port and address are allowed
to be bound into these socks who have the same uid.

Note that the difference from sk_reuse is that it allows multiple socks
to listen on the same port and address.

Acked-by: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/sctp/structs.h
net/sctp/socket.c

index 15d017f33a4631d3c1523026ee052dc0c5104e57..af9d494120ba8b9811b91c6b797cf7b86b97df75 100644 (file)
@@ -96,7 +96,9 @@ struct sctp_stream;
 
 struct sctp_bind_bucket {
        unsigned short  port;
-       unsigned short  fastreuse;
+       signed char     fastreuse;
+       signed char     fastreuseport;
+       kuid_t          fastuid;
        struct hlist_node       node;
        struct hlist_head       owner;
        struct net      *net;
index 2e955f1dbe3f8f9c87a41fc4251aad743dd358f4..5299add6d7aa8df10ca80b5e9cdb29616015a7ed 100644 (file)
@@ -7644,8 +7644,10 @@ static struct sctp_bind_bucket *sctp_bucket_create(
 
 static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
 {
-       bool reuse = (sk->sk_reuse || sctp_sk(sk)->reuse);
+       struct sctp_sock *sp = sctp_sk(sk);
+       bool reuse = (sk->sk_reuse || sp->reuse);
        struct sctp_bind_hashbucket *head; /* hash list */
+       kuid_t uid = sock_i_uid(sk);
        struct sctp_bind_bucket *pp;
        unsigned short snum;
        int ret;
@@ -7721,7 +7723,10 @@ pp_found:
 
                pr_debug("%s: found a possible match\n", __func__);
 
-               if (pp->fastreuse && reuse && sk->sk_state != SCTP_SS_LISTENING)
+               if ((pp->fastreuse && reuse &&
+                    sk->sk_state != SCTP_SS_LISTENING) ||
+                   (pp->fastreuseport && sk->sk_reuseport &&
+                    uid_eq(pp->fastuid, uid)))
                        goto success;
 
                /* Run through the list of sockets bound to the port
@@ -7735,16 +7740,18 @@ pp_found:
                 * in an endpoint.
                 */
                sk_for_each_bound(sk2, &pp->owner) {
-                       struct sctp_endpoint *ep2;
-                       ep2 = sctp_sk(sk2)->ep;
+                       struct sctp_sock *sp2 = sctp_sk(sk2);
+                       struct sctp_endpoint *ep2 = sp2->ep;
 
                        if (sk == sk2 ||
-                           (reuse && (sk2->sk_reuse || sctp_sk(sk2)->reuse) &&
-                            sk2->sk_state != SCTP_SS_LISTENING))
+                           (reuse && (sk2->sk_reuse || sp2->reuse) &&
+                            sk2->sk_state != SCTP_SS_LISTENING) ||
+                           (sk->sk_reuseport && sk2->sk_reuseport &&
+                            uid_eq(uid, sock_i_uid(sk2))))
                                continue;
 
-                       if (sctp_bind_addr_conflict(&ep2->base.bind_addr, addr,
-                                                sctp_sk(sk2), sctp_sk(sk))) {
+                       if (sctp_bind_addr_conflict(&ep2->base.bind_addr,
+                                                   addr, sp2, sp)) {
                                ret = (long)sk2;
                                goto fail_unlock;
                        }
@@ -7767,19 +7774,32 @@ pp_not_found:
                        pp->fastreuse = 1;
                else
                        pp->fastreuse = 0;
-       } else if (pp->fastreuse &&
-                  (!reuse || sk->sk_state == SCTP_SS_LISTENING))
-               pp->fastreuse = 0;
+
+               if (sk->sk_reuseport) {
+                       pp->fastreuseport = 1;
+                       pp->fastuid = uid;
+               } else {
+                       pp->fastreuseport = 0;
+               }
+       } else {
+               if (pp->fastreuse &&
+                   (!reuse || sk->sk_state == SCTP_SS_LISTENING))
+                       pp->fastreuse = 0;
+
+               if (pp->fastreuseport &&
+                   (!sk->sk_reuseport || !uid_eq(pp->fastuid, uid)))
+                       pp->fastreuseport = 0;
+       }
 
        /* We are set, so fill up all the data in the hash table
         * entry, tie the socket list information with the rest of the
         * sockets FIXME: Blurry, NPI (ipg).
         */
 success:
-       if (!sctp_sk(sk)->bind_hash) {
+       if (!sp->bind_hash) {
                inet_sk(sk)->inet_num = snum;
                sk_add_bind_node(sk, &pp->owner);
-               sctp_sk(sk)->bind_hash = pp;
+               sp->bind_hash = pp;
        }
        ret = 0;