Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kcm: fix strp_init() order and cleanup

strp_init() is called just a few lines above this csk->sk_user_data
check, it also initializes strp->work etc., therefore, it is
unnecessary to call strp_done() to cancel the freshly initialized
work.

And if sk_user_data is already used by KCM, psock->strp should not be
touched, particularly strp->work state, so we need to move strp_init()
after the csk->sk_user_data check.

This also makes a lockdep warning reported by syzbot go away.

Reported-and-tested-by: syzbot+9fc084a4348493ef65d2@syzkaller.appspotmail.com
Reported-by: syzbot+e696806ef96cdd2d87cd@syzkaller.appspotmail.com
Fixes: e5571240236c ("kcm: Check if sk_user_data already set in kcm_attach")
Fixes: dff8baa26117 ("kcm: Call strp_stop before strp_done in kcm_attach")
Cc: Tom Herbert <tom@herbertland.com>
Signed-off-by: Cong Wang <cong.wang@bytedance.com>
Link: https://lore.kernel.org/r/20220827181314.193710-1-xiyou.wangcong@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Cong Wang and committed by
Jakub Kicinski
8fc29ff3 3a1a274e

+7 -8
+7 -8
net/kcm/kcmsock.c
··· 1412 1412 psock->sk = csk; 1413 1413 psock->bpf_prog = prog; 1414 1414 1415 - err = strp_init(&psock->strp, csk, &cb); 1416 - if (err) { 1417 - kmem_cache_free(kcm_psockp, psock); 1418 - goto out; 1419 - } 1420 - 1421 1415 write_lock_bh(&csk->sk_callback_lock); 1422 1416 1423 1417 /* Check if sk_user_data is already by KCM or someone else. ··· 1419 1425 */ 1420 1426 if (csk->sk_user_data) { 1421 1427 write_unlock_bh(&csk->sk_callback_lock); 1422 - strp_stop(&psock->strp); 1423 - strp_done(&psock->strp); 1424 1428 kmem_cache_free(kcm_psockp, psock); 1425 1429 err = -EALREADY; 1430 + goto out; 1431 + } 1432 + 1433 + err = strp_init(&psock->strp, csk, &cb); 1434 + if (err) { 1435 + write_unlock_bh(&csk->sk_callback_lock); 1436 + kmem_cache_free(kcm_psockp, psock); 1426 1437 goto out; 1427 1438 } 1428 1439