diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-10 22:43:23 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-10 22:43:23 -0400 |
commit | 442e0973e9273ae8832abd70f52efde8b8326178 (patch) | |
tree | e2358f77f76143fe0f524c5a0e26cb940972e5c1 /arch/x86/kernel/jump_label.c | |
parent | 8d7551eb1916832f2a5b27346edf24e7b2382f67 (diff) | |
parent | fb40d7a8994a3cc7a1e1c1f3258ea8662a366916 (diff) |
Merge branch 'x86/jumplabel' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 jumplabel changes from Peter Anvin:
"One more x86 tree for this merge window. This tree improves the
handling of jump labels, so that most of the time we don't have to do
a massive initial patching run.
Furthermore, we will error out of the jump label is not what is
expected, eg if it has been corrupted or tampered with"
* 'x86/jumplabel' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/jump-label: Show where and what was wrong on errors
x86/jump-label: Add safety checks to jump label conversions
x86/jump-label: Do not bother updating nops if they are correct
x86/jump-label: Use best default nops for inital jump label calls
Diffstat (limited to 'arch/x86/kernel/jump_label.c')
-rw-r--r-- | arch/x86/kernel/jump_label.c | 70 |
1 files changed, 66 insertions, 4 deletions
diff --git a/arch/x86/kernel/jump_label.c b/arch/x86/kernel/jump_label.c index 460f5d9ceebb..ee11b7dfbfbb 100644 --- a/arch/x86/kernel/jump_label.c +++ b/arch/x86/kernel/jump_label.c | |||
@@ -24,18 +24,57 @@ union jump_code_union { | |||
24 | } __attribute__((packed)); | 24 | } __attribute__((packed)); |
25 | }; | 25 | }; |
26 | 26 | ||
27 | static void bug_at(unsigned char *ip, int line) | ||
28 | { | ||
29 | /* | ||
30 | * The location is not an op that we were expecting. | ||
31 | * Something went wrong. Crash the box, as something could be | ||
32 | * corrupting the kernel. | ||
33 | */ | ||
34 | pr_warning("Unexpected op at %pS [%p] (%02x %02x %02x %02x %02x) %s:%d\n", | ||
35 | ip, ip, ip[0], ip[1], ip[2], ip[3], ip[4], __FILE__, line); | ||
36 | BUG(); | ||
37 | } | ||
38 | |||
27 | static void __jump_label_transform(struct jump_entry *entry, | 39 | static void __jump_label_transform(struct jump_entry *entry, |
28 | enum jump_label_type type, | 40 | enum jump_label_type type, |
29 | void *(*poker)(void *, const void *, size_t)) | 41 | void *(*poker)(void *, const void *, size_t), |
42 | int init) | ||
30 | { | 43 | { |
31 | union jump_code_union code; | 44 | union jump_code_union code; |
45 | const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5]; | ||
32 | 46 | ||
33 | if (type == JUMP_LABEL_ENABLE) { | 47 | if (type == JUMP_LABEL_ENABLE) { |
48 | /* | ||
49 | * We are enabling this jump label. If it is not a nop | ||
50 | * then something must have gone wrong. | ||
51 | */ | ||
52 | if (unlikely(memcmp((void *)entry->code, ideal_nop, 5) != 0)) | ||
53 | bug_at((void *)entry->code, __LINE__); | ||
54 | |||
34 | code.jump = 0xe9; | 55 | code.jump = 0xe9; |
35 | code.offset = entry->target - | 56 | code.offset = entry->target - |
36 | (entry->code + JUMP_LABEL_NOP_SIZE); | 57 | (entry->code + JUMP_LABEL_NOP_SIZE); |
37 | } else | 58 | } else { |
59 | /* | ||
60 | * We are disabling this jump label. If it is not what | ||
61 | * we think it is, then something must have gone wrong. | ||
62 | * If this is the first initialization call, then we | ||
63 | * are converting the default nop to the ideal nop. | ||
64 | */ | ||
65 | if (init) { | ||
66 | const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP }; | ||
67 | if (unlikely(memcmp((void *)entry->code, default_nop, 5) != 0)) | ||
68 | bug_at((void *)entry->code, __LINE__); | ||
69 | } else { | ||
70 | code.jump = 0xe9; | ||
71 | code.offset = entry->target - | ||
72 | (entry->code + JUMP_LABEL_NOP_SIZE); | ||
73 | if (unlikely(memcmp((void *)entry->code, &code, 5) != 0)) | ||
74 | bug_at((void *)entry->code, __LINE__); | ||
75 | } | ||
38 | memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE); | 76 | memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE); |
77 | } | ||
39 | 78 | ||
40 | /* | 79 | /* |
41 | * Make text_poke_bp() a default fallback poker. | 80 | * Make text_poke_bp() a default fallback poker. |
@@ -57,15 +96,38 @@ void arch_jump_label_transform(struct jump_entry *entry, | |||
57 | { | 96 | { |
58 | get_online_cpus(); | 97 | get_online_cpus(); |
59 | mutex_lock(&text_mutex); | 98 | mutex_lock(&text_mutex); |
60 | __jump_label_transform(entry, type, NULL); | 99 | __jump_label_transform(entry, type, NULL, 0); |
61 | mutex_unlock(&text_mutex); | 100 | mutex_unlock(&text_mutex); |
62 | put_online_cpus(); | 101 | put_online_cpus(); |
63 | } | 102 | } |
64 | 103 | ||
104 | static enum { | ||
105 | JL_STATE_START, | ||
106 | JL_STATE_NO_UPDATE, | ||
107 | JL_STATE_UPDATE, | ||
108 | } jlstate __initdata_or_module = JL_STATE_START; | ||
109 | |||
65 | __init_or_module void arch_jump_label_transform_static(struct jump_entry *entry, | 110 | __init_or_module void arch_jump_label_transform_static(struct jump_entry *entry, |
66 | enum jump_label_type type) | 111 | enum jump_label_type type) |
67 | { | 112 | { |
68 | __jump_label_transform(entry, type, text_poke_early); | 113 | /* |
114 | * This function is called at boot up and when modules are | ||
115 | * first loaded. Check if the default nop, the one that is | ||
116 | * inserted at compile time, is the ideal nop. If it is, then | ||
117 | * we do not need to update the nop, and we can leave it as is. | ||
118 | * If it is not, then we need to update the nop to the ideal nop. | ||
119 | */ | ||
120 | if (jlstate == JL_STATE_START) { | ||
121 | const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP }; | ||
122 | const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5]; | ||
123 | |||
124 | if (memcmp(ideal_nop, default_nop, 5) != 0) | ||
125 | jlstate = JL_STATE_UPDATE; | ||
126 | else | ||
127 | jlstate = JL_STATE_NO_UPDATE; | ||
128 | } | ||
129 | if (jlstate == JL_STATE_UPDATE) | ||
130 | __jump_label_transform(entry, type, text_poke_early, 1); | ||
69 | } | 131 | } |
70 | 132 | ||
71 | #endif | 133 | #endif |