diff options
author | Tom Herbert <tom@quantonium.net> | 2018-01-24 15:35:41 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-01-24 15:54:30 -0500 |
commit | e5571240236c5652f3e079b1d5866716a7ad819c (patch) | |
tree | 1541ccbaf77a4b034f515865927e175bb7e00bc0 | |
parent | 581e7226a5d43f629eb6399a121f85f6a15f81be (diff) |
kcm: Check if sk_user_data already set in kcm_attach
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>
-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 7632797fb68e..4a8d407f8902 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c | |||
@@ -1410,9 +1410,18 @@ static int kcm_attach(struct socket *sock, struct socket *csock, | |||
1410 | return err; | 1410 | return err; |
1411 | } | 1411 | } |
1412 | 1412 | ||
1413 | sock_hold(csk); | ||
1414 | |||
1415 | write_lock_bh(&csk->sk_callback_lock); | 1413 | write_lock_bh(&csk->sk_callback_lock); |
1414 | |||
1415 | /* Check if sk_user_data is aready by KCM or someone else. | ||
1416 | * Must be done under lock to prevent race conditions. | ||
1417 | */ | ||
1418 | if (csk->sk_user_data) { | ||
1419 | write_unlock_bh(&csk->sk_callback_lock); | ||
1420 | strp_done(&psock->strp); | ||
1421 | kmem_cache_free(kcm_psockp, psock); | ||
1422 | return -EALREADY; | ||
1423 | } | ||
1424 | |||
1416 | psock->save_data_ready = csk->sk_data_ready; | 1425 | psock->save_data_ready = csk->sk_data_ready; |
1417 | psock->save_write_space = csk->sk_write_space; | 1426 | psock->save_write_space = csk->sk_write_space; |
1418 | psock->save_state_change = csk->sk_state_change; | 1427 | psock->save_state_change = csk->sk_state_change; |
@@ -1420,8 +1429,11 @@ static int kcm_attach(struct socket *sock, struct socket *csock, | |||
1420 | csk->sk_data_ready = psock_data_ready; | 1429 | csk->sk_data_ready = psock_data_ready; |
1421 | csk->sk_write_space = psock_write_space; | 1430 | csk->sk_write_space = psock_write_space; |
1422 | csk->sk_state_change = psock_state_change; | 1431 | csk->sk_state_change = psock_state_change; |
1432 | |||
1423 | write_unlock_bh(&csk->sk_callback_lock); | 1433 | write_unlock_bh(&csk->sk_callback_lock); |
1424 | 1434 | ||
1435 | sock_hold(csk); | ||
1436 | |||
1425 | /* Finished initialization, now add the psock to the MUX. */ | 1437 | /* Finished initialization, now add the psock to the MUX. */ |
1426 | spin_lock_bh(&mux->lock); | 1438 | spin_lock_bh(&mux->lock); |
1427 | head = &mux->psocks; | 1439 | head = &mux->psocks; |