rawsock_release() marks the socket for shutdown and cancels tx_work, but a delayed data-exchange completion can still queue tx_work again before the socket is finally freed. The new worker can then access freed socket state. Check SEND_SHUTDOWN under the write-queue lock before requeueing transmit work in rawsock_data_exchange_complete(). Allow the completion to clear the scheduling state without scheduling new work after the release path has begun. A KASAN test with a deferred NFC completion callback reproduced the use-after-free on the unmodified kernel. The same injection-assisted sequence completed without a report after the change. Fixes: 23b7869c0fd08 ("NFC: add the NFC socket raw protocol") Assisted-by: ZCode:GLM-4 Signed-off-by: Yaohan Li --- net/nfc/rawsock.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c index f7d7a599fade7..efdbd512d4600 100644 --- a/net/nfc/rawsock.c +++ b/net/nfc/rawsock.c @@ -168,7 +168,13 @@ static void rawsock_data_exchange_complete(void *context, struct sk_buff *skb, goto error_skb; spin_lock_bh(&sk->sk_write_queue.lock); - if (!skb_queue_empty(&sk->sk_write_queue)) + /* + * The release path sets SEND_SHUTDOWN before cancel_work_sync(): + * once it is set, do not requeue tx_work - the socket may be freed + * right after the cancel returns. + */ + if (!skb_queue_empty(&sk->sk_write_queue) && + !(sk->sk_shutdown & SEND_SHUTDOWN)) schedule_work(&nfc_rawsock(sk)->tx_work); else nfc_rawsock(sk)->tx_work_scheduled = false; -- 2.34.1