aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2016-02-17 17:41:14 -0500
committerIngo Molnar <mingo@kernel.org>2016-02-22 02:51:38 -0500
commit9ccaf77cf05915f51231d158abfd5448aedde758 (patch)
treed6cd4476921b59c2e20773ea585792a867dc328b
parentd2aa1acad22f1bdd0cfa67b3861800e392254454 (diff)
x86/mm: Always enable CONFIG_DEBUG_RODATA and remove the Kconfig option
This removes the CONFIG_DEBUG_RODATA option and makes it always enabled. This simplifies the code and also makes it clearer that read-only mapped memory is just as fundamental a security feature in kernel-space as it is in user-space. Suggested-by: Ingo Molnar <mingo@kernel.org> Signed-off-by: Kees Cook <keescook@chromium.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: David Brown <david.brown@linaro.org> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: Emese Revfy <re.emese@gmail.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Mathias Krause <minipli@googlemail.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: PaX Team <pageexec@freemail.hu> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: kernel-hardening@lists.openwall.com Cc: linux-arch <linux-arch@vger.kernel.org> Link: http://lkml.kernel.org/r/1455748879-21872-4-git-send-email-keescook@chromium.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/Kconfig3
-rw-r--r--arch/x86/Kconfig.debug18
-rw-r--r--arch/x86/include/asm/cacheflush.h5
-rw-r--r--arch/x86/include/asm/kvm_para.h7
-rw-r--r--arch/x86/include/asm/sections.h2
-rw-r--r--arch/x86/kernel/ftrace.c6
-rw-r--r--arch/x86/kernel/kgdb.c8
-rw-r--r--arch/x86/kernel/test_nx.c2
-rw-r--r--arch/x86/kernel/test_rodata.c2
-rw-r--r--arch/x86/kernel/vmlinux.lds.S25
-rw-r--r--arch/x86/mm/init_32.c3
-rw-r--r--arch/x86/mm/init_64.c3
-rw-r--r--arch/x86/mm/pageattr.c2
13 files changed, 25 insertions, 61 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index c46662f64c39..b1051057e5b0 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -303,6 +303,9 @@ config ARCH_SUPPORTS_UPROBES
303config FIX_EARLYCON_MEM 303config FIX_EARLYCON_MEM
304 def_bool y 304 def_bool y
305 305
306config DEBUG_RODATA
307 def_bool y
308
306config PGTABLE_LEVELS 309config PGTABLE_LEVELS
307 int 310 int
308 default 4 if X86_64 311 default 4 if X86_64
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 9b18ed97a8a2..7816b7b276f4 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -74,28 +74,16 @@ config EFI_PGT_DUMP
74 issues with the mapping of the EFI runtime regions into that 74 issues with the mapping of the EFI runtime regions into that
75 table. 75 table.
76 76
77config DEBUG_RODATA
78 bool "Write protect kernel read-only data structures"
79 default y
80 depends on DEBUG_KERNEL
81 ---help---
82 Mark the kernel read-only data as write-protected in the pagetables,
83 in order to catch accidental (and incorrect) writes to such const
84 data. This is recommended so that we can catch kernel bugs sooner.
85 If in doubt, say "Y".
86
87config DEBUG_RODATA_TEST 77config DEBUG_RODATA_TEST
88 bool "Testcase for the DEBUG_RODATA feature" 78 bool "Testcase for the marking rodata read-only"
89 depends on DEBUG_RODATA
90 default y 79 default y
91 ---help--- 80 ---help---
92 This option enables a testcase for the DEBUG_RODATA 81 This option enables a testcase for the setting rodata read-only
93 feature as well as for the change_page_attr() infrastructure. 82 as well as for the change_page_attr() infrastructure.
94 If in doubt, say "N" 83 If in doubt, say "N"
95 84
96config DEBUG_WX 85config DEBUG_WX
97 bool "Warn on W+X mappings at boot" 86 bool "Warn on W+X mappings at boot"
98 depends on DEBUG_RODATA
99 select X86_PTDUMP_CORE 87 select X86_PTDUMP_CORE
100 ---help--- 88 ---help---
101 Generate a warning if any W+X mappings are found at boot. 89 Generate a warning if any W+X mappings are found at boot.
diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h
index c8cff75c5b21..61518cf79437 100644
--- a/arch/x86/include/asm/cacheflush.h
+++ b/arch/x86/include/asm/cacheflush.h
@@ -91,15 +91,10 @@ void clflush_cache_range(void *addr, unsigned int size);
91 91
92#define mmio_flush_range(addr, size) clflush_cache_range(addr, size) 92#define mmio_flush_range(addr, size) clflush_cache_range(addr, size)
93 93
94#ifdef CONFIG_DEBUG_RODATA
95extern const int rodata_test_data; 94extern const int rodata_test_data;
96extern int kernel_set_to_readonly; 95extern int kernel_set_to_readonly;
97void set_kernel_text_rw(void); 96void set_kernel_text_rw(void);
98void set_kernel_text_ro(void); 97void set_kernel_text_ro(void);
99#else
100static inline void set_kernel_text_rw(void) { }
101static inline void set_kernel_text_ro(void) { }
102#endif
103 98
104#ifdef CONFIG_DEBUG_RODATA_TEST 99#ifdef CONFIG_DEBUG_RODATA_TEST
105int rodata_test(void); 100int rodata_test(void);
diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h
index c1adf33fdd0d..bc62e7cbf1b1 100644
--- a/arch/x86/include/asm/kvm_para.h
+++ b/arch/x86/include/asm/kvm_para.h
@@ -17,15 +17,8 @@ static inline bool kvm_check_and_clear_guest_paused(void)
17} 17}
18#endif /* CONFIG_KVM_GUEST */ 18#endif /* CONFIG_KVM_GUEST */
19 19
20#ifdef CONFIG_DEBUG_RODATA
21#define KVM_HYPERCALL \ 20#define KVM_HYPERCALL \
22 ALTERNATIVE(".byte 0x0f,0x01,0xc1", ".byte 0x0f,0x01,0xd9", X86_FEATURE_VMMCALL) 21 ALTERNATIVE(".byte 0x0f,0x01,0xc1", ".byte 0x0f,0x01,0xd9", X86_FEATURE_VMMCALL)
23#else
24/* On AMD processors, vmcall will generate a trap that we will
25 * then rewrite to the appropriate instruction.
26 */
27#define KVM_HYPERCALL ".byte 0x0f,0x01,0xc1"
28#endif
29 22
30/* For KVM hypercalls, a three-byte sequence of either the vmcall or the vmmcall 23/* For KVM hypercalls, a three-byte sequence of either the vmcall or the vmmcall
31 * instruction. The hypervisor may replace it with something else but only the 24 * instruction. The hypervisor may replace it with something else but only the
diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h
index 0a5242428659..13b6cdd0af57 100644
--- a/arch/x86/include/asm/sections.h
+++ b/arch/x86/include/asm/sections.h
@@ -7,7 +7,7 @@
7extern char __brk_base[], __brk_limit[]; 7extern char __brk_base[], __brk_limit[];
8extern struct exception_table_entry __stop___ex_table[]; 8extern struct exception_table_entry __stop___ex_table[];
9 9
10#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA) 10#if defined(CONFIG_X86_64)
11extern char __end_rodata_hpage_align[]; 11extern char __end_rodata_hpage_align[];
12#endif 12#endif
13 13
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 29408d6d6626..05c9e3f5b6d7 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -81,9 +81,9 @@ within(unsigned long addr, unsigned long start, unsigned long end)
81static unsigned long text_ip_addr(unsigned long ip) 81static unsigned long text_ip_addr(unsigned long ip)
82{ 82{
83 /* 83 /*
84 * On x86_64, kernel text mappings are mapped read-only with 84 * On x86_64, kernel text mappings are mapped read-only, so we use
85 * CONFIG_DEBUG_RODATA. So we use the kernel identity mapping instead 85 * the kernel identity mapping instead of the kernel text mapping
86 * of the kernel text mapping to modify the kernel text. 86 * to modify the kernel text.
87 * 87 *
88 * For 32bit kernels, these mappings are same and we can use 88 * For 32bit kernels, these mappings are same and we can use
89 * kernel identity mapping to modify code. 89 * kernel identity mapping to modify code.
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
index 44256a62702b..ed15cd486d06 100644
--- a/arch/x86/kernel/kgdb.c
+++ b/arch/x86/kernel/kgdb.c
@@ -750,9 +750,7 @@ void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
750int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) 750int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
751{ 751{
752 int err; 752 int err;
753#ifdef CONFIG_DEBUG_RODATA
754 char opc[BREAK_INSTR_SIZE]; 753 char opc[BREAK_INSTR_SIZE];
755#endif /* CONFIG_DEBUG_RODATA */
756 754
757 bpt->type = BP_BREAKPOINT; 755 bpt->type = BP_BREAKPOINT;
758 err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr, 756 err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr,
@@ -761,7 +759,6 @@ int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
761 return err; 759 return err;
762 err = probe_kernel_write((char *)bpt->bpt_addr, 760 err = probe_kernel_write((char *)bpt->bpt_addr,
763 arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE); 761 arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE);
764#ifdef CONFIG_DEBUG_RODATA
765 if (!err) 762 if (!err)
766 return err; 763 return err;
767 /* 764 /*
@@ -778,13 +775,12 @@ int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
778 if (memcmp(opc, arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE)) 775 if (memcmp(opc, arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE))
779 return -EINVAL; 776 return -EINVAL;
780 bpt->type = BP_POKE_BREAKPOINT; 777 bpt->type = BP_POKE_BREAKPOINT;
781#endif /* CONFIG_DEBUG_RODATA */ 778
782 return err; 779 return err;
783} 780}
784 781
785int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt) 782int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
786{ 783{
787#ifdef CONFIG_DEBUG_RODATA
788 int err; 784 int err;
789 char opc[BREAK_INSTR_SIZE]; 785 char opc[BREAK_INSTR_SIZE];
790 786
@@ -801,8 +797,8 @@ int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
801 if (err || memcmp(opc, bpt->saved_instr, BREAK_INSTR_SIZE)) 797 if (err || memcmp(opc, bpt->saved_instr, BREAK_INSTR_SIZE))
802 goto knl_write; 798 goto knl_write;
803 return err; 799 return err;
800
804knl_write: 801knl_write:
805#endif /* CONFIG_DEBUG_RODATA */
806 return probe_kernel_write((char *)bpt->bpt_addr, 802 return probe_kernel_write((char *)bpt->bpt_addr,
807 (char *)bpt->saved_instr, BREAK_INSTR_SIZE); 803 (char *)bpt->saved_instr, BREAK_INSTR_SIZE);
808} 804}
diff --git a/arch/x86/kernel/test_nx.c b/arch/x86/kernel/test_nx.c
index 3f92ce07e525..27538f183c3b 100644
--- a/arch/x86/kernel/test_nx.c
+++ b/arch/x86/kernel/test_nx.c
@@ -142,7 +142,6 @@ static int test_NX(void)
142 * by the error message 142 * by the error message
143 */ 143 */
144 144
145#ifdef CONFIG_DEBUG_RODATA
146 /* Test 3: Check if the .rodata section is executable */ 145 /* Test 3: Check if the .rodata section is executable */
147 if (rodata_test_data != 0xC3) { 146 if (rodata_test_data != 0xC3) {
148 printk(KERN_ERR "test_nx: .rodata marker has invalid value\n"); 147 printk(KERN_ERR "test_nx: .rodata marker has invalid value\n");
@@ -151,7 +150,6 @@ static int test_NX(void)
151 printk(KERN_ERR "test_nx: .rodata section is executable\n"); 150 printk(KERN_ERR "test_nx: .rodata section is executable\n");
152 ret = -ENODEV; 151 ret = -ENODEV;
153 } 152 }
154#endif
155 153
156#if 0 154#if 0
157 /* Test 4: Check if the .data section of a module is executable */ 155 /* Test 4: Check if the .data section of a module is executable */
diff --git a/arch/x86/kernel/test_rodata.c b/arch/x86/kernel/test_rodata.c
index 5ecbfe5099da..cb4a01b41e27 100644
--- a/arch/x86/kernel/test_rodata.c
+++ b/arch/x86/kernel/test_rodata.c
@@ -76,5 +76,5 @@ int rodata_test(void)
76} 76}
77 77
78MODULE_LICENSE("GPL"); 78MODULE_LICENSE("GPL");
79MODULE_DESCRIPTION("Testcase for the DEBUG_RODATA infrastructure"); 79MODULE_DESCRIPTION("Testcase for marking rodata as read-only");
80MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>"); 80MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>");
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 74e4bf11f562..fe133b710bef 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -41,29 +41,28 @@ ENTRY(phys_startup_64)
41jiffies_64 = jiffies; 41jiffies_64 = jiffies;
42#endif 42#endif
43 43
44#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA) 44#if defined(CONFIG_X86_64)
45/* 45/*
46 * On 64-bit, align RODATA to 2MB so that even with CONFIG_DEBUG_RODATA 46 * On 64-bit, align RODATA to 2MB so we retain large page mappings for
47 * we retain large page mappings for boundaries spanning kernel text, rodata 47 * boundaries spanning kernel text, rodata and data sections.
48 * and data sections.
49 * 48 *
50 * However, kernel identity mappings will have different RWX permissions 49 * However, kernel identity mappings will have different RWX permissions
51 * to the pages mapping to text and to the pages padding (which are freed) the 50 * to the pages mapping to text and to the pages padding (which are freed) the
52 * text section. Hence kernel identity mappings will be broken to smaller 51 * text section. Hence kernel identity mappings will be broken to smaller
53 * pages. For 64-bit, kernel text and kernel identity mappings are different, 52 * pages. For 64-bit, kernel text and kernel identity mappings are different,
54 * so we can enable protection checks that come with CONFIG_DEBUG_RODATA, 53 * so we can enable protection checks as well as retain 2MB large page
55 * as well as retain 2MB large page mappings for kernel text. 54 * mappings for kernel text.
56 */ 55 */
57#define X64_ALIGN_DEBUG_RODATA_BEGIN . = ALIGN(HPAGE_SIZE); 56#define X64_ALIGN_RODATA_BEGIN . = ALIGN(HPAGE_SIZE);
58 57
59#define X64_ALIGN_DEBUG_RODATA_END \ 58#define X64_ALIGN_RODATA_END \
60 . = ALIGN(HPAGE_SIZE); \ 59 . = ALIGN(HPAGE_SIZE); \
61 __end_rodata_hpage_align = .; 60 __end_rodata_hpage_align = .;
62 61
63#else 62#else
64 63
65#define X64_ALIGN_DEBUG_RODATA_BEGIN 64#define X64_ALIGN_RODATA_BEGIN
66#define X64_ALIGN_DEBUG_RODATA_END 65#define X64_ALIGN_RODATA_END
67 66
68#endif 67#endif
69 68
@@ -112,13 +111,11 @@ SECTIONS
112 111
113 EXCEPTION_TABLE(16) :text = 0x9090 112 EXCEPTION_TABLE(16) :text = 0x9090
114 113
115#if defined(CONFIG_DEBUG_RODATA)
116 /* .text should occupy whole number of pages */ 114 /* .text should occupy whole number of pages */
117 . = ALIGN(PAGE_SIZE); 115 . = ALIGN(PAGE_SIZE);
118#endif 116 X64_ALIGN_RODATA_BEGIN
119 X64_ALIGN_DEBUG_RODATA_BEGIN
120 RO_DATA(PAGE_SIZE) 117 RO_DATA(PAGE_SIZE)
121 X64_ALIGN_DEBUG_RODATA_END 118 X64_ALIGN_RODATA_END
122 119
123 /* Data */ 120 /* Data */
124 .data : AT(ADDR(.data) - LOAD_OFFSET) { 121 .data : AT(ADDR(.data) - LOAD_OFFSET) {
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index cb4ef3de61f9..2ebfbaf61142 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -871,7 +871,6 @@ static noinline int do_test_wp_bit(void)
871 return flag; 871 return flag;
872} 872}
873 873
874#ifdef CONFIG_DEBUG_RODATA
875const int rodata_test_data = 0xC3; 874const int rodata_test_data = 0xC3;
876EXPORT_SYMBOL_GPL(rodata_test_data); 875EXPORT_SYMBOL_GPL(rodata_test_data);
877 876
@@ -960,5 +959,3 @@ void mark_rodata_ro(void)
960 if (__supported_pte_mask & _PAGE_NX) 959 if (__supported_pte_mask & _PAGE_NX)
961 debug_checkwx(); 960 debug_checkwx();
962} 961}
963#endif
964
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 5488d21123bd..a40b755c67e3 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -1074,7 +1074,6 @@ void __init mem_init(void)
1074 mem_init_print_info(NULL); 1074 mem_init_print_info(NULL);
1075} 1075}
1076 1076
1077#ifdef CONFIG_DEBUG_RODATA
1078const int rodata_test_data = 0xC3; 1077const int rodata_test_data = 0xC3;
1079EXPORT_SYMBOL_GPL(rodata_test_data); 1078EXPORT_SYMBOL_GPL(rodata_test_data);
1080 1079
@@ -1166,8 +1165,6 @@ void mark_rodata_ro(void)
1166 debug_checkwx(); 1165 debug_checkwx();
1167} 1166}
1168 1167
1169#endif
1170
1171int kern_addr_valid(unsigned long addr) 1168int kern_addr_valid(unsigned long addr)
1172{ 1169{
1173 unsigned long above = ((long)addr) >> __VIRTUAL_MASK_SHIFT; 1170 unsigned long above = ((long)addr) >> __VIRTUAL_MASK_SHIFT;
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 2440814b0069..2450488f39ef 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -283,7 +283,7 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
283 __pa_symbol(__end_rodata) >> PAGE_SHIFT)) 283 __pa_symbol(__end_rodata) >> PAGE_SHIFT))
284 pgprot_val(forbidden) |= _PAGE_RW; 284 pgprot_val(forbidden) |= _PAGE_RW;
285 285
286#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA) 286#if defined(CONFIG_X86_64)
287 /* 287 /*
288 * Once the kernel maps the text as RO (kernel_set_to_readonly is set), 288 * Once the kernel maps the text as RO (kernel_set_to_readonly is set),
289 * kernel text mappings for the large page aligned text, rodata sections 289 * kernel text mappings for the large page aligned text, rodata sections