mm: add arch-independent testcases for RODATA
authorJinbum Park <jinb.park7@gmail.com>
Mon, 27 Feb 2017 22:30:22 +0000 (14:30 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 28 Feb 2017 02:43:48 +0000 (18:43 -0800)
This patch makes arch-independent testcases for RODATA.  Both x86 and
x86_64 already have testcases for RODATA, But they are arch-specific
because using inline assembly directly.

And cacheflush.h is not a suitable location for rodata-test related
things.  Since they were in cacheflush.h, If someone change the state of
CONFIG_DEBUG_RODATA_TEST, It cause overhead of kernel build.

To solve the above issues, write arch-independent testcases and move it
to shared location.

[jinb.park7@gmail.com: fix config dependency]
Link: http://lkml.kernel.org/r/20170209131625.GA16954@pjb1027-Latitude-E5410
Link: http://lkml.kernel.org/r/20170129105436.GA9303@pjb1027-Latitude-E5410
Signed-off-by: Jinbum Park <jinb.park7@gmail.com>
Acked-by: Kees Cook <keescook@chromium.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Laura Abbott <labbott@redhat.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Valentin Rothberg <valentinrothberg@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/x86/Kconfig.debug
arch/x86/include/asm/cacheflush.h
arch/x86/kernel/Makefile
arch/x86/kernel/test_rodata.c [deleted file]
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
include/linux/rodata_test.h [new file with mode: 0644]
init/main.c
mm/Kconfig.debug
mm/Makefile
mm/rodata_test.c [new file with mode: 0644]

index c4cba00dbdee5ec48af1fff44adbe0f7e6582c26..63c1d13aaf9f99934c4e02a7ca6eb8ced4389056 100644 (file)
@@ -74,14 +74,6 @@ config EFI_PGT_DUMP
          issues with the mapping of the EFI runtime regions into that
          table.
 
-config DEBUG_RODATA_TEST
-       bool "Testcase for the marking rodata read-only"
-       default y
-       ---help---
-         This option enables a testcase for the setting rodata read-only
-         as well as for the change_page_attr() infrastructure.
-         If in doubt, say "N"
-
 config DEBUG_WX
        bool "Warn on W+X mappings at boot"
        select X86_PTDUMP_CORE
index 872877d930de5018b16f3029ba780cbd1058e2e2..e7e1942edff7360bb36be03bd0f097c2f04e34e7 100644 (file)
@@ -90,18 +90,8 @@ void clflush_cache_range(void *addr, unsigned int size);
 
 #define mmio_flush_range(addr, size) clflush_cache_range(addr, size)
 
-extern const int rodata_test_data;
 extern int kernel_set_to_readonly;
 void set_kernel_text_rw(void);
 void set_kernel_text_ro(void);
 
-#ifdef CONFIG_DEBUG_RODATA_TEST
-int rodata_test(void);
-#else
-static inline int rodata_test(void)
-{
-       return 0;
-}
-#endif
-
 #endif /* _ASM_X86_CACHEFLUSH_H */
index bdcdb3b3a219308544c0e669ca7dd9831f3f5146..84c00592d3598a2dc851202893bcc3e62cf8e669 100644 (file)
@@ -100,7 +100,6 @@ obj-$(CONFIG_HPET_TIMER)    += hpet.o
 obj-$(CONFIG_APB_TIMER)                += apb_timer.o
 
 obj-$(CONFIG_AMD_NB)           += amd_nb.o
-obj-$(CONFIG_DEBUG_RODATA_TEST)        += test_rodata.o
 obj-$(CONFIG_DEBUG_NMI_SELFTEST) += nmi_selftest.o
 
 obj-$(CONFIG_KVM_GUEST)                += kvm.o kvmclock.o
diff --git a/arch/x86/kernel/test_rodata.c b/arch/x86/kernel/test_rodata.c
deleted file mode 100644 (file)
index 222e84e..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * test_rodata.c: functional test for mark_rodata_ro function
- *
- * (C) Copyright 2008 Intel Corporation
- * Author: Arjan van de Ven <arjan@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2
- * of the License.
- */
-#include <asm/cacheflush.h>
-#include <asm/sections.h>
-#include <asm/asm.h>
-
-int rodata_test(void)
-{
-       unsigned long result;
-       unsigned long start, end;
-
-       /* test 1: read the value */
-       /* If this test fails, some previous testrun has clobbered the state */
-       if (!rodata_test_data) {
-               printk(KERN_ERR "rodata_test: test 1 fails (start data)\n");
-               return -ENODEV;
-       }
-
-       /* test 2: write to the variable; this should fault */
-       /*
-        * If this test fails, we managed to overwrite the data
-        *
-        * This is written in assembly to be able to catch the
-        * exception that is supposed to happen in the correct
-        * case
-        */
-
-       result = 1;
-       asm volatile(
-               "0:     mov %[zero],(%[rodata_test])\n"
-               "       mov %[zero], %[rslt]\n"
-               "1:\n"
-               ".section .fixup,\"ax\"\n"
-               "2:     jmp 1b\n"
-               ".previous\n"
-               _ASM_EXTABLE(0b,2b)
-               : [rslt] "=r" (result)
-               : [rodata_test] "r" (&rodata_test_data), [zero] "r" (0UL)
-       );
-
-
-       if (!result) {
-               printk(KERN_ERR "rodata_test: test data was not read only\n");
-               return -ENODEV;
-       }
-
-       /* test 3: check the value hasn't changed */
-       /* If this test fails, we managed to overwrite the data */
-       if (!rodata_test_data) {
-               printk(KERN_ERR "rodata_test: Test 3 fails (end data)\n");
-               return -ENODEV;
-       }
-       /* test 4: check if the rodata section is 4Kb aligned */
-       start = (unsigned long)__start_rodata;
-       end = (unsigned long)__end_rodata;
-       if (start & (PAGE_SIZE - 1)) {
-               printk(KERN_ERR "rodata_test: .rodata is not 4k aligned\n");
-               return -ENODEV;
-       }
-       if (end & (PAGE_SIZE - 1)) {
-               printk(KERN_ERR "rodata_test: .rodata end is not 4k aligned\n");
-               return -ENODEV;
-       }
-
-       return 0;
-}
index 928d657de8295d8f617f3e0b7ba69be81006be4b..2b4b53e6793f16b24d2e96199166c724d068f339 100644 (file)
@@ -864,9 +864,6 @@ static noinline int do_test_wp_bit(void)
        return flag;
 }
 
