CVE-2026-93224: svcrdma: Fix unmatched rn_unregister on failed accept
In the Linux kernel, the following vulnerability has been resolved:
svcrdma: Fix unmatched rnunregister on failed accept
When svcrdmaaccept() takes the errout path before rpcrdmarnregister() has succeeded, the existing cleanup block calls rpcrdmarnunregister(dev, &newxprt->scrn) unconditionally. svcxprtrdma is kzalloc'd, so on that path scrn.rnindex is 0 and scrn.rndone is NULL; the unregister therefore xaerase()s another caller's slot 0 and performs an unmatched krefput() on the rpcrdmadevice's rdkref.
The same errout also brackets the cleanup with svcxprtget()/ svcxprtput() around the krefinit() birth reference. The kref goes 1 -> 2 -> 1 and never reaches 0, so the svcxprtrdma (and the net/nstracker it pinned) is leaked on every failed accept.
rpcrdmarnregister() writes rn->rndone last, only after xaalloc() and krefget() have both succeeded, so rndone == NULL is a natural "never registered" sentinel. Guard rpcrdmarnunregister() with an early return when rndone is NULL, and clear rndone before the matching xaerase() so a repeated unregister is also a no-op.
With that guard in place, the accept errout drops the krefinit() birth reference via svcxprtput(), which dispatches svcrdmafree(). Teardown of scqp, scsqcq, scrqcq, and scpd runs under existing ISERR/NULL guards in svcrdmafree(); scrn is covered by the new rndone sentinel; sccmid is non-NULL on every errout path because svcrdmaaccept() dereferences it above the first goto errout.
svcxprtfree() drops the module reference associated with the freed transport, and svchandlexprt() drops its pre-acquired reference when ->xpoaccept() returns NULL. Take a replacement module reference before svcxprtput() so the two moduleput()s remain balanced.
The rndone guard also covers svcrdmafree()'s non-listener call to rpcrdmarnunregister() for transports whose register attempt failed or never ran.
Affected Software
Event History
Frequently Asked Questions
Which systems are affected by this cleanup flaw?
The issue is relevant when the svcrdma accept path fails before rpcrdma_rn_register() has completed successfully. In that state, the transport's rn_done field remains NULL.
What can happen when the failed-accept cleanup runs?
The unconditional unregister can erase another caller's slot 0 and perform an unmatched kref_put() on the rpcrdma device. The failed accept can also leak the svcxprt_rdma object and the net/ns_tracker it pins.
What state should prevent unregister from running?
A NULL rn_done indicates that registration never completed and should make unregister a no-op. Clearing rn_done before the matching xa_erase also makes a repeated unregister a no-op.