All Virtuozzo development lists (kernel + QEMU)
 help / color / mirror / Atom feed
From: Konstantin Khorenko <khorenko@virtuozzo.com>
To: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>,
	Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>,
	Vasileios Almpanis <vasileios.almpanis@virtuozzo.com>
Cc: devel@openvz.org
Subject: [Devel] [PATCH hci-8.1 3/7] oracle/mm: keep a MADV_DOEXEC range from becoming executable
Date: Wed, 14 Oct 2026 19:12:22 +0200	[thread overview]
Message-ID: <20261014-b4-prep-khorenko-vstor-149847-3-doexec-oracle-fixes-v1-3-e34cbe0d1440@virtuozzo.com> (raw)
In-Reply-To: <20261014-b4-prep-khorenko-vstor-149847-3-doexec-oracle-fixes-v1-0-e34cbe0d1440@virtuozzo.com>

MADV_DOEXEC rejects executable memory and MADV_DONTEXEC gives
VM_MAYEXEC back, so the intent is that a preserved range cannot become
executable. Two bugs break it:

- The OR-assignment in the MADV_DOEXEC case never drops VM_MAYEXEC, so
  mprotect(PROT_EXEC) on the range succeeds and exec carries the
  executable mapping into the new image.
- MADV_DONTEXEC sets VM_MAYEXEC unconditionally. A private /dev/zero
  mapping from a noexec mount, which do_mmap() created without
  VM_MAYEXEC, becomes executable after MADV_DOEXEC and MADV_DONTEXEC.

Clear the bit on MADV_DOEXEC and give back what do_mmap() grants such a
mapping whenever the mark goes: on MADV_DONTEXEC, and when exec or fork
drops it from a copy, which could otherwise never be made executable
again.

Fixes: 056724255f5f ("oracle/mm: introduce MADV_DOEXEC")
https://virtuozzo.atlassian.net/browse/VSTOR-150232

Feature: oracle/mm: MADV_DOEXEC madvise() flag
Assisted-by: LLM
Signed-off-by: Konstantin Khorenko <khorenko@virtuozzo.com>
---
 include/linux/mm.h |  1 +
 kernel/fork.c      |  4 +++-
 mm/madvise.c       |  5 +++--
 mm/mmap.c          | 13 ++++++++++++-
 4 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 9ebf3c6dcb978..91f305fd5c025 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2463,6 +2463,7 @@ struct page *vm_normal_page_pmd(struct vm_area_struct *vma, unsigned long addr,
 void zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
 		  unsigned long size);
 void zap_vma_mt(struct vm_area_struct *vma);
+vm_flags_t vma_doexec_mayexec(struct vm_area_struct *vma);
 void zap_page_range_single(struct vm_area_struct *vma, unsigned long address,
 			   unsigned long size, struct zap_details *details);
 static inline void zap_vma_pages(struct vm_area_struct *vma)
diff --git a/kernel/fork.c b/kernel/fork.c
index 92a7e9aae9278..25e87cdbeb073 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -715,7 +715,9 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
 			tmp->anon_vma = NULL;
 		} else if (anon_vma_fork(tmp, mpnt))
 			goto fail_nomem_anon_vma_fork;
-		vm_flags_clear(tmp, VM_LOCKED_MASK | VM_EXEC_KEEP);
+		if (tmp->vm_flags & VM_EXEC_KEEP)
+			vm_flags_mod(tmp, vma_doexec_mayexec(tmp), VM_EXEC_KEEP);
+		vm_flags_clear(tmp, VM_LOCKED_MASK);
 		/*
 		 * Copy/update hugetlb private vma information.
 		 */
diff --git a/mm/madvise.c b/mm/madvise.c
index 644057a2bbbb0..e6972bcfc9749 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -1318,7 +1318,7 @@ static int madvise_vma_behavior(struct vm_area_struct *vma,
 			error = -EINVAL;
 			goto out;
 		}
-		new_flags |= (new_flags & ~VM_MAYEXEC) | VM_EXEC_KEEP;
+		new_flags = (new_flags & ~VM_MAYEXEC) | VM_EXEC_KEEP;
 		break;
 	case MADV_DONTEXEC:
 		if (!VM_EXEC_KEEP) {
@@ -1326,7 +1326,8 @@ static int madvise_vma_behavior(struct vm_area_struct *vma,
 			goto out;
 		}
 		if (new_flags & VM_EXEC_KEEP)
-			new_flags = (new_flags & ~VM_EXEC_KEEP) | VM_MAYEXEC;
+			new_flags = (new_flags & ~VM_EXEC_KEEP) |
+				    vma_doexec_mayexec(vma);
 		break;
 	case MADV_DONTDUMP:
 		new_flags |= VM_DONTDUMP;
diff --git a/mm/mmap.c b/mm/mmap.c
index 52e971aee020f..69dd1514d750e 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1750,6 +1750,17 @@ int insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma)
 	return 0;
 }
 
+/*
+ * The VM_MAYEXEC that MADV_DOEXEC took from @vma, to give back when the mark
+ * goes: what do_mmap() grants such a mapping.
+ */
+vm_flags_t vma_doexec_mayexec(struct vm_area_struct *vma)
+{
+	if (vma->vm_file && path_noexec(&vma->vm_file->f_path))
+		return 0;
+	return VM_MAYEXEC;
+}
+
 /*
  * Duplicate an anonymous VMA into a new mm as part of preserving
  * it across exec.
@@ -1811,7 +1822,7 @@ int vma_dup(struct vm_area_struct *old_vma, struct mm_struct *mm)
 #else
 	ret = copy_page_range(vma, old_vma);
 #endif
-	vm_flags_clear(vma, VM_EXEC_KEEP);
+	vm_flags_mod(vma, vma_doexec_mayexec(vma), VM_EXEC_KEEP);
 
 	return ret;
 

-- 
2.43.0

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

  parent reply	other threads:[~2026-10-14 17:13 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-14 17:12 [Devel] [PATCH hci-8.1 0/7] mm, exec: fix the MADV_DOEXEC code we carry from Oracle Konstantin Khorenko
2026-10-14 17:12 ` [Devel] [PATCH hci-8.1 1/7] oracle/mm: take a file reference when preserving a file-backed VMA Konstantin Khorenko
2026-10-14 17:12 ` [Devel] [PATCH hci-8.1 2/7] oracle/mm: refuse MADV_DOEXEC on special mappings Konstantin Khorenko
2026-10-14 17:12 ` Konstantin Khorenko [this message]
2026-10-14 17:12 ` [Devel] [PATCH hci-8.1 4/7] oracle/exec, elf: look for the opt-in note in every PT_NOTE segment Konstantin Khorenko
2026-10-14 17:12 ` [Devel] [PATCH hci-8.1 5/7] exec: refuse to preserve memory across a privilege-changing exec Konstantin Khorenko
2026-10-14 17:12 ` [Devel] [PATCH hci-8.1 6/7] selftests/mm: check that a setuid exec refuses preserved memory Konstantin Khorenko
2026-10-14 17:12 ` [Devel] [PATCH hci-8.1 7/7] selftests/mm: check MADV_DOEXEC on /dev/zero and exec permission Konstantin Khorenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261014-b4-prep-khorenko-vstor-149847-3-doexec-oracle-fixes-v1-3-e34cbe0d1440@virtuozzo.com \
    --to=khorenko@virtuozzo.com \
    --cc=andrey.drobyshev@virtuozzo.com \
    --cc=devel@openvz.org \
    --cc=ptikhomirov@virtuozzo.com \
    --cc=vasileios.almpanis@virtuozzo.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.