7.3-stable review patch. If anyone has any objections, please let me know. ------------------ From: Chuck Lever commit f5b7634f0f213299a07b461fb10385c8639a4ab8 upstream. nlmsvc_retry_blocked() examines the block at the head of nlm_blocked under nlm_blocked_lock, then releases the lock before calling nlmsvc_grant_blocked() or retry_deferred_block(). The nlm_blocked list reference is all that keeps the block alive across that window. nlmsvc_grant_blocked() does take one of its own, but not until after the lock has been dropped. Unmounting the nfsd filesystem while a lock request is still blocked reaches nlmsvc_traverse_blocks(), which drops the list reference and frees the block along with the nlm_rqst hanging off it. BUG: KASAN: slab-use-after-free in nlm_async_call+0xd6/0x230 Read of size 8 at addr ffff88811b04c808 by task lockd/8377 nlm_async_call+0xd6/0x230 nlmsvc_retry_blocked+0x61c/0x800 lockd+0x144/0x1c0 Freed by task 8392: nlmsvc_release_block+0x231/0x290 nlmsvc_traverse_blocks+0x139/0x1b0 nlm_traverse_files+0x1aa/0xa00 nlmsvc_free_host_resources+0x12/0x60 nlm_shutdown_hosts_net+0x127/0x280 lockd_down+0xd5/0x1c0 Take a reference before releasing nlm_blocked_lock and drop it once the retry has run. Fixes: 0e4ac9d93515 ("lockd: handle fl_grant callbacks") Cc: stable@vger.kernel.org Reported-by: Shuangpeng Bai Closes: https://lore.kernel.org/linux-nfs/20260818235808.3458075-1-shuangpeng.kernel@gmail.com/ Reviewed-by: Jeff Layton Link: https://patch.msgid.link/20260822-lockd-retry-blocked-uaf-v3-1-761661eae60c@kernel.org Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/lockd/svclock.c | 2 ++ 1 file changed, 2 insertions(+) --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -1023,6 +1023,7 @@ nlmsvc_retry_blocked(struct svc_rqst *rq timeout = block->b_when - jiffies; break; } + kref_get(&block->b_count); spin_unlock(&nlm_blocked_lock); dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", @@ -1033,6 +1034,7 @@ nlmsvc_retry_blocked(struct svc_rqst *rq retry_deferred_block(block); } else nlmsvc_grant_blocked(block); + nlmsvc_release_block(block); spin_lock(&nlm_blocked_lock); } spin_unlock(&nlm_blocked_lock);