--- v12
+++ v10
@@ -1,56 +1,47 @@
From: Russell Currey <ruscur@russell.cc>
-The set_memory_{ro/rw/nx/x}() functions are required for
-STRICT_MODULE_RWX, and are generally useful primitives to have. This
-implementation is designed to be generic across powerpc's many MMUs.
+The set_memory_{ro/rw/nx/x}() functions are required for STRICT_MODULE_RWX,
+and are generally useful primitives to have. This implementation is
+designed to be completely generic across powerpc's many MMUs.
+
It's possible that this could be optimised to be faster for specific
-MMUs.
+MMUs, but the focus is on having a generic and safe implementation for
+now.
This implementation does not handle cases where the caller is attempting
to change the mapping of the page it is executing from, or if another
CPU is concurrently using the page being altered. These cases likely
shouldn't happen, but a more complex implementation with MMU-specific code
-could safely handle them.
+could safely handle them, so that is left as a TODO for now.
-On hash, the linear mapping is not kept in the linux pagetable, so this
+On hash the linear mapping is not kept in the linux pagetable, so this
will not change the protection if used on that range. Currently these
functions are not used on the linear map so just WARN for now.
-apply_to_existing_page_range() does not work on huge pages so for now
-disallow changing the protection of huge pages.
+These functions do nothing if STRICT_KERNEL_RWX is not enabled.
Reviewed-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
-[jpn: - Allow set memory functions to be used without Strict RWX
- - Hash: Disallow certain regions
- - Have change_page_attr() take function pointers to manipulate ptes
- - Radix: Add ptesync after set_pte_at()]
+[jpn: -rebase on next plus "powerpc/mm/64s: Allow STRICT_KERNEL_RWX again"
+ - WARN on hash linear map]
Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
---
v10: WARN if trying to change the hash linear map
-v11: - Update copywrite dates
- - Allow set memory functions to be used without Strict RWX
- - Hash: Disallow certain regions and add comment explaining why
- - Have change_page_attr() take function pointers to manipulate ptes
- - Clarify change_page_attr()'s comment
- - Radix: Add ptesync after set_pte_at()
-v12: - change_page_attr() back to taking an action value
- - disallow operating on huge pages
---
- arch/powerpc/Kconfig | 1 +
- arch/powerpc/include/asm/set_memory.h | 32 +++++++++
- arch/powerpc/mm/Makefile | 2 +-
- arch/powerpc/mm/pageattr.c | 100 ++++++++++++++++++++++++++
- 4 files changed, 134 insertions(+), 1 deletion(-)
+ arch/powerpc/Kconfig | 1 +
+ arch/powerpc/include/asm/set_memory.h | 32 ++++++++++
+ arch/powerpc/mm/Makefile | 2 +-
+ arch/powerpc/mm/pageattr.c | 88 +++++++++++++++++++++++++++
+ 4 files changed, 122 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/include/asm/set_memory.h
create mode 100644 arch/powerpc/mm/pageattr.c
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
-index 3f863dd21374..cce0a137b046 100644
+index fc7f5c5933e6..4498a27ac9db 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
-@@ -138,6 +138,7 @@ config PPC
+@@ -135,6 +135,7 @@ config PPC
select ARCH_HAS_MEMBARRIER_CALLBACKS
select ARCH_HAS_MEMBARRIER_SYNC_CORE
select ARCH_HAS_SCALED_CPUTIME if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64
@@ -97,7 +88,7 @@
+
+#endif
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
-index c3df3a8501d4..9142cf1fb0d5 100644
+index 3b4e9e4e25ea..d8a08abde1ae 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -5,7 +5,7 @@
@@ -108,23 +99,22 @@
+obj-y := fault.o mem.o pgtable.o mmap.o maccess.o pageattr.o \
init_$(BITS).o pgtable_$(BITS).o \
pgtable-frag.o ioremap.o ioremap_$(BITS).o \
- init-common.o mmu_context.o drmem.o \
+ init-common.o mmu_context.o drmem.o
diff --git a/arch/powerpc/mm/pageattr.c b/arch/powerpc/mm/pageattr.c
new file mode 100644
-index 000000000000..acfdde78e0fb
+index 000000000000..9efcb01088da
--- /dev/null
+++ b/arch/powerpc/mm/pageattr.c
-@@ -0,0 +1,100 @@
+@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * MMU-generic set_memory implementation for powerpc
+ *
-+ * Copyright 2019-2021, IBM Corporation.
++ * Copyright 2019, IBM Corporation.
+ */
+
+#include <linux/mm.h>
-+#include <linux/vmalloc.h>
+#include <linux/set_memory.h>
+
+#include <asm/mmu.h>
@@ -139,12 +129,13 @@
+ * 2. flush the TLB
+ * 3. install the new entry with the updated attributes
+ *
-+ * Invalidating the pte means there are situations where this will not work
-+ * when in theory it should.
-+ * For example:
-+ * - removing write from page whilst it is being executed
-+ * - setting a page read-only whilst it is being read by another CPU
++ * This is unsafe if the caller is attempting to change the mapping of the
++ * page it is executing from, or if another CPU is concurrently using the
++ * page being altered.
+ *
++ * TODO make the implementation resistant to this.
++ *
++ * NOTE: can be dangerous to call without STRICT_KERNEL_RWX
+ */
+static int change_page_attr(pte_t *ptep, unsigned long addr, void *data)
+{
@@ -163,7 +154,7 @@
+ pte = pte_wrprotect(pte);
+ break;
+ case SET_MEMORY_RW:
-+ pte = pte_mkwrite(pte_mkdirty(pte));
++ pte = pte_mkwrite(pte);
+ break;
+ case SET_MEMORY_NX:
+ pte = pte_exprotect(pte);
@@ -177,10 +168,6 @@
+ }
+
+ set_pte_at(&init_mm, addr, ptep, pte);
-+
-+ /* See ptesync comment in radix__set_pte_at() */
-+ if (radix_enabled())
-+ asm volatile("ptesync": : :"memory");
+ spin_unlock(&init_mm.page_table_lock);
+
+ return 0;
@@ -189,30 +176,22 @@
+int change_memory_attr(unsigned long addr, int numpages, long action)
+{
+ unsigned long start = ALIGN_DOWN(addr, PAGE_SIZE);
-+ unsigned long size = numpages * PAGE_SIZE;
++ unsigned long sz = numpages * PAGE_SIZE;
+
-+ if (!numpages)
++ if (!IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
+ return 0;
+
-+ if (WARN_ON_ONCE(is_vm_area_hugepages((void *)addr)))
-+ return -EINVAL;
++ if (numpages <= 0)
++ return 0;
+
+#ifdef CONFIG_PPC_BOOK3S_64
-+ /*
-+ * On hash, the linear mapping is not in the Linux page table so
-+ * apply_to_existing_page_range() will have no effect. If in the future
-+ * the set_memory_* functions are used on the linear map this will need
-+ * to be updated.
-+ */
-+ if (!radix_enabled()) {
-+ int region = get_region_id(addr);
-+
-+ if (WARN_ON_ONCE(region != VMALLOC_REGION_ID && region != IO_REGION_ID))
-+ return -EINVAL;
++ if (WARN_ON_ONCE(!radix_enabled() &&
++ get_region_id(addr) == LINEAR_MAP_REGION_ID)) {
++ return -1;
+ }
+#endif
+
-+ return apply_to_existing_page_range(&init_mm, start, size,
++ return apply_to_existing_page_range(&init_mm, start, sz,
+ change_page_attr, (void *)action);
+}
--