* [PATCH v3 1/4] powerpc/mm: Implement set_memory() routines
2019-10-04 7:50 [PATCH v3 0/4] Implement STRICT_MODULE_RWX for powerpc Russell Currey
@ 2019-10-04 7:50 ` Russell Currey
2019-10-23 2:56 ` Michael Ellerman
2019-10-04 7:50 ` [PATCH v3 2/4] powerpc/kprobes: Mark newly allocated probes as RO Russell Currey
` (2 subsequent siblings)
3 siblings, 1 reply; 11+ messages in thread
From: Russell Currey @ 2019-10-04 7:50 UTC (permalink / raw)
To: linuxppc-dev; +Cc: ajd, npiggin, joel, Russell Currey, rashmica.g, dja
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, but the focus is on having a generic and safe implementation for
now.
Signed-off-by: Russell Currey <ruscur@russell.cc>
---
arch/powerpc/Kconfig | 1 +
arch/powerpc/include/asm/set_memory.h | 32 ++++++++++++++
arch/powerpc/mm/Makefile | 1 +
arch/powerpc/mm/pageattr.c | 60 +++++++++++++++++++++++++++
4 files changed, 94 insertions(+)
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 3e56c9c2f16e..8f7005f0d097 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -133,6 +133,7 @@ config PPC
select ARCH_HAS_PTE_SPECIAL
select ARCH_HAS_MEMBARRIER_CALLBACKS
select ARCH_HAS_SCALED_CPUTIME if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64
+ select ARCH_HAS_SET_MEMORY
select ARCH_HAS_STRICT_KERNEL_RWX if ((PPC_BOOK3S_64 || PPC32) && !RELOCATABLE && !HIBERNATION)
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_HAS_UACCESS_FLUSHCACHE
diff --git a/arch/powerpc/include/asm/set_memory.h b/arch/powerpc/include/asm/set_memory.h
new file mode 100644
index 000000000000..5230ddb2fefd
--- /dev/null
+++ b/arch/powerpc/include/asm/set_memory.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_SET_MEMORY_H
+#define _ASM_POWERPC_SET_MEMORY_H
+
+#define SET_MEMORY_RO 1
+#define SET_MEMORY_RW 2
+#define SET_MEMORY_NX 3
+#define SET_MEMORY_X 4
+
+int change_memory_attr(unsigned long addr, int numpages, int action);
+
+static inline int set_memory_ro(unsigned long addr, int numpages)
+{
+ return change_memory_attr(addr, numpages, SET_MEMORY_RO);
+}
+
+static inline int set_memory_rw(unsigned long addr, int numpages)
+{
+ return change_memory_attr(addr, numpages, SET_MEMORY_RW);
+}
+
+static inline int set_memory_nx(unsigned long addr, int numpages)
+{
+ return change_memory_attr(addr, numpages, SET_MEMORY_NX);
+}
+
+static inline int set_memory_x(unsigned long addr, int numpages)
+{
+ return change_memory_attr(addr, numpages, SET_MEMORY_X);
+}
+
+#endif
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 5e147986400d..d0a0bcbc9289 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_HIGHMEM) += highmem.o
obj-$(CONFIG_PPC_COPRO_BASE) += copro_fault.o
obj-$(CONFIG_PPC_PTDUMP) += ptdump/
obj-$(CONFIG_KASAN) += kasan/
+obj-$(CONFIG_ARCH_HAS_SET_MEMORY) += pageattr.o
diff --git a/arch/powerpc/mm/pageattr.c b/arch/powerpc/mm/pageattr.c
new file mode 100644
index 000000000000..fe3ecbfb8e10
--- /dev/null
+++ b/arch/powerpc/mm/pageattr.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * MMU-generic set_memory implementation for powerpc
+ *
+ * Author: Russell Currey <ruscur@russell.cc>
+ *
+ * Copyright 2019, IBM Corporation.
+ */
+
+#include <linux/mm.h>
+#include <linux/set_memory.h>
+
+#include <asm/mmu.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+static int change_page_attr(pte_t *ptep, unsigned long addr, void *data)
+{
+ int action = *((int *)data);
+ pte_t pte_val;
+
+ // invalidate the PTE so it's safe to modify
+ pte_val = ptep_get_and_clear(&init_mm, addr, ptep);
+ flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+
+ // modify the PTE bits as desired, then apply
+ switch (action) {
+ case SET_MEMORY_RO:
+ pte_val = pte_wrprotect(pte_val);
+ break;
+ case SET_MEMORY_RW:
+ pte_val = pte_mkwrite(pte_val);
+ break;
+ case SET_MEMORY_NX:
+ pte_val = pte_exprotect(pte_val);
+ break;
+ case SET_MEMORY_X:
+ pte_val = pte_mkexec(pte_val);
+ break;
+ default:
+ WARN_ON(true);
+ return -EINVAL;
+ }
+
+ set_pte_at(&init_mm, addr, ptep, pte_val);
+
+ return 0;
+}
+
+int change_memory_attr(unsigned long addr, int numpages, int action)
+{
+ unsigned long start = ALIGN_DOWN(addr, PAGE_SIZE);
+ unsigned long size = numpages * PAGE_SIZE;
+
+ if (!numpages)
+ return 0;
+
+ return apply_to_page_range(&init_mm, start, size, change_page_attr, &action);
+}
--
2.23.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v3 1/4] powerpc/mm: Implement set_memory() routines
2019-10-04 7:50 ` [PATCH v3 1/4] powerpc/mm: Implement set_memory() routines Russell Currey
@ 2019-10-23 2:56 ` Michael Ellerman
0 siblings, 0 replies; 11+ messages in thread
From: Michael Ellerman @ 2019-10-23 2:56 UTC (permalink / raw)
To: Russell Currey, linuxppc-dev; +Cc: ajd, npiggin, joel, rashmica.g, dja
Russell Currey <ruscur@russell.cc> writes:
> diff --git a/arch/powerpc/mm/pageattr.c b/arch/powerpc/mm/pageattr.c
> new file mode 100644
> index 000000000000..fe3ecbfb8e10
> --- /dev/null
> +++ b/arch/powerpc/mm/pageattr.c
> @@ -0,0 +1,60 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * MMU-generic set_memory implementation for powerpc
> + *
> + * Author: Russell Currey <ruscur@russell.cc>
Please don't add email addresses in new files, they just risk
bit-rotting, they're in the git log anyway.
> + *
> + * Copyright 2019, IBM Corporation.
> + */
> +
> +#include <linux/mm.h>
> +#include <linux/set_memory.h>
> +
> +#include <asm/mmu.h>
> +#include <asm/page.h>
> +#include <asm/pgtable.h>
> +
> +static int change_page_attr(pte_t *ptep, unsigned long addr, void *data)
> +{
> + int action = *((int *)data);
> + pte_t pte_val;
> +
> + // invalidate the PTE so it's safe to modify
> + pte_val = ptep_get_and_clear(&init_mm, addr, ptep);
> + flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
This doesn't work if for example we're setting the text mapping we're
executing from read-only, which in principle should work.
Or if another CPU is concurrently reading from a mapping we're marking
read-only.
I /think/ that's acceptable for all the current users, but I don't know
that for sure and it's not documented anywhere AFAICS.
At the very least it needs a big comment, and to be mentioned in the
change log.
Also there's no locking here, or in apply_to_page_range() AFAICS.
And because we're doing clear/modify/write, two CPUs that race doing eg.
set_memory_ro() and set_memory_nx() will potentially result in some PTEs
being marked permanently invalid, if one CPU sees the other CPUs clear
of the PTE before the write.
Again I'm not sure any current callers do that, but it's a bit fragile.
I think we can fix the race at least by taking the init_mm
page_table_lock around the clear/modify/write.
> + // modify the PTE bits as desired, then apply
> + switch (action) {
> + case SET_MEMORY_RO:
> + pte_val = pte_wrprotect(pte_val);
> + break;
> + case SET_MEMORY_RW:
> + pte_val = pte_mkwrite(pte_val);
> + break;
> + case SET_MEMORY_NX:
> + pte_val = pte_exprotect(pte_val);
> + break;
> + case SET_MEMORY_X:
> + pte_val = pte_mkexec(pte_val);
> + break;
> + default:
> + WARN_ON(true);
> + return -EINVAL;
> + }
> +
> + set_pte_at(&init_mm, addr, ptep, pte_val);
> +
> + return 0;
> +}
cheers
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 2/4] powerpc/kprobes: Mark newly allocated probes as RO
2019-10-04 7:50 [PATCH v3 0/4] Implement STRICT_MODULE_RWX for powerpc Russell Currey
2019-10-04 7:50 ` [PATCH v3 1/4] powerpc/mm: Implement set_memory() routines Russell Currey
@ 2019-10-04 7:50 ` Russell Currey
2019-10-14 2:22 ` Andrew Donnellan
2019-10-04 7:50 ` [PATCH v3 3/4] powerpc/mm/ptdump: debugfs handler for W+X checks at runtime Russell Currey
2019-10-04 7:50 ` [PATCH v3 4/4] powerpc: Enable STRICT_MODULE_RWX Russell Currey
3 siblings, 1 reply; 11+ messages in thread
From: Russell Currey @ 2019-10-04 7:50 UTC (permalink / raw)
To: linuxppc-dev; +Cc: ajd, npiggin, joel, Russell Currey, rashmica.g, dja
With CONFIG_STRICT_KERNEL_RWX=y and CONFIG_KPROBES=y, there will be one
W+X page at boot by default. This can be tested with
CONFIG_PPC_PTDUMP=y and CONFIG_PPC_DEBUG_WX=y set, and checking the
kernel log during boot.
powerpc doesn't implement its own alloc() for kprobes like other
architectures do, but we couldn't immediately mark RO anyway since we do
a memcpy to the page we allocate later. After that, nothing should be
allowed to modify the page, and write permissions are removed well
before the kprobe is armed.
Signed-off-by: Russell Currey <ruscur@russell.cc>
---
arch/powerpc/kernel/kprobes.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index 2d27ec4feee4..2610496de7c7 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -24,6 +24,7 @@
#include <asm/sstep.h>
#include <asm/sections.h>
#include <linux/uaccess.h>
+#include <linux/set_memory.h>
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -131,6 +132,8 @@ int arch_prepare_kprobe(struct kprobe *p)
(unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t));
}
+ set_memory_ro((unsigned long)p->ainsn.insn, 1);
+
p->ainsn.boostable = 0;
return ret;
}
--
2.23.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v3 2/4] powerpc/kprobes: Mark newly allocated probes as RO
2019-10-04 7:50 ` [PATCH v3 2/4] powerpc/kprobes: Mark newly allocated probes as RO Russell Currey
@ 2019-10-14 2:22 ` Andrew Donnellan
0 siblings, 0 replies; 11+ messages in thread
From: Andrew Donnellan @ 2019-10-14 2:22 UTC (permalink / raw)
To: Russell Currey, linuxppc-dev; +Cc: npiggin, joel, rashmica.g, dja
On 4/10/19 5:50 pm, Russell Currey wrote:
> With CONFIG_STRICT_KERNEL_RWX=y and CONFIG_KPROBES=y, there will be one
> W+X page at boot by default. This can be tested with
> CONFIG_PPC_PTDUMP=y and CONFIG_PPC_DEBUG_WX=y set, and checking the
> kernel log during boot.
>
> powerpc doesn't implement its own alloc() for kprobes like other
> architectures do, but we couldn't immediately mark RO anyway since we do
> a memcpy to the page we allocate later. After that, nothing should be
> allowed to modify the page, and write permissions are removed well
> before the kprobe is armed.
>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
Commit message nit: if there's an important detail in the summary line,
repeat that in the body of the commit message, those two paragraphs
don't tell you what the commit actually _does_, that's in the summary line
> ---
> arch/powerpc/kernel/kprobes.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
> index 2d27ec4feee4..2610496de7c7 100644
> --- a/arch/powerpc/kernel/kprobes.c
> +++ b/arch/powerpc/kernel/kprobes.c
> @@ -24,6 +24,7 @@
> #include <asm/sstep.h>
> #include <asm/sections.h>
> #include <linux/uaccess.h>
> +#include <linux/set_memory.h>
>
> DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
> DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
> @@ -131,6 +132,8 @@ int arch_prepare_kprobe(struct kprobe *p)
> (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t));
> }
>
> + set_memory_ro((unsigned long)p->ainsn.insn, 1);
> +
> p->ainsn.boostable = 0;
> return ret;
> }
>
--
Andrew Donnellan OzLabs, ADL Canberra
ajd@linux.ibm.com IBM Australia Limited
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 3/4] powerpc/mm/ptdump: debugfs handler for W+X checks at runtime
2019-10-04 7:50 [PATCH v3 0/4] Implement STRICT_MODULE_RWX for powerpc Russell Currey
2019-10-04 7:50 ` [PATCH v3 1/4] powerpc/mm: Implement set_memory() routines Russell Currey
2019-10-04 7:50 ` [PATCH v3 2/4] powerpc/kprobes: Mark newly allocated probes as RO Russell Currey
@ 2019-10-04 7:50 ` Russell Currey
2019-10-08 1:59 ` Daniel Axtens
2019-10-08 6:21 ` Christophe Leroy
2019-10-04 7:50 ` [PATCH v3 4/4] powerpc: Enable STRICT_MODULE_RWX Russell Currey
3 siblings, 2 replies; 11+ messages in thread
From: Russell Currey @ 2019-10-04 7:50 UTC (permalink / raw)
To: linuxppc-dev; +Cc: ajd, npiggin, joel, Russell Currey, rashmica.g, dja
Very rudimentary, just
echo 1 > [debugfs]/check_wx_pages
and check the kernel log. Useful for testing strict module RWX.
Also fixed a typo.
Signed-off-by: Russell Currey <ruscur@russell.cc>
---
arch/powerpc/mm/ptdump/ptdump.c | 31 +++++++++++++++++++++++++------
1 file changed, 25 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/mm/ptdump/ptdump.c b/arch/powerpc/mm/ptdump/ptdump.c
index 2f9ddc29c535..0547cd9f264e 100644
--- a/arch/powerpc/mm/ptdump/ptdump.c
+++ b/arch/powerpc/mm/ptdump/ptdump.c
@@ -4,7 +4,7 @@
*
* This traverses the kernel pagetables and dumps the
* information about the used sections of memory to
- * /sys/kernel/debug/kernel_pagetables.
+ * /sys/kernel/debug/kernel_page_tables.
*
* Derived from the arm64 implementation:
* Copyright (c) 2014, The Linux Foundation, Laura Abbott.
@@ -409,16 +409,35 @@ void ptdump_check_wx(void)
else
pr_info("Checked W+X mappings: passed, no W+X pages found\n");
}
+
+static int check_wx_debugfs_set(void *data, u64 val)
+{
+ if (val != 1ULL)
+ return -EINVAL;
+
+ ptdump_check_wx();
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(check_wx_fops, NULL, check_wx_debugfs_set, "%llu\n");
#endif
static int ptdump_init(void)
{
- struct dentry *debugfs_file;
-
populate_markers();
build_pgtable_complete_mask();
- debugfs_file = debugfs_create_file("kernel_page_tables", 0400, NULL,
- NULL, &ptdump_fops);
- return debugfs_file ? 0 : -ENOMEM;
+
+ if (!debugfs_create_file("kernel_page_tables", 0400, NULL,
+ NULL, &ptdump_fops))
+ return -ENOMEM;
+
+#ifdef CONFIG_PPC_DEBUG_WX
+ if (!debugfs_create_file("check_wx_pages", 0200, NULL,
+ NULL, &check_wx_fops))
+ return -ENOMEM;
+#endif
+
+ return 0;
}
device_initcall(ptdump_init);
--
2.23.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v3 3/4] powerpc/mm/ptdump: debugfs handler for W+X checks at runtime
2019-10-04 7:50 ` [PATCH v3 3/4] powerpc/mm/ptdump: debugfs handler for W+X checks at runtime Russell Currey
@ 2019-10-08 1:59 ` Daniel Axtens
2019-10-08 6:21 ` Christophe Leroy
1 sibling, 0 replies; 11+ messages in thread
From: Daniel Axtens @ 2019-10-08 1:59 UTC (permalink / raw)
To: Russell Currey, linuxppc-dev; +Cc: ajd, npiggin, joel, rashmica.g
Russell Currey <ruscur@russell.cc> writes:
> Very rudimentary, just
>
> echo 1 > [debugfs]/check_wx_pages
>
> and check the kernel log. Useful for testing strict module RWX.
I was very confused that this requires the boot-time testing to be
enabled to appear in debugfs. Could you change the kconfig snippet for
PPC_DEBUG_WX to mention the runtime testing?
Kind regards,
Daniel
>
> Also fixed a typo.
>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
> ---
> arch/powerpc/mm/ptdump/ptdump.c | 31 +++++++++++++++++++++++++------
> 1 file changed, 25 insertions(+), 6 deletions(-)
>
> diff --git a/arch/powerpc/mm/ptdump/ptdump.c b/arch/powerpc/mm/ptdump/ptdump.c
> index 2f9ddc29c535..0547cd9f264e 100644
> --- a/arch/powerpc/mm/ptdump/ptdump.c
> +++ b/arch/powerpc/mm/ptdump/ptdump.c
> @@ -4,7 +4,7 @@
> *
> * This traverses the kernel pagetables and dumps the
> * information about the used sections of memory to
> - * /sys/kernel/debug/kernel_pagetables.
> + * /sys/kernel/debug/kernel_page_tables.
> *
> * Derived from the arm64 implementation:
> * Copyright (c) 2014, The Linux Foundation, Laura Abbott.
> @@ -409,16 +409,35 @@ void ptdump_check_wx(void)
> else
> pr_info("Checked W+X mappings: passed, no W+X pages found\n");
> }
> +
> +static int check_wx_debugfs_set(void *data, u64 val)
> +{
> + if (val != 1ULL)
> + return -EINVAL;
> +
> + ptdump_check_wx();
> +
> + return 0;
> +}
> +
> +DEFINE_SIMPLE_ATTRIBUTE(check_wx_fops, NULL, check_wx_debugfs_set, "%llu\n");
> #endif
>
> static int ptdump_init(void)
> {
> - struct dentry *debugfs_file;
> -
> populate_markers();
> build_pgtable_complete_mask();
> - debugfs_file = debugfs_create_file("kernel_page_tables", 0400, NULL,
> - NULL, &ptdump_fops);
> - return debugfs_file ? 0 : -ENOMEM;
> +
> + if (!debugfs_create_file("kernel_page_tables", 0400, NULL,
> + NULL, &ptdump_fops))
> + return -ENOMEM;
> +
> +#ifdef CONFIG_PPC_DEBUG_WX
> + if (!debugfs_create_file("check_wx_pages", 0200, NULL,
> + NULL, &check_wx_fops))
> + return -ENOMEM;
> +#endif
> +
> + return 0;
> }
> device_initcall(ptdump_init);
> --
> 2.23.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 3/4] powerpc/mm/ptdump: debugfs handler for W+X checks at runtime
2019-10-04 7:50 ` [PATCH v3 3/4] powerpc/mm/ptdump: debugfs handler for W+X checks at runtime Russell Currey
2019-10-08 1:59 ` Daniel Axtens
@ 2019-10-08 6:21 ` Christophe Leroy
2019-10-14 2:36 ` Russell Currey
1 sibling, 1 reply; 11+ messages in thread
From: Christophe Leroy @ 2019-10-08 6:21 UTC (permalink / raw)
To: Russell Currey, linuxppc-dev; +Cc: ajd, npiggin, joel, rashmica.g, dja
Le 04/10/2019 à 09:50, Russell Currey a écrit :
> Very rudimentary, just
>
> echo 1 > [debugfs]/check_wx_pages
>
> and check the kernel log. Useful for testing strict module RWX.
>
> Also fixed a typo.
>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
> ---
> arch/powerpc/mm/ptdump/ptdump.c | 31 +++++++++++++++++++++++++------
> 1 file changed, 25 insertions(+), 6 deletions(-)
>
> diff --git a/arch/powerpc/mm/ptdump/ptdump.c b/arch/powerpc/mm/ptdump/ptdump.c
> index 2f9ddc29c535..0547cd9f264e 100644
> --- a/arch/powerpc/mm/ptdump/ptdump.c
> +++ b/arch/powerpc/mm/ptdump/ptdump.c
> @@ -4,7 +4,7 @@
> *
> * This traverses the kernel pagetables and dumps the
> * information about the used sections of memory to
> - * /sys/kernel/debug/kernel_pagetables.
> + * /sys/kernel/debug/kernel_page_tables.
> *
> * Derived from the arm64 implementation:
> * Copyright (c) 2014, The Linux Foundation, Laura Abbott.
> @@ -409,16 +409,35 @@ void ptdump_check_wx(void)
> else
> pr_info("Checked W+X mappings: passed, no W+X pages found\n");
> }
> +
> +static int check_wx_debugfs_set(void *data, u64 val)
> +{
> + if (val != 1ULL)
> + return -EINVAL;
> +
> + ptdump_check_wx();
> +
> + return 0;
> +}
> +
> +DEFINE_SIMPLE_ATTRIBUTE(check_wx_fops, NULL, check_wx_debugfs_set, "%llu\n");
> #endif
>
> static int ptdump_init(void)
> {
> - struct dentry *debugfs_file;
> -
> populate_markers();
> build_pgtable_complete_mask();
> - debugfs_file = debugfs_create_file("kernel_page_tables", 0400, NULL,
> - NULL, &ptdump_fops);
> - return debugfs_file ? 0 : -ENOMEM;
> +
> + if (!debugfs_create_file("kernel_page_tables", 0400, NULL,
> + NULL, &ptdump_fops))
> + return -ENOMEM;
> +
> +#ifdef CONFIG_PPC_DEBUG_WX
> + if (!debugfs_create_file("check_wx_pages", 0200, NULL,
> + NULL, &check_wx_fops))
> + return -ENOMEM;
> +#endif
The above seems to be completely independant from everything else in
ptdump_init().
Could we avoid this #ifdef block inside ptdump_init() by creating a
selfstanding device_initcall() for that through a function called
ptdump_check_wx_init() defined inside the same #ifdef block as
ptdump_check_wx() ?
Christophe
> +
> + return 0;
> }
> device_initcall(ptdump_init);
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 3/4] powerpc/mm/ptdump: debugfs handler for W+X checks at runtime
2019-10-08 6:21 ` Christophe Leroy
@ 2019-10-14 2:36 ` Russell Currey
0 siblings, 0 replies; 11+ messages in thread
From: Russell Currey @ 2019-10-14 2:36 UTC (permalink / raw)
To: Christophe Leroy, linuxppc-dev; +Cc: ajd, npiggin, joel, rashmica.g, dja
On Tue, 2019-10-08 at 08:21 +0200, Christophe Leroy wrote:
>
> Le 04/10/2019 à 09:50, Russell Currey a écrit :
> > Very rudimentary, just
> >
> > echo 1 > [debugfs]/check_wx_pages
> >
> > and check the kernel log. Useful for testing strict module RWX.
> >
> > Also fixed a typo.
> >
> > Signed-off-by: Russell Currey <ruscur@russell.cc>
> > ---
> > arch/powerpc/mm/ptdump/ptdump.c | 31 +++++++++++++++++++++++++---
> > ---
> > 1 file changed, 25 insertions(+), 6 deletions(-)
> >
> > diff --git a/arch/powerpc/mm/ptdump/ptdump.c
> > b/arch/powerpc/mm/ptdump/ptdump.c
> > index 2f9ddc29c535..0547cd9f264e 100644
> > --- a/arch/powerpc/mm/ptdump/ptdump.c
> > +++ b/arch/powerpc/mm/ptdump/ptdump.c
> > @@ -4,7 +4,7 @@
> > *
> > * This traverses the kernel pagetables and dumps the
> > * information about the used sections of memory to
> > - * /sys/kernel/debug/kernel_pagetables.
> > + * /sys/kernel/debug/kernel_page_tables.
> > *
> > * Derived from the arm64 implementation:
> > * Copyright (c) 2014, The Linux Foundation, Laura Abbott.
> > @@ -409,16 +409,35 @@ void ptdump_check_wx(void)
> > else
> > pr_info("Checked W+X mappings: passed, no W+X pages
> > found\n");
> > }
> > +
> > +static int check_wx_debugfs_set(void *data, u64 val)
> > +{
> > + if (val != 1ULL)
> > + return -EINVAL;
> > +
> > + ptdump_check_wx();
> > +
> > + return 0;
> > +}
> > +
> > +DEFINE_SIMPLE_ATTRIBUTE(check_wx_fops, NULL, check_wx_debugfs_set,
> > "%llu\n");
> > #endif
> >
> > static int ptdump_init(void)
> > {
> > - struct dentry *debugfs_file;
> > -
> > populate_markers();
> > build_pgtable_complete_mask();
> > - debugfs_file = debugfs_create_file("kernel_page_tables", 0400,
> > NULL,
> > - NULL, &ptdump_fops);
> > - return debugfs_file ? 0 : -ENOMEM;
> > +
> > + if (!debugfs_create_file("kernel_page_tables", 0400, NULL,
> > + NULL, &ptdump_fops))
> > + return -ENOMEM;
> > +
> > +#ifdef CONFIG_PPC_DEBUG_WX
> > + if (!debugfs_create_file("check_wx_pages", 0200, NULL,
> > + NULL, &check_wx_fops))
> > + return -ENOMEM;
> > +#endif
>
> The above seems to be completely independant from everything else in
> ptdump_init().
>
> Could we avoid this #ifdef block inside ptdump_init() by creating a
> selfstanding device_initcall() for that through a function called
> ptdump_check_wx_init() defined inside the same #ifdef block as
> ptdump_check_wx() ?
Yes that would be nicer, thanks
>
> Christophe
>
> > +
> > + return 0;
> > }
> > device_initcall(ptdump_init);
> >
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 4/4] powerpc: Enable STRICT_MODULE_RWX
2019-10-04 7:50 [PATCH v3 0/4] Implement STRICT_MODULE_RWX for powerpc Russell Currey
` (2 preceding siblings ...)
2019-10-04 7:50 ` [PATCH v3 3/4] powerpc/mm/ptdump: debugfs handler for W+X checks at runtime Russell Currey
@ 2019-10-04 7:50 ` Russell Currey
2019-10-10 13:13 ` Daniel Axtens
3 siblings, 1 reply; 11+ messages in thread
From: Russell Currey @ 2019-10-04 7:50 UTC (permalink / raw)
To: linuxppc-dev; +Cc: ajd, npiggin, joel, Russell Currey, rashmica.g, dja
Whether STRICT_MODULE_RWX is enabled by default depends on powerpc
platform - in arch/Kconfig, STRICT_MODULE_RWX depends on
ARCH_OPTIONAL_KERNEL_RWX, which in arch/powerpc/Kconfig is selected if
ARCH_HAS_STRICT_KERNEL_RWX is selected, which is only true with
CONFIG_RELOCATABLE *disabled*.
defconfigs like skiroot_defconfig which turn STRICT_KERNEL_RWX on when
it is not already on by default also do NOT enable STRICT_MODULE_RWX
automatically, so it is explicitly enabled there in this patch.
Thus, on by default for ppc32 only. Module RWX doesn't provide a whole
lot of value with Kernel RWX off, but it doesn't hurt, either. The next
step is to make STRICT_KERNEL_RWX compatible with RELOCATABLE so it can
be on by default.
Signed-off-by: Russell Currey <ruscur@russell.cc>
---
arch/powerpc/Kconfig | 1 +
arch/powerpc/configs/skiroot_defconfig | 1 +
2 files changed, 2 insertions(+)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 8f7005f0d097..212c4d02be40 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -135,6 +135,7 @@ config PPC
select ARCH_HAS_SCALED_CPUTIME if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64
select ARCH_HAS_SET_MEMORY
select ARCH_HAS_STRICT_KERNEL_RWX if ((PPC_BOOK3S_64 || PPC32) && !RELOCATABLE && !HIBERNATION)
+ select ARCH_HAS_STRICT_MODULE_RWX
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_HAS_UACCESS_FLUSHCACHE
select ARCH_HAS_UACCESS_MCSAFE if PPC64
diff --git a/arch/powerpc/configs/skiroot_defconfig b/arch/powerpc/configs/skiroot_defconfig
index 1253482a67c0..719d899081b3 100644
--- a/arch/powerpc/configs/skiroot_defconfig
+++ b/arch/powerpc/configs/skiroot_defconfig
@@ -31,6 +31,7 @@ CONFIG_PERF_EVENTS=y
CONFIG_SLAB_FREELIST_HARDENED=y
CONFIG_JUMP_LABEL=y
CONFIG_STRICT_KERNEL_RWX=y
+CONFIG_STRICT_MODULE_RWX=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_SIG=y
--
2.23.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v3 4/4] powerpc: Enable STRICT_MODULE_RWX
2019-10-04 7:50 ` [PATCH v3 4/4] powerpc: Enable STRICT_MODULE_RWX Russell Currey
@ 2019-10-10 13:13 ` Daniel Axtens
0 siblings, 0 replies; 11+ messages in thread
From: Daniel Axtens @ 2019-10-10 13:13 UTC (permalink / raw)
To: Russell Currey, linuxppc-dev; +Cc: ajd, npiggin, joel, rashmica.g
Hi Russell,
Tested-by: Daniel Axtens <dja@axtens.net> # e6500
Because ptdump isn't quite working on book3e 64bit atm, I hacked it up
to print the raw PTE and the extracted flags. After loading a module, I
see the supervisor write bit set without module RWX, and it cleared with
module RWX. Modules still seem to work, which is good.
There is one small quirk which I mention only for completeness, and it
comes from arch/Kconfig:
config STRICT_MODULE_RWX
bool "Set loadable kernel module data as NX and text as RO" if ARCH_OPTIONAL_KERNEL_RWX
^^^^^^^^^^^^^^^^^^^^^^^^^^^
depends on ARCH_HAS_STRICT_MODULE_RWX && MODULES
default !ARCH_OPTIONAL_KERNEL_RWX || ARCH_OPTIONAL_KERNEL_RWX_DEFAULT
64bit Book3E doesn't have ARCH_OPTIONAL_KERNEL_RWX, so the option
doesn't show up in the config menus. Instead, we always get the default,
which is for it to be enabled. That's probably not a problem (so long as
I haven't missed some edge case), but it is a bit weird.
I don't think you can fix this without either hacking up arch/Kconfig
or actually implementing Strict RWX for book3e. I think both of those
are cures worse than the disease, so I think just let it be for now.
Regards,
Daniel
> Whether STRICT_MODULE_RWX is enabled by default depends on powerpc
> platform - in arch/Kconfig, STRICT_MODULE_RWX depends on
> ARCH_OPTIONAL_KERNEL_RWX, which in arch/powerpc/Kconfig is selected if
> ARCH_HAS_STRICT_KERNEL_RWX is selected, which is only true with
> CONFIG_RELOCATABLE *disabled*.
>
> defconfigs like skiroot_defconfig which turn STRICT_KERNEL_RWX on when
> it is not already on by default also do NOT enable STRICT_MODULE_RWX
> automatically, so it is explicitly enabled there in this patch.
>
> Thus, on by default for ppc32 only. Module RWX doesn't provide a whole
> lot of value with Kernel RWX off, but it doesn't hurt, either. The next
> step is to make STRICT_KERNEL_RWX compatible with RELOCATABLE so it can
> be on by default.
>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
> ---
> arch/powerpc/Kconfig | 1 +
> arch/powerpc/configs/skiroot_defconfig | 1 +
> 2 files changed, 2 insertions(+)
>
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 8f7005f0d097..212c4d02be40 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -135,6 +135,7 @@ config PPC
> select ARCH_HAS_SCALED_CPUTIME if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64
> select ARCH_HAS_SET_MEMORY
> select ARCH_HAS_STRICT_KERNEL_RWX if ((PPC_BOOK3S_64 || PPC32) && !RELOCATABLE && !HIBERNATION)
> + select ARCH_HAS_STRICT_MODULE_RWX
> select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
> select ARCH_HAS_UACCESS_FLUSHCACHE
> select ARCH_HAS_UACCESS_MCSAFE if PPC64
> diff --git a/arch/powerpc/configs/skiroot_defconfig b/arch/powerpc/configs/skiroot_defconfig
> index 1253482a67c0..719d899081b3 100644
> --- a/arch/powerpc/configs/skiroot_defconfig
> +++ b/arch/powerpc/configs/skiroot_defconfig
> @@ -31,6 +31,7 @@ CONFIG_PERF_EVENTS=y
> CONFIG_SLAB_FREELIST_HARDENED=y
> CONFIG_JUMP_LABEL=y
> CONFIG_STRICT_KERNEL_RWX=y
> +CONFIG_STRICT_MODULE_RWX=y
> CONFIG_MODULES=y
> CONFIG_MODULE_UNLOAD=y
> CONFIG_MODULE_SIG=y
> --
> 2.23.0
^ permalink raw reply [flat|nested] 11+ messages in thread