diff options
| author | Dmitry Torokhov <[email protected]> | 2023-05-01 15:20:08 -0700 | 
|---|---|---|
| committer | Dmitry Torokhov <[email protected]> | 2023-05-01 15:20:08 -0700 | 
| commit | 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e (patch) | |
| tree | d57f3a63479a07b4e0cece029886e76e04feb984 /net/core/sock_map.c | |
| parent | 5dc63e56a9cf8df0b59c234a505a1653f1bdf885 (diff) | |
| parent | 53bea86b5712c7491bb3dae12e271666df0a308c (diff) | |
Merge branch 'next' into for-linus
Prepare input updates for 6.4 merge window.
Diffstat (limited to 'net/core/sock_map.c')
| -rw-r--r-- | net/core/sock_map.c | 61 | 
1 files changed, 34 insertions, 27 deletions
diff --git a/net/core/sock_map.c b/net/core/sock_map.c index 22fa2c5bc6ec..a68a7290a3b2 100644 --- a/net/core/sock_map.c +++ b/net/core/sock_map.c @@ -1569,15 +1569,16 @@ void sock_map_unhash(struct sock *sk)  	psock = sk_psock(sk);  	if (unlikely(!psock)) {  		rcu_read_unlock(); -		if (sk->sk_prot->unhash) -			sk->sk_prot->unhash(sk); -		return; +		saved_unhash = READ_ONCE(sk->sk_prot)->unhash; +	} else { +		saved_unhash = psock->saved_unhash; +		sock_map_remove_links(sk, psock); +		rcu_read_unlock();  	} - -	saved_unhash = psock->saved_unhash; -	sock_map_remove_links(sk, psock); -	rcu_read_unlock(); -	saved_unhash(sk); +	if (WARN_ON_ONCE(saved_unhash == sock_map_unhash)) +		return; +	if (saved_unhash) +		saved_unhash(sk);  }  EXPORT_SYMBOL_GPL(sock_map_unhash); @@ -1590,17 +1591,18 @@ void sock_map_destroy(struct sock *sk)  	psock = sk_psock_get(sk);  	if (unlikely(!psock)) {  		rcu_read_unlock(); -		if (sk->sk_prot->destroy) -			sk->sk_prot->destroy(sk); -		return; +		saved_destroy = READ_ONCE(sk->sk_prot)->destroy; +	} else { +		saved_destroy = psock->saved_destroy; +		sock_map_remove_links(sk, psock); +		rcu_read_unlock(); +		sk_psock_stop(psock); +		sk_psock_put(sk, psock);  	} - -	saved_destroy = psock->saved_destroy; -	sock_map_remove_links(sk, psock); -	rcu_read_unlock(); -	sk_psock_stop(psock); -	sk_psock_put(sk, psock); -	saved_destroy(sk); +	if (WARN_ON_ONCE(saved_destroy == sock_map_destroy)) +		return; +	if (saved_destroy) +		saved_destroy(sk);  }  EXPORT_SYMBOL_GPL(sock_map_destroy); @@ -1615,16 +1617,21 @@ void sock_map_close(struct sock *sk, long timeout)  	if (unlikely(!psock)) {  		rcu_read_unlock();  		release_sock(sk); -		return sk->sk_prot->close(sk, timeout); +		saved_close = READ_ONCE(sk->sk_prot)->close; +	} else { +		saved_close = psock->saved_close; +		sock_map_remove_links(sk, psock); +		rcu_read_unlock(); +		sk_psock_stop(psock); +		release_sock(sk); +		cancel_work_sync(&psock->work); +		sk_psock_put(sk, psock);  	} - -	saved_close = psock->saved_close; -	sock_map_remove_links(sk, psock); -	rcu_read_unlock(); -	sk_psock_stop(psock); -	release_sock(sk); -	cancel_work_sync(&psock->work); -	sk_psock_put(sk, psock); +	/* Make sure we do not recurse. This is a bug. +	 * Leak the socket instead of crashing on a stack overflow. +	 */ +	if (WARN_ON_ONCE(saved_close == sock_map_close)) +		return;  	saved_close(sk, timeout);  }  EXPORT_SYMBOL_GPL(sock_map_close);  |