-const int rodata_test_data = 0xC3;
-EXPORT_SYMBOL_GPL(rodata_test_data);
-
 int kernel_set_to_readonly __read_mostly;
 
 void set_kernel_text_rw(void)
@@ -939,7 +936,6 @@ void mark_rodata_ro(void)
        set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT);
        printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
                size >> 10);
-       rodata_test();
 
 #ifdef CONFIG_CPA_DEBUG
        printk(KERN_INFO "Testing CPA: undo %lx-%lx\n", start, start + size);
index 97346f987ef20d80ab74eba8801f3475906a0c32..15173d37f399610caf8969fa942b17b175dd466b 100644 (file)
@@ -1000,9 +1000,6 @@ void __init mem_init(void)
        mem_init_print_info(NULL);
 }
 
-const int rodata_test_data = 0xC3;
-EXPORT_SYMBOL_GPL(rodata_test_data);
-
 int kernel_set_to_readonly;
 
 void set_kernel_text_rw(void)
@@ -1071,8 +1068,6 @@ void mark_rodata_ro(void)
        all_end = roundup((unsigned long)_brk_end, PMD_SIZE);
        set_memory_nx(text_end, (all_end - text_end) >> PAGE_SHIFT);
 
-       rodata_test();
-
 #ifdef CONFIG_CPA_DEBUG
        printk(KERN_INFO "Testing CPA: undo %lx-%lx\n", start, end);
        set_memory_rw(start, (end-start) >> PAGE_SHIFT);
