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-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>
This commit is contained in:
parent
8d85063adb
commit
2959a5f726
11 changed files with 90 additions and 105 deletions
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
23
include/linux/rodata_test.h
Normal file
23
include/linux/rodata_test.h
Normal file
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
56
mm/rodata_test.c
Normal file
56
mm/rodata_test.c
Normal file
|
@ -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");
|
||||
}
|
Loading…
Reference in a new issue