All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC] XArray: fix index jumping backwards in xas_find()
@ 2026-08-17  1:04 syzbot
  2026-08-19  7:32 ` Krystian Kaniewski
  0 siblings, 1 reply; 2+ messages in thread
From: syzbot @ 2026-08-17  1:04 UTC (permalink / raw)
  To: syzkaller-upstream-moderation; +Cc: syzbot

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: syzbot+b72767277f29b6407083@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=b72767277f29b6407083
Link: https://syzkaller.appspot.com/ai_job?id=608570d2-1765-472d-a79b-ea5b0b3a226a
To: "Andrew Morton" <akpm@linux-foundation.org>
To: <linux-fsdevel@vger.kernel.org>
To: <linux-mm@kvack.org>
To: "Matthew Wilcox" <willy@infradead.org>
Cc: <linux-kernel@vger.kernel.org>

---
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 syzkaller@googlegroups.com.

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH RFC] XArray: fix index jumping backwards in xas_find()
  2026-08-17  1:04 [PATCH RFC] XArray: fix index jumping backwards in xas_find() syzbot
@ 2026-08-19  7:32 ` Krystian Kaniewski
  0 siblings, 0 replies; 2+ messages in thread
From: Krystian Kaniewski @ 2026-08-19  7:32 UTC (permalink / raw)
  To: syzbot, syzkaller-upstream-moderation; +Cc: syzbot

Resynchronize a non-leaf `xas_find()` cursor to the node slot containing
`xa_index` before the existing `xas_next_offset()` call. The current
`get_offset(xa_index - 1, node) + 1` assignment already moves past the
resynchronization slot, then the common increment moves once more. For an
order-7 entry covering indexes 0 through 127, an adjacent entry at 128, 
and a
walk beginning at 100, the current code changes the offset from 0 to 2 
and then
to 3. It skips the stable entry at offset 2. This violates the documented
forward-iteration contract without any concurrent modification.

Keep the shift-aware mismatch detection and the XArray-layer repair. Use the
slot containing `xa_index` as the non-leaf resynchronization point, then 
let the
existing helper perform the single forward step. Preserve the 
established leaf
boundary calculation. Add deterministic coverage for the order-7 adjacent
entry case and for splitting a multi-index entry after a lookup begins 
inside
it. Implement both cases in a new `check_multi_find_4()` helper in
`lib/test_xarray.c` and invoke it from `check_find()`.

Correct the commit message to describe the retained KASAN use-after-free in
`filemap_map_pages()` through `ptep_get()`, not a slab-out-of-bounds report.
Preserve the verified backward-index mechanism, the `Fixes` tag, syzbot 
links,
and the existing Gemini provenance tag. Do not change locking, public 
APIs, or
caller error behavior.

On 8/17/2026 3:04 AM, syzbot wrote:
> 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: syzbot+b72767277f29b6407083@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=b72767277f29b6407083
> Link: https://syzkaller.appspot.com/ai_job?id=608570d2-1765-472d-a79b-ea5b0b3a226a
> To: "Andrew Morton" <akpm@linux-foundation.org>
> To: <linux-fsdevel@vger.kernel.org>
> To: <linux-mm@kvack.org>
> To: "Matthew Wilcox" <willy@infradead.org>
> Cc: <linux-kernel@vger.kernel.org>
>
> ---
> 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

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-08-19  7:32 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-17  1:04 [PATCH RFC] XArray: fix index jumping backwards in xas_find() syzbot
2026-08-19  7:32 ` Krystian Kaniewski

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.