In the Linux kernel, the following vulnerability has been resolved:
net: If sock is dead don't access sock's skwq in skstreamwaitmemory
Fixes the below NULL pointer dereference:
[...] [ 14.471200] Call Trace: [ 14.471562] <TASK> [ 14.471882] lockacquire+0x245/0x2e0 [ 14.472416] ? removewaitqueue+0x12/0x50 [ 14.473014] ? _rawspinlockirqsave+0x17/0x50 [ 14.473681] rawspinlockirqsave+0x3d/0x50 [ 14.474318] ? removewaitqueue+0x12/0x50 [ 14.474907] removewaitqueue+0x12/0x50 [ 14.475480] skstreamwaitmemory+0x20d/0x340 [ 14.476127] ? dowaitintrirq+0x80/0x80 [ 14.476704] dotcpsendpages+0x287/0x600 [ 14.477283] tcpbpfpush+0xab/0x260 [ 14.477817] tcpbpfsendmsgredir+0x297/0x500 [ 14.478461] ? localbhenableip+0x77/0xe0 [ 14.479096] tcpbpfsendverdict+0x105/0x470 [ 14.479729] tcpbpfsendmsg+0x318/0x4f0 [ 14.480311] socksendmsg+0x2d/0x40 [ 14.480822] syssendmsg+0x1b4/0x1c0 [ 14.481390] ? copymsghdrfromuser+0x62/0x80 [ 14.482048] _syssendmsg+0x78/0xb0 [ 14.482580] ? vmfinsertpfnprot+0x91/0x150 [ 14.483215] ? _dofault+0x2a/0x1a0 [ 14.483738] ? dofault+0x15e/0x5d0 [ 14.484246] ? _handlemmfault+0x56b/0x1040 [ 14.484874] ? lockisheldtype+0xdf/0x130 [ 14.485474] ? findheldlock+0x2d/0x90 [ 14.486046] ? _syssendmsg+0x41/0x70 [ 14.486587] _syssendmsg+0x41/0x70 [ 14.487105] ? intelpmudrainpebscore+0x350/0x350 [ 14.487822] dosyscall64+0x34/0x80 [ 14.488345] entrySYSCALL64after_hwframe+0x63/0xcd [...]
The test scenario has the following flow:
thread1 thread2 ----------- --------------- tcpbpfsendmsg tcpbpfsendverdict tcpbpfsendmsgredir sockclose tcpbpfpushlocked sockrelease tcpbpfpush //inetrelease dotcpsendpages sock->ops->release skstreamwaitmemory // tcpclose skwaitevent sk->skprot->close releasesock(sk); * locksock(sk); _tcpclose sockorphan(sk) sk->skwq = NULL releasesock locksock(sk); removewaitqueue(sksleep(sk), &wait); sksleep(sk) //NULL pointer dereference &rcudereferenceraw(sk->skwq)->wait
While waiting for memory in thread1, the socket is released with its wait queue because thread2 has closed it. This caused by tcpbpfsendverdict didn't increase the fcount of psock->skredir->sksocket->file in thread1.
We should check if SOCKDEAD flag is set on wakeup in skstreamwaitmemory before accessing the wait queue.