diff --git a/include/linux/rodata_test.h b/include/linux/rodata_test.h
new file mode 100644 (file)
index 0000000..ea05f6c
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * rodata_test.h: functional test for mark_rodata_ro function
+ *
+ * (C) Copyright 2008 Intel Corporation
+ * Author: Arjan van de Ven <arjan@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#ifndef _RODATA_TEST_H
+#define _RODATA_TEST_H
+
+#ifdef CONFIG_DEBUG_RODATA_TEST
+extern const int rodata_test_data;
+void rodata_test(void);
+#else
+static inline void rodata_test(void) {}
+#endif
+
+#endif /* _RODATA_TEST_H */
index 6eb10ce472b9376ef87f59c46b36d78a7b0b65ad..47ea22d181effd47af32f8a908d39b0e5d3c4629 100644 (file)
@@ -82,6 +82,7 @@
 #include <linux/proc_ns.h>
 #include <linux/io.h>
 #include <linux/cache.h>
+#include <linux/rodata_test.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -935,9 +936,10 @@ __setup("rodata=", set_debug_rodata);
 #ifdef CONFIG_STRICT_KERNEL_RWX
 static void mark_readonly(void)
 {
-       if (rodata_enabled)
+       if (rodata_enabled) {
                mark_rodata_ro();
-       else
+               rodata_test();
+       } else
                pr_info("Kernel memory protection disabled.\n");
 }
 #else
index afcc550877fff9d81ef68b10fc28b1a21108f2c5..79d0fd13b5b3c1a826f472398fd60a1ae1cb5da6 100644 (file)
@@ -90,3 +90,9 @@ config DEBUG_PAGE_REF
          careful when enabling this feature because it adds about 30 KB to the
          kernel code.  However the runtime performance overhead is virtually
          nil until the tracepoints are actually enabled.
+
+config DEBUG_RODATA_TEST
+    bool "Testcase for the marking rodata read-only"
+    depends on STRICT_KERNEL_RWX
+    ---help---
+      This option enables a testcase for the setting rodata read-only.
index aa0aa17cb413ad223bac0fff88c15ec8ee3f8dd9..026f6a828a5023cdfa1b3239075a77c904409463 100644 (file)
@@ -85,6 +85,7 @@ obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o
 obj-$(CONFIG_HWPOISON_INJECT) += hwpoison-inject.o
 obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o
 obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.o
+obj-$(CONFIG_DEBUG_RODATA_TEST) += rodata_test.o
 obj-$(CONFIG_PAGE_OWNER) += page_owner.o
 obj-$(CONFIG_CLEANCACHE) += cleancache.o
 obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o
diff --git a/mm/rodata_test.c b/mm/rodata_test.c
new file mode 100644 (file)
index 0000000..0fd2167
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * rodata_test.c: functional test for mark_rodata_ro function
+ *
+ * (C) Copyright 2008 Intel Corporation
+ * Author: Arjan van de Ven <arjan@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+#include <linux/uaccess.h>
+#include <asm/sections.h>
+
+const int rodata_test_data = 0xC3;
+EXPORT_SYMBOL_GPL(rodata_test_data);
+
+void rodata_test(void)
+{
+       unsigned long start, end;
+       int zero = 0;
+
+       /* test 1: read the value */
+       /* If this test fails, some previous testrun has clobbered the state */
+       if (!rodata_test_data) {
+               pr_err("rodata_test: test 1 fails (start data)\n");
+               return;
+       }
+
+       /* test 2: write to the variable; this should fault */
+       if (!probe_kernel_write((void *)&rodata_test_data,
+                                               (void *)&zero, sizeof(zero))) {
+               pr_err("rodata_test: test data was not read only\n");
+               return;
+       }
+
+       /* test 3: check the value hasn't changed */
+       if (rodata_test_data == zero) {
+               pr_err("rodata_test: test data was changed\n");
+               return;
+       }
+
+       /* test 4: check if the rodata section is PAGE_SIZE aligned */
+       start = (unsigned long)__start_rodata;
+       end = (unsigned long)__end_rodata;
+       if (start & (PAGE_SIZE - 1)) {
+               pr_err("rodata_test: start of .rodata is not page size aligned\n");
+               return;
+       }
+       if (end & (PAGE_SIZE - 1)) {
+               pr_err("rodata_test: end of .rodata is not page size aligned\n");
+               return;
+       }
+
+       pr_info("rodata_test: all tests were successful\n");
+}