diff options
Diffstat (limited to 'net/kcm/kcmsock.c')
| -rw-r--r-- | net/kcm/kcmsock.c | 33 | 
1 files changed, 23 insertions, 10 deletions
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index f297d53a11aa..34355fd19f27 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -1381,24 +1381,32 @@ static int kcm_attach(struct socket *sock, struct socket *csock,  		.parse_msg = kcm_parse_func_strparser,  		.read_sock_done = kcm_read_sock_done,  	}; -	int err; +	int err = 0;  	csk = csock->sk;  	if (!csk)  		return -EINVAL; +	lock_sock(csk); +  	/* Only allow TCP sockets to be attached for now */  	if ((csk->sk_family != AF_INET && csk->sk_family != AF_INET6) || -	    csk->sk_protocol != IPPROTO_TCP) -		return -EOPNOTSUPP; +	    csk->sk_protocol != IPPROTO_TCP) { +		err = -EOPNOTSUPP; +		goto out; +	}  	/* Don't allow listeners or closed sockets */ -	if (csk->sk_state == TCP_LISTEN || csk->sk_state == TCP_CLOSE) -		return -EOPNOTSUPP; +	if (csk->sk_state == TCP_LISTEN || csk->sk_state == TCP_CLOSE) { +		err = -EOPNOTSUPP; +		goto out; +	}  	psock = kmem_cache_zalloc(kcm_psockp, GFP_KERNEL); -	if (!psock) -		return -ENOMEM; +	if (!psock) { +		err = -ENOMEM; +		goto out; +	}  	psock->mux = mux;  	psock->sk = csk; @@ -1407,7 +1415,7 @@ static int kcm_attach(struct socket *sock, struct socket *csock,  	err = strp_init(&psock->strp, csk, &cb);  	if (err) {  		kmem_cache_free(kcm_psockp, psock); -		return err; +		goto out;  	}  	write_lock_bh(&csk->sk_callback_lock); @@ -1419,7 +1427,8 @@ static int kcm_attach(struct socket *sock, struct socket *csock,  		write_unlock_bh(&csk->sk_callback_lock);  		strp_done(&psock->strp);  		kmem_cache_free(kcm_psockp, psock); -		return -EALREADY; +		err = -EALREADY; +		goto out;  	}  	psock->save_data_ready = csk->sk_data_ready; @@ -1455,7 +1464,10 @@ static int kcm_attach(struct socket *sock, struct socket *csock,  	/* Schedule RX work in case there are already bytes queued */  	strp_check_rcv(&psock->strp); -	return 0; +out: +	release_sock(csk); + +	return err;  }  static int kcm_attach_ioctl(struct socket *sock, struct kcm_attach *info) @@ -1507,6 +1519,7 @@ static void kcm_unattach(struct kcm_psock *psock)  	if (WARN_ON(psock->rx_kcm)) {  		write_unlock_bh(&csk->sk_callback_lock); +		release_sock(csk);  		return;  	}  | 
