[Devel] [PATCH hci-8.1 3/8] oracle/mm: do not write protect COW mappings when preserving across exec
Konstantin Khorenko
khorenko at virtuozzo.com
Wed Oct 14 20:11:06 MSK 2026
From: Anthony Yznaga <anthony.yznaga at oracle.com>
A mapping that is pinned for DMA and preserved across exec can incur
a COW if write protected. The elevated reference count prevents reuse
of the mapped folio.
Orabug: 38029049
Suggested-by: Steve Sistare <steven.sistare at oracle.com>
Signed-off-by: Anthony Yznaga <anthony.yznaga at oracle.com>
Reviewed-by: Harry Yoo <harry.yoo at oracle.com>
(cherry picked from commit f2e56cc70e62fe07efb71a1e1c2360a78cba5aff)
Taken from Oracle linux-uek branch uek8/u2. Applied cleanly.
This is the fix for the ticket: a FOLL_LONGTERM-pinned anonymous page
preserved with MADV_DOEXEC was write-protected and lost
PageAnonExclusive in vma_dup(), so the first write in the new image
COWed it and the pin kept the old page. The pinned pages now stay
exclusive and writable in the new mm, and the old mm keeps its own. The
fixes that follow write protect both again and zap the old mm's mappings
right after the copy.
Fixes: 9e6d16a6c0a1 ("oracle/mm: introduce VM_EXEC_KEEP")
https://virtuozzo.atlassian.net/browse/VSTOR-150231
Feature: oracle/mm: MADV_DOEXEC madvise() flag
Assisted-by: LLM
Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
---
include/linux/rmap.h | 8 ++++----
mm/memory.c | 13 ++++++++++---
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index 5dc4cd6e4e2c9..01e46123ab2dc 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -431,22 +431,22 @@ static __always_inline int __folio_try_dup_anon_rmap(struct folio *folio,
}
if (!folio_test_large(folio)) {
- if (PageAnonExclusive(page))
+ if (PageAnonExclusive(page) && !is_exec_keep)
ClearPageAnonExclusive(page);
atomic_inc(&folio->_mapcount);
break;
}
do {
- if (PageAnonExclusive(page))
+ if (PageAnonExclusive(page) && !is_exec_keep)
ClearPageAnonExclusive(page);
atomic_inc(&page->_mapcount);
} while (page++, --nr_pages > 0);
atomic_add(orig_nr_pages, &folio->_large_mapcount);
break;
case RMAP_LEVEL_PMD:
- if (PageAnonExclusive(page)) {
- if (unlikely(maybe_pinned) && likely(!is_exec_keep))
+ if (PageAnonExclusive(page) && !is_exec_keep) {
+ if (unlikely(maybe_pinned))
return -EBUSY;
ClearPageAnonExclusive(page);
}
diff --git a/mm/memory.c b/mm/memory.c
index d4821379529bf..a240246762751 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -956,9 +956,15 @@ static __always_inline void __copy_present_ptes(struct vm_area_struct *dst_vma,
pte_t pte, unsigned long addr, int nr)
{
struct mm_struct *src_mm = src_vma->vm_mm;
+ bool is_exec_keep = !!(dst_vma->vm_flags & VM_EXEC_KEEP);
/* If it's a COW mapping, write protect it both processes. */
- if (is_cow_mapping(src_vma->vm_flags) && pte_write(pte)) {
+ /*
+ * But don't protect it if PTEs are being copied as part of preserving
+ * memory across exec since the page may be pinned for DMA and must not
+ * be COW'd.
+ */
+ if (is_cow_mapping(src_vma->vm_flags) && pte_write(pte) && !is_exec_keep) {
wrprotect_ptes(src_mm, addr, src_pte, nr);
pte = pte_wrprotect(pte);
}
@@ -991,6 +997,7 @@ copy_present_ptes(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma
bool any_writable;
fpb_t flags = 0;
int err, nr;
+ bool is_exec_keep = !!(dst_vma->vm_flags & VM_EXEC_KEEP);
page = vm_normal_page(src_vma, addr, pte);
if (unlikely(!page))
@@ -1019,7 +1026,7 @@ copy_present_ptes(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma
return -EAGAIN;
}
rss[MM_ANONPAGES] += nr;
- VM_WARN_ON_FOLIO(PageAnonExclusive(page), folio);
+ VM_WARN_ON_FOLIO(PageAnonExclusive(page) && !is_exec_keep, folio);
} else {
folio_dup_file_rmap_ptes(folio, page, nr);
rss[mm_counter_file(folio)] += nr;
@@ -1047,7 +1054,7 @@ copy_present_ptes(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma
return err ? err : 1;
}
rss[MM_ANONPAGES]++;
- VM_WARN_ON_FOLIO(PageAnonExclusive(page), folio);
+ VM_WARN_ON_FOLIO(PageAnonExclusive(page) && !is_exec_keep, folio);
} else {
folio_dup_file_rmap_pte(folio, page);
rss[mm_counter_file(folio)]++;
--
2.43.0
More information about the Devel
mailing list