linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/4] Implement STRICT_MODULE_RWX for powerpc
@ 2019-10-04  7:50 Russell Currey
  2019-10-04  7:50 ` [PATCH v3 1/4] powerpc/mm: Implement set_memory() routines Russell Currey
                   ` (3 more replies)
  0 siblings, 4 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

It's been quite a while since the last iteration, there were a few
things to hunt down and fix.

The first was the way that I was updating PTEs was using set_pte_at()
unsafely - now, each page is updated by clearing -> flushing -> setting.
This should be generic across all MMUs, I know that there are some
potential inefficiencies - for example, Hash flushes the entire PID
regardless of the given page range - but I don't think it's a very big
deal.

The next was that there is an errant page that was tricky to hunt down,
it turned out to be that kprobes never get marked RO after creation,    
leading to (at least) one W+X page present in the kernel, even with both
STRICT_KERNEL_RWX and STRICT_MODULE_RWX on.

I added a debugfs handler to call ptdump_check_wx() to facilitate making
sure module RWX continues to work after boot.

There's more detail in the final patch about exactly how "on by default"
module RWX is, but it doesn't really matter until STRICT_KERNEL_RWX is  
on by default too.

Thanks to Nick Piggin, Michael Ellerman, Daniel Axtens, and others for  
helping.

Christophe, I did test this in qemu mac99 so hopefully it works for all
32bit, I'm sure you'll let me know if it doesn't.

Would appreciate an ack from Joel to enable this in skiroot_defconfig.

Russell Currey (4):
  powerpc/mm: Implement set_memory() routines
  powerpc/kprobes: Mark newly allocated probes as RO
  powerpc/mm/ptdump: debugfs handler for W+X checks at runtime
  powerpc: Enable STRICT_MODULE_RWX

 arch/powerpc/Kconfig                   |  2 +
 arch/powerpc/configs/skiroot_defconfig |  1 +
 arch/powerpc/include/asm/set_memory.h  | 32 ++++++++++++++
 arch/powerpc/kernel/kprobes.c          |  3 ++
 arch/powerpc/mm/Makefile               |  1 +
 arch/powerpc/mm/pageattr.c             | 60 ++++++++++++++++++++++++++
 arch/powerpc/mm/ptdump/ptdump.c        | 31 ++++++++++---
 7 files changed, 124 insertions(+), 6 deletions(-)
 create mode 100644 arch/powerpc/include/asm/set_memory.h
 create mode 100644 arch/powerpc/mm/pageattr.c

-- 
2.23.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [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

* [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

* [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

* [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 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 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

* 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

* 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

* 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

end of thread, other threads:[~2019-10-23  2:58 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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-23  2:56   ` Michael Ellerman
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
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
2019-10-04  7:50 ` [PATCH v3 4/4] powerpc: Enable STRICT_MODULE_RWX Russell Currey
2019-10-10 13:13   ` Daniel Axtens

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).