forked from mirrors/linux
		
	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: Neil Horman <nhorman@tuxdriver.com> Signed-off-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									76c6d988ae
								
							
						
					
					
						commit
						6ba8457402
					
				
					 2 changed files with 36 additions and 14 deletions
				
			
		| 
						 | 
					@ -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(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		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)
 | 
				
			||||||
		 * 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)
 | 
				
			||||||
			pp->fastreuse = 1;
 | 
								pp->fastreuse = 1;
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			pp->fastreuse = 0;
 | 
								pp->fastreuse = 0;
 | 
				
			||||||
	} else if (pp->fastreuse &&
 | 
					
 | 
				
			||||||
		   (!reuse || sk->sk_state == SCTP_SS_LISTENING))
 | 
							if (sk->sk_reuseport) {
 | 
				
			||||||
		pp->fastreuse = 0;
 | 
								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
 | 
						/* 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue