From 9027a5e5be0889cd0b969ca17e3e8015980ed290 Mon Sep 17 00:00:00 2001 From: Cheng Jian Date: Thu, 4 Apr 2019 18:53:19 +0800 Subject: [PATCH] livepatch/arm64: fix current backtracking in klp_check_calltrace hulk inclusion category: bugfix bugzilla: 13277 CVE: NA ------------------------------------------------- We through stack checking to ensure the consistency of livepatch. Task blocked in __switch_to when switch out, thread_saved_fs/pc store the FP and PC when switching, it can be useful when tracing blocked threads. For running task, __builtin_frame_address can be used, but it's difficult to backtracking the running task on other CPUs. Fortunately, all CPUs will stay in this function, the current's backtrace is so similar. so just backtracking the current on this CPU, skip the current of other CPUs. Signed-off-by: Cheng Jian Reviewed-by: Li Bin Signed-off-by: Yang Yingliang --- arch/arm64/kernel/livepatch.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/livepatch.c b/arch/arm64/kernel/livepatch.c index 460e8585f5c0..5587e646ae47 100644 --- a/arch/arm64/kernel/livepatch.c +++ b/arch/arm64/kernel/livepatch.c @@ -110,8 +110,32 @@ int klp_check_calltrace(struct klp_patch *patch, int enable) }; for_each_process_thread(g, t) { - frame.fp = thread_saved_fp(t); - frame.pc = thread_saved_pc(t); + /* + * Handle the current carefully on each CPUs, we shouldn't + * use saved FP and PC when backtrace current. It's difficult + * to backtrack other CPU currents here. But fortunately, + * all CPUs will stay in this function, so the current's + * backtrace is so similar + */ + if (t == current) { + /* current on this CPU */ + frame.fp = (unsigned long)__builtin_frame_address(0); + frame.pc = (unsigned long)klp_check_calltrace; + } else if (strncmp(t->comm, "migration/", 10) == 0) { + /* + * current on other CPU + * we call this in stop_machine, so the current + * of each CPUs is mirgation, just compare the + * task_comm here, because we can't get the + * cpu_curr(task_cpu(t))). This assumes that no + * other thread will pretend to be a stopper via + * task_comm.  + */ + continue; + } else { + frame.fp = thread_saved_fp(t); + frame.pc = thread_saved_pc(t); + } #ifdef CONFIG_FUNCTION_GRAPH_TRACER frame.graph = t->curr_ret_stack; #endif -- GitLab