VYPR
Unrated severityNVD Advisory· Published May 27, 2026· Updated May 27, 2026

CVE-2026-46013

CVE-2026-46013

Description

In the Linux kernel, the following vulnerability has been resolved:

mm/memfd_luo: fix physical address conversion in put_folios cleanup

In memfd_luo_retrieve_folios()'s put_folios cleanup path:

1. kho_restore_folio() expects a phys_addr_t (physical address) but receives a raw PFN (pfolio->pfn). This causes kho_restore_page() to check the wrong physical address (pfn << PAGE_SHIFT instead of the actual physical address).

2. This loop lacks the !pfolio->pfn check that exists in the main retrieval loop and memfd_luo_discard_folios(), which could incorrectly process sparse file holes where pfn=0.

Fix by converting PFN to physical address with PFN_PHYS() and adding the !pfolio->pfn check, matching the pattern used elsewhere in this file.

This issue was identified by the AI review. https://sashiko.dev/#/patchset/20260323110747.193569-1-duanchenghao@kylinos.cn

Affected products

1

Patches

4
bd0d6bde286a

mm/memfd_luo: fix physical address conversion in put_folios cleanup

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitChenghao DuanMar 26, 2026Fixed in 7.0.4via kernel-cna
2 files changed · +12 4
  • mm/memfd_luo.c+6 2 modified
    diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
    index b8edb9f981d7ff..cfd665a5b78748 100644
    --- a/mm/memfd_luo.c
    +++ b/mm/memfd_luo.c
    @@ -466,8 +466,13 @@ put_folios:
     	 */
     	for (long j = i + 1; j < nr_folios; j++) {
     		const struct memfd_luo_folio_ser *pfolio = &folios_ser[j];
    +		phys_addr_t phys;
    +
    +		if (!pfolio->pfn)
    +			continue;
     
    -		folio = kho_restore_folio(pfolio->pfn);
    +		phys = PFN_PHYS(pfolio->pfn);
    +		folio = kho_restore_folio(phys);
     		if (folio)
     			folio_put(folio);
     	}
    -- 
    cgit 1.3-korg
    
    
    
  • mm/memfd_luo.c+6 2 modified
    diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
    index b8edb9f981d7ff..cfd665a5b78748 100644
    --- a/mm/memfd_luo.c
    +++ b/mm/memfd_luo.c
    @@ -466,8 +466,13 @@ put_folios:
     	 */
     	for (long j = i + 1; j < nr_folios; j++) {
     		const struct memfd_luo_folio_ser *pfolio = &folios_ser[j];
    +		phys_addr_t phys;
    +
    +		if (!pfolio->pfn)
    +			continue;
     
    -		folio = kho_restore_folio(pfolio->pfn);
    +		phys = PFN_PHYS(pfolio->pfn);
    +		folio = kho_restore_folio(phys);
     		if (folio)
     			folio_put(folio);
     	}
    -- 
    cgit 1.3-korg
    
    
    
3538f90ab89a

mm/memfd_luo: fix physical address conversion in put_folios cleanup

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitChenghao DuanMar 26, 2026Fixed in 7.1-rc1via kernel-cna
2 files changed · +12 4
  • mm/memfd_luo.c+6 2 modified
    diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
    index eb9f4cc0e7ae6a..eb611527dedd64 100644
    --- a/mm/memfd_luo.c
    +++ b/mm/memfd_luo.c
    @@ -484,8 +484,13 @@ put_folios:
     	 */
     	for (long j = i + 1; j < nr_folios; j++) {
     		const struct memfd_luo_folio_ser *pfolio = &folios_ser[j];
    +		phys_addr_t phys;
    +
    +		if (!pfolio->pfn)
    +			continue;
     
    -		folio = kho_restore_folio(pfolio->pfn);
    +		phys = PFN_PHYS(pfolio->pfn);
    +		folio = kho_restore_folio(phys);
     		if (folio)
     			folio_put(folio);
     	}
    -- 
    cgit 1.3-korg
    
    
    
  • mm/memfd_luo.c+6 2 modified
    diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
    index eb9f4cc0e7ae6a..eb611527dedd64 100644
    --- a/mm/memfd_luo.c
    +++ b/mm/memfd_luo.c
    @@ -484,8 +484,13 @@ put_folios:
     	 */
     	for (long j = i + 1; j < nr_folios; j++) {
     		const struct memfd_luo_folio_ser *pfolio = &folios_ser[j];
    +		phys_addr_t phys;
    +
    +		if (!pfolio->pfn)
    +			continue;
     
    -		folio = kho_restore_folio(pfolio->pfn);
    +		phys = PFN_PHYS(pfolio->pfn);
    +		folio = kho_restore_folio(phys);
     		if (folio)
     			folio_put(folio);
     	}
    -- 
    cgit 1.3-korg
    
    
    
3538f90ab89a

mm/memfd_luo: fix physical address conversion in put_folios cleanup

