[PATCH RFC] XArray: fix index jumping backwards in xas_find()

"syzbot" <[email protected]>
Newsgroups dev.linux.lists.syzbot
Message-ID <[email protected]>
A bug in the XArray iterator xas_find() causes the iterator's index
(xas->xa_index) to jump backwards when iterating over a multi-index entry
(like a THP) that resides in a non-leaf node and is concurrently split.

When iterating over a multi-index entry in a non-leaf node, xas_load() sets
xas->xa_offset to the base offset of the entry, but leaves xas->xa_index at
the requested index. When the caller subsequently wants to advance to the
next entry, xas_find() is called. xas_find() attempts to synchronize
xas->xa_offset with xas->xa_index before advancing. However, the fixup
logic was incorrectly restricted to leaf nodes (!xas->xa_node->shift).
Because the THP resides in a non-leaf node, the fixup is skipped.

As a result, xas_find() simply increments xas->xa_offset and recalculates
xas->xa_index based on this new offset. This causes xas->xa_index to jump
backwards. If the THP was concurrently split, the entry at the new offset
is a node pointer, so xas_find() descends into it and returns the folio at
the backwards index. The caller (filemap_map_pages()) then calculates the
PTE pointer based on this backwards index, resulting in an out-of-bounds
memory access.

For example, a KASAN slab-out-of-bounds read can be triggered in ptep_get()
via filemap_map_pages():

BUG: KASAN: slab-out-of-bounds in ptep_get include/linux/pgtable.h:495
[inline]
BUG: KASAN: slab-out-of-bounds in filemap_map_folio_range mm/filemap.c:3820
[inline]
BUG: KASAN: slab-out-of-bounds in filemap_map_pages+0x1100/0x2090
mm/filemap.c:3955
Read of size 8 at addr ffff88811b3b4a00 by task syz-executor411/5876

To fix this, remove the !xas->xa_node->shift restriction and use the
get_offset() helper to correctly calculate the offset for any node shift.
This ensures that xas->xa_offset is correctly synchronized with
xas->xa_index before advancing, regardless of the node's depth in the tree.

Fixes: b803b42823d0 ("xarray: Add XArray iterators")
Assisted-by: Gemini:gemini-3.6-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=b72767277f29b6407083
Link: https://syzkaller.appspot.com/ai_job?id=608570d2-1765-472d-a79b-ea5b0b3a226a
To: "Andrew Morton" <[email protected]>
To: <[email protected]>
To: <[email protected]>
To: "Matthew Wilcox" <[email protected]>
Cc: <[email protected]>

---
diff --git a/lib/xarray.c b/lib/xarray.c
index 9a8b49165..5695618bf 100644
--- a/lib/xarray.c
+++ b/lib/xarray.c
@@ -1406,9 +1406,8 @@ void *xas_find(struct xa_state *xas, unsigned long max)
 		entry = xas_load(xas);
 		if (entry || xas_not_node(xas->xa_node))
 			return entry;
-	} else if (!xas->xa_node->shift &&
-		    xas->xa_offset != (xas->xa_index & XA_CHUNK_MASK)) {
-		xas->xa_offset = ((xas->xa_index - 1) & XA_CHUNK_MASK) + 1;
+	} else if (xas->xa_offset != get_offset(xas->xa_index, xas->xa_node)) {
+		xas->xa_offset = get_offset(xas->xa_index - 1, xas->xa_node) + 1;
 	}
 
 	xas_next_offset(xas);


base-commit: 8d3ae59288f1e7d58d76558a6ee96d533bc5019f
-- 
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).

See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at [email protected].
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.