diff options
-rw-r--r-- | arch/x86/include/asm/cacheflush.h | 5 | ||||
-rw-r--r-- | arch/x86/kernel/ftrace.c | 17 | ||||
-rw-r--r-- | arch/x86/kernel/vmiclock_32.c | 5 | ||||
-rw-r--r-- | arch/x86/mm/init_32.c | 35 | ||||
-rw-r--r-- | arch/x86/mm/init_64.c | 37 | ||||
-rw-r--r-- | arch/x86/mm/pageattr.c | 15 | ||||
-rw-r--r-- | include/linux/ftrace.h | 3 | ||||
-rw-r--r-- | kernel/trace/ftrace.c | 33 |
8 files changed, 130 insertions, 20 deletions
diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h index 2f8466540fb5..6145063cfe0e 100644 --- a/arch/x86/include/asm/cacheflush.h +++ b/arch/x86/include/asm/cacheflush.h | |||
@@ -104,6 +104,11 @@ void clflush_cache_range(void *addr, unsigned int size); | |||
104 | #ifdef CONFIG_DEBUG_RODATA | 104 | #ifdef CONFIG_DEBUG_RODATA |
105 | void mark_rodata_ro(void); | 105 | void mark_rodata_ro(void); |
106 | extern const int rodata_test_data; | 106 | extern const int rodata_test_data; |
107 | void set_kernel_text_rw(void); | ||
108 | void set_kernel_text_ro(void); | ||
109 | #else | ||
110 | static inline void set_kernel_text_rw(void) { } | ||
111 | static inline void set_kernel_text_ro(void) { } | ||
107 | #endif | 112 | #endif |
108 | 113 | ||
109 | #ifdef CONFIG_DEBUG_RODATA_TEST | 114 | #ifdef CONFIG_DEBUG_RODATA_TEST |
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index c2e057d9f88c..3925ec0184b1 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/list.h> | 19 | #include <linux/list.h> |
20 | 20 | ||
21 | #include <asm/cacheflush.h> | ||
21 | #include <asm/ftrace.h> | 22 | #include <asm/ftrace.h> |
22 | #include <linux/ftrace.h> | 23 | #include <linux/ftrace.h> |
23 | #include <asm/nops.h> | 24 | #include <asm/nops.h> |
@@ -26,6 +27,18 @@ | |||
26 | 27 | ||
27 | #ifdef CONFIG_DYNAMIC_FTRACE | 28 | #ifdef CONFIG_DYNAMIC_FTRACE |
28 | 29 | ||
30 | int ftrace_arch_code_modify_prepare(void) | ||
31 | { | ||
32 | set_kernel_text_rw(); | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | int ftrace_arch_code_modify_post_process(void) | ||
37 | { | ||
38 | set_kernel_text_ro(); | ||
39 | return 0; | ||
40 | } | ||
41 | |||
29 | union ftrace_code_union { | 42 | union ftrace_code_union { |
30 | char code[MCOUNT_INSN_SIZE]; | 43 | char code[MCOUNT_INSN_SIZE]; |
31 | struct { | 44 | struct { |
@@ -111,6 +124,10 @@ static void ftrace_mod_code(void) | |||
111 | */ | 124 | */ |
112 | mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode, | 125 | mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode, |
113 | MCOUNT_INSN_SIZE); | 126 | MCOUNT_INSN_SIZE); |
127 | |||
128 | /* if we fail, then kill any new writers */ | ||
129 | if (mod_code_status) | ||
130 | mod_code_write = 0; | ||
114 | } | 131 | } |
115 | 132 | ||
116 | void ftrace_nmi_enter(void) | 133 | void ftrace_nmi_enter(void) |
diff --git a/arch/x86/kernel/vmiclock_32.c b/arch/x86/kernel/vmiclock_32.c index c4c1f9e09402..bde106cae0a9 100644 --- a/arch/x86/kernel/vmiclock_32.c +++ b/arch/x86/kernel/vmiclock_32.c | |||
@@ -283,10 +283,13 @@ void __devinit vmi_time_ap_init(void) | |||
283 | #endif | 283 | #endif |
284 | 284 | ||
285 | /** vmi clocksource */ | 285 | /** vmi clocksource */ |
286 | static struct clocksource clocksource_vmi; | ||
286 | 287 | ||
287 | static cycle_t read_real_cycles(void) | 288 | static cycle_t read_real_cycles(void) |
288 | { | 289 | { |
289 | return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_REAL); | 290 | cycle_t ret = (cycle_t)vmi_timer_ops.get_cycle_counter(VMI_CYCLES_REAL); |
291 | return ret >= clocksource_vmi.cycle_last ? | ||
292 | ret : clocksource_vmi.cycle_last; | ||
290 | } | 293 | } |
291 | 294 | ||
292 | static struct clocksource clocksource_vmi = { | 295 | static struct clocksource clocksource_vmi = { |
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 2cef05074413..3eb2ed188a4c 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c | |||
@@ -1155,17 +1155,47 @@ static noinline int do_test_wp_bit(void) | |||
1155 | const int rodata_test_data = 0xC3; | 1155 | const int rodata_test_data = 0xC3; |
1156 | EXPORT_SYMBOL_GPL(rodata_test_data); | 1156 | EXPORT_SYMBOL_GPL(rodata_test_data); |
1157 | 1157 | ||
1158 | static int kernel_set_to_readonly; | ||
1159 | |||
1160 | void set_kernel_text_rw(void) | ||
1161 | { | ||
1162 | unsigned long start = PFN_ALIGN(_text); | ||
1163 | unsigned long size = PFN_ALIGN(_etext) - start; | ||
1164 | |||
1165 | if (!kernel_set_to_readonly) | ||
1166 | return; | ||
1167 | |||
1168 | pr_debug("Set kernel text: %lx - %lx for read write\n", | ||
1169 | start, start+size); | ||
1170 | |||
1171 | set_pages_rw(virt_to_page(start), size >> PAGE_SHIFT); | ||
1172 | } | ||
1173 | |||
1174 | void set_kernel_text_ro(void) | ||
1175 | { | ||
1176 | unsigned long start = PFN_ALIGN(_text); | ||
1177 | unsigned long size = PFN_ALIGN(_etext) - start; | ||
1178 | |||
1179 | if (!kernel_set_to_readonly) | ||
1180 | return; | ||
1181 | |||
1182 | pr_debug("Set kernel text: %lx - %lx for read only\n", | ||
1183 | start, start+size); | ||
1184 | |||
1185 | set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); | ||
1186 | } | ||
1187 | |||
1158 | void mark_rodata_ro(void) | 1188 | void mark_rodata_ro(void) |
1159 | { | 1189 | { |
1160 | unsigned long start = PFN_ALIGN(_text); | 1190 | unsigned long start = PFN_ALIGN(_text); |
1161 | unsigned long size = PFN_ALIGN(_etext) - start; | 1191 | unsigned long size = PFN_ALIGN(_etext) - start; |
1162 | 1192 | ||
1163 | #ifndef CONFIG_DYNAMIC_FTRACE | ||
1164 | /* Dynamic tracing modifies the kernel text section */ | ||
1165 | set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); | 1193 | set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); |
1166 | printk(KERN_INFO "Write protecting the kernel text: %luk\n", | 1194 | printk(KERN_INFO "Write protecting the kernel text: %luk\n", |
1167 | size >> 10); | 1195 | size >> 10); |
1168 | 1196 | ||
1197 | kernel_set_to_readonly = 1; | ||
1198 | |||
1169 | #ifdef CONFIG_CPA_DEBUG | 1199 | #ifdef CONFIG_CPA_DEBUG |
1170 | printk(KERN_INFO "Testing CPA: Reverting %lx-%lx\n", | 1200 | printk(KERN_INFO "Testing CPA: Reverting %lx-%lx\n", |
1171 | start, start+size); | 1201 | start, start+size); |
@@ -1174,7 +1204,6 @@ void mark_rodata_ro(void) | |||
1174 | printk(KERN_INFO "Testing CPA: write protecting again\n"); | 1204 | printk(KERN_INFO "Testing CPA: write protecting again\n"); |
1175 | set_pages_ro(virt_to_page(start), size>>PAGE_SHIFT); | 1205 | set_pages_ro(virt_to_page(start), size>>PAGE_SHIFT); |
1176 | #endif | 1206 | #endif |
1177 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
1178 | 1207 | ||
1179 | start += size; | 1208 | start += size; |
1180 | size = (unsigned long)__end_rodata - start; | 1209 | size = (unsigned long)__end_rodata - start; |
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index e6d36b490250..63fdc531601d 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c | |||
@@ -986,21 +986,48 @@ void free_initmem(void) | |||
986 | const int rodata_test_data = 0xC3; | 986 | const int rodata_test_data = 0xC3; |
987 | EXPORT_SYMBOL_GPL(rodata_test_data); | 987 | EXPORT_SYMBOL_GPL(rodata_test_data); |
988 | 988 | ||
989 | static int kernel_set_to_readonly; | ||
990 | |||
991 | void set_kernel_text_rw(void) | ||
992 | { | ||
993 | unsigned long start = PFN_ALIGN(_stext); | ||
994 | unsigned long end = PFN_ALIGN(__start_rodata); | ||
995 | |||
996 | if (!kernel_set_to_readonly) | ||
997 | return; | ||
998 | |||
999 | pr_debug("Set kernel text: %lx - %lx for read write\n", | ||
1000 | start, end); | ||
1001 | |||
1002 | set_memory_rw(start, (end - start) >> PAGE_SHIFT); | ||
1003 | } | ||
1004 | |||
1005 | void set_kernel_text_ro(void) | ||
1006 | { | ||
1007 | unsigned long start = PFN_ALIGN(_stext); | ||
1008 | unsigned long end = PFN_ALIGN(__start_rodata); | ||
1009 | |||
1010 | if (!kernel_set_to_readonly) | ||
1011 | return; | ||
1012 | |||
1013 | pr_debug("Set kernel text: %lx - %lx for read only\n", | ||
1014 | start, end); | ||
1015 | |||
1016 | set_memory_ro(start, (end - start) >> PAGE_SHIFT); | ||
1017 | } | ||
1018 | |||
989 | void mark_rodata_ro(void) | 1019 | void mark_rodata_ro(void) |
990 | { | 1020 | { |
991 | unsigned long start = PFN_ALIGN(_stext), end = PFN_ALIGN(__end_rodata); | 1021 | unsigned long start = PFN_ALIGN(_stext), end = PFN_ALIGN(__end_rodata); |
992 | unsigned long rodata_start = | 1022 | unsigned long rodata_start = |
993 | ((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK; | 1023 | ((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK; |
994 | 1024 | ||
995 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
996 | /* Dynamic tracing modifies the kernel text section */ | ||
997 | start = rodata_start; | ||
998 | #endif | ||
999 | |||
1000 | printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", | 1025 | printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", |
1001 | (end - start) >> 10); | 1026 | (end - start) >> 10); |
1002 | set_memory_ro(start, (end - start) >> PAGE_SHIFT); | 1027 | set_memory_ro(start, (end - start) >> PAGE_SHIFT); |
1003 | 1028 | ||
1029 | kernel_set_to_readonly = 1; | ||
1030 | |||
1004 | /* | 1031 | /* |
1005 | * The rodata section (but not the kernel text!) should also be | 1032 | * The rodata section (but not the kernel text!) should also be |
1006 | * not-executable. | 1033 | * not-executable. |
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 8ca0d8566fc8..7be47d1a97e4 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -508,18 +508,13 @@ static int split_large_page(pte_t *kpte, unsigned long address) | |||
508 | #endif | 508 | #endif |
509 | 509 | ||
510 | /* | 510 | /* |
511 | * Install the new, split up pagetable. Important details here: | 511 | * Install the new, split up pagetable. |
512 | * | 512 | * |
513 | * On Intel the NX bit of all levels must be cleared to make a | 513 | * We use the standard kernel pagetable protections for the new |
514 | * page executable. See section 4.13.2 of Intel 64 and IA-32 | 514 | * pagetable protections, the actual ptes set above control the |
515 | * Architectures Software Developer's Manual). | 515 | * primary protection behavior: |
516 | * | ||
517 | * Mark the entry present. The current mapping might be | ||
518 | * set to not present, which we preserved above. | ||
519 | */ | 516 | */ |
520 | ref_prot = pte_pgprot(pte_mkexec(pte_clrhuge(*kpte))); | 517 | __set_pmd_pte(kpte, address, mk_pte(base, __pgprot(_KERNPG_TABLE))); |
521 | pgprot_val(ref_prot) |= _PAGE_PRESENT; | ||
522 | __set_pmd_pte(kpte, address, mk_pte(base, ref_prot)); | ||
523 | base = NULL; | 518 | base = NULL; |
524 | 519 | ||
525 | out_unlock: | 520 | out_unlock: |
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 915f4723fc8b..847bb3c48dd0 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -106,6 +106,9 @@ struct ftrace_func_command { | |||
106 | /* asm/ftrace.h must be defined for archs supporting dynamic ftrace */ | 106 | /* asm/ftrace.h must be defined for archs supporting dynamic ftrace */ |
107 | #include <asm/ftrace.h> | 107 | #include <asm/ftrace.h> |
108 | 108 | ||
109 | int ftrace_arch_code_modify_prepare(void); | ||
110 | int ftrace_arch_code_modify_post_process(void); | ||
111 | |||
109 | struct seq_file; | 112 | struct seq_file; |
110 | 113 | ||
111 | struct ftrace_probe_ops { | 114 | struct ftrace_probe_ops { |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index cf59f4c54745..5a3a06b21eee 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -557,8 +557,11 @@ static void ftrace_replace_code(int enable) | |||
557 | if ((system_state == SYSTEM_BOOTING) || | 557 | if ((system_state == SYSTEM_BOOTING) || |
558 | !core_kernel_text(rec->ip)) { | 558 | !core_kernel_text(rec->ip)) { |
559 | ftrace_free_rec(rec); | 559 | ftrace_free_rec(rec); |
560 | } else | 560 | } else { |
561 | ftrace_bug(failed, rec->ip); | 561 | ftrace_bug(failed, rec->ip); |
562 | /* Stop processing */ | ||
563 | return; | ||
564 | } | ||
562 | } | 565 | } |
563 | } while_for_each_ftrace_rec(); | 566 | } while_for_each_ftrace_rec(); |
564 | } | 567 | } |
@@ -580,6 +583,24 @@ ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec) | |||
580 | return 1; | 583 | return 1; |
581 | } | 584 | } |
582 | 585 | ||
586 | /* | ||
587 | * archs can override this function if they must do something | ||
588 | * before the modifying code is performed. | ||
589 | */ | ||
590 | int __weak ftrace_arch_code_modify_prepare(void) | ||
591 | { | ||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | /* | ||
596 | * archs can override this function if they must do something | ||
597 | * after the modifying code is performed. | ||
598 | */ | ||
599 | int __weak ftrace_arch_code_modify_post_process(void) | ||
600 | { | ||
601 | return 0; | ||
602 | } | ||
603 | |||
583 | static int __ftrace_modify_code(void *data) | 604 | static int __ftrace_modify_code(void *data) |
584 | { | 605 | { |
585 | int *command = data; | 606 | int *command = data; |
@@ -602,7 +623,17 @@ static int __ftrace_modify_code(void *data) | |||
602 | 623 | ||
603 | static void ftrace_run_update_code(int command) | 624 | static void ftrace_run_update_code(int command) |
604 | { | 625 | { |
626 | int ret; | ||
627 | |||
628 | ret = ftrace_arch_code_modify_prepare(); | ||
629 | FTRACE_WARN_ON(ret); | ||
630 | if (ret) | ||
631 | return; | ||
632 | |||
605 | stop_machine(__ftrace_modify_code, &command, NULL); | 633 | stop_machine(__ftrace_modify_code, &command, NULL); |
634 | |||
635 | ret = ftrace_arch_code_modify_post_process(); | ||
636 | FTRACE_WARN_ON(ret); | ||
606 | } | 637 | } |
607 | 638 | ||
608 | static ftrace_func_t saved_ftrace_func; | 639 | static ftrace_func_t saved_ftrace_func; |