2 files changed · +12 4
  • mm/memfd_luo.c+6 2 modified
    diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
    index eb9f4cc0e7ae6a..eb611527dedd64 100644
    --- a/mm/memfd_luo.c
    +++ b/mm/memfd_luo.c
    @@ -484,8 +484,13 @@ put_folios:
     	 */
     	for (long j = i + 1; j < nr_folios; j++) {
     		const struct memfd_luo_folio_ser *pfolio = &folios_ser[j];
    +		phys_addr_t phys;
    +
    +		if (!pfolio->pfn)
    +			continue;
     
    -		folio = kho_restore_folio(pfolio->pfn);
    +		phys = PFN_PHYS(pfolio->pfn);
    +		folio = kho_restore_folio(phys);
     		if (folio)
     			folio_put(folio);
     	}
    -- 
    cgit 1.3-korg
    
    
    
  • mm/memfd_luo.c+6 2 modified
    diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
    index eb9f4cc0e7ae6a..eb611527dedd64 100644
    --- a/mm/memfd_luo.c
    +++ b/mm/memfd_luo.c
    @@ -484,8 +484,13 @@ put_folios:
     	 */
     	for (long j = i + 1; j < nr_folios; j++) {
     		const struct memfd_luo_folio_ser *pfolio = &folios_ser[j];
    +		phys_addr_t phys;
    +
    +		if (!pfolio->pfn)
    +			continue;
     
    -		folio = kho_restore_folio(pfolio->pfn);
    +		phys = PFN_PHYS(pfolio->pfn);
    +		folio = kho_restore_folio(phys);
     		if (folio)
     			folio_put(folio);
     	}
    -- 
    cgit 1.3-korg
    
    
    
bd0d6bde286a

mm/memfd_luo: fix physical address conversion in put_folios cleanup

2 files changed · +12 4
  • mm/memfd_luo.c+6 2 modified
    diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
    index b8edb9f981d7ff..cfd665a5b78748 100644
    --- a/mm/memfd_luo.c
    +++ b/mm/memfd_luo.c
    @@ -466,8 +466,13 @@ put_folios:
     	 */
     	for (long j = i + 1; j < nr_folios; j++) {
     		const struct memfd_luo_folio_ser *pfolio = &folios_ser[j];
    +		phys_addr_t phys;
    +
    +		if (!pfolio->pfn)
    +			continue;
     
    -		folio = kho_restore_folio(pfolio->pfn);
    +		phys = PFN_PHYS(pfolio->pfn);
    +		folio = kho_restore_folio(phys);
     		if (folio)
     			folio_put(folio);
     	}
    -- 
    cgit 1.3-korg
    
    
    
  • mm/memfd_luo.c+6 2 modified
    diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
    index b8edb9f981d7ff..cfd665a5b78748 100644
    --- a/mm/memfd_luo.c
    +++ b/mm/memfd_luo.c
    @@ -466,8 +466,13 @@ put_folios:
     	 */
     	for (long j = i + 1; j < nr_folios; j++) {
     		const struct memfd_luo_folio_ser *pfolio = &folios_ser[j];
    +		phys_addr_t phys;
    +
    +		if (!pfolio->pfn)
    +			continue;
     
    -		folio = kho_restore_folio(pfolio->pfn);
    +		phys = PFN_PHYS(pfolio->pfn);
    +		folio = kho_restore_folio(phys);
     		if (folio)
     			folio_put(folio);
     	}
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"In memfd_luo_retrieve_folios()'s put_folios cleanup path, a raw PFN is passed to kho_restore_folio() instead of a physical address, and the loop lacks a check for sparse file holes (pfn=0)."

Attack vector

An attacker who can trigger the put_folios cleanup path in memfd_luo_retrieve_folios() — for example by causing a partial failure during folio retrieval on a memfd_luo file — will cause kho_restore_folio() to receive a raw PFN instead of a physical address. This results in kho_restore_page() checking the wrong physical address (pfn &lt;&lt; PAGE_SHIFT rather than the actual physical address). Additionally, sparse file holes where pfn=0 are not skipped, potentially causing incorrect processing of those entries. The exact preconditions depend on the memfd_luo subsystem's error-handling paths, which the advisory does not fully detail.

Affected code

The bug is in mm/memfd_luo.c in the function memfd_luo_retrieve_folios(), specifically in the put_folios cleanup loop at around line 466 (or line 484 depending on the tree). The loop passes pfolio->pfn (a raw PFN) directly to kho_restore_folio() instead of converting it to a physical address, and lacks a !pfolio->pfn guard.

What the fix does

The patch adds a local phys_addr_t variable and converts the PFN to a physical address using PFN_PHYS(pfolio->pfn) before passing it to kho_restore_folio(). It also adds a !pfolio->pfn guard to skip sparse file holes, matching the pattern already used in the main retrieval loop and in memfd_luo_discard_folios(). These two changes ensure the correct physical address is checked and that zero-PFN entries are safely ignored.

Preconditions

  • inputThe attacker must trigger the put_folios cleanup path in memfd_luo_retrieve_folios(), which occurs on partial failure during folio retrieval.

Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

2

News mentions

0

No linked articles in our index yet.