diff options
Diffstat (limited to 'kernel/panic.c')
-rw-r--r-- | kernel/panic.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/kernel/panic.c b/kernel/panic.c index 17aad578a2f2..50cf9257b234 100644 --- a/kernel/panic.c +++ b/kernel/panic.c | |||
@@ -324,14 +324,82 @@ EXPORT_SYMBOL(warn_on_slowpath); | |||
324 | #endif | 324 | #endif |
325 | 325 | ||
326 | #ifdef CONFIG_CC_STACKPROTECTOR | 326 | #ifdef CONFIG_CC_STACKPROTECTOR |
327 | |||
328 | static unsigned long __stack_check_testing; | ||
329 | /* | ||
330 | * Self test function for the stack-protector feature. | ||
331 | * This test requires that the local variable absolutely has | ||
332 | * a stack slot, hence the barrier()s. | ||
333 | */ | ||
334 | static noinline void __stack_chk_test_func(void) | ||
335 | { | ||
336 | unsigned long foo; | ||
337 | barrier(); | ||
338 | /* | ||
339 | * we need to make sure we're not about to clobber the return address, | ||
340 | * while real exploits do this, it's unhealthy on a running system. | ||
341 | * Besides, if we would, the test is already failed anyway so | ||
342 | * time to pull the emergency brake on it. | ||
343 | */ | ||
344 | if ((unsigned long)__builtin_return_address(0) == | ||
345 | *(((unsigned long *)&foo)+1)) { | ||
346 | printk(KERN_ERR "No -fstack-protector-stack-frame!\n"); | ||
347 | return; | ||
348 | } | ||
349 | #ifdef CONFIG_FRAME_POINTER | ||
350 | /* We also don't want to clobber the frame pointer */ | ||
351 | if ((unsigned long)__builtin_return_address(0) == | ||
352 | *(((unsigned long *)&foo)+2)) { | ||
353 | printk(KERN_ERR "No -fstack-protector-stack-frame!\n"); | ||
354 | return; | ||
355 | } | ||
356 | #endif | ||
357 | barrier(); | ||
358 | if (current->stack_canary == *(((unsigned long *)&foo)+1)) | ||
359 | *(((unsigned long *)&foo)+1) = 0; | ||
360 | else | ||
361 | printk(KERN_ERR "No -fstack-protector canary found\n"); | ||
362 | barrier(); | ||
363 | } | ||
364 | |||
365 | static int __stack_chk_test(void) | ||
366 | { | ||
367 | printk(KERN_INFO "Testing -fstack-protector-all feature\n"); | ||
368 | __stack_check_testing = (unsigned long)&__stack_chk_test_func; | ||
369 | __stack_chk_test_func(); | ||
370 | if (__stack_check_testing) { | ||
371 | printk(KERN_ERR "-fstack-protector-all test failed\n"); | ||
372 | WARN_ON(1); | ||
373 | } | ||
374 | return 0; | ||
375 | } | ||
327 | /* | 376 | /* |
328 | * Called when gcc's -fstack-protector feature is used, and | 377 | * Called when gcc's -fstack-protector feature is used, and |
329 | * gcc detects corruption of the on-stack canary value | 378 | * gcc detects corruption of the on-stack canary value |
330 | */ | 379 | */ |
331 | void __stack_chk_fail(void) | 380 | void __stack_chk_fail(void) |
332 | { | 381 | { |
382 | if (__stack_check_testing == (unsigned long)&__stack_chk_test_func) { | ||
383 | long delta; | ||
384 | |||
385 | delta = (unsigned long)__builtin_return_address(0) - | ||
386 | __stack_check_testing; | ||
387 | /* | ||
388 | * The test needs to happen inside the test function, so | ||
389 | * check if the return address is close to that function. | ||
390 | * The function is only 2 dozen bytes long, but keep a wide | ||
391 | * safety margin to avoid panic()s for normal users regardless | ||
392 | * of the quality of the compiler. | ||
393 | */ | ||
394 | if (delta >= 0 && delta <= 400) { | ||
395 | __stack_check_testing = 0; | ||
396 | return; | ||
397 | } | ||
398 | } | ||
333 | panic("stack-protector: Kernel stack is corrupted in: %p\n", | 399 | panic("stack-protector: Kernel stack is corrupted in: %p\n", |
334 | __builtin_return_address(0)); | 400 | __builtin_return_address(0)); |
335 | } | 401 | } |
336 | EXPORT_SYMBOL(__stack_chk_fail); | 402 | EXPORT_SYMBOL(__stack_chk_fail); |
403 | |||
404 | late_initcall(__stack_chk_test); | ||
337 | #endif | 405 | #endif |