aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Mladek <pmladek@suse.cz>2014-02-24 11:12:22 -0500
committerSteven Rostedt <rostedt@goodmis.org>2014-03-07 10:06:16 -0500
commit7f11f5ecf4ae09815dc2de267c5e04d1de01d862 (patch)
tree51014fbc43d559884d4c95d57d86b8c69426718c
parentcd21067f69240041d36e491ff5597e0217615465 (diff)
ftrace/x86: BUG when ftrace recovery fails
Ftrace modifies function calls using Int3 breakpoints on x86. The breakpoints are handled only when the patching is in progress. If something goes wrong, there is a recovery code that removes the breakpoints. If this fails, the system might get silently rebooted when a remaining break is not handled or an invalid instruction is proceed. We should BUG() when the breakpoint could not be removed. Otherwise, the system silently crashes when the function finishes the Int3 handler is disabled. Note that we need to modify remove_breakpoint() to return non-zero value only when there is an error. The return value was ignored before, so it does not cause any troubles. Link: http://lkml.kernel.org/r/1393258342-29978-4-git-send-email-pmladek@suse.cz Signed-off-by: Petr Mladek <pmladek@suse.cz> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--arch/x86/kernel/ftrace.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 4b66adf17369..52819e816f87 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -425,7 +425,7 @@ static int remove_breakpoint(struct dyn_ftrace *rec)
425 425
426 /* If this does not have a breakpoint, we are done */ 426 /* If this does not have a breakpoint, we are done */
427 if (ins[0] != brk) 427 if (ins[0] != brk)
428 return -1; 428 return 0;
429 429
430 nop = ftrace_nop_replace(); 430 nop = ftrace_nop_replace();
431 431
@@ -625,7 +625,12 @@ void ftrace_replace_code(int enable)
625 printk(KERN_WARNING "Failed on %s (%d):\n", report, count); 625 printk(KERN_WARNING "Failed on %s (%d):\n", report, count);
626 for_ftrace_rec_iter(iter) { 626 for_ftrace_rec_iter(iter) {
627 rec = ftrace_rec_iter_record(iter); 627 rec = ftrace_rec_iter_record(iter);
628 remove_breakpoint(rec); 628 /*
629 * Breakpoints are handled only when this function is in
630 * progress. The system could not work with them.
631 */
632 if (remove_breakpoint(rec))
633 BUG();
629 } 634 }
630 run_sync(); 635 run_sync();
631} 636}
@@ -649,12 +654,19 @@ ftrace_modify_code(unsigned long ip, unsigned const char *old_code,
649 run_sync(); 654 run_sync();
650 655
651 ret = ftrace_write(ip, new_code, 1); 656 ret = ftrace_write(ip, new_code, 1);
657 /*
658 * The breakpoint is handled only when this function is in progress.
659 * The system could not work if we could not remove it.
660 */
661 BUG_ON(ret);
652 out: 662 out:
653 run_sync(); 663 run_sync();
654 return ret; 664 return ret;
655 665
656 fail_update: 666 fail_update:
657 ftrace_write(ip, old_code, 1); 667 /* Also here the system could not work with the breakpoint */
668 if (ftrace_write(ip, old_code, 1))
669 BUG();
658 goto out; 670 goto out;
659} 671}
660 672