diff options
author | Tom Herbert <tom@quantonium.net> | 2018-01-24 12:35:41 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-02-25 11:05:40 +0100 |
commit | 085cbbda4b4cc7dd2ba63806346881c2c2e10107 (patch) | |
tree | 241be7f4e963529c188c72a40ab3380bc85401f2 /net/kcm | |
parent | bd3ccdc6f922c6b7db4b7075d1b6596ddb986a98 (diff) | |
download | linux-stable-085cbbda4b4cc7dd2ba63806346881c2c2e10107.tar.gz linux-stable-085cbbda4b4cc7dd2ba63806346881c2c2e10107.tar.bz2 linux-stable-085cbbda4b4cc7dd2ba63806346881c2c2e10107.zip |
kcm: Check if sk_user_data already set in kcm_attach
commit e5571240236c5652f3e079b1d5866716a7ad819c upstream.
This is needed to prevent sk_user_data being overwritten.
The check is done under the callback lock. This should prevent
a socket from being attached twice to a KCM mux. It also prevents
a socket from being attached for other use cases of sk_user_data
as long as the other cases set sk_user_data under the lock.
Followup work is needed to unify all the use cases of sk_user_data
to use the same locking.
Reported-by: syzbot+114b15f2be420a8886c3@syzkaller.appspotmail.com
Fixes: ab7ac4eb9832 ("kcm: Kernel Connection Multiplexor module")
Signed-off-by: Tom Herbert <tom@quantonium.net>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net/kcm')
-rw-r--r-- | net/kcm/kcmsock.c | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 22785dc03051..69bef8ee04b4 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -1404,9 +1404,18 @@ static int kcm_attach(struct socket *sock, struct socket *csock, return err; } - sock_hold(csk); - write_lock_bh(&csk->sk_callback_lock); + + /* Check if sk_user_data is aready by KCM or someone else. + * Must be done under lock to prevent race conditions. + */ + if (csk->sk_user_data) { + write_unlock_bh(&csk->sk_callback_lock); + strp_done(&psock->strp); + kmem_cache_free(kcm_psockp, psock); + return -EALREADY; + } + psock->save_data_ready = csk->sk_data_ready; psock->save_write_space = csk->sk_write_space; psock->save_state_change = csk->sk_state_change; @@ -1414,8 +1423,11 @@ static int kcm_attach(struct socket *sock, struct socket *csock, csk->sk_data_ready = psock_data_ready; csk->sk_write_space = psock_write_space; csk->sk_state_change = psock_state_change; + write_unlock_bh(&csk->sk_callback_lock); + sock_hold(csk); + /* Finished initialization, now add the psock to the MUX. */ spin_lock_bh(&mux->lock); head = &mux->psocks; |