Skip to content

Commit 1c2a936

Browse files
ryncsnakpm00
authored andcommitted
mm, swap: fix potential UAF issue for VMA readahead
Since commit 78524b0 ("mm, swap: avoid redundant swap device pinning"), the common helper for allocating and preparing a folio in the swap cache layer no longer tries to get a swap device reference internally, because all callers of __read_swap_cache_async are already holding a swap entry reference. The repeated swap device pinning isn't needed on the same swap device. Caller of VMA readahead is also holding a reference to the target entry's swap device, but VMA readahead walks the page table, so it might encounter swap entries from other devices, and call __read_swap_cache_async on another device without holding a reference to it. So it is possible to cause a UAF when swapoff of device A raced with swapin on device B, and VMA readahead tries to read swap entries from device A. It's not easy to trigger, but in theory, it could cause real issues. Make VMA readahead try to get the device reference first if the swap device is a different one from the target entry. Link: https://lkml.kernel.org/r/[email protected] Fixes: 78524b0 ("mm, swap: avoid redundant swap device pinning") Suggested-by: Huang Ying <[email protected]> Signed-off-by: Kairui Song <[email protected]> Acked-by: Chris Li <[email protected]> Cc: Baoquan He <[email protected]> Cc: Barry Song <[email protected]> Cc: Kemeng Shi <[email protected]> Cc: Nhat Pham <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 216158f commit 1c2a936

File tree

1 file changed

+13
-0
lines changed

1 file changed

+13
-0
lines changed

mm/swap_state.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,8 @@ static struct folio *swap_vma_readahead(swp_entry_t targ_entry, gfp_t gfp_mask,
748748

749749
blk_start_plug(&plug);
750750
for (addr = start; addr < end; ilx++, addr += PAGE_SIZE) {
751+
struct swap_info_struct *si = NULL;
752+
751753
if (!pte++) {
752754
pte = pte_offset_map(vmf->pmd, addr);
753755
if (!pte)
@@ -761,8 +763,19 @@ static struct folio *swap_vma_readahead(swp_entry_t targ_entry, gfp_t gfp_mask,
761763
continue;
762764
pte_unmap(pte);
763765
pte = NULL;
766+
/*
767+
* Readahead entry may come from a device that we are not
768+
* holding a reference to, try to grab a reference, or skip.
769+
*/
770+
if (swp_type(entry) != swp_type(targ_entry)) {
771+
si = get_swap_device(entry);
772+
if (!si)
773+
continue;
774+
}
764775
folio = __read_swap_cache_async(entry, gfp_mask, mpol, ilx,
765776
&page_allocated, false);
777+
if (si)
778+
put_swap_device(si);
766779
if (!folio)
767780
continue;
768781
if (page_allocated) {

0 commit comments

Comments
 (0)