Skip to content

Commit e582cbd

Browse files
mrpreKernel Patches Daemon
authored and
Kernel Patches Daemon
committed
bpf, sockmap: avoid using sk_socket after free when sending
The sk->sk_socket is not locked or referenced, and during the call to skb_send_sock(), there is a race condition with the release of sk_socket. All types of sockets(tcp/udp/unix/vsock) will be affected. Race conditions: ''' CPU0 CPU1 skb_send_sock sendmsg_unlocked sock_sendmsg sock_sendmsg_nosec close(fd): ... ops->release() sock_map_close() sk_socket->ops = NULL free(socket) sock->ops->sendmsg ^ panic here ''' Based on the fact that we already wait for the workqueue to finish in sock_map_close() if psock is held, we simply increase the psock reference count to avoid race conditions. ''' void sock_map_close() { ... if (likely(psock)) { ... psock = sk_psock_get(sk); if (unlikely(!psock)) goto no_psock; <=== Control usually jumps here via goto ... cancel_delayed_work_sync(&psock->work); <=== not executed sk_psock_put(sk, psock); ... } ''' The panic I catched: ''' Workqueue: events sk_psock_backlog RIP: 0010:sock_sendmsg+0x21d/0x440 RAX: 0000000000000000 RBX: ffffc9000521fad8 RCX: 0000000000000001 ... Call Trace: <TASK> ? die_addr+0x40/0xa0 ? exc_general_protection+0x14c/0x230 ? asm_exc_general_protection+0x26/0x30 ? sock_sendmsg+0x21d/0x440 ? sock_sendmsg+0x3e0/0x440 ? __pfx_sock_sendmsg+0x10/0x10 __skb_send_sock+0x543/0xb70 sk_psock_backlog+0x247/0xb80 ... ''' Reported-by: Michal Luczaj <[email protected]> Fixes: 799aa7f ("skmsg: Avoid lock_sock() in sk_psock_backlog()") Signed-off-by: Jiayuan Chen <[email protected]>
1 parent 503edd4 commit e582cbd

File tree

1 file changed

+9
-0
lines changed

1 file changed

+9
-0
lines changed

net/core/skmsg.c

+9
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,14 @@ static void sk_psock_backlog(struct work_struct *work)
655655
bool ingress;
656656
int ret;
657657

658+
/* Increment the psock refcnt to synchronize with close(fd) path in
659+
* sock_map_close(), ensuring we wait for backlog thread completion
660+
* before sk_socket freed. If refcnt increment fails, it indicates
661+
* sock_map_close() completed with sk_socket potentially already freed.
662+
*/
663+
if (!sk_psock_get(psock->sk))
664+
return;
665+
658666
mutex_lock(&psock->work_mutex);
659667
if (unlikely(state->len)) {
660668
len = state->len;
@@ -702,6 +710,7 @@ static void sk_psock_backlog(struct work_struct *work)
702710
}
703711
end:
704712
mutex_unlock(&psock->work_mutex);
713+
sk_psock_put(psock->sk, psock);
705714
}
706715

707716
struct sk_psock *sk_psock_init(struct sock *sk, int node)

0 commit comments

Comments
 (0)