[PATCH] ARM: mm: add testcases for RODATA

Jinbum Park jinb.park7 at gmail.com
Wed Jan 18 05:53:10 PST 2017


This patch adds testcases for the CONFIG_DEBUG_RODATA option.
It's similar to x86's testcases.
It tests read-only mapped data and page-size aligned rodata section.

Signed-off-by: Jinbum Park <jinb.park7 at gmail.com>
---
 arch/arm/Kconfig.debug            |  5 +++
 arch/arm/include/asm/cacheflush.h | 10 +++++
 arch/arm/mm/Makefile              |  1 +
 arch/arm/mm/init.c                |  6 +++
 arch/arm/mm/test_rodata.c         | 80 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 102 insertions(+)
 create mode 100644 arch/arm/mm/test_rodata.c

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index d83f7c3..511e5e1 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -1749,6 +1749,11 @@ config DEBUG_SET_MODULE_RONX
 	  against certain classes of kernel exploits.
 	  If in doubt, say "N".
 
+config DEBUG_RODATA_TEST
+	bool "Testcase for the marking rodata read-only"
+	---help---
+	  This option enables a testcase for the setting rodata read-only.
+
 source "drivers/hwtracing/coresight/Kconfig"
 
 endmenu
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index bdd283b..741e2e8 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -498,6 +498,16 @@ static inline void set_kernel_text_rw(void) { }
 static inline void set_kernel_text_ro(void) { }
 #endif
 
+#ifdef CONFIG_DEBUG_RODATA_TEST
+extern const int rodata_test_data;
+int rodata_test(void);
+#else
+static inline int rodata_test(void)
+{
+	return 0;
+}
+#endif
+
 void flush_uprobe_xol_access(struct page *page, unsigned long uaddr,
 			     void *kaddr, unsigned long len);
 
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index b3dea80..dbb76ff 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -15,6 +15,7 @@ endif
 obj-$(CONFIG_ARM_PTDUMP)	+= dump.o
 obj-$(CONFIG_MODULES)		+= proc-syms.o
 obj-$(CONFIG_DEBUG_VIRTUAL)	+= physaddr.o
+obj-$(CONFIG_DEBUG_RODATA_TEST)	+= test_rodata.o
 
 obj-$(CONFIG_ALIGNMENT_TRAP)	+= alignment.o
 obj-$(CONFIG_HIGHMEM)		+= highmem.o
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 4127f57..3c15f3b 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -716,6 +716,7 @@ void fix_kernmem_perms(void)
 int __mark_rodata_ro(void *unused)
 {
 	update_sections_early(ro_perms, ARRAY_SIZE(ro_perms));
+	rodata_test();
 	return 0;
 }
 
@@ -740,6 +741,11 @@ void set_kernel_text_ro(void)
 static inline void fix_kernmem_perms(void) { }
 #endif /* CONFIG_DEBUG_RODATA */
 
+#ifdef CONFIG_DEBUG_RODATA_TEST
+const int rodata_test_data = 0xC3;
+EXPORT_SYMBOL_GPL(rodata_test_data);
+#endif
+
 void free_tcmmem(void)
 {
 #ifdef CONFIG_HAVE_TCM
diff --git a/arch/arm/mm/test_rodata.c b/arch/arm/mm/test_rodata.c
new file mode 100644
index 0000000..133d092
--- /dev/null
+++ b/arch/arm/mm/test_rodata.c
@@ -0,0 +1,79 @@
+/*
+ * test_rodata.c: functional test for mark_rodata_ro function
+ *
+ * (C) Copyright 2017 Jinbum Park <jinb.park7 at gmail.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>
+
+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) {
+		pr_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:	str %[zero], [%[rodata_test]]\n"
+		"	mov %[rslt], %[zero]\n"
+		"1:\n"
+		".pushsection .text.fixup,\"ax\"\n"
+		".align 2\n"
+		"2:\n"
+		"b 1b\n"
+		".popsection\n"
+		".pushsection __ex_table,\"a\"\n"
+		".align 3\n"
+		".long 0b, 2b\n"
+		".popsection\n"
+		: [rslt] "=r" (result)
+		: [zero] "r" (0UL), [rodata_test] "r" (&rodata_test_data)
+	);
+
+	if (!result) {
+		pr_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) {
+		pr_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)) {
+		pr_err("rodata_test: .rodata is not 4k aligned\n");
+		return -ENODEV;
+	}
+	if (end & (PAGE_SIZE - 1)) {
+		pr_err("rodata_test: .rodata end is not 4k aligned\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
-- 
1.9.1




More information about the linux-arm-kernel mailing list