Commit 2959a5f7 authored by Jinbum Park's avatar Jinbum Park Committed by Linus Torvalds

mm: add arch-independent testcases for RODATA

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-E5410Signed-off-by: default avatarJinbum Park <jinb.park7@gmail.com>
Acked-by: default avatarKees 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 8d85063a
...@@ -74,14 +74,6 @@ config EFI_PGT_DUMP ...@@ -74,14 +74,6 @@ config EFI_PGT_DUMP
issues with the mapping of the EFI runtime regions into that issues with the mapping of the EFI runtime regions into that
table. 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 config DEBUG_WX
bool "Warn on W+X mappings at boot" bool "Warn on W+X mappings at boot"
select X86_PTDUMP_CORE select X86_PTDUMP_CORE
......
...@@ -90,18 +90,8 @@ void clflush_cache_range(void *addr, unsigned int size); ...@@ -90,18 +90,8 @@ void clflush_cache_range(void *addr, unsigned int size);
#define mmio_flush_range(addr, size) clflush_cache_range(addr, size) #define mmio_flush_range(addr, size) clflush_cache_range(addr, size)
extern const int rodata_test_data;
extern int kernel_set_to_readonly; extern int kernel_set_to_readonly;
void set_kernel_text_rw(void); void set_kernel_text_rw(void);
void set_kernel_text_ro(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 */ #endif /* _ASM_X86_CACHEFLUSH_H */
...@@ -100,7 +100,6 @@ obj-$(CONFIG_HPET_TIMER) += hpet.o ...@@ -100,7 +100,6 @@ obj-$(CONFIG_HPET_TIMER) += hpet.o
obj-$(CONFIG_APB_TIMER) += apb_timer.o obj-$(CONFIG_APB_TIMER) += apb_timer.o
obj-$(CONFIG_AMD_NB) += amd_nb.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_DEBUG_NMI_SELFTEST) += nmi_selftest.o
obj-$(CONFIG_KVM_GUEST) += kvm.o kvmclock.o obj-$(CONFIG_KVM_GUEST) += kvm.o kvmclock.o
......
...@@ -864,9 +864,6 @@ static noinline int do_test_wp_bit(void) ...@@ -864,9 +864,6 @@ static noinline int do_test_wp_bit(void)
return flag; return flag;
} }
const int rodata_test_data = 0xC3;
EXPORT_SYMBOL_GPL(rodata_test_data);
int kernel_set_to_readonly __read_mostly; int kernel_set_to_readonly __read_mostly;
void set_kernel_text_rw(void) void set_kernel_text_rw(void)
...@@ -939,7 +936,6 @@ void mark_rodata_ro(void) ...@@ -939,7 +936,6 @@ void mark_rodata_ro(void)
set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT);
printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
size >> 10); size >> 10);
rodata_test();
#ifdef CONFIG_CPA_DEBUG #ifdef CONFIG_CPA_DEBUG
printk(KERN_INFO "Testing CPA: undo %lx-%lx\n", start, start + size); printk(KERN_INFO "Testing CPA: undo %lx-%lx\n", start, start + size);
......
...@@ -1000,9 +1000,6 @@ void __init mem_init(void) ...@@ -1000,9 +1000,6 @@ void __init mem_init(void)
mem_init_print_info(NULL); mem_init_print_info(NULL);
} }
const int rodata_test_data = 0xC3;
EXPORT_SYMBOL_GPL(rodata_test_data);
int kernel_set_to_readonly; int kernel_set_to_readonly;
void set_kernel_text_rw(void) void set_kernel_text_rw(void)
...@@ -1071,8 +1068,6 @@ void mark_rodata_ro(void) ...@@ -1071,8 +1068,6 @@ void mark_rodata_ro(void)
all_end = roundup((unsigned long)_brk_end, PMD_SIZE); all_end = roundup((unsigned long)_brk_end, PMD_SIZE);
set_memory_nx(text_end, (all_end - text_end) >> PAGE_SHIFT); set_memory_nx(text_end, (all_end - text_end) >> PAGE_SHIFT);
rodata_test();
#ifdef CONFIG_CPA_DEBUG #ifdef CONFIG_CPA_DEBUG
printk(KERN_INFO "Testing CPA: undo %lx-%lx\n", start, end); printk(KERN_INFO "Testing CPA: undo %lx-%lx\n", start, end);
set_memory_rw(start, (end-start) >> PAGE_SHIFT); set_memory_rw(start, (end-start) >> PAGE_SHIFT);
......
/*
* 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 */
...@@ -82,6 +82,7 @@ ...@@ -82,6 +82,7 @@
#include <linux/proc_ns.h> #include <linux/proc_ns.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/cache.h> #include <linux/cache.h>
#include <linux/rodata_test.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/bugs.h> #include <asm/bugs.h>
...@@ -935,9 +936,10 @@ __setup("rodata=", set_debug_rodata); ...@@ -935,9 +936,10 @@ __setup("rodata=", set_debug_rodata);
#ifdef CONFIG_STRICT_KERNEL_RWX #ifdef CONFIG_STRICT_KERNEL_RWX
static void mark_readonly(void) static void mark_readonly(void)
{ {
if (rodata_enabled) if (rodata_enabled) {
mark_rodata_ro(); mark_rodata_ro();
else rodata_test();
} else
pr_info("Kernel memory protection disabled.\n"); pr_info("Kernel memory protection disabled.\n");
} }
#else #else
......
...@@ -90,3 +90,9 @@ config DEBUG_PAGE_REF ...@@ -90,3 +90,9 @@ config DEBUG_PAGE_REF
careful when enabling this feature because it adds about 30 KB to the careful when enabling this feature because it adds about 30 KB to the
kernel code. However the runtime performance overhead is virtually kernel code. However the runtime performance overhead is virtually
nil until the tracepoints are actually enabled. 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.
...@@ -85,6 +85,7 @@ obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o ...@@ -85,6 +85,7 @@ obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o
obj-$(CONFIG_HWPOISON_INJECT) += hwpoison-inject.o obj-$(CONFIG_HWPOISON_INJECT) += hwpoison-inject.o
obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o
obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.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_PAGE_OWNER) += page_owner.o
obj-$(CONFIG_CLEANCACHE) += cleancache.o obj-$(CONFIG_CLEANCACHE) += cleancache.o
obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o
......
/* /*
* test_rodata.c: functional test for mark_rodata_ro function * rodata_test.c: functional test for mark_rodata_ro function
* *
* (C) Copyright 2008 Intel Corporation * (C) Copyright 2008 Intel Corporation
* Author: Arjan van de Ven <arjan@linux.intel.com> * Author: Arjan van de Ven <arjan@linux.intel.com>
...@@ -9,67 +9,48 @@ ...@@ -9,67 +9,48 @@
* as published by the Free Software Foundation; version 2 * as published by the Free Software Foundation; version 2
* of the License. * of the License.
*/ */
#include <asm/cacheflush.h> #include <linux/uaccess.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/asm.h>
int rodata_test(void) const int rodata_test_data = 0xC3;
EXPORT_SYMBOL_GPL(rodata_test_data);
void rodata_test(void)
{ {
unsigned long result;
unsigned long start, end; unsigned long start, end;
int zero = 0;
/* test 1: read the value */ /* test 1: read the value */
/* If this test fails, some previous testrun has clobbered the state */ /* If this test fails, some previous testrun has clobbered the state */
if (!rodata_test_data) { if (!rodata_test_data) {
printk(KERN_ERR "rodata_test: test 1 fails (start data)\n"); pr_err("rodata_test: test 1 fails (start data)\n");
return -ENODEV; return;
} }
/* test 2: write to the variable; this should fault */ /* test 2: write to the variable; this should fault */
/* if (!probe_kernel_write((void *)&rodata_test_data,
* If this test fails, we managed to overwrite the data (void *)&zero, sizeof(zero))) {
* pr_err("rodata_test: test data was not read only\n");
* This is written in assembly to be able to catch the return;
* 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 */ /* test 3: check the value hasn't changed */
/* If this test fails, we managed to overwrite the data */ if (rodata_test_data == zero) {
if (!rodata_test_data) { pr_err("rodata_test: test data was changed\n");
printk(KERN_ERR "rodata_test: Test 3 fails (end data)\n"); return;
return -ENODEV;
} }
/* test 4: check if the rodata section is 4Kb aligned */
/* test 4: check if the rodata section is PAGE_SIZE aligned */
start = (unsigned long)__start_rodata; start = (unsigned long)__start_rodata;
end = (unsigned long)__end_rodata; end = (unsigned long)__end_rodata;
if (start & (PAGE_SIZE - 1)) { if (start & (PAGE_SIZE - 1)) {
printk(KERN_ERR "rodata_test: .rodata is not 4k aligned\n"); pr_err("rodata_test: start of .rodata is not page size aligned\n");
return -ENODEV; return;
} }
if (end & (PAGE_SIZE - 1)) { if (end & (PAGE_SIZE - 1)) {
printk(KERN_ERR "rodata_test: .rodata end is not 4k aligned\n"); pr_err("rodata_test: end of .rodata is not page size aligned\n");
return -ENODEV; return;
} }
return 0; pr_info("rodata_test: all tests were successful\n");
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment