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

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
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -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;
+33 −13
Original line number Diff line number Diff line
@@ -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 &&

		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;