[PATCH] lockd: fix use-after-free in nlmsvc_retry_blocked

Chuck Lever <[email protected]>
Newsgroups org.kernel.vger.linux-nfs
Message-ID <[email protected]>
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(). It holds no
reference of its own across that window, so the nlm_blocked list
reference is all that keeps the block alive. Unmounting the nfsd
filesystem while a lock request is still blocked reaches
nlmsvc_traverse_blocks(), which drops that reference.
nlmsvc_grant_blocked() does take a reference, but only after
nlm_blocked_lock has been dropped, so the block and the nlm_rqst
hanging off it can be freed before it runs.

  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. retry_deferred_block() borrows its
caller's reference as well, so this covers both arms of the loop.

Fixes: 0e4ac9d93515 ("lockd: handle fl_grant callbacks")
Reported-by: Shuangpeng Bai <[email protected]>
Closes: https://lore.kernel.org/linux-nfs/[email protected]/
Signed-off-by: Chuck Lever <[email protected]>
---
 fs/lockd/svclock.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index e628b5d35507..8d83283d3e21 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -1023,6 +1023,7 @@ nlmsvc_retry_blocked(struct svc_rqst *rqstp)
 			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 *rqstp)
 			retry_deferred_block(block);
 		} else
 			nlmsvc_grant_blocked(block);
+		nlmsvc_release_block(block);
 		spin_lock(&nlm_blocked_lock);
 	}
 	spin_unlock(&nlm_blocked_lock);
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.