All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dave Jones <davej@codemonkey.org.uk>
To: linux-nfs@vger.kernel.org
Cc: Olga Kornievskaia <okorniev@redhat.com>,
	Trond Myklebust <trond.myklebust@hammerspace.com>,
	Anna Schumaker <anna@kernel.org>
Subject: [PATCH] NFS: write_completion: dereference loop-local req, not hdr->req
Date: Mon, 18 May 2026 14:46:28 -0400	[thread overview]
Message-ID: <agtehErxs5HVJJb0@codemonkey.org.uk> (raw)

5d3869a41f36 ("NFS: fix writeback in presence of errors") introduced
a dereference of hdr->req->wb_lock_context in nfs_write_completion's
per-request loop.  hdr->req is set once at nfs_pgheader_init() time
and is not refcount-protected for the lifetime of the loop; when hdr
aggregates requests from multiple page groups (common under heavy
NFSv3 writeback), a parallel COMMIT on hdr->req's group can drop the
last reference and free it while the outer loop is still iterating
requests from other groups.  KASAN catches this as an 8-byte read at
offset +24 of a freed nfs_page slab object (wb_lock_context).

All requests in a given pgio share the same open_context, so reading
the loop-local req's wb_lock_context yields the same value and is
safe -- req is still on hdr->pages and holds its writeback kref
through the commit branch.

Caught with kasan:

BUG: KASAN: slab-use-after-free in nfs_write_completion+0x8f8/0xa50 [nfs]
Read of size 8 at addr ffff888118af2058 by task kworker/u16:16/122062
CPU: 2 UID: 0 PID: 122062 Comm: kworker/u16:16 Kdump: loaded Not tainted 7.1.0-rc4+ #ge05a759574b2 PREEMPT 
Workqueue: nfsiod rpc_async_release
Call Trace:
 <TASK>
 dump_stack_lvl+0xaf/0x100
 ? nfs_write_completion+0x8f8/0xa50 [nfs]
 print_report+0x157/0x4a1
 ? __virt_addr_valid+0x1fb/0x400
 ? nfs_write_completion+0x8f8/0xa50 [nfs]
 kasan_report+0xc2/0x190
 ? nfs_write_completion+0x8f8/0xa50 [nfs]
 nfs_write_completion+0x8f8/0xa50 [nfs]
 ? nfs_commit_release_pages+0xbd0/0xbd0 [nfs]
 ? lock_acquire+0x182/0x2e0
 ? process_one_work+0x937/0x1890
 ? nfs_pgio_header_alloc+0xd0/0xd0 [nfs]
 rpc_free_task+0xee/0x160
 rpc_async_release+0x5d/0xb0
 process_one_work+0x9b0/0x1890
 ? pwq_dec_nr_in_flight+0xed0/0xed0
 ? rpc_final_put_task+0x140/0x140
 worker_thread+0x75a/0x10a0
 ? process_one_work+0x1890/0x1890
 ? kthread+0x1af/0x4d0
 ? process_one_work+0x1890/0x1890
 kthread+0x3d3/0x4d0
 ? kthread_affine_node+0x2c0/0x2c0
 ret_from_fork+0x669/0xa50
 ? native_tss_update_io_bitmap+0x660/0x660
 ? __switch_to+0x9dd/0x1310
 ? kthread_affine_node+0x2c0/0x2c0
 ret_from_fork_asm+0x11/0x20
 </TASK>

Allocated by task 121997 on cpu 3 at 31643.290294s:
 kasan_save_stack+0x1e/0x40
 kasan_save_track+0x13/0x60
 __kasan_slab_alloc+0x62/0x70
 kmem_cache_alloc_noprof+0x1ab/0x4e0
 nfs_page_create+0x152/0x460 [nfs]
 nfs_page_create_from_folio+0x7e/0x210 [nfs]
 nfs_update_folio+0x7a9/0x32a0 [nfs]
 nfs_write_end+0x290/0xc60 [nfs]
 generic_perform_write+0x4ce/0x990
 nfs_file_write+0x6b3/0xce0 [nfs]
 vfs_write+0x63c/0xfa0
 ksys_write+0x122/0x240
 do_syscall_64+0xc3/0x13f0
 entry_SYSCALL_64_after_hwframe+0x4b/0x53

Freed by task 122046 on cpu 0 at 31647.037964s:
 kasan_save_stack+0x1e/0x40
 kasan_save_track+0x13/0x60
 kasan_save_free_info+0x37/0x60
 __kasan_slab_free+0x3b/0x60
 kmem_cache_free+0x11b/0x5a0
 nfs_page_group_destroy+0x13a/0x210 [nfs]
 nfs_unlock_and_release_request+0x64/0x90 [nfs]
 nfs_commit_release_pages+0x339/0xbd0 [nfs]
 nfs_commit_release+0x51/0xb0 [nfs]
 rpc_free_task+0xee/0x160
 rpc_async_release+0x5d/0xb0
 process_one_work+0x9b0/0x1890
 worker_thread+0x75a/0x10a0
 kthread+0x3d3/0x4d0
 ret_from_fork+0x669/0xa50
 ret_from_fork_asm+0x11/0x20

