diff options
author | Kamalesh Babulal <kamalesh@linux.vnet.ibm.com> | 2017-09-20 06:19:51 -0400 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2017-10-10 00:27:42 -0400 |
commit | e36a82ee4c514a2f4f8fa30c780ad059282f5d64 (patch) | |
tree | 7648167660b5bfba12cfca281966af9d6404b19e | |
parent | 53ecde0b9126ff140abe3aefd7f0ec64d6fa36b0 (diff) |
powerpc/livepatch: Fix livepatch stack access
While running stress test with livepatch module loaded, kernel bug was
triggered.
cpu 0x5: Vector: 400 (Instruction Access) at [c0000000eb9d3b60]
5:mon> t
[c0000000eb9d3de0] c0000000eb9d3e30 (unreliable)
[c0000000eb9d3e30] c000000000008ab4 hardware_interrupt_common+0x114/0x120
--- Exception: 501 (Hardware Interrupt) at c000000000053040 livepatch_handler+0x4c/0x74
[c0000000eb9d4120] 0000000057ac6e9d (unreliable)
[d0000000089d9f78] 2e0965747962382e
SP (965747962342e09) is in userspace
When an interrupt occurs during the livepatch_handler execution, it's
possible for the livepatch_stack and/or thread_info to be corrupted.
eg:
Task A Interrupt Handler
========= =================
livepatch_handler:
mr r0, r1
ld r1, TI_livepatch_sp(r12)
hardware_interrupt_common:
do_IRQ+0x8:
mflr r0 <- saved stack pointer is overwritten
bl _mcount
...
std r27,-40(r1) <- overwrite of thread_info()
lis r2, STACK_END_MAGIC@h
ori r2, r2, STACK_END_MAGIC@l
ld r12, -8(r1)
Fix the corruption by using r11 register for livepatch stack
manipulation, instead of shuffling task stack and livepatch stack into
r1 register. Using r11 register also avoids disabling/enabling irq's
while setting up the livepatch stack.
Signed-off-by: Kamalesh Babulal <kamalesh@linux.vnet.ibm.com>
Reviewed-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Reviewed-by: Balbir Singh <bsingharora@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r-- | arch/powerpc/kernel/trace/ftrace_64_mprofile.S | 45 |
1 files changed, 15 insertions, 30 deletions
diff --git a/arch/powerpc/kernel/trace/ftrace_64_mprofile.S b/arch/powerpc/kernel/trace/ftrace_64_mprofile.S index c98e90b4ea7b..b4e2b7165f79 100644 --- a/arch/powerpc/kernel/trace/ftrace_64_mprofile.S +++ b/arch/powerpc/kernel/trace/ftrace_64_mprofile.S | |||
@@ -181,34 +181,25 @@ _GLOBAL(ftrace_stub) | |||
181 | * - we have no stack frame and can not allocate one | 181 | * - we have no stack frame and can not allocate one |
182 | * - LR points back to the original caller (in A) | 182 | * - LR points back to the original caller (in A) |
183 | * - CTR holds the new NIP in C | 183 | * - CTR holds the new NIP in C |
184 | * - r0 & r12 are free | 184 | * - r0, r11 & r12 are free |
185 | * | ||
186 | * r0 can't be used as the base register for a DS-form load or store, so | ||
187 | * we temporarily shuffle r1 (stack pointer) into r0 and then put it back. | ||
188 | */ | 185 | */ |
189 | livepatch_handler: | 186 | livepatch_handler: |
190 | CURRENT_THREAD_INFO(r12, r1) | 187 | CURRENT_THREAD_INFO(r12, r1) |
191 | 188 | ||
192 | /* Save stack pointer into r0 */ | ||
193 | mr r0, r1 | ||
194 | |||
195 | /* Allocate 3 x 8 bytes */ | 189 | /* Allocate 3 x 8 bytes */ |
196 | ld r1, TI_livepatch_sp(r12) | 190 | ld r11, TI_livepatch_sp(r12) |
197 | addi r1, r1, 24 | 191 | addi r11, r11, 24 |
198 | std r1, TI_livepatch_sp(r12) | 192 | std r11, TI_livepatch_sp(r12) |
199 | 193 | ||
200 | /* Save toc & real LR on livepatch stack */ | 194 | /* Save toc & real LR on livepatch stack */ |
201 | std r2, -24(r1) | 195 | std r2, -24(r11) |
202 | mflr r12 | 196 | mflr r12 |
203 | std r12, -16(r1) | 197 | std r12, -16(r11) |
204 | 198 | ||
205 | /* Store stack end marker */ | 199 | /* Store stack end marker */ |
206 | lis r12, STACK_END_MAGIC@h | 200 | lis r12, STACK_END_MAGIC@h |
207 | ori r12, r12, STACK_END_MAGIC@l | 201 | ori r12, r12, STACK_END_MAGIC@l |
208 | std r12, -8(r1) | 202 | std r12, -8(r11) |
209 | |||
210 | /* Restore real stack pointer */ | ||
211 | mr r1, r0 | ||
212 | 203 | ||
213 | /* Put ctr in r12 for global entry and branch there */ | 204 | /* Put ctr in r12 for global entry and branch there */ |
214 | mfctr r12 | 205 | mfctr r12 |
@@ -216,36 +207,30 @@ livepatch_handler: | |||
216 | 207 | ||
217 | /* | 208 | /* |
218 | * Now we are returning from the patched function to the original | 209 | * Now we are returning from the patched function to the original |
219 | * caller A. We are free to use r0 and r12, and we can use r2 until we | 210 | * caller A. We are free to use r11, r12 and we can use r2 until we |
220 | * restore it. | 211 | * restore it. |
221 | */ | 212 | */ |
222 | 213 | ||
223 | CURRENT_THREAD_INFO(r12, r1) | 214 | CURRENT_THREAD_INFO(r12, r1) |
224 | 215 | ||
225 | /* Save stack pointer into r0 */ | 216 | ld r11, TI_livepatch_sp(r12) |
226 | mr r0, r1 | ||
227 | |||
228 | ld r1, TI_livepatch_sp(r12) | ||
229 | 217 | ||
230 | /* Check stack marker hasn't been trashed */ | 218 | /* Check stack marker hasn't been trashed */ |
231 | lis r2, STACK_END_MAGIC@h | 219 | lis r2, STACK_END_MAGIC@h |
232 | ori r2, r2, STACK_END_MAGIC@l | 220 | ori r2, r2, STACK_END_MAGIC@l |
233 | ld r12, -8(r1) | 221 | ld r12, -8(r11) |
234 | 1: tdne r12, r2 | 222 | 1: tdne r12, r2 |
235 | EMIT_BUG_ENTRY 1b, __FILE__, __LINE__ - 1, 0 | 223 | EMIT_BUG_ENTRY 1b, __FILE__, __LINE__ - 1, 0 |
236 | 224 | ||
237 | /* Restore LR & toc from livepatch stack */ | 225 | /* Restore LR & toc from livepatch stack */ |
238 | ld r12, -16(r1) | 226 | ld r12, -16(r11) |
239 | mtlr r12 | 227 | mtlr r12 |
240 | ld r2, -24(r1) | 228 | ld r2, -24(r11) |
241 | 229 | ||
242 | /* Pop livepatch stack frame */ | 230 | /* Pop livepatch stack frame */ |
243 | CURRENT_THREAD_INFO(r12, r0) | 231 | CURRENT_THREAD_INFO(r12, r1) |
244 | subi r1, r1, 24 | 232 | subi r11, r11, 24 |
245 | std r1, TI_livepatch_sp(r12) | 233 | std r11, TI_livepatch_sp(r12) |
246 | |||
247 | /* Restore real stack pointer */ | ||
248 | mr r1, r0 | ||
249 | 234 | ||
250 | /* Return to original caller of live patched function */ | 235 | /* Return to original caller of live patched function */ |
251 | blr | 236 | blr |