[PATCH] mm/swapfile: validate swap offset in unuse_pte_range()

Deepanshu Kartikey posted 1 patch 11 hours ago
mm/swapfile.c | 2 ++
1 file changed, 2 insertions(+)
[PATCH] mm/swapfile: validate swap offset in unuse_pte_range()
Posted by Deepanshu Kartikey 11 hours ago
syzbot reported a WARNING in __swap_offset_to_cluster() triggered by
an invalid swap offset during swapoff:

  WARNING: CPU: 0 PID: 9861 at mm/swap.h:87 swap_cache_get_folio+0x186/0x200

The issue occurs because unuse_pte_range() extracts a swap entry from
a PTE and uses the offset without validating it is within bounds of
the swap area.

While the existing swp_type() check filters entries for other swap
areas, it cannot catch cases where the type bits are valid but the
offset is corrupted or stale - for example, due to a race condition
during PTE updates or memory corruption.

Add validation to ensure offset < si->max before using the swap entry.

Reported-by: syzbot+d7bc9ec4a100437aa7a2@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=d7bc9ec4a100437aa7a2
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
 mm/swapfile.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/mm/swapfile.c b/mm/swapfile.c
index 46d2008e4b99..fdf358df7116 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -2277,6 +2277,8 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
 			continue;
 
 		offset = swp_offset(entry);
+		if (offset >= si->max)
+			continue;
 		pte_unmap(pte);
 		pte = NULL;
 
-- 
2.43.0
Re: [PATCH] mm/swapfile: validate swap offset in unuse_pte_range()
Posted by YoungJun Park 10 hours ago
On Mon, Dec 01, 2025 at 03:07:41PM +0530, Deepanshu Kartikey wrote:
> syzbot reported a WARNING in __swap_offset_to_cluster() triggered by
> an invalid swap offset during swapoff:
> 
>   WARNING: CPU: 0 PID: 9861 at mm/swap.h:87 swap_cache_get_folio+0x186/0x200
> 
> The issue occurs because unuse_pte_range() extracts a swap entry from
> a PTE and uses the offset without validating it is within bounds of
> the swap area.
> 
> While the existing swp_type() check filters entries for other swap
> areas, it cannot catch cases where the type bits are valid but the
> offset is corrupted or stale - for example, due to a race condition
> during PTE updates or memory corruption.

Since this indicates a system-level issue (race/corruption), simply
avoiding the crash seems to be the goal here.
Should we at least add a WARN_ON or somthing? 
(Unless this corruption is expected 
to be reported elsewhere beforehand, in which case a silent skip is
fine as I think)

And it looks like swap_vma_readahead() share similar logic. 
The differene is intentionally allow entries from different swap
devices (to support vma readahead). 

If the offset is corrupted or invalid in those paths, wouldn't they
suffer from similar issues? Do you think we should add the boundary
check (offset >= si->max) there as well?

Best Regards,
Youngjun Park

> 
> Reported-by: syzbot+d7bc9ec4a100437aa7a2@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=d7bc9ec4a100437aa7a2
> Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
> ---
>  mm/swapfile.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/mm/swapfile.c b/mm/swapfile.c
> index 46d2008e4b99..fdf358df7116 100644
> --- a/mm/swapfile.c
> +++ b/mm/swapfile.c
> @@ -2277,6 +2277,8 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
>  			continue;
>  
>  		offset = swp_offset(entry);
> +		if (offset >= si->max)
> +			continue;
>  		pte_unmap(pte);
>  		pte = NULL;
>  
> -- 
> 2.43.0
Re: [PATCH] mm/swapfile: validate swap offset in unuse_pte_range()
Posted by Kairui Song 10 hours ago
On Mon, Dec 1, 2025 at 5:39 PM Deepanshu Kartikey <kartikey406@gmail.com> wrote:
>
> syzbot reported a WARNING in __swap_offset_to_cluster() triggered by
> an invalid swap offset during swapoff:
>
>   WARNING: CPU: 0 PID: 9861 at mm/swap.h:87 swap_cache_get_folio+0x186/0x200
>
> The issue occurs because unuse_pte_range() extracts a swap entry from
> a PTE and uses the offset without validating it is within bounds of
> the swap area.
>
> While the existing swp_type() check filters entries for other swap
> areas, it cannot catch cases where the type bits are valid but the
> offset is corrupted or stale - for example, due to a race condition
> during PTE updates or memory corruption.
>
> Add validation to ensure offset < si->max before using the swap entry.
>
> Reported-by: syzbot+d7bc9ec4a100437aa7a2@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=d7bc9ec4a100437aa7a2

Thanks for posting a fix!

But it seems the report is no longer triggering after the softleaf v3
change right?

Checking the syzbot link, last reproduce was 11/11, and my analyze was
posted here:
https://lore.kernel.org/all/CAMgjq7B=OizLoqKca3RjeV0h3p0GQ4uen+gDo3=WdAxQ1gfxnw@mail.gmail.com/

Then we have soft leaf v3 merged, and the warning is gone.

Your analyze:
> for example, due to a race condition
> during PTE updates or memory corruption.

What kind of race will lead to a invalid swap entry in the page table?
During swapoff no one can allocate any swap entry from this swap
device, and the swap type can't be used by other swap devices, so any
swap entry still in the page table must be a valid swap entry that was
allocated from this swap device before swapoff starts. And we are not
releasing the swap_map or si->cluster_info until swapoff is done, seem
no risk of OOB or UAF.

Memory corruption may cause it indeed, but memory corruption can also
cause failures in too many ways.

I'm not against a sanity check like this though, just want to double
check before we process.

> Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
> ---
>  mm/swapfile.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/mm/swapfile.c b/mm/swapfile.c
> index 46d2008e4b99..fdf358df7116 100644
> --- a/mm/swapfile.c
> +++ b/mm/swapfile.c
> @@ -2277,6 +2277,8 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
>                         continue;
>
>                 offset = swp_offset(entry);
> +               if (offset >= si->max)
> +                       continue;
>                 pte_unmap(pte);
>                 pte = NULL;
>
> --
> 2.43.0
>
>
Re: [PATCH] mm/swapfile: validate swap offset in unuse_pte_range()
Posted by Deepanshu Kartikey 10 hours ago
Hi Kairui,

Thank you for the detailed feedback!

> But it seems the report is no longer triggering after the softleaf v3
> change right? Checking the syzbot link, last reproduce was 11/11

You're right - I should have checked the syzbot status more carefully.
If softleaf v3 has already fixed this, then this patch may not be
needed.

Could you point me to which specific change in softleaf v3 fixed it?
I'd like to understand the root cause better.

> What kind of race will lead to a invalid swap entry in the page table?

You make a good point. I was speculating about possible causes without
concrete evidence.

> I'm not against a sanity check like this though, just want to double
> check before we process.

If softleaf v3 has fixed the underlying issue, I can withdraw this
patch. Or if you think a defensive sanity check still has value, I can
update the commit message to reflect that it is defensive hardening
rather than a fix for an active bug.

Please let me know how you'd like to proceed.

Thanks,
Deepanshu