The buggy address belongs to the object at ffff888118af2040\x0a which belongs to the cache nfs_page of size 96
The buggy address is located 24 bytes inside of\x0a freed 96-byte region [ffff888118af2040, ffff888118af20a0)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x118af2
head: order:1 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x4000000000000040(head|zone=2)
page_type: f5(slab)
raw: 4000000000000040 ffff88818cf2c4c0 ffffea000e61b990 ffffea0004e7d110
raw: 0000000000000000 0000000800190019 00000000f5000000 0000000000000000
head: 4000000000000040 ffff88818cf2c4c0 ffffea000e61b990 ffffea0004e7d110
head: 0000000000000000 0000000800190019 00000000f5000000 0000000000000000
head: 4000000000000001 ffffffffffffff81 00000000ffffffff 00000000ffffffff
head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000002
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 1, migratetype Unmovable, gfp_mask 0xd20c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 121997, tgid 121997 (rsync), ts 31643290274577, free_ts 31642154777182
 post_alloc_hook+0xd1/0x100
 get_page_from_freelist+0xbad/0x2910
 __alloc_frozen_pages_noprof+0x1c6/0x4a0
 allocate_slab+0x330/0x620
 ___slab_alloc+0xe9/0x930
 kmem_cache_alloc_noprof+0x35b/0x4e0
 nfs_page_create+0x152/0x460 [nfs]
 nfs_page_create_from_folio+0x7e/0x210 [nfs]
 nfs_update_folio+0x7a9/0x32a0 [nfs]
 nfs_write_end+0x290/0xc60 [nfs]
 generic_perform_write+0x4ce/0x990
 nfs_file_write+0x6b3/0xce0 [nfs]
 vfs_write+0x63c/0xfa0
 ksys_write+0x122/0x240
 do_syscall_64+0xc3/0x13f0
 entry_SYSCALL_64_after_hwframe+0x4b/0x53
page last free pid 122202 tgid 122202 stack trace:
 __free_frozen_pages+0x6da/0xf30
 qlist_free_all+0x53/0x130
 kasan_quarantine_reduce+0x198/0x1f0
 __kasan_slab_alloc+0x46/0x70
 kmem_cache_alloc_noprof+0x1ab/0x4e0
 __alloc_object+0x2f/0x230
 __create_object+0x22/0x80
 kmem_cache_alloc_node_noprof+0x416/0x4d0
 __alloc_skb+0x146/0x6e0
 tcp_stream_alloc_skb+0x35/0x660
 tcp_sendmsg_locked+0x1746/0x4260
 tcp_sendmsg+0x2f/0x40
 inet_sendmsg+0x9e/0xe0
 __sock_sendmsg+0xd9/0x180
 sock_sendmsg+0x122/0x200
 xprt_sock_sendmsg+0x4ff/0x9a0

Memory state around the buggy address:
 ffff888118af1f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 fc fc fc
 ffff888118af1f80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff888118af2000: fc fc fc fc fc fc fc fc fa fb fb fb fb fb fb fb
                                                    ^
 ffff888118af2080: fb fb fb fb fc fc fc fc fc fc fc fc fc fc fc fc
 ffff888118af2100: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================


Fixes: 5d3869a41f36 ("NFS: fix writeback in presence of errors")
Cc: Olga Kornievskaia <okorniev@redhat.com>
Cc: Trond Myklebust <trond.myklebust@hammerspace.com>
Cc: Anna Schumaker <anna@kernel.org>
Cc: linux-nfs@vger.kernel.org
Reviewed-by Jeff Layton <jlayton@kernel.org>
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Dave Jones <davej@codemonkey.org.uk>
---
 fs/nfs/write.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 3134bb17f3e3..d7c399763ad9 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -927,7 +927,7 @@ static void nfs_write_completion(struct nfs_pgio_header *hdr)
 		}
 		if (nfs_write_need_commit(hdr)) {
 			struct nfs_open_context *ctx =
-				hdr->req->wb_lock_context->open_context;
+				req->wb_lock_context->open_context;
 
 			/* Reset wb_nio, since the write was successful. */
 			req->wb_nio = 0;


                 reply	other threads:[~2026-05-18 19:17 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=agtehErxs5HVJJb0@codemonkey.org.uk \
    --to=davej@codemonkey.org.uk \
    --cc=anna@kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=okorniev@redhat.com \
    --cc=trond.myklebust@hammerspace.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.