Skip to content

Commit 1623963

Browse files
author
Steven Rostedt
committed
ftrace, x86: make kernel text writable only for conversions
Impact: keep kernel text read only Because dynamic ftrace converts the calls to mcount into and out of nops at run time, we needed to always keep the kernel text writable. But this defeats the point of CONFIG_DEBUG_RODATA. This patch converts the kernel code to writable before ftrace modifies the text, and converts it back to read only afterward. The kernel text is converted to read/write, stop_machine is called to modify the code, then the kernel text is converted back to read only. The original version used SYSTEM_STATE to determine when it was OK or not to change the code to rw or ro. Andrew Morton pointed out that using SYSTEM_STATE is a bad idea since there is no guarantee to what its state will actually be. Instead, I moved the check into the set_kernel_text_* functions themselves, and use a local variable to determine when it is OK to change the kernel text RW permissions. [ Update: Ingo Molnar suggested moving the prototypes to cacheflush.h ] Reviewed-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Steven Rostedt <srostedt@redhat.com>
1 parent 000ab69 commit 1623963

File tree

4 files changed

+82
-8
lines changed

4 files changed

+82
-8
lines changed

arch/x86/include/asm/cacheflush.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ void clflush_cache_range(void *addr, unsigned int size);
104104
#ifdef CONFIG_DEBUG_RODATA
105105
void mark_rodata_ro(void);
106106
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) { }
107112
#endif
108113

109114
#ifdef CONFIG_DEBUG_RODATA_TEST

arch/x86/kernel/ftrace.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/init.h>
1919
#include <linux/list.h>
2020

21+
#include <asm/cacheflush.h>
2122
#include <asm/ftrace.h>
2223
#include <linux/ftrace.h>
2324
#include <asm/nops.h>
@@ -26,6 +27,18 @@
2627

2728
#ifdef CONFIG_DYNAMIC_FTRACE
2829

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+
2942
union ftrace_code_union {
3043
char code[MCOUNT_INSN_SIZE];
3144
struct {

arch/x86/mm/init_32.c

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,17 +1155,47 @@ static noinline int do_test_wp_bit(void)
11551155
const int rodata_test_data = 0xC3;
11561156
EXPORT_SYMBOL_GPL(rodata_test_data);
11571157

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+
11581188
void mark_rodata_ro(void)
11591189
{
11601190
unsigned long start = PFN_ALIGN(_text);
11611191
unsigned long size = PFN_ALIGN(_etext) - start;
11621192

1163-
#ifndef CONFIG_DYNAMIC_FTRACE
1164-
/* Dynamic tracing modifies the kernel text section */
11651193
set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT);
11661194
printk(KERN_INFO "Write protecting the kernel text: %luk\n",
11671195
size >> 10);
11681196

1197+
kernel_set_to_readonly = 1;
1198+
11691199
#ifdef CONFIG_CPA_DEBUG
11701200
printk(KERN_INFO "Testing CPA: Reverting %lx-%lx\n",
11711201
start, start+size);
@@ -1174,7 +1204,6 @@ void mark_rodata_ro(void)
11741204
printk(KERN_INFO "Testing CPA: write protecting again\n");
11751205
set_pages_ro(virt_to_page(start), size>>PAGE_SHIFT);
11761206
#endif
1177-
#endif /* CONFIG_DYNAMIC_FTRACE */
11781207

11791208
start += size;
11801209
size = (unsigned long)__end_rodata - start;

arch/x86/mm/init_64.c

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -986,21 +986,48 @@ void free_initmem(void)
986986
const int rodata_test_data = 0xC3;
987987
EXPORT_SYMBOL_GPL(rodata_test_data);
988988

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+
9891019
void mark_rodata_ro(void)
9901020
{
9911021
unsigned long start = PFN_ALIGN(_stext), end = PFN_ALIGN(__end_rodata);
9921022
unsigned long rodata_start =
9931023
((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK;
9941024

995-
#ifdef CONFIG_DYNAMIC_FTRACE
996-
/* Dynamic tracing modifies the kernel text section */
997-
start = rodata_start;
998-
#endif
999-
10001025
printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
10011026
(end - start) >> 10);
10021027
set_memory_ro(start, (end - start) >> PAGE_SHIFT);
10031028

1029+
kernel_set_to_readonly = 1;
1030+
10041031
/*
10051032
* The rodata section (but not the kernel text!) should also be
10061033
* not-executable.

0 commit comments

Comments
 (0)