diff options
| author | Thomas Zimmermann <tzimmermann@suse.de> | 2021-12-17 11:33:33 +0100 | 
|---|---|---|
| committer | Thomas Zimmermann <tzimmermann@suse.de> | 2021-12-17 11:33:33 +0100 | 
| commit | 1758047057dbe329be712a31b79db7151b5871f8 (patch) | |
| tree | 00203eb55328f2feda70b3d37c964287b364796f /net/unix/af_unix.c | |
| parent | bcae3af286f49bf4f6cda03f165fbe530f4a6bed (diff) | |
| parent | 1c405ca11bf563de1725e5ecfb4a74ee289d2ee9 (diff) | |
Merge drm/drm-next into drm-misc-next-fixes
Backmerging to bring drm-misc-next-fixes up to the latest state for
the current release cycle.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Diffstat (limited to 'net/unix/af_unix.c')
| -rw-r--r-- | net/unix/af_unix.c | 97 | 
1 files changed, 68 insertions, 29 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index eb47b9de2380..b0bfc78e421c 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -608,20 +608,42 @@ static void unix_release_sock(struct sock *sk, int embrion)  static void init_peercred(struct sock *sk)  { -	put_pid(sk->sk_peer_pid); -	if (sk->sk_peer_cred) -		put_cred(sk->sk_peer_cred); +	const struct cred *old_cred; +	struct pid *old_pid; + +	spin_lock(&sk->sk_peer_lock); +	old_pid = sk->sk_peer_pid; +	old_cred = sk->sk_peer_cred;  	sk->sk_peer_pid  = get_pid(task_tgid(current));  	sk->sk_peer_cred = get_current_cred(); +	spin_unlock(&sk->sk_peer_lock); + +	put_pid(old_pid); +	put_cred(old_cred);  }  static void copy_peercred(struct sock *sk, struct sock *peersk)  { -	put_pid(sk->sk_peer_pid); -	if (sk->sk_peer_cred) -		put_cred(sk->sk_peer_cred); +	const struct cred *old_cred; +	struct pid *old_pid; + +	if (sk < peersk) { +		spin_lock(&sk->sk_peer_lock); +		spin_lock_nested(&peersk->sk_peer_lock, SINGLE_DEPTH_NESTING); +	} else { +		spin_lock(&peersk->sk_peer_lock); +		spin_lock_nested(&sk->sk_peer_lock, SINGLE_DEPTH_NESTING); +	} +	old_pid = sk->sk_peer_pid; +	old_cred = sk->sk_peer_cred;  	sk->sk_peer_pid  = get_pid(peersk->sk_peer_pid);  	sk->sk_peer_cred = get_cred(peersk->sk_peer_cred); + +	spin_unlock(&sk->sk_peer_lock); +	spin_unlock(&peersk->sk_peer_lock); + +	put_pid(old_pid); +	put_cred(old_cred);  }  static int unix_listen(struct socket *sock, int backlog) @@ -806,7 +828,7 @@ static void unix_unhash(struct sock *sk)  }  struct proto unix_dgram_proto = { -	.name			= "UNIX-DGRAM", +	.name			= "UNIX",  	.owner			= THIS_MODULE,  	.obj_size		= sizeof(struct unix_sock),  	.close			= unix_close, @@ -828,20 +850,25 @@ struct proto unix_stream_proto = {  static struct sock *unix_create1(struct net *net, struct socket *sock, int kern, int type)  { -	struct sock *sk = NULL;  	struct unix_sock *u; +	struct sock *sk; +	int err;  	atomic_long_inc(&unix_nr_socks); -	if (atomic_long_read(&unix_nr_socks) > 2 * get_max_files()) -		goto out; +	if (atomic_long_read(&unix_nr_socks) > 2 * get_max_files()) { +		err = -ENFILE; +		goto err; +	}  	if (type == SOCK_STREAM)  		sk = sk_alloc(net, PF_UNIX, GFP_KERNEL, &unix_stream_proto, kern);  	else /*dgram and  seqpacket */  		sk = sk_alloc(net, PF_UNIX, GFP_KERNEL, &unix_dgram_proto, kern); -	if (!sk) -		goto out; +	if (!sk) { +		err = -ENOMEM; +		goto err; +	}  	sock_init_data(sock, sk); @@ -861,20 +888,23 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern,  	init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay);  	memset(&u->scm_stat, 0, sizeof(struct scm_stat));  	unix_insert_socket(unix_sockets_unbound(sk), sk); -out: -	if (sk == NULL) -		atomic_long_dec(&unix_nr_socks); -	else { -		local_bh_disable(); -		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); -		local_bh_enable(); -	} + +	local_bh_disable(); +	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); +	local_bh_enable(); +  	return sk; + +err: +	atomic_long_dec(&unix_nr_socks); +	return ERR_PTR(err);  }  static int unix_create(struct net *net, struct socket *sock, int protocol,  		       int kern)  { +	struct sock *sk; +  	if (protocol && protocol != PF_UNIX)  		return -EPROTONOSUPPORT; @@ -901,7 +931,11 @@ static int unix_create(struct net *net, struct socket *sock, int protocol,  		return -ESOCKTNOSUPPORT;  	} -	return unix_create1(net, sock, kern, sock->type) ? 0 : -ENOMEM; +	sk = unix_create1(net, sock, kern, sock->type); +	if (IS_ERR(sk)) +		return PTR_ERR(sk); + +	return 0;  }  static int unix_release(struct socket *sock) @@ -1314,12 +1348,15 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,  	   we will have to recheck all again in any case.  	 */ -	err = -ENOMEM; -  	/* create new sock for complete connection */  	newsk = unix_create1(sock_net(sk), NULL, 0, sock->type); -	if (newsk == NULL) +	if (IS_ERR(newsk)) { +		err = PTR_ERR(newsk); +		newsk = NULL;  		goto out; +	} + +	err = -ENOMEM;  	/* Allocate skb for sending to listening sock */  	skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL); @@ -2867,12 +2904,10 @@ static int unix_shutdown(struct socket *sock, int mode)  		other->sk_shutdown |= peer_mode;  		unix_state_unlock(other);  		other->sk_state_change(other); -		if (peer_mode == SHUTDOWN_MASK) { +		if (peer_mode == SHUTDOWN_MASK)  			sk_wake_async(other, SOCK_WAKE_WAITD, POLL_HUP); -			other->sk_state = TCP_CLOSE; -		} else if (peer_mode & RCV_SHUTDOWN) { +		else if (peer_mode & RCV_SHUTDOWN)  			sk_wake_async(other, SOCK_WAKE_WAITD, POLL_IN); -		}  	}  	if (other)  		sock_put(other); @@ -3014,6 +3049,8 @@ static __poll_t unix_poll(struct file *file, struct socket *sock, poll_table *wa  	/* readable? */  	if (!skb_queue_empty_lockless(&sk->sk_receive_queue))  		mask |= EPOLLIN | EPOLLRDNORM; +	if (sk_is_readable(sk)) +		mask |= EPOLLIN | EPOLLRDNORM;  	/* Connection-based need to check for termination and startup */  	if ((sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) && @@ -3053,6 +3090,8 @@ static __poll_t unix_dgram_poll(struct file *file, struct socket *sock,  	/* readable? */  	if (!skb_queue_empty_lockless(&sk->sk_receive_queue))  		mask |= EPOLLIN | EPOLLRDNORM; +	if (sk_is_readable(sk)) +		mask |= EPOLLIN | EPOLLRDNORM;  	/* Connection-based need to check for termination and startup */  	if (sk->sk_type == SOCK_SEQPACKET) { @@ -3073,7 +3112,7 @@ static __poll_t unix_dgram_poll(struct file *file, struct socket *sock,  		other = unix_peer(sk);  		if (other && unix_peer(other) != sk && -		    unix_recvq_full(other) && +		    unix_recvq_full_lockless(other) &&  		    unix_dgram_peer_wake_me(sk, other))  			writable = 0;  | 
