Commit 6ba84574 authored by Xin Long's avatar Xin Long Committed by David S. Miller

sctp: process sk_reuseport in sctp_get_port_local

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: default avatarNeil Horman <nhorman@tuxdriver.com>
Signed-off-by: default avatarXin Long <lucien.xin@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 76c6d988
...@@ -96,7 +96,9 @@ struct sctp_stream; ...@@ -96,7 +96,9 @@ struct sctp_stream;
struct sctp_bind_bucket { struct sctp_bind_bucket {
unsigned short port; unsigned short port;
unsigned short fastreuse; signed char fastreuse;
signed char fastreuseport;
kuid_t fastuid;
struct hlist_node node; struct hlist_node node;
struct hlist_head owner; struct hlist_head owner;
struct net *net; struct net *net;
......
...@@ -7644,8 +7644,10 @@ static struct sctp_bind_bucket *sctp_bucket_create( ...@@ -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) 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 */ struct sctp_bind_hashbucket *head; /* hash list */
kuid_t uid = sock_i_uid(sk);
struct sctp_bind_bucket *pp; struct sctp_bind_bucket *pp;
unsigned short snum; unsigned short snum;
int ret; int ret;
...@@ -7721,7 +7723,10 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -7721,7 +7723,10 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
pr_debug("%s: found a possible match\n", __func__); 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; goto success;
/* Run through the list of sockets bound to the port /* Run through the list of sockets bound to the port
...@@ -7735,16 +7740,18 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -7735,16 +7740,18 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
* in an endpoint. * in an endpoint.
*/ */
sk_for_each_bound(sk2, &pp->owner) { sk_for_each_bound(sk2, &pp->owner) {
struct sctp_endpoint *ep2; struct sctp_sock *sp2 = sctp_sk(sk2);
ep2 = sctp_sk(sk2)->ep; struct sctp_endpoint *ep2 = sp2->ep;
if (sk == sk2 || if (sk == sk2 ||
(reuse && (sk2->sk_reuse || sctp_sk(sk2)->reuse) && (reuse && (sk2->sk_reuse || sp2->reuse) &&
sk2->sk_state != SCTP_SS_LISTENING)) sk2->sk_state != SCTP_SS_LISTENING) ||
(sk->sk_reuseport && sk2->sk_reuseport &&
uid_eq(uid, sock_i_uid(sk2))))
continue; continue;
if (sctp_bind_addr_conflict(&ep2->base.bind_addr, addr, if (sctp_bind_addr_conflict(&ep2->base.bind_addr,
sctp_sk(sk2), sctp_sk(sk))) { addr, sp2, sp)) {
ret = (long)sk2; ret = (long)sk2;
goto fail_unlock; goto fail_unlock;
} }
...@@ -7767,19 +7774,32 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -7767,19 +7774,32 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
pp->fastreuse = 1; pp->fastreuse = 1;
else else
pp->fastreuse = 0; pp->fastreuse = 0;
} else if (pp->fastreuse &&
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)) (!reuse || sk->sk_state == SCTP_SS_LISTENING))
pp->fastreuse = 0; 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 /* We are set, so fill up all the data in the hash table
* entry, tie the socket list information with the rest of the * entry, tie the socket list information with the rest of the
* sockets FIXME: Blurry, NPI (ipg). * sockets FIXME: Blurry, NPI (ipg).
*/ */
success: success:
if (!sctp_sk(sk)->bind_hash) { if (!sp->bind_hash) {
inet_sk(sk)->inet_num = snum; inet_sk(sk)->inet_num = snum;
sk_add_bind_node(sk, &pp->owner); sk_add_bind_node(sk, &pp->owner);
sctp_sk(sk)->bind_hash = pp; sp->bind_hash = pp;
} }
ret = 0; ret = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment