diff mbox series

[1/2] mm: Add arch hook to map_deny_write_exec()

Message ID 20240314094804.3094098-5-ardb+git@google.com (mailing list archive)
State New, archived
Headers show
Series arm64: Implement WXN using MDWE hook | expand

Commit Message

Ard Biesheuvel March 14, 2024, 9:48 a.m. UTC
From: Ard Biesheuvel <ardb@kernel.org>

Prepare for WXN support on arm64, which disallows mappings that are both
writable and executable at the same time altogether. This is less strict
than MemoryDenyWriteExecute [which disallows any transition that adds
PROT_EXEC], and is not configurable per-process so it is not a seamless
fit.

So reorganize the map_deny_write_exec() check so that we can deny W+X
mappings based on an arch defined policy, while only disallowing other
+X transitions if MDWE is really enabled for the process.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 include/linux/mman.h | 32 ++++++++++++++------
 1 file changed, 23 insertions(+), 9 deletions(-)
diff mbox series

Patch

diff --git a/include/linux/mman.h b/include/linux/mman.h
index dc7048824be8..de2e2f8b39da 100644
--- a/include/linux/mman.h
+++ b/include/linux/mman.h
@@ -162,6 +162,14 @@  calc_vm_flag_bits(unsigned long flags)
 
 unsigned long vm_commit_limit(void);
 
+#ifndef arch_deny_write_exec
+static inline bool arch_deny_write_exec(void)
+{
+	return false;
+}
+#define arch_deny_write_exec arch_deny_write_exec
+#endif
+
 /*
  * Denies creating a writable executable mapping or gaining executable permissions.
  *
@@ -180,19 +188,25 @@  unsigned long vm_commit_limit(void);
  *
  *	d)	mmap(PROT_READ | PROT_EXEC)
  *		mmap(PROT_READ | PROT_EXEC | PROT_BTI)
+ *
+ * In addition, permit the arch to implement a strict policy regarding
+ * PROT_WRITE|PROT_EXEC even if the MDWE prctl() is not in use.
  */
 static inline bool map_deny_write_exec(struct vm_area_struct *vma,  unsigned long vm_flags)
 {
-	if (!test_bit(MMF_HAS_MDWE, &current->mm->flags))
+	switch (vm_flags & (VM_WRITE | VM_EXEC)) {
+	case VM_EXEC:
+		if (vma->vm_flags & VM_EXEC)
+			return false;
+		break;
+	case VM_WRITE | VM_EXEC:
+		if (arch_deny_write_exec())
+			return true;
+		break;
+	default:
 		return false;
-
-	if ((vm_flags & VM_EXEC) && (vm_flags & VM_WRITE))
-		return true;
-
-	if (!(vma->vm_flags & VM_EXEC) && (vm_flags & VM_EXEC))
-		return true;
-
-	return false;
+	}
+	return test_bit(MMF_HAS_MDWE, &current->mm->flags);
 }
 
 #endif /* _LINUX_MMAN_H */