forked from mirrors/linux
		
	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
	
	 Jinbum Park
						Jinbum Park