kprobes: Fix stacktrace with kretprobes on x86
Subsystems (20)
Masami Hiramatsu
maintainerv11 cover kprobes: Fix stacktrace with kretprobes on x86
Hello,
This is the 11th version of the series to fix the stacktrace with kretprobe on x86.
The previous version is here;
https://lore.kernel.org/all/162756755600.301564.4957591913842010341.stgit@devnote2/
This version is rebased on the latest tip/master branch and includes the kprobe cleanup series[1][2]. No code change.
[1] https://lore.kernel.org/bpf/162748615977.59465.13262421617578791515.stgit@devnote2/
[2] https://lore.kernel.org/linux-csky/[email protected]/
With this series, unwinder can unwind stack correctly from ftrace as below;
# cd /sys/kernel/debug/tracing
# echo > trace
# echo 1 > options/sym-offset
# echo r vfs_read >> kprobe_events
# echo r full_proxy_read >> kprobe_events
# echo traceoff:1 > events/kprobes/r_vfs_read_0/trigger
# echo stacktrace:1 > events/kprobes/r_full_proxy_read_0/trigger
# echo 1 > events/kprobes/enable
# cat /sys/kernel/debug/kprobes/list
ffffffff813bedf0 r full_proxy_read+0x0 [FTRACE]
ffffffff812c13e0 r vfs_read+0x0 [FTRACE]
# echo 0 > events/kprobes/enable
# cat trace
# tracer: nop
#
# entries-in-buffer/entries-written: 3/3 #P:8
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / _-=> migrate-disable
# |||| / delay
# TASK-PID CPU# ||||| TIMESTAMP FUNCTION
# | | | ||||| | |
cat-136 [000] ...1. 14.474966: r_full_proxy_read_0: (vfs_read+0x99/0x190 <- full_proxy_read)
cat-136 [000] ...1. 14.474970: <stack trace>
=> kretprobe_trace_func+0x209/0x300
=> kretprobe_dispatcher+0x9d/0xb0
=> __kretprobe_trampoline_handler+0xd4/0x1b0
=> trampoline_handler+0x43/0x60
=> __kretprobe_trampoline+0x2a/0x50
=> vfs_read+0x99/0x190
=> ksys_read+0x68/0xe0
=> do_syscall_64+0x3b/0x90
=> entry_SYSCALL_64_after_hwframe+0x44/0xae
cat-136 [000] ...1. 14.474971: r_vfs_read_0: (ksys_read+0x68/0xe0 <- vfs_read)This shows the double return probes (vfs_read() and full_proxy_read()) on the stack correctly unwinded. (vfs_read() returns to 'ksys_read+0x68' and full_proxy_read() returns to 'vfs_read+0x99')
This also changes the kretprobe behavisor a bit, now the instraction pointer in the 'pt_regs' passed to kretprobe user handler is correctly set the real return address. So user handlers can get it via instruction_pointer() API, and can use stack_trace_save_regs().
You can also get this series from
git://git.kernel.org/pub/scm/linux/kernel/git/mhiramat/linux.git kprobes/kretprobe-stackfix-v11
Thank you,
---
Josh Poimboeuf (3):
objtool: Add frame-pointer-specific function ignore
objtool: Ignore unwind hints for ignored functions x86/kprobes: Add UNWIND_HINT_FUNC on kretprobe_trampoline()
Masami Hiramatsu (19):
kprobes: treewide: Cleanup the error messages for kprobes
kprobes: Fix coding style issues
kprobes: Use IS_ENABLED() instead of kprobes_built_in()
kprobes: Add assertions for required lock
kprobes: treewide: Use 'kprobe_opcode_t *' for the code address in get_optimized_kprobe()
kprobes: Use bool type for functions which returns boolean value
ia64: kprobes: Fix to pass correct trampoline address to the handler
kprobes: treewide: Replace arch_deref_entry_point() with dereference_symbol_descriptor()
kprobes: treewide: Remove trampoline_address from kretprobe_trampoline_handler()
kprobes: treewide: Make it harder to refer kretprobe_trampoline directly
kprobes: Add kretprobe_find_ret_addr() for searching return address
ARC: Add instruction_pointer_set() API
ia64: Add instruction_pointer_set() API
arm: kprobes: Make space for instruction pointer on stack
kprobes: Enable stacktrace from pt_regs in kretprobe handler
x86/kprobes: Push a fake return address at kretprobe_trampoline x86/unwind: Recover kretprobe trampoline entry
tracing: Show kretprobe unknown indicator only for kretprobe_trampoline x86/kprobes: Fixup return address in generic trampoline handler
Punit Agrawal (5):
kprobes: Do not use local variable when creating debugfs file
kprobes: Use helper to parse boolean input from userspace
kprobe: Simplify prepare_kprobe() by dropping redundant version
csky: ftrace: Drop duplicate implementation of arch_check_ftrace_location()
kprobes: Make arch_check_ftrace_location static
arch/arc/include/asm/kprobes.h | 2 arch/arc/include/asm/ptrace.h | 5 arch/arc/kernel/kprobes.c | 13 - arch/arm/probes/kprobes/core.c | 15 - arch/arm/probes/kprobes/opt-arm.c | 7 arch/arm64/include/asm/kprobes.h | 2 arch/arm64/kernel/probes/kprobes.c | 10 arch/arm64/kernel/probes/kprobes_trampoline.S | 4 arch/csky/include/asm/kprobes.h | 2 arch/csky/kernel/probes/ftrace.c | 7 arch/csky/kernel/probes/kprobes.c | 14 - arch/csky/kernel/probes/kprobes_trampoline.S | 4 arch/ia64/include/asm/ptrace.h | 5 arch/ia64/kernel/kprobes.c | 15 - arch/mips/kernel/kprobes.c | 26 + arch/parisc/kernel/kprobes.c | 6 arch/powerpc/include/asm/kprobes.h | 2 arch/powerpc/kernel/kprobes.c | 29 - arch/powerpc/kernel/optprobes.c | 8 arch/powerpc/kernel/stacktrace.c | 2 arch/riscv/include/asm/kprobes.h | 2 arch/riscv/kernel/probes/kprobes.c | 15 - arch/riscv/kernel/probes/kprobes_trampoline.S | 4 arch/s390/include/asm/kprobes.h | 2 arch/s390/kernel/kprobes.c | 16 - arch/s390/kernel/stacktrace.c | 2 arch/sh/include/asm/kprobes.h | 2 arch/sh/kernel/kprobes.c | 12 - arch/sparc/include/asm/kprobes.h | 2 arch/sparc/kernel/kprobes.c | 12 - arch/x86/include/asm/kprobes.h | 1 arch/x86/include/asm/unwind.h | 23 + arch/x86/include/asm/unwind_hints.h | 5 arch/x86/kernel/kprobes/core.c | 71 +++- arch/x86/kernel/kprobes/opt.c | 6 arch/x86/kernel/unwind_frame.c | 3 arch/x86/kernel/unwind_guess.c | 3 arch/x86/kernel/unwind_orc.c | 21 + include/linux/kprobes.h | 113 ++++-- include/linux/objtool.h | 12 + kernel/kprobes.c | 502 ++++++++++++++----------- kernel/trace/trace_kprobe.c | 2 kernel/trace/trace_output.c | 17 - lib/error-inject.c | 3 tools/include/linux/objtool.h | 12 + tools/objtool/check.c | 2 46 files changed, 607 insertions(+), 436 deletions(-)
--
Masami Hiramatsu (Linaro) <[email protected]>
Masami Hiramatsu
maintainerPATCH v11 1/27 kprobes: Do not use local variable when creating debugfs file
From: Punit Agrawal <[email protected]>
debugfs_create_file() takes a pointer argument that can be used during file operation callbacks (accessible via i_private in the inode structure). An obvious requirement is for the pointer to refer to valid memory when used.
When creating the debugfs file to dynamically enable / disable kprobes, a pointer to local variable is passed to debugfs_create_file(); which will go out of scope when the init function returns. The reason this hasn't triggered random memory corruption is because the pointer is not accessed during the debugfs file callbacks.
Since the enabled state is managed by the kprobes_all_disabled global variable, the local variable is not needed. Fix the incorrect (and unnecessary) usage of local variable during debugfs_file_create() by passing NULL instead.
--- kernel/kprobes.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
kernel/kprobes.c +1 -2
@@ -2809,13 +2809,12 @@ static const struct file_operations fops_kp = {static int __init debugfs_kprobe_init (void ) {struct dentry *dir; -unsigned int value =1 ; dir =debugfs_create_dir ("kprobes" ,NULL );debugfs_create_file ("list" ,0400 , dir,NULL , &kprobes_fops); -debugfs_create_file ("enabled" ,0600 , dir, &value, &fops_kp); +debugfs_create_file ("enabled" ,0600 , dir,NULL , &fops_kp);debugfs_create_file ("blacklist" ,0400 , dir,NULL , &kprobe_blacklist_fops);
Masami Hiramatsu
maintainerPATCH v11 2/27 kprobes: Use helper to parse boolean input from userspace
In reply to Masami HiramatsuFrom: Punit Agrawal <[email protected]>
The "enabled" file provides a debugfs interface to arm / disarm kprobes in the kernel. In order to parse the buffer containing the values written from userspace, the callback manually parses the user input to convert it to a boolean value.
As taking a string value from userspace and converting it to boolean is a common operation, a helper kstrtobool_from_user() is already available in the kernel. Update the callback to use the common helper to parse the write buffer from userspace.
--- kernel/kprobes.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-)
kernel/kprobes.c +6 -22
@@ -2770,30 +2770,14 @@ static ssize_t read_enabled_file_bool(struct file *file,static ssize_t write_enabled_file_bool (struct file *file,const char __user *user_buf,size_t count,loff_t *ppos) { -char buf[32 ]; -size_t buf_size; -int ret =0 ; - - buf_size =min (count, (sizeof (buf)-1 )); -if (copy_from_user (buf, user_buf, buf_size)) -return -EFAULT ; +bool enable; +int ret; - buf[buf_size] ='\0' ; -switch (buf[0 ]) { -case 'y' : -case 'Y' : -case '1' : - ret =arm_all_kprobes (); -break ; -case 'n' : -case 'N' : -case '0' : - ret =disarm_all_kprobes (); -break ; -default : -return -EINVAL ; - } + ret =kstrtobool_from_user (user_buf, count, &enable); +if (ret) +return ret; + ret = enable ?arm_all_kprobes () :disarm_all_kprobes ();if (ret)return ret;
Masami Hiramatsu
maintainerPATCH v11 3/27 kprobe: Simplify prepare_kprobe() by dropping redundant version
In reply to Masami HiramatsuFrom: Punit Agrawal <[email protected]>
The function prepare_kprobe() is called during kprobe registration and is responsible for ensuring any architecture related preparation for the kprobe is done before returning.
One of two versions of prepare_kprobe() is chosen depending on the availability of KPROBE_ON_FTRACE in the kernel configuration.
Simplify the code by dropping the version when KPROBE_ON_FTRACE is not selected - instead relying on kprobe_ftrace() to return false when KPROBE_ON_FTRACE is not set.
No functional change.
--- include/linux/kprobes.h | 5 +++++ kernel/kprobes.c | 23 +++++++++-------------- 2 files changed, 14 insertions(+), 14 deletions(-)
include/linux/kprobes.h +5 -0
@@ -354,6 +354,11 @@ static inline void wait_for_kprobe_optimizer(void) { }extern void kprobe_ftrace_handler (unsigned long ip,unsigned long parent_ip,struct ftrace_ops *ops,struct ftrace_regs *fregs);extern int arch_prepare_kprobe_ftrace (struct kprobe *p); +#else +static inline int arch_prepare_kprobe_ftrace (struct kprobe *p) +{ +return -EINVAL ; +}#endif int arch_check_ftrace_location (struct kprobe *p);
kernel/kprobes.c +9 -14
@@ -1033,15 +1033,6 @@ static struct ftrace_ops kprobe_ipmodify_ops __read_mostly = {static int kprobe_ipmodify_enabled;static int kprobe_ftrace_enabled; -/* Must ensure p->addr is really on ftrace */ -static int prepare_kprobe (struct kprobe *p) -{ -if (!kprobe_ftrace (p)) -return arch_prepare_kprobe (p); - -return arch_prepare_kprobe_ftrace (p); -} -/* Caller must lock kprobe_mutex */ static int __arm_kprobe_ftrace (struct kprobe *p,struct ftrace_ops *ops,int *cnt)
@@ -1113,11 +1104,6 @@ static int disarm_kprobe_ftrace(struct kprobe *p) ipmodify ? &kprobe_ipmodify_enabled : &kprobe_ftrace_enabled); }#else /* !CONFIG_KPROBES_ON_FTRACE */ -static inline int prepare_kprobe (struct kprobe *p) -{ -return arch_prepare_kprobe (p); -} -static inline int arm_kprobe_ftrace (struct kprobe *p) {return -ENODEV ;
@@ -1129,6 +1115,15 @@ static inline int disarm_kprobe_ftrace(struct kprobe *p) }#endif +static int prepare_kprobe (struct kprobe *p) +{ +/* Must ensure p->addr is really on ftrace */ +if (kprobe_ftrace (p)) +return arch_prepare_kprobe_ftrace (p); + +return arch_prepare_kprobe (p); +} +/* Arm a kprobe with text_mutex */ static int arm_kprobe (struct kprobe *kp) {
Masami Hiramatsu
maintainerPATCH v11 4/27 csky: ftrace: Drop duplicate implementation of arch_check_ftrace_location()
In reply to Masami HiramatsuFrom: Punit Agrawal <[email protected]>
The csky specific arch_check_ftrace_location() shadows a weak implementation of the function in core code that offers the same functionality but with additional error checking.
Drop the architecture specific function as a step towards further cleanup in core code.
--- arch/csky/kernel/probes/ftrace.c | 7 ------- 1 file changed, 7 deletions(-)
arch/csky/kernel/probes/ftrace.c +0 -7
@@ -2,13 +2,6 @@#include <linux/kprobes.h> -int arch_check_ftrace_location (struct kprobe *p) -{ -if (ftrace_location ((unsigned long )p->addr)) - p->flags |=KPROBE_FLAG_FTRACE ; -return 0 ; -} -/* Ftrace callback handler for kprobes -- called under preepmt disabled */ void kprobe_ftrace_handler (unsigned long ip,unsigned long parent_ip,struct ftrace_ops *ops,struct ftrace_regs *fregs)
Masami Hiramatsu
maintainerPATCH v11 5/27 kprobes: Make arch_check_ftrace_location static
In reply to Masami HiramatsuFrom: Punit Agrawal <[email protected]>
arch_check_ftrace_location() was introduced as a weak function in commit f7f242ff004499 ("kprobes: introduce weak arch_check_ftrace_location() helper function") to allow architectures to handle kprobes call site on their own.
Recently, the only architecture (csky) to implement arch_check_ftrace_location() was migrated to using the common version.
As a result, further cleanup the code to drop the weak attribute and rename the function to remove the architecture specific implementation.
--- include/linux/kprobes.h | 2 -- kernel/kprobes.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-)
include/linux/kprobes.h +0 -2
@@ -361,8 +361,6 @@ static inline int arch_prepare_kprobe_ftrace(struct kprobe *p) }#endif -int arch_check_ftrace_location (struct kprobe *p); -/* Get the kprobe at this addr (if any) - called with preemption disabled */ struct kprobe *get_kprobe (void *addr);
kernel/kprobes.c +2 -2
@@ -1524,7 +1524,7 @@ static inline int warn_kprobe_rereg(struct kprobe *p)return ret; } -int __weak arch_check_ftrace_location (struct kprobe *p) +static int check_ftrace_location (struct kprobe *p) {unsigned long ftrace_addr;
@@ -1547,7 +1547,7 @@ static int check_kprobe_address_safe(struct kprobe *p, {int ret; - ret =arch_check_ftrace_location (p); + ret =check_ftrace_location (p);if (ret)return ret;jump_label_lock ();
Masami Hiramatsu
maintainerPATCH v11 6/27 kprobes: treewide: Cleanup the error messages for kprobes
In reply to Masami HiramatsuThis clean up the error/notification messages in kprobes related code. Basically this defines 'pr_fmt()' macros for each files and update the messages which describes
- what happened,
- what is the kernel going to do or not do,
- is the kernel fine,
- what can the user do about it.
Also, if the message is not needed (e.g. the function returns unique error code, or other error message is already shown.) remove it, and replace the message with WARN_*() macros if suitable.
--- arch/arm/probes/kprobes/core.c | 4 +++- arch/arm64/kernel/probes/kprobes.c | 5 ++++- arch/csky/kernel/probes/kprobes.c | 10 +++++----- arch/mips/kernel/kprobes.c | 11 +++++------ arch/riscv/kernel/probes/kprobes.c | 11 +++++------ arch/s390/kernel/kprobes.c | 4 +++- kernel/kprobes.c | 36 ++++++++++++++++-------------------- 7 files changed, 41 insertions(+), 40 deletions(-)
arch/arm/probes/kprobes/core.c +3 -1
@@ -11,6 +11,8 @@* Copyright (C) 2007 Marvell Ltd. */ +#define pr_fmt (fmt) "kprobes: " fmt +#include <linux/kernel.h> #include <linux/kprobes.h> #include <linux/module.h>
@@ -278,7 +280,7 @@ void __kprobes kprobe_handler(struct pt_regs *regs)break ;case KPROBE_REENTER :/* A nested probe was hit in FIQ, it is a BUG */ -pr_warn ("Unrecoverable kprobe detected.\n" ); +pr_warn ("Failed to recover from reentered kprobes.\n" );dump_kprobe (p); fallthrough;default :
arch/arm64/kernel/probes/kprobes.c +4 -1
@@ -7,6 +7,9 @@* Copyright (C) 2013 Linaro Limited. * Author: Sandeepa Prabhu <[email protected]> */ + +#define pr_fmt (fmt) "kprobes: " fmt +#include <linux/extable.h> #include <linux/kasan.h> #include <linux/kernel.h>
@@ -218,7 +221,7 @@ static int __kprobes reenter_kprobe(struct kprobe *p,break ;case KPROBE_HIT_SS :case KPROBE_REENTER : -pr_warn ("Unrecoverable kprobe detected.\n" ); +pr_warn ("Failed to recover from reentered kprobes.\n" );dump_kprobe (p);BUG ();break ;
arch/csky/kernel/probes/kprobes.c +5 -5
@@ -1,5 +1,7 @@// SPDX-License-Identifier: GPL-2.0+ +#define pr_fmt (fmt) "kprobes: " fmt +#include <linux/kprobes.h> #include <linux/extable.h> #include <linux/slab.h>
@@ -77,10 +79,8 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) {unsigned long probe_addr = (unsigned long )p->addr; -if (probe_addr &0x1 ) { -pr_warn ("Address not aligned.\n" ); -return -EINVAL ; - } +if (probe_addr &0x1 ) +return -EILSEQ ;/* copy instruction */ p->opcode =le32_to_cpu (*p->addr);
@@ -225,7 +225,7 @@ static int __kprobes reenter_kprobe(struct kprobe *p,break ;case KPROBE_HIT_SS :case KPROBE_REENTER : -pr_warn ("Unrecoverable kprobe detected.\n" ); +pr_warn ("Failed to recover from reentered kprobes.\n" );dump_kprobe (p);BUG ();break ;
arch/mips/kernel/kprobes.c +5 -6
@@ -11,6 +11,8 @@* Copyright (C) IBM Corporation, 2002, 2004 */ +#define pr_fmt (fmt) "kprobes: " fmt +#include <linux/kprobes.h> #include <linux/preempt.h> #include <linux/uaccess.h>
@@ -80,8 +82,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) insn = p->addr[0 ];if (insn_has_ll_or_sc (insn)) { -pr_notice ("Kprobes for ll and sc instructions are not" -"supported\n" ); +pr_notice ("Kprobes for ll and sc instructions are not supported\n" ); ret = -EINVAL ; goto out; }
@@ -219,7 +220,7 @@ static int evaluate_branch_instruction(struct kprobe *p, struct pt_regs *regs,return 0 ; unaligned: -pr_notice ("%s: unaligned epc - sending SIGBUS.\n" , current->comm); +pr_notice ("Failed to emulate branch instruction because of unaligned epc - sending SIGBUS to %s.\n" , current->comm);force_sig (SIGBUS );return -EFAULT ;
@@ -238,10 +239,8 @@ static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs, regs->cp0_epc = (unsigned long )p->addr; else if (insn_has_delayslot(p->opcode)) { ret =evaluate_branch_instruction (p, regs, kcb); -if (ret <0 ) { -pr_notice ("Kprobes: Error in evaluating branch\n" ); +if (ret <0 )return ; - } } regs->cp0_epc = (unsigned long )&p->ainsn.insn[0 ]; }
arch/riscv/kernel/probes/kprobes.c +5 -6
@@ -1,5 +1,7 @@// SPDX-License-Identifier: GPL-2.0+ +#define pr_fmt (fmt) "kprobes: " fmt +#include <linux/kprobes.h> #include <linux/extable.h> #include <linux/slab.h>
@@ -50,11 +52,8 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) {unsigned long probe_addr = (unsigned long )p->addr; -if (probe_addr &0x1 ) { -pr_warn ("Address not aligned.\n" ); - -return -EINVAL ; - } +if (probe_addr &0x1 ) +return -EILSEQ ;/* copy instruction */ p->opcode = *p->addr;
@@ -191,7 +190,7 @@ static int __kprobes reenter_kprobe(struct kprobe *p,break ;case KPROBE_HIT_SS :case KPROBE_REENTER : -pr_warn ("Unrecoverable kprobe detected.\n" ); +pr_warn ("Failed to recover from reentered kprobes.\n" );dump_kprobe (p);BUG ();break ;
arch/s390/kernel/kprobes.c +3 -1
@@ -7,6 +7,8 @@* s390 port, used ppc64 as template. Mike Grundy <[email protected]> */ +#define pr_fmt (fmt) "kprobes: " fmt +#include <linux/moduleloader.h> #include <linux/kprobes.h> #include <linux/ptrace.h>
@@ -259,7 +261,7 @@ static void kprobe_reenter_check(struct kprobe_ctlblk *kcb, struct kprobe *p)* is a BUG. The code path resides in the .kprobes.text * section and is executed with interrupts disabled. */ -pr_err ("Invalid kprobe detected.\n" ); +pr_err ("Failed to recover from reentered kprobes.\n" );dump_kprobe (p);BUG (); }
kernel/kprobes.c +16 -20
@@ -18,6 +18,9 @@* <[email protected]> and Prasanna S Panchamukhi * <[email protected]> added function-return probes. */ + +#define pr_fmt (fmt) "kprobes: " fmt +#include <linux/kprobes.h> #include <linux/hash.h> #include <linux/init.h>
@@ -892,7 +895,7 @@ static void optimize_all_kprobes(void)optimize_kprobe (p); }cpus_read_unlock (); -printk (KERN_INFO "Kprobes globally optimized\n" ); +pr_info ("kprobe jump-optimization is enabled. All kprobes are optimized if possible.\n" ); out:mutex_unlock (&kprobe_mutex); }
@@ -925,7 +928,7 @@ static void unoptimize_all_kprobes(void)/* Wait for unoptimizing completion */ wait_for_kprobe_optimizer (); -printk (KERN_INFO "Kprobes globally unoptimized\n" ); +pr_info ("kprobe jump-optimization is disabled. All kprobes are based on software breakpoint.\n" ); }static DEFINE_MUTEX (kprobe_sysctl_mutex);
@@ -1003,7 +1006,7 @@ static int reuse_unused_kprobe(struct kprobe *ap)* unregistered. * Thus there should be no chance to reuse unused kprobe. */ -printk (KERN_ERR "Error: There should be no unused kprobe here.\n" ); +WARN_ON_ONCE (1 );return -EINVAL ; }
@@ -1040,18 +1043,13 @@ static int __arm_kprobe_ftrace(struct kprobe *p, struct ftrace_ops *ops,int ret =0 ; ret =ftrace_set_filter_ip (ops, (unsigned long )p->addr,0 ,0 ); -if (ret) { -pr_debug ("Failed to arm kprobe-ftrace at %pS (%d)\n" , - p->addr, ret); +if (WARN_ONCE (ret <0 ,"Failed to arm kprobe-ftrace at %pS (error %d)\n" , p->addr, ret))return ret; - }if (*cnt =0 ) { ret =register_ftrace_function (ops); -if (ret) { -pr_debug ("Failed to init kprobe-ftrace (%d)\n" , ret); +if (WARN (ret <0 ,"Failed to register kprobe-ftrace (error %d)\n" , ret)) goto err_ftrace; - } } (*cnt)++;
@@ -1083,14 +1081,14 @@ static int __disarm_kprobe_ftrace(struct kprobe *p, struct ftrace_ops *ops,if (*cnt =1 ) { ret =unregister_ftrace_function (ops); -if (WARN (ret <0 ,"Failed to unregister kprobe-ftrace (%d)\n" , ret)) +if (WARN (ret <0 ,"Failed to unregister kprobe-ftrace (error %d)\n" , ret))return ret; } (*cnt)--; ret =ftrace_set_filter_ip (ops, (unsigned long )p->addr,1 ,0 ); -WARN_ONCE (ret <0 ,"Failed to disarm kprobe-ftrace at %pS (%d)\n" , +WARN_ONCE (ret <0 ,"Failed to disarm kprobe-ftrace at %pS (error %d)\n" , p->addr, ret);return ret; }
@@ -1880,7 +1878,7 @@ unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs, node = node->next; } -pr_err ("Oops! Kretprobe fails to find correct return address.\n" ); +pr_err ("kretprobe: Return address not found, not execute handler. Maybe there is a bug in the kernel.\n" );BUG_ON (1 ); found:
@@ -2209,8 +2207,7 @@ EXPORT_SYMBOL_GPL(enable_kprobe);/* Caller must NOT call this in usual path. This is only for critical case */ void dump_kprobe (struct kprobe *kp) { -pr_err ("Dumping kprobe:\n" ); -pr_err ("Name: %s\nOffset: %x\nAddress: %pS\n" , +pr_err ("Dump kprobe:\n.symbol_name = %s, .offset = %x, .addr = %pS\n" , kp->symbol_name, kp->offset, kp->addr); }NOKPROBE_SYMBOL (dump_kprobe);
@@ -2473,8 +2470,7 @@ static int __init init_kprobes(void) err =populate_kprobe_blacklist (__start_kprobe_blacklist, __stop_kprobe_blacklist);if (err) { -pr_err ("kprobes: failed to populate blacklist: %d\n" , err); -pr_err ("Please take care of using kprobes.\n" ); +pr_err ("Failed to populate blacklist (error %d), kprobes not restricted, be careful using them!\n" , err); }if (kretprobe_blacklist_size) {
@@ -2483,7 +2479,7 @@ static int __init init_kprobes(void) kretprobe_blacklist[i].addr kprobe_lookup_name(kretprobe_blacklist[i].name, 0);if (!kretprobe_blacklist[i].addr) -printk ("kretprobe: lookup failed: %s\n" , +pr_err ("Failed to lookup symbol '%s' for kretprobe blacklist. Maybe the target function is removed or renamed.\n" , kretprobe_blacklist[i].name); } }
@@ -2687,7 +2683,7 @@ static int arm_all_kprobes(void) }if (errors) -pr_warn ("Kprobes globally enabled, but failed to arm %d out of %d probes\n" , +pr_warn ("Kprobes globally enabled, but failed to enable %d out of %d probes. Please check which kprobes are kept disabled via debugfs.\n" , errors, total);else pr_info ("Kprobes globally enabled\n" );
@@ -2730,7 +2726,7 @@ static int disarm_all_kprobes(void) }if (errors) -pr_warn ("Kprobes globally disabled, but failed to disarm %d out of %d probes\n" , +pr_warn ("Kprobes globally disabled, but failed to disable %d out of %d probes. Please check which kprobes are kept enabled via debugfs.\n" , errors, total);else pr_info ("Kprobes globally disabled\n" );
Masami Hiramatsu
maintainerPATCH v11 7/27 kprobes: Fix coding style issues
In reply to Masami HiramatsuFix coding style issues reported by checkpatch.pl and update comments to quote variable names and add "()" to function name.
One TODO comment in __disarm_kprobe() is removed because it has been done by following commit.
--- include/linux/kprobes.h | 40 +++++--- kernel/kprobes.c | 236 ++++++++++++++++++++++++----------------------- 2 files changed, 145 insertions(+), 131 deletions(-)
include/linux/kprobes.h +23 -17
@@ -3,7 +3,6 @@#define _LINUX_KPROBES_H/* * Kernel Probes (KProbes) -* include/linux/kprobes.h * * Copyright (C) IBM Corporation, 2002, 2004 *
@@ -39,7 +38,7 @@#define KPROBE_REENTER 0x00000004#define KPROBE_HIT_SSDONE 0x00000008 -#else /* CONFIG_KPROBES */ +#else /* !CONFIG_KPROBES */ #include <asm-generic/kprobes.h> typedef int kprobe_opcode_t ; struct arch_specific_insn {
@@ -228,7 +227,7 @@ static nokprobe_inline struct kretprobe *get_kretprobe(struct kretprobe_instance return READ_ONCE(ri->rph->rp); } -#else /* CONFIG_KRETPROBES */ +#else /* !CONFIG_KRETPROBES */ static inline void arch_prepare_kretprobe (struct kretprobe *rp,struct pt_regs *regs) {
@@ -239,11 +238,15 @@ static inline int arch_trampoline_kprobe(struct kprobe *p) }#endif /* CONFIG_KRETPROBES */ +/* Markers of '_kprobe_blacklist' section */ +extern unsigned long __start_kprobe_blacklist[]; +extern unsigned long __stop_kprobe_blacklist[]; +extern struct kretprobe_blackpoint kretprobe_blacklist[];#ifdef CONFIG_KPROBES_SANITY_TEST extern int init_test_probes (void ); -#else +#else /* !CONFIG_KPROBES_SANITY_TEST */ static inline int init_test_probes (void ) {return 0 ;
@@ -303,7 +306,7 @@ static inline bool is_kprobe_##__name##_slot(unsigned long addr) \#define KPROBE_OPTINSN_PAGE_SYM "kprobe_optinsn_page"int kprobe_cache_get_kallsym (struct kprobe_insn_cache *c,unsigned int *symnum,unsigned long *value,char *type,char *sym); -#else /* __ARCH_WANT_KPROBES_INSN_SLOT */ +#else /* !__ARCH_WANT_KPROBES_INSN_SLOT */ #define DEFINE_INSN_CACHE_OPS (__name) \ static inline bool is_kprobe_##__name##_slot(unsigned long addr) \ { \
@@ -345,11 +348,12 @@ extern int sysctl_kprobes_optimization;extern int proc_kprobes_optimization_handler (struct ctl_table *table,int write,void *buffer,size_t *length,loff_t *ppos); -#endif +#endif /* CONFIG_SYSCTL */ extern void wait_for_kprobe_optimizer (void ); -#else +#else /* !CONFIG_OPTPROBES */ static inline void wait_for_kprobe_optimizer (void ) { }#endif /* CONFIG_OPTPROBES */ +#ifdef CONFIG_KPROBES_ON_FTRACE extern void kprobe_ftrace_handler (unsigned long ip,unsigned long parent_ip,struct ftrace_ops *ops,struct ftrace_regs *fregs);
@@ -359,7 +363,7 @@ static inline int arch_prepare_kprobe_ftrace(struct kprobe *p) {return -EINVAL ; } -#endif +#endif /* CONFIG_KPROBES_ON_FTRACE */ /* Get the kprobe at this addr (if any) - called with preemption disabled */ struct kprobe *get_kprobe (void *addr);
@@ -367,7 +371,7 @@ struct kprobe *get_kprobe(void *addr);/* kprobe_running() will just return the current_kprobe on this CPU */ static inline struct kprobe *kprobe_running (void ) { -return (__this_cpu_read (current_kprobe)); +return __this_cpu_read (current_kprobe); }static inline void reset_current_kprobe (void )
@@ -431,11 +435,11 @@ static inline struct kprobe *kprobe_running(void) }static inline int register_kprobe (struct kprobe *p) { -return -ENOSYS ; +return -EOPNOTSUPP ; }static inline int register_kprobes (struct kprobe **kps,int num) { -return -ENOSYS ; +return -EOPNOTSUPP ; }static inline void unregister_kprobe (struct kprobe *p) {
@@ -445,11 +449,11 @@ static inline void unregister_kprobes(struct kprobe **kps, int num) }static inline int register_kretprobe (struct kretprobe *rp) { -return -ENOSYS ; +return -EOPNOTSUPP ; }static inline int register_kretprobes (struct kretprobe **rps,int num) { -return -ENOSYS ; +return -EOPNOTSUPP ; }static inline void unregister_kretprobe (struct kretprobe *rp) {
@@ -465,11 +469,11 @@ static inline void kprobe_free_init_mem(void) }static inline int disable_kprobe (struct kprobe *kp) { -return -ENOSYS ; +return -EOPNOTSUPP ; }static inline int enable_kprobe (struct kprobe *kp) { -return -ENOSYS ; +return -EOPNOTSUPP ; }static inline bool within_kprobe_blacklist (unsigned long addr)
@@ -482,6 +486,7 @@ static inline int kprobe_get_kallsym(unsigned int symnum, unsigned long *value, return -ERANGE; }#endif /* CONFIG_KPROBES */ +static inline int disable_kretprobe (struct kretprobe *rp) {return disable_kprobe (&rp->kp);
@@ -496,13 +501,14 @@ static inline bool is_kprobe_insn_slot(unsigned long addr) {return false; } -#endif +#endif /* !CONFIG_KPROBES */ +#ifndef CONFIG_OPTPROBES static inline bool is_kprobe_optinsn_slot (unsigned long addr) {return false; } -#endif +#endif /* !CONFIG_OPTPROBES */ /* Returns true if kprobes handled the fault */ static nokprobe_inline bool kprobe_page_fault(struct pt_regs *regs,
kernel/kprobes.c +122 -114
730 lines not on this page · raw message
Masami Hiramatsu
maintainerPATCH v11 8/27 kprobes: Use IS_ENABLED() instead of kprobes_built_in()
In reply to Masami HiramatsuUse IS_ENABLED(CONFIG_KPROBES) instead of kprobes_built_in(). This inline function is introduced only for avoiding #ifdef. But since now we have IS_ENABLED(), it is no longer needed.
--- include/linux/kprobes.h | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-)
include/linux/kprobes.h +1 -13
@@ -180,14 +180,6 @@ struct kprobe_blacklist_entry { DECLARE_PER_CPU(struct kprobe *, current_kprobe); DECLARE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); -/* -* For #ifdef avoidance: -*/ -static inline int kprobes_built_in (void ) -{ -return 1 ; -} -extern void kprobe_busy_begin (void );extern void kprobe_busy_end (void );
@@ -417,10 +409,6 @@ int arch_kprobe_get_kallsym(unsigned int *symnum, unsigned long *value, char *type, char *sym);#else /* !CONFIG_KPROBES: */ -static inline int kprobes_built_in (void ) -{ -return 0 ; -}static inline int kprobe_fault_handler (struct pt_regs *regs,int trapnr) {return 0 ;
@@ -514,7 +502,7 @@ static inline bool is_kprobe_optinsn_slot(unsigned long addr) static nokprobe_inline bool kprobe_page_fault(struct pt_regs *regs,unsigned int trap) { -if (!kprobes_built_in ()) +if (!IS_ENABLED (CONFIG_KPROBES ))return false;if (user_mode (regs))return false;
Masami Hiramatsu
maintainerPATCH v11 9/27 kprobes: Add assertions for required lock
In reply to Masami HiramatsuAdd assertions for required locks instead of comment it so that the lockdep can inspect locks automatically.
--- kernel/kprobes.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
kernel/kprobes.c +12 -7
@@ -959,11 +959,13 @@ int proc_kprobes_optimization_handler(struct ctl_table *table, int write, }#endif /* CONFIG_SYSCTL */ -/* Put a breakpoint for a probe. Must be called with 'text_mutex' locked. */ +/* Put a breakpoint for a probe. */ static void __arm_kprobe (struct kprobe *p) {struct kprobe *_p; +lockdep_assert_held (&text_mutex); +/* Find the overlapping optimized kprobes. */ _p =get_optimized_kprobe ((unsigned long )p->addr);if (unlikely (_p))
@@ -974,11 +976,13 @@ static void __arm_kprobe(struct kprobe *p)optimize_kprobe (p);/* Try to optimize (add kprobe to a list) */ } -/* Remove the breakpoint of a probe. Must be called with 'text_mutex' locked. */ +/* Remove the breakpoint of a probe. */ static void __disarm_kprobe (struct kprobe *p,bool reopt) {struct kprobe *_p; +lockdep_assert_held (&text_mutex); +/* Try to unoptimize */ unoptimize_kprobe (p, kprobes_all_disarmed);
@@ -1047,12 +1051,13 @@ static struct ftrace_ops kprobe_ipmodify_ops __read_mostly = {static int kprobe_ipmodify_enabled;static int kprobe_ftrace_enabled; -/* Caller must lock 'kprobe_mutex' */ static int __arm_kprobe_ftrace (struct kprobe *p,struct ftrace_ops *ops,int *cnt) {int ret =0 ; +lockdep_assert_held (&kprobe_mutex); + ret =ftrace_set_filter_ip (ops, (unsigned long )p->addr,0 ,0 );if (WARN_ONCE (ret <0 ,"Failed to arm kprobe-ftrace at %pS (error %d)\n" , p->addr, ret))return ret;
@@ -1084,12 +1089,13 @@ static int arm_kprobe_ftrace(struct kprobe *p) ipmodify ? &kprobe_ipmodify_enabled : &kprobe_ftrace_enabled); } -/* Caller must lock 'kprobe_mutex'. */ static int __disarm_kprobe_ftrace (struct kprobe *p,struct ftrace_ops *ops,int *cnt) {int ret =0 ; +lockdep_assert_held (&kprobe_mutex); +if (*cnt =1 ) { ret =unregister_ftrace_function (ops);if (WARN (ret <0 ,"Failed to unregister kprobe-ftrace (error %d)\n" , ret))
@@ -1133,7 +1139,6 @@ static int prepare_kprobe(struct kprobe *p)return arch_prepare_kprobe (p); } -/* Arm a kprobe with 'text_mutex'. */ static int arm_kprobe (struct kprobe *kp) {if (unlikely (kprobe_ftrace (kp)))
@@ -1148,7 +1153,6 @@ static int arm_kprobe(struct kprobe *kp)return 0 ; } -/* Disarm a kprobe with 'text_mutex'. */ static int disarm_kprobe (struct kprobe *kp,bool reopt) {if (unlikely (kprobe_ftrace (kp)))
@@ -1691,12 +1695,13 @@ static int aggr_kprobe_disabled(struct kprobe *ap)return 1 ; } -/* Disable one kprobe: Make sure called under 'kprobe_mutex' is locked. */ static struct kprobe *__disable_kprobe (struct kprobe *p) {struct kprobe *orig_p;int ret; +lockdep_assert_held (&kprobe_mutex); +/* Get an original kprobe for return */ orig_p =__get_valid_kprobe (p);if (unlikely (orig_p =NULL ))
Masami Hiramatsu
maintainerPATCH v11 10/27 kprobes: treewide: Use 'kprobe_opcode_t *' for the code address in get_optimized_kprobe()
In reply to Masami HiramatsuSince get_optimized_kprobe() is only used inside kprobes, it doesn't need to use 'unsigned long' type for 'addr' parameter. Make it use 'kprobe_opcode_t *' for the 'addr' parameter and subsequent call of arch_within_optimized_kprobe() also should use 'kprobe_opcode_t *'.
Note that MAX_OPTIMIZED_LENGTH and RELATIVEJUMP_SIZE are defined by byte-size, but the size of 'kprobe_opcode_t' depends on the architecture. Therefore, we must be careful when calculating addresses using those macros.
--- arch/arm/probes/kprobes/opt-arm.c | 7 ++++--- arch/powerpc/kernel/optprobes.c | 6 +++--- arch/x86/kernel/kprobes/opt.c | 6 +++--- include/linux/kprobes.h | 2 +- kernel/kprobes.c | 10 +++++----- 5 files changed, 16 insertions(+), 15 deletions(-)
arch/arm/probes/kprobes/opt-arm.c +4 -3
@@ -347,10 +347,11 @@ void arch_unoptimize_kprobes(struct list_head *oplist, }int arch_within_optimized_kprobe (struct optimized_kprobe *op, -unsigned long addr) +kprobe_opcode_t *addr) { -return ((unsigned long )op->kp.addr <= addr && - (unsigned long )op->kp.addr +RELATIVEJUMP_SIZE > addr); +return (op->kp.addr <= addr && + op->kp.addr + (RELATIVEJUMP_SIZE /sizeof (kprobe_opcode_t)) > addr); + }void arch_remove_optimized_kprobe (struct optimized_kprobe *op)
arch/powerpc/kernel/optprobes.c +3 -3
@@ -301,8 +301,8 @@ void arch_unoptimize_kprobes(struct list_head *oplist, struct list_head *done_li } } -int arch_within_optimized_kprobe (struct optimized_kprobe *op,unsigned long addr) +int arch_within_optimized_kprobe (struct optimized_kprobe *op,kprobe_opcode_t *addr) { -return ((unsigned long )op->kp.addr <= addr && - (unsigned long )op->kp.addr +RELATIVEJUMP_SIZE > addr); +return (op->kp.addr <= addr && + op->kp.addr + (RELATIVEJUMP_SIZE /sizeof (kprobe_opcode_t)) > addr); }
arch/x86/kernel/kprobes/opt.c +3 -3
@@ -367,10 +367,10 @@ int arch_check_optimized_kprobe(struct optimized_kprobe *op)/* Check the addr is within the optimized instructions. */ int arch_within_optimized_kprobe (struct optimized_kprobe *op, -unsigned long addr) +kprobe_opcode_t *addr) { -return ((unsigned long )op->kp.addr <= addr && - (unsigned long )op->kp.addr + op->optinsn.size > addr); +return (op->kp.addr <= addr && + op->kp.addr + op->optinsn.size > addr); }/* Free optimized instruction slot */
include/linux/kprobes.h +1 -1
@@ -329,7 +329,7 @@ extern void arch_unoptimize_kprobes(struct list_head *oplist, struct list_head *done_list);extern void arch_unoptimize_kprobe (struct optimized_kprobe *op);extern int arch_within_optimized_kprobe (struct optimized_kprobe *op, -unsigned long addr); +kprobe_opcode_t *addr);extern void opt_pre_handler (struct kprobe *p,struct pt_regs *regs);
kernel/kprobes.c +5 -5
@@ -485,15 +485,15 @@ static int kprobe_queued(struct kprobe *p)* Return an optimized kprobe whose optimizing code replaces * instructions including 'addr' (exclude breakpoint). */ -static struct kprobe *get_optimized_kprobe (unsigned long addr) +static struct kprobe *get_optimized_kprobe (kprobe_opcode_t *addr) {int i;struct kprobe *p =NULL ;struct optimized_kprobe *op;/* Don't check i = 0, since that is a breakpoint case. */ -for (i =1 ; !p && i <MAX_OPTIMIZED_LENGTH ; i++) - p =get_kprobe ((void *)(addr - i)); +for (i =1 ; !p && i <MAX_OPTIMIZED_LENGTH /sizeof (kprobe_opcode_t); i++) + p =get_kprobe (addr - i);if (p &&kprobe_optready (p)) { op = container_of(p, struct optimized_kprobe, kp);
@@ -967,7 +967,7 @@ static void __arm_kprobe(struct kprobe *p)lockdep_assert_held (&text_mutex);/* Find the overlapping optimized kprobes. */ - _p =get_optimized_kprobe ((unsigned long )p->addr); + _p =get_optimized_kprobe (p->addr);if (unlikely (_p))/* Fallback to unoptimized kprobe */ unoptimize_kprobe (_p, true);
@@ -989,7 +989,7 @@ static void __disarm_kprobe(struct kprobe *p, bool reopt)if (!kprobe_queued (p)) {arch_disarm_kprobe (p);/* If another kprobe was blocked, re-optimize it. */ - _p =get_optimized_kprobe ((unsigned long )p->addr); + _p =get_optimized_kprobe (p->addr);if (unlikely (_p) && reopt)optimize_kprobe (_p); }
Masami Hiramatsu
maintainerPATCH v11 11/27 kprobes: Use bool type for functions which returns boolean value
In reply to Masami HiramatsuUse the 'bool' type instead of 'int' for the functions which returns a boolean value, because this makes clear that those functions don't return any error code.
---
Changes in v2:
- Fix trace_kprobe's kprobe_gone() too.
--- include/linux/kprobes.h | 8 ++++---- kernel/kprobes.c | 26 +++++++++++++------------- kernel/trace/trace_kprobe.c | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-)
include/linux/kprobes.h +4 -4
@@ -104,25 +104,25 @@ struct kprobe {#define KPROBE_FLAG_FTRACE 8/* probe is using ftrace */ /* Has this kprobe gone ? */ -static inline int kprobe_gone (struct kprobe *p) +static inline bool kprobe_gone (struct kprobe *p) {return p->flags &KPROBE_FLAG_GONE ; }/* Is this kprobe disabled ? */ -static inline int kprobe_disabled (struct kprobe *p) +static inline bool kprobe_disabled (struct kprobe *p) {return p->flags & (KPROBE_FLAG_DISABLED |KPROBE_FLAG_GONE ); }/* Is this kprobe really running optimized path ? */ -static inline int kprobe_optimized (struct kprobe *p) +static inline bool kprobe_optimized (struct kprobe *p) {return p->flags &KPROBE_FLAG_OPTIMIZED ; }/* Is this kprobe uses ftrace ? */ -static inline int kprobe_ftrace (struct kprobe *p) +static inline bool kprobe_ftrace (struct kprobe *p) {return p->flags &KPROBE_FLAG_FTRACE ; }
kernel/kprobes.c +13 -13
@@ -198,8 +198,8 @@ kprobe_opcode_t *__get_insn_slot(struct kprobe_insn_cache *c)return slot; } -/* Return 1 if all garbages are collected, otherwise 0. */ -static int collect_one_slot (struct kprobe_insn_page *kip,int idx) +/* Return true if all garbages are collected, otherwise false. */ +static bool collect_one_slot (struct kprobe_insn_page *kip,int idx) { kip->slot_used[idx] =SLOT_CLEAN ; kip->nused--;
@@ -223,9 +223,9 @@ static int collect_one_slot(struct kprobe_insn_page *kip, int idx) kip->cache->free (kip->insns);kfree (kip); } -return 1 ; +return true; } -return 0 ; +return false; }static int collect_garbage_slots (struct kprobe_insn_cache *c)
@@ -389,13 +389,13 @@ NOKPROBE_SYMBOL(get_kprobe);static int aggr_pre_handler (struct kprobe *p,struct pt_regs *regs);/* Return true if 'p' is an aggregator */ -static inline int kprobe_aggrprobe (struct kprobe *p) +static inline bool kprobe_aggrprobe (struct kprobe *p) {return p->pre_handler = aggr_pre_handler; }/* Return true if 'p' is unused */ -static inline int kprobe_unused (struct kprobe *p) +static inline bool kprobe_unused (struct kprobe *p) {return kprobe_aggrprobe (p) &&kprobe_disabled (p) &&list_empty (&p->list);
@@ -455,7 +455,7 @@ static inline int kprobe_optready(struct kprobe *p) }/* Return true if the kprobe is disarmed. Note: p must be on hash list */ -static inline int kprobe_disarmed (struct kprobe *p) +static inline bool kprobe_disarmed (struct kprobe *p) {struct optimized_kprobe *op;
@@ -469,16 +469,16 @@ static inline int kprobe_disarmed(struct kprobe *p) }/* Return true if the probe is queued on (un)optimizing lists */ -static int kprobe_queued (struct kprobe *p) +static bool kprobe_queued (struct kprobe *p) {struct optimized_kprobe *op;if (kprobe_aggrprobe (p)) { op = container_of(p, struct optimized_kprobe, kp);if (!list_empty (&op->list)) -return 1 ; +return true; } -return 0 ; +return false; }/*
@@ -1678,7 +1678,7 @@ int register_kprobe(struct kprobe *p)EXPORT_SYMBOL_GPL (register_kprobe);/* Check if all probes on the 'ap' are disabled. */ -static int aggr_kprobe_disabled (struct kprobe *ap) +static bool aggr_kprobe_disabled (struct kprobe *ap) {struct kprobe *kp;
@@ -1690,9 +1690,9 @@ static int aggr_kprobe_disabled(struct kprobe *ap)* Since there is an active probe on the list, * we can't disable this 'ap'. */ -return 0 ; +return false; -return 1 ; +return true; }static struct kprobe *__disable_kprobe (struct kprobe *p)
kernel/trace/trace_kprobe.c +1 -1
@@ -97,7 +97,7 @@ static nokprobe_inline unsigned long trace_kprobe_offset(struct trace_kprobe *tk static nokprobe_inline bool trace_kprobe_has_gone(struct trace_kprobe *tk) { -return !!(kprobe_gone (&tk->rp.kp)); +return kprobe_gone (&tk->rp.kp); } static nokprobe_inline bool trace_kprobe_within_module(struct trace_kprobe *tk,
Masami Hiramatsu
maintainerPATCH v11 12/27 ia64: kprobes: Fix to pass correct trampoline address to the handler
In reply to Masami HiramatsuThe following commit:
Commit e792ff804f49 ("ia64: kprobes: Use generic kretprobe trampoline handler")
Passed the wrong trampoline address to __kretprobe_trampoline_handler(): it passes the descriptor address instead of function entry address.
Pass the right parameter.
Also use correct symbol dereference function to get the function address from 'kretprobe_trampoline' - an IA64 special.
---
Changes in v9:
- Update changelog according to Ingo's suggestion.
- Add Cc: stable tag.
Changes in v5:
- Fix a compile error typo.
--- arch/ia64/kernel/kprobes.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
arch/ia64/kernel/kprobes.c +5 -3
@@ -398,7 +398,8 @@ static void kretprobe_trampoline(void)int __kprobes trampoline_probe_handler (struct kprobe *p,struct pt_regs *regs) { - regs->cr_iip =__kretprobe_trampoline_handler (regs, kretprobe_trampoline,NULL ); + regs->cr_iip =__kretprobe_trampoline_handler (regs, +dereference_function_descriptor (kretprobe_trampoline),NULL );/* * By returning a non-zero value, we are telling * kprobe_handler() that we don't want the post_handler
@@ -414,7 +415,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ri->fp =NULL ;/* Replace the return addr with trampoline addr */ - regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip; + regs->b0 = (unsigned long )dereference_function_descriptor (kretprobe_trampoline); }/* Check the instruction in the slot is break */
@@ -902,14 +903,14 @@ static struct kprobe trampoline_p = {int __init arch_init_kprobes (void ) { trampoline_p.addr - (kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip; +dereference_function_descriptor (kretprobe_trampoline);return register_kprobe (&trampoline_p); }int __kprobes arch_trampoline_kprobe (struct kprobe *p) {if (p->addr = - (kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip) +dereference_function_descriptor (kretprobe_trampoline))return 1 ;return 0 ;
Masami Hiramatsu
maintainerPATCH v11 13/27 kprobes: treewide: Replace arch_deref_entry_point() with dereference_symbol_descriptor()
In reply to Masami Hiramatsu~15 years ago kprobes grew the 'arch_deref_entry_point()' __weak function:
3d7e33825d87: ("jprobes: make jprobes a little safer for users")
But this is just open-coded dereference_symbol_descriptor() in essence, and its obscure nature was causing bugs.
Just use the real thing and remove arch_deref_entry_point().
---
Changes in v9:
- Update changelog according to Ingo's suggestion.
Changes in v6:
- Use dereference_symbol_descriptor() so that it can handle address in modules correctly.
--- arch/ia64/kernel/kprobes.c | 5 ----- arch/powerpc/kernel/kprobes.c | 11 ----------- include/linux/kprobes.h | 1 - kernel/kprobes.c | 7 +------ lib/error-inject.c | 3 ++- 5 files changed, 3 insertions(+), 24 deletions(-)
arch/ia64/kernel/kprobes.c +0 -5
@@ -891,11 +891,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,return ret; } -unsigned long arch_deref_entry_point (void *entry) -{ -return ((struct fnptr *)entry)->ip; -} -static struct kprobe trampoline_p = { .pre_handler = trampoline_probe_handler };
arch/powerpc/kernel/kprobes.c +0 -11
@@ -542,17 +542,6 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr) }NOKPROBE_SYMBOL (kprobe_fault_handler); -unsigned long arch_deref_entry_point (void *entry) -{ -#ifdef PPC64_ELF_ABI_v1 -if (!kernel_text_address ((unsigned long )entry)) -return ppc_global_function_entry (entry); - else -#endif -return (unsigned long )entry; -} -NOKPROBE_SYMBOL (arch_deref_entry_point); -static struct kprobe trampoline_p = { .addr = (kprobe_opcode_t *) &kretprobe_trampoline, .pre_handler = trampoline_probe_handler
include/linux/kprobes.h +0 -1
@@ -381,7 +381,6 @@ int register_kprobe(struct kprobe *p);void unregister_kprobe (struct kprobe *p);int register_kprobes (struct kprobe **kps,int num);void unregister_kprobes (struct kprobe **kps,int num); -unsigned long arch_deref_entry_point (void *);int register_kretprobe (struct kretprobe *rp);void unregister_kretprobe (struct kretprobe *rp);
kernel/kprobes.c +1 -6
@@ -1861,11 +1861,6 @@ static struct notifier_block kprobe_exceptions_nb = { .priority = 0x7fffffff /* we need to be notified first */ }; -unsigned long __weak arch_deref_entry_point (void *entry) -{ -return (unsigned long )entry; -} -#ifdef CONFIG_KRETPROBES unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs,
@@ -2327,7 +2322,7 @@ static int __init populate_kprobe_blacklist(unsigned long *start,int ret;for (iter = start; iter < end; iter++) { - entry =arch_deref_entry_point ((void *)*iter); + entry = (unsigned long )dereference_symbol_descriptor ((void *)*iter); ret =kprobe_add_ksym_blacklist (entry);if (ret = -EINVAL )continue ;
lib/error-inject.c +2 -1
@@ -8,6 +8,7 @@#include <linux/mutex.h> #include <linux/list.h> #include <linux/slab.h> +#include <asm/sections.h> /* Whitelist of symbols that can be overridden for error injection. */ static LIST_HEAD (error_injection_list);
@@ -64,7 +65,7 @@ static void populate_error_injection_list(struct error_injection_entry *start,mutex_lock (&ei_mutex);for (iter = start; iter < end; iter++) { - entry =arch_deref_entry_point ((void *)iter->addr); + entry = (unsigned long )dereference_symbol_descriptor ((void *)iter->addr);if (!kernel_text_address (entry) || !kallsyms_lookup_size_offset (entry, &size, &offset)) {
Masami Hiramatsu
maintainerPATCH v11 14/27 kprobes: treewide: Remove trampoline_address from kretprobe_trampoline_handler()
In reply to Masami HiramatsuThe __kretprobe_trampoline_handler() callback, called from low level arch kprobes methods, has the 'trampoline_address' parameter, which is entirely superfluous as it basically just replicates:
dereference_kernel_function_descriptor(kretprobe_trampoline)
In fact we had bugs in arch code where it wasn't replicated correctly.
So remove this superfluous parameter and use kretprobe_trampoline_addr() instead.
---
Changes in v9:
- Update changelog according to Ingo's suggestion.
Changes in v8:
- Use dereference_kernel_function_descriptor() to get the kretprobe_trampoline address.
Changes in v3:
- Remove wrong kretprobe_trampoline declaration from
arch/x86/include/asm/kprobes.h. Changes in v2: - Remove arch_deref_entry_point() from comment. --- arch/arc/kernel/kprobes.c | 2 +- arch/arm/probes/kprobes/core.c | 3 +-- arch/arm64/kernel/probes/kprobes.c | 3 +-- arch/csky/kernel/probes/kprobes.c | 2 +- arch/ia64/kernel/kprobes.c | 5 ++--- arch/mips/kernel/kprobes.c | 3 +-- arch/parisc/kernel/kprobes.c | 4 ++-- arch/powerpc/kernel/kprobes.c | 2 +- arch/riscv/kernel/probes/kprobes.c | 2 +- arch/s390/kernel/kprobes.c | 2 +- arch/sh/kernel/kprobes.c | 2 +- arch/sparc/kernel/kprobes.c | 2 +- arch/x86/include/asm/kprobes.h | 1 - arch/x86/kernel/kprobes/core.c | 2 +- include/linux/kprobes.h | 18 +++++++++++++----- kernel/kprobes.c | 3 +-- 16 files changed, 29 insertions(+), 27 deletions(-)
arch/arc/kernel/kprobes.c +1 -1
@@ -381,7 +381,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,static int __kprobes trampoline_probe_handler (struct kprobe *p,struct pt_regs *regs) { - regs->ret =__kretprobe_trampoline_handler (regs, &kretprobe_trampoline,NULL ); + regs->ret =__kretprobe_trampoline_handler (regs,NULL );/* By returning a non zero value, we are telling the kprobe handler * that we don't want the post_handler to run
arch/arm/probes/kprobes/core.c +1 -2
@@ -392,8 +392,7 @@ void __naked __kprobes kretprobe_trampoline(void)/* Called from kretprobe_trampoline */ static __used __kprobes void *trampoline_handler (struct pt_regs *regs) { -return (void *)kretprobe_trampoline_handler (regs, &kretprobe_trampoline, - (void *)regs->ARM_fp); +return (void *)kretprobe_trampoline_handler (regs, (void *)regs->ARM_fp); } void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
arch/arm64/kernel/probes/kprobes.c +1 -2
@@ -401,8 +401,7 @@ int __init arch_populate_kprobe_blacklist(void)void __kprobes __used *trampoline_probe_handler (struct pt_regs *regs) { -return (void *)kretprobe_trampoline_handler (regs, &kretprobe_trampoline, - (void *)kernel_stack_pointer (regs)); +return (void *)kretprobe_trampoline_handler (regs, (void *)kernel_stack_pointer (regs)); } void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
arch/csky/kernel/probes/kprobes.c +1 -1
@@ -386,7 +386,7 @@ int __init arch_populate_kprobe_blacklist(void)void __kprobes __used *trampoline_probe_handler (struct pt_regs *regs) { -return (void *)kretprobe_trampoline_handler (regs, &kretprobe_trampoline,NULL ); +return (void *)kretprobe_trampoline_handler (regs,NULL ); } void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
arch/ia64/kernel/kprobes.c +2 -3
@@ -392,14 +392,13 @@ static void __kprobes set_current_kprobe(struct kprobe *p,__this_cpu_write (current_kprobe, p); } -static void kretprobe_trampoline (void ) +void kretprobe_trampoline (void ) { }int __kprobes trampoline_probe_handler (struct kprobe *p,struct pt_regs *regs) { - regs->cr_iip =__kretprobe_trampoline_handler (regs, -dereference_function_descriptor (kretprobe_trampoline),NULL ); + regs->cr_iip =__kretprobe_trampoline_handler (regs,NULL );/* * By returning a non-zero value, we are telling * kprobe_handler() that we don't want the post_handler
arch/mips/kernel/kprobes.c +1 -2
@@ -485,8 +485,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,static int __kprobes trampoline_probe_handler (struct kprobe *p,struct pt_regs *regs) { -instruction_pointer (regs) =__kretprobe_trampoline_handler (regs, - kretprobe_trampoline,NULL ); +instruction_pointer (regs) =__kretprobe_trampoline_handler (regs,NULL );/* * By returning a non-zero value, we are telling * kprobe_handler() that we don't want the post_handler
arch/parisc/kernel/kprobes.c +2 -2
@@ -175,7 +175,7 @@ int __kprobes parisc_kprobe_ss_handler(struct pt_regs *regs)return 1 ; } -static inline void kretprobe_trampoline (void ) +void kretprobe_trampoline (void ) { asmvolatile ("nop" ); asmvolatile ("nop" );
@@ -193,7 +193,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p, {unsigned long orig_ret_address; - orig_ret_address =__kretprobe_trampoline_handler (regs, trampoline_p.addr,NULL ); + orig_ret_address =__kretprobe_trampoline_handler (regs,NULL );instruction_pointer_set (regs, orig_ret_address);return 1 ;
arch/powerpc/kernel/kprobes.c +1 -1
@@ -417,7 +417,7 @@ static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) {unsigned long orig_ret_address; - orig_ret_address =__kretprobe_trampoline_handler (regs, &kretprobe_trampoline,NULL ); + orig_ret_address =__kretprobe_trampoline_handler (regs,NULL );/* * We get here through one of two paths: * 1. by taking a trap -> kprobe_handler() -> here
arch/riscv/kernel/probes/kprobes.c +1 -1
@@ -347,7 +347,7 @@ int __init arch_populate_kprobe_blacklist(void)void __kprobes __used *trampoline_probe_handler (struct pt_regs *regs) { -return (void *)kretprobe_trampoline_handler (regs, &kretprobe_trampoline,NULL ); +return (void *)kretprobe_trampoline_handler (regs,NULL ); } void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
arch/s390/kernel/kprobes.c +1 -1
@@ -343,7 +343,7 @@ static void __used kretprobe_trampoline_holder(void)*/ static int trampoline_probe_handler (struct kprobe *p,struct pt_regs *regs) { - regs->psw.addr =__kretprobe_trampoline_handler (regs, &kretprobe_trampoline,NULL ); + regs->psw.addr =__kretprobe_trampoline_handler (regs,NULL );/* * By returning a non-zero value, we are telling * kprobe_handler() that we don't want the post_handler
arch/sh/kernel/kprobes.c +1 -1
@@ -303,7 +303,7 @@ static void __used kretprobe_trampoline_holder(void)*/ int __kprobes trampoline_probe_handler (struct kprobe *p,struct pt_regs *regs) { - regs->pc =__kretprobe_trampoline_handler (regs, &kretprobe_trampoline,NULL ); + regs->pc =__kretprobe_trampoline_handler (regs,NULL );return 1 ; }
arch/sparc/kernel/kprobes.c +1 -1
@@ -451,7 +451,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p, {unsigned long orig_ret_address =0 ; - orig_ret_address =__kretprobe_trampoline_handler (regs, &kretprobe_trampoline,NULL ); + orig_ret_address =__kretprobe_trampoline_handler (regs,NULL ); regs->tpc = orig_ret_address; regs->tnpc = orig_ret_address +4 ;
arch/x86/include/asm/kprobes.h +0 -1
@@ -49,7 +49,6 @@ extern __visible kprobe_opcode_t optprobe_template_end[];extern const int kretprobe_blacklist_size;void arch_remove_kprobe (struct kprobe *p); -asmlinkage void kretprobe_trampoline(void);extern void arch_kprobe_override_function (struct pt_regs *regs);
arch/x86/kernel/kprobes/core.c +1 -1
@@ -1064,7 +1064,7 @@ __used __visible void *trampoline_handler(struct pt_regs *regs) regs->ip = (unsigned long )&kretprobe_trampoline; regs->orig_ax = ~0UL ; -return (void *)kretprobe_trampoline_handler (regs, &kretprobe_trampoline, ®s->sp); +return (void *)kretprobe_trampoline_handler (regs, ®s->sp); }NOKPROBE_SYMBOL (trampoline_handler);
include/linux/kprobes.h +13 -5
@@ -188,15 +188,23 @@ extern void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs);extern int arch_trampoline_kprobe (struct kprobe *p); +void kretprobe_trampoline (void ); +/* +* Since some architecture uses structured function pointer, +* use dereference_function_descriptor() to get real function address. +*/ +static nokprobe_inline void *kretprobe_trampoline_addr(void) +{ +return dereference_kernel_function_descriptor (kretprobe_trampoline); +} +/* If the trampoline handler called from a kprobe, use this version */ unsigned long __kretprobe_trampoline_handler (struct pt_regs *regs, -void *trampoline_address, -void *frame_pointer); +void *frame_pointer);static nokprobe_inline unsigned long kretprobe_trampoline_handler (struct pt_regs *regs, -void *trampoline_address, -void *frame_pointer) +void *frame_pointer) {unsigned long ret;/*
@@ -205,7 +213,7 @@ unsigned long kretprobe_trampoline_handler(struct pt_regs *regs,* be running at this point. */ kprobe_busy_begin (); - ret =__kretprobe_trampoline_handler (regs, trampoline_address, frame_pointer); + ret =__kretprobe_trampoline_handler (regs, frame_pointer);kprobe_busy_end ();return ret;
kernel/kprobes.c +1 -2
@@ -1864,7 +1864,6 @@ static struct notifier_block kprobe_exceptions_nb = {#ifdef CONFIG_KRETPROBES unsigned long __kretprobe_trampoline_handler (struct pt_regs *regs, -void *trampoline_address,void *frame_pointer) {kprobe_opcode_t *correct_ret_addr =NULL ;
@@ -1879,7 +1878,7 @@ unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs,BUG_ON (ri->fp != frame_pointer); -if (ri->ret_addr != trampoline_address) { +if (ri->ret_addr !=kretprobe_trampoline_addr ()) { correct_ret_addr = ri->ret_addr;/* * This is the real return address. Any other
Masami Hiramatsu
maintainerPATCH v11 15/27 kprobes: treewide: Make it harder to refer kretprobe_trampoline directly
In reply to Masami HiramatsuSince now there is kretprobe_trampoline_addr() for referring the address of kretprobe trampoline code, we don't need to access kretprobe_trampoline directly.
Make it harder to refer by renaming it to __kretprobe_trampoline().
--- arch/arc/include/asm/kprobes.h | 2 +- arch/arc/kernel/kprobes.c | 11 ++++++----- arch/arm/probes/kprobes/core.c | 6 +++--- arch/arm64/include/asm/kprobes.h | 2 +- arch/arm64/kernel/probes/kprobes.c | 2 +- arch/arm64/kernel/probes/kprobes_trampoline.S | 4 ++-- arch/csky/include/asm/kprobes.h | 2 +- arch/csky/kernel/probes/kprobes.c | 2 +- arch/csky/kernel/probes/kprobes_trampoline.S | 4 ++-- arch/ia64/kernel/kprobes.c | 8 ++++---- arch/mips/kernel/kprobes.c | 12 ++++++------ arch/parisc/kernel/kprobes.c | 4 ++-- arch/powerpc/include/asm/kprobes.h | 2 +- arch/powerpc/kernel/kprobes.c | 16 ++++++++-------- arch/powerpc/kernel/optprobes.c | 2 +- arch/powerpc/kernel/stacktrace.c | 2 +- arch/riscv/include/asm/kprobes.h | 2 +- arch/riscv/kernel/probes/kprobes.c | 2 +- arch/riscv/kernel/probes/kprobes_trampoline.S | 4 ++-- arch/s390/include/asm/kprobes.h | 2 +- arch/s390/kernel/kprobes.c | 10 +++++----- arch/s390/kernel/stacktrace.c | 2 +- arch/sh/include/asm/kprobes.h | 2 +- arch/sh/kernel/kprobes.c | 10 +++++----- arch/sparc/include/asm/kprobes.h | 2 +- arch/sparc/kernel/kprobes.c | 10 +++++----- arch/x86/kernel/kprobes/core.c | 18 +++++++++--------- include/linux/kprobes.h | 4 ++-- kernel/trace/trace_output.c | 2 +- 29 files changed, 76 insertions(+), 75 deletions(-)
arch/arc/include/asm/kprobes.h +1 -1
@@ -46,7 +46,7 @@ struct kprobe_ctlblk { };int kprobe_fault_handler (struct pt_regs *regs,unsigned long cause); -void kretprobe_trampoline (void ); +void __kretprobe_trampoline (void );void trap_is_kprobe (unsigned long address,struct pt_regs *regs);#else #define trap_is_kprobe (address, regs)
arch/arc/kernel/kprobes.c +6 -5
@@ -363,8 +363,9 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,static void __used kretprobe_trampoline_holder (void ) { - __asm__ __volatile__(".global kretprobe_trampoline\n" -"kretprobe_trampoline:\n" "nop\n" ); + __asm__ __volatile__(".global __kretprobe_trampoline\n" +"__kretprobe_trampoline:\n" +"nop\n" ); } void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
@@ -375,7 +376,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ri->fp =NULL ;/* Replace the return addr with trampoline addr */ - regs->blink = (unsigned long )&kretprobe_trampoline; + regs->blink = (unsigned long )&__kretprobe_trampoline; } static int __kprobes trampoline_probe_handler(struct kprobe *p,
@@ -390,7 +391,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p, }static struct kprobe trampoline_p = { - .addr = (kprobe_opcode_t *) &kretprobe_trampoline, + .addr = (kprobe_opcode_t *) &__kretprobe_trampoline, .pre_handler = trampoline_probe_handler };
@@ -402,7 +403,7 @@ int __init arch_init_kprobes(void)int __kprobes arch_trampoline_kprobe (struct kprobe *p) { -if (p->addr = (kprobe_opcode_t *) &kretprobe_trampoline) +if (p->addr = (kprobe_opcode_t *) &__kretprobe_trampoline)return 1 ;return 0 ;
arch/arm/probes/kprobes/core.c +3 -3
@@ -373,7 +373,7 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,* for kretprobe handlers which should normally be interested in r0 only * anyway. */ -void __naked __kprobes kretprobe_trampoline (void ) +void __naked __kprobes __kretprobe_trampoline (void ) { __asm__ __volatile__ ( "stmdb sp!, {r0 - r11} \n\t"
@@ -389,7 +389,7 @@ void __naked __kprobes kretprobe_trampoline(void) : : : "memory"); } -/* Called from kretprobe_trampoline */ +/* Called from __kretprobe_trampoline */ static __used __kprobes void *trampoline_handler (struct pt_regs *regs) {return (void *)kretprobe_trampoline_handler (regs, (void *)regs->ARM_fp);
@@ -402,7 +402,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ri->fp = (void *)regs->ARM_fp;/* Replace the return addr with trampoline addr. */ - regs->ARM_lr = (unsigned long )&kretprobe_trampoline; + regs->ARM_lr = (unsigned long )&__kretprobe_trampoline; }int __kprobes arch_trampoline_kprobe (struct kprobe *p)
arch/arm64/include/asm/kprobes.h +1 -1
@@ -39,7 +39,7 @@ void arch_remove_kprobe(struct kprobe *);int kprobe_fault_handler (struct pt_regs *regs,unsigned int fsr);int kprobe_exceptions_notify (struct notifier_block *self,unsigned long val,void *data); -void kretprobe_trampoline (void ); +void __kretprobe_trampoline (void );void __kprobes *trampoline_probe_handler (struct pt_regs *regs);#endif /* CONFIG_KPROBES */
arch/arm64/kernel/probes/kprobes.c +1 -1
@@ -411,7 +411,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ri->fp = (void *)kernel_stack_pointer (regs);/* replace return addr (x30) with trampoline */ - regs->regs[30 ] = (long )&kretprobe_trampoline; + regs->regs[30 ] = (long )&__kretprobe_trampoline; }int __kprobes arch_trampoline_kprobe (struct kprobe *p)
arch/arm64/kernel/probes/kprobes_trampoline.S +2 -2
@@ -61,7 +61,7 @@ ldp x28, x29, [sp, #S_X28] .endm -SYM_CODE_START(kretprobe_trampoline) +SYM_CODE_START(__kretprobe_trampoline) sub sp, sp, #PT_REGS_SIZE save_all_base_regs
@@ -79,4 +79,4 @@ SYM_CODE_START(kretprobe_trampoline) add sp, sp, #PT_REGS_SIZE ret -SYM_CODE_END(kretprobe_trampoline) +SYM_CODE_END(__kretprobe_trampoline)
arch/csky/include/asm/kprobes.h +1 -1
@@ -41,7 +41,7 @@ void arch_remove_kprobe(struct kprobe *p);int kprobe_fault_handler (struct pt_regs *regs,unsigned int trapnr);int kprobe_breakpoint_handler (struct pt_regs *regs);int kprobe_single_step_handler (struct pt_regs *regs); -void kretprobe_trampoline (void ); +void __kretprobe_trampoline (void );void __kprobes *trampoline_probe_handler (struct pt_regs *regs);#endif /* CONFIG_KPROBES */
arch/csky/kernel/probes/kprobes.c +1 -1
@@ -394,7 +394,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, { ri->ret_addr = (kprobe_opcode_t *)regs->lr; ri->fp =NULL ; - regs->lr = (unsigned long ) &kretprobe_trampoline; + regs->lr = (unsigned long ) &__kretprobe_trampoline; }int __kprobes arch_trampoline_kprobe (struct kprobe *p)
arch/csky/kernel/probes/kprobes_trampoline.S +2 -2
@@ -4,7 +4,7 @@ #include <abi/entry.h> -ENTRY(kretprobe_trampoline) +ENTRY(__kretprobe_trampoline) SAVE_REGS_FTRACE mov a0, sp /* pt_regs */
@@ -16,4 +16,4 @@ ENTRY(kretprobe_trampoline) RESTORE_REGS_FTRACE rts -ENDPROC(kretprobe_trampoline) +ENDPROC(__kretprobe_trampoline)
arch/ia64/kernel/kprobes.c +4 -3
@@ -392,7 +392,7 @@ static void __kprobes set_current_kprobe(struct kprobe *p,__this_cpu_write (current_kprobe, p); } -void kretprobe_trampoline (void ) +void __kretprobe_trampoline (void ) { }
@@ -414,7 +414,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ri->fp =NULL ;/* Replace the return addr with trampoline addr */ - regs->b0 = (unsigned long )dereference_function_descriptor (kretprobe_trampoline); + regs->b0 = (unsigned long )dereference_function_descriptor (__kretprobe_trampoline); }/* Check the instruction in the slot is break */
@@ -897,14 +897,14 @@ static struct kprobe trampoline_p = {int __init arch_init_kprobes (void ) { trampoline_p.addr -dereference_function_descriptor (kretprobe_trampoline); +dereference_function_descriptor (__kretprobe_trampoline);return register_kprobe (&trampoline_p); }int __kprobes arch_trampoline_kprobe (struct kprobe *p) {if (p->addr = -dereference_function_descriptor (kretprobe_trampoline)) +dereference_function_descriptor (__kretprobe_trampoline))return 1 ;return 0 ;
arch/mips/kernel/kprobes.c +6 -6
@@ -460,14 +460,14 @@ static void __used kretprobe_trampoline_holder(void)/* Keep the assembler from reordering and placing JR here. */ ".set noreorder\n\t" "nop\n\t" -".global kretprobe_trampoline\n" -"kretprobe_trampoline:\n\t" +".global __kretprobe_trampoline\n" +"__kretprobe_trampoline:\n\t" "nop\n\t" ".set pop" : : : "memory"); } -void kretprobe_trampoline (void ); +void __kretprobe_trampoline (void );void __kprobes arch_prepare_kretprobe (struct kretprobe_instance *ri,struct pt_regs *regs)
@@ -476,7 +476,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ri->fp =NULL ;/* Replace the return addr with trampoline addr */ - regs->regs[31 ] = (unsigned long )kretprobe_trampoline; + regs->regs[31 ] = (unsigned long )__kretprobe_trampoline; }/*
@@ -496,14 +496,14 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,int __kprobes arch_trampoline_kprobe (struct kprobe *p) { -if (p->addr = (kprobe_opcode_t *)kretprobe_trampoline) +if (p->addr = (kprobe_opcode_t *)__kretprobe_trampoline)return 1 ;return 0 ; }static struct kprobe trampoline_p = { - .addr = (kprobe_opcode_t *)kretprobe_trampoline, + .addr = (kprobe_opcode_t *)__kretprobe_trampoline, .pre_handler = trampoline_probe_handler };
arch/parisc/kernel/kprobes.c +2 -2
@@ -175,7 +175,7 @@ int __kprobes parisc_kprobe_ss_handler(struct pt_regs *regs)return 1 ; } -void kretprobe_trampoline (void ) +void __kretprobe_trampoline (void ) { asmvolatile ("nop" ); asmvolatile ("nop" );
@@ -217,6 +217,6 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p)int __init arch_init_kprobes (void ) { trampoline_p.addr = (kprobe_opcode_t *) -dereference_function_descriptor (kretprobe_trampoline); +dereference_function_descriptor (__kretprobe_trampoline);return register_kprobe (&trampoline_p); }
arch/powerpc/include/asm/kprobes.h +1 -1
@@ -51,7 +51,7 @@ extern kprobe_opcode_t optprobe_template_end[];#define flush_insn_slot (p) do { } while (0)#define kretprobe_blacklist_size 0 -void kretprobe_trampoline (void ); +void __kretprobe_trampoline (void );extern void arch_remove_kprobe (struct kprobe *p);/* Architecture specific copy of original instruction */
arch/powerpc/kernel/kprobes.c +8 -8
@@ -237,7 +237,7 @@ void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) ri->fp =NULL ;/* Replace the return addr with trampoline addr */ - regs->link = (unsigned long )kretprobe_trampoline; + regs->link = (unsigned long )__kretprobe_trampoline; }NOKPROBE_SYMBOL (arch_prepare_kretprobe);
@@ -403,12 +403,12 @@ NOKPROBE_SYMBOL(kprobe_handler);* - When the probed function returns, this probe * causes the handlers to fire */ -asm(".global kretprobe_trampoline\n" -".type kretprobe_trampoline, @function\n" -"kretprobe_trampoline:\n" +asm(".global __kretprobe_trampoline\n" +".type __kretprobe_trampoline, @function\n" +"__kretprobe_trampoline:\n" "nop\n" "blr\n" -".size kretprobe_trampoline, .-kretprobe_trampoline\n" ); +".size __kretprobe_trampoline, .-__kretprobe_trampoline\n" );/* * Called when the probe at kretprobe trampoline is hit
@@ -427,7 +427,7 @@ static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)* as it is used to determine the return address from the trap. * For (2), since nip is not honoured with optprobes, we instead setup * the link register properly so that the subsequent 'blr' in -* kretprobe_trampoline jumps back to the right instruction. +* __kretprobe_trampoline jumps back to the right instruction. * * For nip, we should set the address to the previous instruction since * we end up emulating it in kprobe_handler(), which increments the nip
@@ -543,7 +543,7 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr)NOKPROBE_SYMBOL (kprobe_fault_handler);static struct kprobe trampoline_p = { - .addr = (kprobe_opcode_t *) &kretprobe_trampoline, + .addr = (kprobe_opcode_t *) &__kretprobe_trampoline, .pre_handler = trampoline_probe_handler };
@@ -554,7 +554,7 @@ int __init arch_init_kprobes(void)int arch_trampoline_kprobe (struct kprobe *p) { -if (p->addr = (kprobe_opcode_t *)&kretprobe_trampoline) +if (p->addr = (kprobe_opcode_t *)&__kretprobe_trampoline)return 1 ;return 0 ;
arch/powerpc/kernel/optprobes.c +1 -1
@@ -56,7 +56,7 @@ static unsigned long can_optimize(struct kprobe *p)* has a 'nop' instruction, which can be emulated. * So further checks can be skipped. */ -if (p->addr = (kprobe_opcode_t *)&kretprobe_trampoline) +if (p->addr = (kprobe_opcode_t *)&__kretprobe_trampoline)return addr +sizeof (kprobe_opcode_t);/*
arch/powerpc/kernel/stacktrace.c +1 -1
@@ -155,7 +155,7 @@ int __no_sanitize_address arch_stack_walk_reliable(stack_trace_consume_fn consum* Mark stacktraces with kretprobed functions on them * as unreliable. */ -if (ip = (unsigned long )kretprobe_trampoline) +if (ip = (unsigned long )__kretprobe_trampoline)return -EINVAL ;#endif
arch/riscv/include/asm/kprobes.h +1 -1
@@ -40,7 +40,7 @@ void arch_remove_kprobe(struct kprobe *p);int kprobe_fault_handler (struct pt_regs *regs,unsigned int trapnr);bool kprobe_breakpoint_handler (struct pt_regs *regs);bool kprobe_single_step_handler (struct pt_regs *regs); -void kretprobe_trampoline (void ); +void __kretprobe_trampoline (void );void __kprobes *trampoline_probe_handler (struct pt_regs *regs);#endif /* CONFIG_KPROBES */
arch/riscv/kernel/probes/kprobes.c +1 -1
@@ -355,7 +355,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, { ri->ret_addr = (kprobe_opcode_t *)regs->ra; ri->fp =NULL ; - regs->ra = (unsigned long ) &kretprobe_trampoline; + regs->ra = (unsigned long ) &__kretprobe_trampoline; }int __kprobes arch_trampoline_kprobe (struct kprobe *p)
arch/riscv/kernel/probes/kprobes_trampoline.S +2 -2
@@ -75,7 +75,7 @@ REG_L x31, PT_T6(sp) .endm -ENTRY(kretprobe_trampoline) +ENTRY(__kretprobe_trampoline) addi sp, sp, -(PT_SIZE_ON_STACK) save_all_base_regs
@@ -90,4 +90,4 @@ ENTRY(kretprobe_trampoline) addi sp, sp, PT_SIZE_ON_STACK ret -ENDPROC(kretprobe_trampoline) +ENDPROC(__kretprobe_trampoline)
arch/s390/include/asm/kprobes.h +1 -1
@@ -70,7 +70,7 @@ struct kprobe_ctlblk { };void arch_remove_kprobe (struct kprobe *p); -void kretprobe_trampoline (void ); +void __kretprobe_trampoline (void );int kprobe_fault_handler (struct pt_regs *regs,int trapnr); int kprobe_exceptions_notify(struct notifier_block *self,
arch/s390/kernel/kprobes.c +5 -5
@@ -242,7 +242,7 @@ void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) ri->fp =NULL ;/* Replace the return addr with trampoline addr */ - regs->gprs[14 ] = (unsigned long ) &kretprobe_trampoline; + regs->gprs[14 ] = (unsigned long ) &__kretprobe_trampoline; }NOKPROBE_SYMBOL (arch_prepare_kretprobe);
@@ -334,8 +334,8 @@ NOKPROBE_SYMBOL(kprobe_handler);*/ static void __used kretprobe_trampoline_holder (void ) { - asmvolatile (".global kretprobe_trampoline\n" -"kretprobe_trampoline: bcr 0,0\n" ); + asmvolatile (".global __kretprobe_trampoline\n" +"__kretprobe_trampoline: bcr 0,0\n" ); }/*
@@ -509,7 +509,7 @@ int kprobe_exceptions_notify(struct notifier_block *self,NOKPROBE_SYMBOL (kprobe_exceptions_notify);static struct kprobe trampoline = { - .addr = (kprobe_opcode_t *) &kretprobe_trampoline, + .addr = (kprobe_opcode_t *) &__kretprobe_trampoline, .pre_handler = trampoline_probe_handler };
@@ -520,6 +520,6 @@ int __init arch_init_kprobes(void)int arch_trampoline_kprobe (struct kprobe *p) { -return p->addr = (kprobe_opcode_t *) &kretprobe_trampoline; +return p->addr = (kprobe_opcode_t *) &__kretprobe_trampoline; }NOKPROBE_SYMBOL (arch_trampoline_kprobe);
arch/s390/kernel/stacktrace.c +1 -1
@@ -46,7 +46,7 @@ int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,* Mark stacktraces with kretprobed functions on them * as unreliable. */ -if (state.ip = (unsigned long )kretprobe_trampoline) +if (state.ip = (unsigned long )__kretprobe_trampoline)return -EINVAL ;#endif
arch/sh/include/asm/kprobes.h +1 -1
@@ -26,7 +26,7 @@ typedef insn_size_t kprobe_opcode_t;struct kprobe ;void arch_remove_kprobe (struct kprobe *); -void kretprobe_trampoline (void ); +void __kretprobe_trampoline (void );/* Architecture specific copy of original instruction*/ struct arch_specific_insn {
arch/sh/kernel/kprobes.c +5 -5
@@ -207,7 +207,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ri->fp =NULL ;/* Replace the return addr with trampoline addr */ - regs->pr = (unsigned long )kretprobe_trampoline; + regs->pr = (unsigned long )__kretprobe_trampoline; }static int __kprobes kprobe_handler (struct pt_regs *regs)
@@ -293,13 +293,13 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)*/ static void __used kretprobe_trampoline_holder (void ) { - asmvolatile (".globl kretprobe_trampoline\n" -"kretprobe_trampoline:\n\t" + asmvolatile (".globl __kretprobe_trampoline\n" +"__kretprobe_trampoline:\n\t" "nop\n" ); }/* -* Called when we hit the probe point at kretprobe_trampoline +* Called when we hit the probe point at __kretprobe_trampoline */ int __kprobes trampoline_probe_handler (struct kprobe *p,struct pt_regs *regs) {
@@ -442,7 +442,7 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, }static struct kprobe trampoline_p = { - .addr = (kprobe_opcode_t *)&kretprobe_trampoline, + .addr = (kprobe_opcode_t *)&__kretprobe_trampoline, .pre_handler = trampoline_probe_handler };
arch/sparc/include/asm/kprobes.h +1 -1
@@ -24,7 +24,7 @@ do { flushi(&(p)->ainsn.insn[0]); \flushi (&(p)->ainsn.insn[1 ]); \ }while (0 ) -void kretprobe_trampoline(void); +void __kretprobe_trampoline(void);/* Architecture specific copy of original instruction*/ struct arch_specific_insn {
arch/sparc/kernel/kprobes.c +5 -4
@@ -440,7 +440,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,/* Replace the return addr with trampoline addr */ regs->u_regs[UREG_RETPC ] - ((unsigned long )kretprobe_trampoline) -8 ; + ((unsigned long )__kretprobe_trampoline) -8 ; }/*
@@ -465,13 +465,13 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,static void __used kretprobe_trampoline_holder (void ) { - asmvolatile (".global kretprobe_trampoline\n" -"kretprobe_trampoline:\n" + asmvolatile (".global __kretprobe_trampoline\n" +"__kretprobe_trampoline:\n" "\tnop\n" "\tnop\n" ); }static struct kprobe trampoline_p = { - .addr = (kprobe_opcode_t *) &kretprobe_trampoline, + .addr = (kprobe_opcode_t *) &__kretprobe_trampoline, .pre_handler = trampoline_probe_handler };
@@ -482,7 +482,7 @@ int __init arch_init_kprobes(void)int __kprobes arch_trampoline_kprobe (struct kprobe *p) { -if (p->addr = (kprobe_opcode_t *)&kretprobe_trampoline) +if (p->addr = (kprobe_opcode_t *)&__kretprobe_trampoline)return 1 ;return 0 ;
arch/x86/kernel/kprobes/core.c +9 -9
@@ -809,7 +809,7 @@ void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) ri->fp = sara;/* Replace the return addr with trampoline addr */ - *sara = (unsigned long ) &kretprobe_trampoline; + *sara = (unsigned long ) &__kretprobe_trampoline; }NOKPROBE_SYMBOL (arch_prepare_kretprobe);
@@ -1019,9 +1019,9 @@ NOKPROBE_SYMBOL(kprobe_int3_handler);*/ asm(".text\n" -".global kretprobe_trampoline\n" -".type kretprobe_trampoline, @function\n" -"kretprobe_trampoline:\n" +".global __kretprobe_trampoline\n" +".type __kretprobe_trampoline, @function\n" +"__kretprobe_trampoline:\n" /* We don't bother saving the ss register */ #ifdef CONFIG_X86_64 " pushq %rsp\n"
@@ -1045,14 +1045,14 @@ asm(" popfl\n" #endif" ret\n" -".size kretprobe_trampoline, .-kretprobe_trampoline\n" +".size __kretprobe_trampoline, .-__kretprobe_trampoline\n" ); -NOKPROBE_SYMBOL (kretprobe_trampoline); -STACK_FRAME_NON_STANDARD (kretprobe_trampoline); +NOKPROBE_SYMBOL (__kretprobe_trampoline); +STACK_FRAME_NON_STANDARD (__kretprobe_trampoline);/* -* Called from kretprobe_trampoline +* Called from __kretprobe_trampoline */ __used __visible void *trampoline_handler(struct pt_regs *regs) {
@@ -1061,7 +1061,7 @@ __used __visible void *trampoline_handler(struct pt_regs *regs)#ifdef CONFIG_X86_32 regs->gs =0 ;#endif - regs->ip = (unsigned long )&kretprobe_trampoline; + regs->ip = (unsigned long )&__kretprobe_trampoline; regs->orig_ax = ~0UL ;return (void *)kretprobe_trampoline_handler (regs, ®s->sp);
include/linux/kprobes.h +2 -2
@@ -188,14 +188,14 @@ extern void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs);extern int arch_trampoline_kprobe (struct kprobe *p); -void kretprobe_trampoline (void ); +void __kretprobe_trampoline (void );/* * Since some architecture uses structured function pointer, * use dereference_function_descriptor() to get real function address. */ static nokprobe_inline void *kretprobe_trampoline_addr(void) { -return dereference_kernel_function_descriptor (kretprobe_trampoline); +return dereference_kernel_function_descriptor (__kretprobe_trampoline); }/* If the trampoline handler called from a kprobe, use this version */
kernel/trace/trace_output.c +1 -1
@@ -349,7 +349,7 @@ EXPORT_SYMBOL_GPL(trace_output_call);#ifdef CONFIG_KRETPROBES static inline const char *kretprobed (const char *name) { -static const char tramp_name[] ="kretprobe_trampoline" ; +static const char tramp_name[] ="__kretprobe_trampoline" ;int size =sizeof (tramp_name);if (strncmp (tramp_name, name, size) =0 )
Masami Hiramatsu
maintainerPATCH v11 16/27 kprobes: Add kretprobe_find_ret_addr() for searching return address
In reply to Masami HiramatsuIntroduce kretprobe_find_ret_addr() and is_kretprobe_trampoline(). These APIs will be used by the ORC stack unwinder and ftrace, so that they can check whether the given address points kretprobe trampoline code and query the correct return address in that case.
---
Changes in v10:
- Add a document about kretprobe_find_ret_addr() and check cur = NULL.
Changes in v9:
- Update changelog to explain why this is introduced.
- Move the prototype of kretprobe_find_ret_addr() and is_kretprobe_trampoline() in the same place.
- Make __kretprobe_find_ret_addr() return 'kprobe_opcode_t *'.
- Update comments in the __kretprobe_trampoline_handler().
Changes in v6:
- Replace BUG_ON() with WARN_ON_ONCE() in __kretprobe_trampoline_handler().
Changes in v3:
- Remove generic stacktrace fixup. Instead, it should be solved in each unwinder. This just provide the generic interface.
Changes in v2:
- Add is_kretprobe_trampoline() for checking address outside of kretprobe_find_ret_addr()
- Remove unneeded addr from kretprobe_find_ret_addr()
- Rename fixup_kretprobe_tramp_addr() to fixup_kretprobe_trampoline()
--- include/linux/kprobes.h | 22 +++++++++ kernel/kprobes.c | 109 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 105 insertions(+), 26 deletions(-)
include/linux/kprobes.h +22 -0
@@ -505,6 +505,28 @@ static inline bool is_kprobe_optinsn_slot(unsigned long addr) }#endif /* !CONFIG_OPTPROBES */ +#ifdef CONFIG_KRETPROBES +static nokprobe_inline bool is_kretprobe_trampoline(unsigned long addr) +{ +return (void *)addr =kretprobe_trampoline_addr (); +} + +unsigned long kretprobe_find_ret_addr (struct task_struct *tsk,void *fp, +struct llist_node **cur); +#else +static nokprobe_inline bool is_kretprobe_trampoline(unsigned long addr) +{ +return false; +} + +static nokprobe_inline +unsigned long kretprobe_find_ret_addr (struct task_struct *tsk,void *fp, +struct llist_node **cur) +{ +return 0 ; +} +#endif +/* Returns true if kprobes handled the fault */ static nokprobe_inline bool kprobe_page_fault(struct pt_regs *regs,unsigned int trap)
kernel/kprobes.c +83 -26
134 lines not on this page · raw message
Masami Hiramatsu
maintainerPATCH v11 17/27 objtool: Add frame-pointer-specific function ignore
In reply to Masami HiramatsuFrom: Josh Poimboeuf <[email protected]>
Add a CONFIG_FRAME_POINTER-specific version of STACK_FRAME_NON_STANDARD() for the case where a function is intentionally missing frame pointer setup, but otherwise needs objtool/ORC coverage when frame pointers are disabled.
---
Changes in v10:
- Fixes error in CONFIG_STACK_VALIDATION=n case.
--- include/linux/objtool.h | 12 ++++++++++++ tools/include/linux/objtool.h | 12 ++++++++++++ 2 files changed, 24 insertions(+)
include/linux/objtool.h +12 -0
@@ -66,6 +66,17 @@ struct unwind_hint { static void __used __section(".discard.func_stack_frame_non_standard") \ *__func_stack_frame_non_standard_##func = func +/* +* STACK_FRAME_NON_STANDARD_FP() is a frame-pointer-specific function ignore +* for the case where a function is intentionally missing frame pointer setup, +* but otherwise needs objtool/ORC coverage when frame pointers are disabled. +*/ +#ifdef CONFIG_FRAME_POINTER +#define STACK_FRAME_NON_STANDARD_FP (func) STACK_FRAME_NON_STANDARD(func) +#else +#define STACK_FRAME_NON_STANDARD_FP (func) +#endif +#else /* __ASSEMBLY__ */ /*
@@ -127,6 +138,7 @@ struct unwind_hint {#define UNWIND_HINT (sp_reg, sp_offset, type, end) \ "\n\t"#define STACK_FRAME_NON_STANDARD (func) +#define STACK_FRAME_NON_STANDARD_FP (func)#else #define ANNOTATE_INTRA_FUNCTION_CALL .macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
tools/include/linux/objtool.h +12 -0
@@ -66,6 +66,17 @@ struct unwind_hint { static void __used __section(".discard.func_stack_frame_non_standard") \ *__func_stack_frame_non_standard_##func = func +/* +* STACK_FRAME_NON_STANDARD_FP() is a frame-pointer-specific function ignore +* for the case where a function is intentionally missing frame pointer setup, +* but otherwise needs objtool/ORC coverage when frame pointers are disabled. +*/ +#ifdef CONFIG_FRAME_POINTER +#define STACK_FRAME_NON_STANDARD_FP (func) STACK_FRAME_NON_STANDARD(func) +#else +#define STACK_FRAME_NON_STANDARD_FP (func) +#endif +#else /* __ASSEMBLY__ */ /*
@@ -127,6 +138,7 @@ struct unwind_hint {#define UNWIND_HINT (sp_reg, sp_offset, type, end) \ "\n\t"#define STACK_FRAME_NON_STANDARD (func) +#define STACK_FRAME_NON_STANDARD_FP (func)#else #define ANNOTATE_INTRA_FUNCTION_CALL .macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
Masami Hiramatsu
maintainerPATCH v11 18/27 objtool: Ignore unwind hints for ignored functions
In reply to Masami HiramatsuFrom: Josh Poimboeuf <[email protected]>
If a function is ignored, also ignore its hints. This is useful for the case where the function ignore is conditional on frame pointers, e.g. STACK_FRAME_NON_STANDARD_FP().
--- tools/objtool/check.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/objtool/check.c +1 -1
@@ -2909,7 +2909,7 @@ static int validate_unwind_hints(struct objtool_file *file, struct section *sec) }while (&insn->list != &file->insn_list && (!sec || insn->sec = sec)) { -if (insn->hint && !insn->visited) { +if (insn->hint && !insn->visited && !insn->ignore) { ret =validate_branch (file, insn->func, insn, state);if (ret && backtrace)BT_FUNC ("<== (hint)" , insn);
Masami Hiramatsu
maintainerPATCH v11 19/27 x86/kprobes: Add UNWIND_HINT_FUNC on kretprobe_trampoline()
In reply to Masami HiramatsuFrom: Josh Poimboeuf <[email protected]>
Add UNWIND_HINT_FUNC on __kretprobe_trampoline() code so that ORC information is generated on the __kretprobe_trampoline() correctly. Also, this uses STACK_FRAME_NON_STANDARD_FP(), CONFIG_FRAME_POINTER- -specific version of STACK_FRAME_NON_STANDARD().
---
Changes in v9:
- Update changelog and fix comment.
- Use STACK_FRAME_NON_STANDARD_FP().
Changes in v4:
- Apply UNWIND_HINT_FUNC only if CONFIG_FRAME_POINTER=n.
--- arch/x86/include/asm/unwind_hints.h | 5 +++++ arch/x86/kernel/kprobes/core.c | 13 +++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-)
arch/x86/include/asm/unwind_hints.h +5 -0
@@ -52,6 +52,11 @@ UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=8 type=UNWIND_HINT_TYPE_FUNC .endm +#else + +#define UNWIND_HINT_FUNC \ + UNWIND_HINT(ORC_REG_SP, 8, UNWIND_HINT_TYPE_FUNC, 0) +#endif /* __ASSEMBLY__ */ #endif /* _ASM_X86_UNWIND_HINTS_H */
arch/x86/kernel/kprobes/core.c +11 -2
@@ -1025,6 +1025,7 @@ asm(/* We don't bother saving the ss register */ #ifdef CONFIG_X86_64 " pushq %rsp\n" +UNWIND_HINT_FUNC " pushfq\n" SAVE_REGS_STRING " movq %rsp, %rdi\n"
@@ -1035,6 +1036,7 @@ asm(" popfq\n" #else" pushl %esp\n" +UNWIND_HINT_FUNC " pushfl\n" SAVE_REGS_STRING " movl %esp, %eax\n"
@@ -1048,8 +1050,15 @@ asm(".size __kretprobe_trampoline, .-__kretprobe_trampoline\n" );NOKPROBE_SYMBOL (__kretprobe_trampoline); -STACK_FRAME_NON_STANDARD (__kretprobe_trampoline); - +/* +* __kretprobe_trampoline() skips updating frame pointer. The frame pointer +* saved in trampoline_handler() points to the real caller function's +* frame pointer. Thus the __kretprobe_trampoline() doesn't have a +* standard stack frame with CONFIG_FRAME_POINTER=y. +* Let's mark it non-standard function. Anyway, FP unwinder can correctly +* unwind without the hint. +*/ +STACK_FRAME_NON_STANDARD_FP (__kretprobe_trampoline);/* * Called from __kretprobe_trampoline
Masami Hiramatsu
maintainerPATCH v11 20/27 ARC: Add instruction_pointer_set() API
In reply to Masami HiramatsuAdd instruction_pointer_set() API for arc.
--- arch/arc/include/asm/ptrace.h | 5 +++++ 1 file changed, 5 insertions(+)
arch/arc/include/asm/ptrace.h +5 -0
@@ -149,6 +149,11 @@ static inline long regs_return_value(struct pt_regs *regs)return (long )regs->r0; } +static inline void instruction_pointer_set (struct pt_regs *regs, +unsigned long val) +{ +instruction_pointer (regs) = val; +}#endif /* !__ASSEMBLY__ */ #endif /* __ASM_PTRACE_H */
Masami Hiramatsu
maintainerPATCH v11 21/27 ia64: Add instruction_pointer_set() API
In reply to Masami HiramatsuAdd instruction_pointer_set() API for ia64.
---
Changes in v9:
- Fix "space at the start of a line" checkpatch warnings.
Changes in v4:
- Make the API macro for avoiding a build error.
--- arch/ia64/include/asm/ptrace.h | 5 +++++ 1 file changed, 5 insertions(+)
arch/ia64/include/asm/ptrace.h +5 -0
@@ -51,6 +51,11 @@* the canonical representation by adding to instruction pointer. */ # define instruction_pointer (regs) ((regs)->cr_iip + ia64_psr(regs)->ri) +# define instruction_pointer_set (regs, val) \ +({ \ + ia64_psr(regs)->ri = (val & 0xf); \ + regs->cr_iip = (val & ~0xfULL); \ +})static inline unsigned long user_stack_pointer (struct pt_regs *regs) {
Masami Hiramatsu
maintainerPATCH v11 22/27 arm: kprobes: Make space for instruction pointer on stack
In reply to Masami HiramatsuSince arm's __kretprobe_trampoline() saves partial 'pt_regs' on the stack, 'regs->ARM_pc' (instruction pointer) is not accessible from the kretprobe handler. This means if instruction_pointer_set() is used from kretprobe handler, it will break the data on the stack.
Make space for instruction pointer (ARM_pc) on the stack in the __kretprobe_trampoline() for fixing this problem.
---
Changes in v9:
- Update changelog.
--- arch/arm/probes/kprobes/core.c | 2 ++ 1 file changed, 2 insertions(+)
arch/arm/probes/kprobes/core.c +2 -0
@@ -376,11 +376,13 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,void __naked __kprobes __kretprobe_trampoline (void ) { __asm__ __volatile__ ( + "sub sp, sp, #16 \n\t" "stmdb sp!, {r0 - r11} \n\t" "mov r0, sp \n\t" "bl trampoline_handler \n\t" "mov lr, r0 \n\t" "ldmia sp!, {r0 - r11} \n\t" + "add sp, sp, #16 \n\t" #ifdef CONFIG_THUMB2_KERNEL "bx lr \n\t" #else
Masami Hiramatsu
maintainerPATCH v11 23/27 kprobes: Enable stacktrace from pt_regs in kretprobe handler
In reply to Masami HiramatsuSince the ORC unwinder from pt_regs requires setting up regs->ip correctly, set the correct return address to the regs->ip before calling user kretprobe handler.
This allows the kretrprobe handler to trace stack from the kretprobe's pt_regs by stack_trace_save_regs() (eBPF will do this), instead of stack tracing from the handler context by stack_trace_save() (ftrace will do this).
---
Changes in v9:
- Update comment to explain specifically why this is necessary.
Changes in v8:
- Update comment to clarify why this is needed.
Changes in v3:
- Cast the correct_ret_addr to unsigned long.
--- kernel/kprobes.c | 7 +++++++ 1 file changed, 7 insertions(+)
kernel/kprobes.c +7 -0
@@ -1937,6 +1937,13 @@ unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs,BUG_ON (1 ); } +/* +* Set the return address as the instruction pointer, because if the +* user handler calls stack_trace_save_regs() with this 'regs', +* the stack trace will start from the instruction pointer. +*/ +instruction_pointer_set (regs, (unsigned long )correct_ret_addr); +/* Run the user handler of the nodes. */ first = current->kretprobe_instances.first;while (first) {
Masami Hiramatsu
maintainerPATCH v11 24/27 x86/kprobes: Push a fake return address at kretprobe_trampoline
In reply to Masami HiramatsuChange __kretprobe_trampoline() to push the address of the __kretprobe_trampoline() as a fake return address at the bottom of the stack frame. This fake return address will be replaced with the correct return address in the trampoline_handler().
With this change, the ORC unwinder can check whether the return address is modified by kretprobes or not.
---
Changes in v9:
- Update changelog and comment.
- Remove unneeded type casting.
--- arch/x86/kernel/kprobes/core.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-)
arch/x86/kernel/kprobes/core.c +25 -9
@@ -1022,28 +1022,33 @@ asm( ".global __kretprobe_trampoline\n" ".type __kretprobe_trampoline, @function\n" "__kretprobe_trampoline:\n" -/* We don't bother saving the ss register */ #ifdef CONFIG_X86_64 -" pushq %rsp\n" + /* Push a fake return address to tell the unwinder it's a kretprobe. */ + " pushq $__kretprobe_trampoline\n" UNWIND_HINT_FUNC + /* Save the 'sp - 8', this will be fixed later. */ + " pushq %rsp\n" " pushfq\n" SAVE_REGS_STRING " movq %rsp, %rdi\n" " call trampoline_handler\n" -/* Replace saved sp with true return address. */ -" movq %rax, 19*8(%rsp)\n" RESTORE_REGS_STRING + /* In trampoline_handler(), 'regs->flags' is copied to 'regs->sp'. */ + " addq $8, %rsp\n" " popfq\n" #else - " pushl %esp\n" +/* Push a fake return address to tell the unwinder it's a kretprobe. */ +" pushl $__kretprobe_trampoline\n" UNWIND_HINT_FUNC +/* Save the 'sp - 4', this will be fixed later. */ +" pushl %esp\n" " pushfl\n" SAVE_REGS_STRING " movl %esp, %eax\n" " call trampoline_handler\n" -/* Replace saved sp with true return address. */ -" movl %eax, 15*4(%esp)\n" RESTORE_REGS_STRING +/* In trampoline_handler(), 'regs->flags' is copied to 'regs->sp'. */ +" addl $4, %esp\n" " popfl\n" #endif " ret\n"
@@ -1063,8 +1068,10 @@ STACK_FRAME_NON_STANDARD_FP(__kretprobe_trampoline);/* * Called from __kretprobe_trampoline */ -__used __visible void *trampoline_handler(struct pt_regs *regs) +__used __visible void trampoline_handler(struct pt_regs *regs) { +unsigned long *frame_pointer; +/* fixup registers */ regs->cs = __KERNEL_CS;#ifdef CONFIG_X86_32
@@ -1072,8 +1079,17 @@ __used __visible void *trampoline_handler(struct pt_regs *regs)#endif regs->ip = (unsigned long )&__kretprobe_trampoline; regs->orig_ax = ~0UL ; + regs->sp +=sizeof (long ); + frame_pointer = ®s->sp +1 ; + +/* Replace fake return address with real one. */ + *frame_pointer =kretprobe_trampoline_handler (regs, frame_pointer); -return (void *)kretprobe_trampoline_handler (regs, ®s->sp); +/* +* Copy FLAGS to 'pt_regs::sp' so that __kretprobe_trapmoline() +* can do RET right after POPF. +*/ + regs->sp = regs->flags; }NOKPROBE_SYMBOL (trampoline_handler);
Masami Hiramatsu
maintainerPATCH v11 25/27 x86/unwind: Recover kretprobe trampoline entry
In reply to Masami HiramatsuSince the kretprobe replaces the function return address with the kretprobe_trampoline on the stack, x86 unwinders can not continue the stack unwinding at that point, or record kretprobe_trampoline instead of correct return address.
To fix this issue, find the correct return address from task's kretprobe_instances as like as function-graph tracer does.
With this fix, the unwinder can correctly unwind the stack from kretprobe event on x86, as below.
<...>-135 [003] ...1 6.722338: r_full_proxy_read_0: (vfs_read+0xab/0x1a0 <- full_proxy_read)
<...>-135 [003] ...1 6.722377: <stack trace> => kretprobe_trace_func+0x209/0x2f0
=> kretprobe_dispatcher+0x4a/0x70
=> __kretprobe_trampoline_handler+0xca/0x150
=> trampoline_handler+0x44/0x70
=> kretprobe_trampoline+0x2a/0x50
=> vfs_read+0xab/0x1a0
=> ksys_read+0x5f/0xe0
=> do_syscall_64+0x33/0x40
=> entry_SYSCALL_64_after_hwframe+0x44/0xae
---
Changes in v9:
- Update comment so that it explains why the strange address passed to unwind_recover_kretprobe().
Changes in v7:
- Remove superfluous #include <linux/kprobes.h>.
Changes in v5:
- Fix the case of interrupt happens on kretprobe_trampoline+0.
Changes in v3:
- Split out the kretprobe side patch
- Fix build error when CONFIG_KRETPROBES=n.
Changes in v2:
- Remove kretprobe wrapper functions from unwind_orc.c
- Do not fixup state->ip when unwinding with regs because kretprobe fixup instruction pointer before calling handler.
--- arch/x86/include/asm/unwind.h | 23 +++++++++++++++++++++++ arch/x86/kernel/unwind_frame.c | 3 +-- arch/x86/kernel/unwind_guess.c | 3 +-- arch/x86/kernel/unwind_orc.c | 21 +++++++++++++++++---- 4 files changed, 42 insertions(+), 8 deletions(-)
arch/x86/include/asm/unwind.h +23 -0
@@ -4,6 +4,7 @@#include <linux/sched.h> #include <linux/ftrace.h> +#include <linux/kprobes.h> #include <asm/ptrace.h> #include <asm/stacktrace.h>
@@ -15,6 +16,7 @@ struct unwind_state {unsigned long stack_mask;struct task_struct *task;int graph_idx; +struct llist_node *kr_cur;bool error;#if defined(CONFIG_UNWINDER_ORC )bool signal, full_regs;
@@ -99,6 +101,27 @@ void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size, void *orc, size_t orc_size) {}#endif +static inline +unsigned long unwind_recover_kretprobe (struct unwind_state *state, +unsigned long addr,unsigned long *addr_p) +{ +return is_kretprobe_trampoline (addr) ? +kretprobe_find_ret_addr (state->task, addr_p, &state->kr_cur) : + addr; +} + +/* Recover the return address modified by kretprobe and ftrace_graph. */ +static inline +unsigned long unwind_recover_ret_addr (struct unwind_state *state, +unsigned long addr,unsigned long *addr_p) +{ +unsigned long ret; + + ret =ftrace_graph_ret_addr (state->task, &state->graph_idx, + addr, addr_p); +return unwind_recover_kretprobe (state, ret, addr_p); +} +/* * This disables KASAN checking when reading a value from another task's stack, * since the other task could be running on another CPU and could have poisoned
arch/x86/kernel/unwind_frame.c +1 -2
@@ -240,8 +240,7 @@ static bool update_stack_state(struct unwind_state *state,else { addr_p =unwind_get_return_address_ptr (state); addr =READ_ONCE_TASK_STACK (state->task, *addr_p); - state->ip =ftrace_graph_ret_addr (state->task, &state->graph_idx, - addr, addr_p); + state->ip =unwind_recover_ret_addr (state, addr, addr_p); }/* Save the original stack pointer for unwind_dump(): */
arch/x86/kernel/unwind_guess.c +1 -2
@@ -15,8 +15,7 @@ unsigned long unwind_get_return_address(struct unwind_state *state) addr =READ_ONCE_NOCHECK (*state->sp); -return ftrace_graph_ret_addr (state->task, &state->graph_idx, - addr, state->sp); +return unwind_recover_ret_addr (state, addr, state->sp); }EXPORT_SYMBOL_GPL (unwind_get_return_address);
arch/x86/kernel/unwind_orc.c +17 -4
@@ -534,9 +534,8 @@ bool unwind_next_frame(struct unwind_state *state)if (!deref_stack_reg (state, ip_p, &state->ip)) goto err; - state->ip =ftrace_graph_ret_addr (state->task, &state->graph_idx, - state->ip, (void *)ip_p); - + state->ip =unwind_recover_ret_addr (state, state->ip, + (unsigned long *)ip_p); state->sp = sp; state->regs =NULL ; state->prev_regs =NULL ;
@@ -549,7 +548,18 @@ bool unwind_next_frame(struct unwind_state *state) (void *)orig_ip); goto err; } - +/* +* There is a small chance to interrupt at the entry of +* __kretprobe_trampoline() where the ORC info doesn't exist. +* That point is right after the RET to __kretprobe_trampoline() +* which was modified return address. +* At that point, the @addr_p of the unwind_recover_kretprobe() +* (this has to point the address of the stack entry storing +* the modified return address) must be "SP - (a stack entry)" +* because SP is incremented by the RET. +*/ + state->ip =unwind_recover_kretprobe (state, state->ip, + (unsigned long *)(state->sp -sizeof (long ))); state->regs = (struct pt_regs *)sp; state->prev_regs =NULL ; state->full_regs = true;
@@ -562,6 +572,9 @@ bool unwind_next_frame(struct unwind_state *state) (void *)orig_ip); goto err; } +/* See UNWIND_HINT_TYPE_REGS case comment. */ + state->ip =unwind_recover_kretprobe (state, state->ip, + (unsigned long *)(state->sp -sizeof (long )));if (state->full_regs) state->prev_regs = state->regs;
Masami Hiramatsu
maintainerPATCH v11 26/27 tracing: Show kretprobe unknown indicator only for kretprobe_trampoline
In reply to Masami Hiramatsuftrace shows "[unknown/kretprobe'd]" indicator all addresses in the kretprobe_trampoline, but the modified address by kretprobe should be only kretprobe_trampoline+0.
--- kernel/trace/trace_output.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-)
kernel/trace/trace_output.c +4 -13
@@ -8,6 +8,7 @@#include <linux/module.h> #include <linux/mutex.h> #include <linux/ftrace.h> +#include <linux/kprobes.h> #include <linux/sched/clock.h> #include <linux/sched/mm.h>
@@ -346,22 +347,12 @@ int trace_output_call(struct trace_iterator *iter, char *name, char *fmt, ...) }EXPORT_SYMBOL_GPL (trace_output_call); -#ifdef CONFIG_KRETPROBES -static inline const char *kretprobed (const char *name) +static inline const char *kretprobed (const char *name,unsigned long addr) { -static const char tramp_name[] ="__kretprobe_trampoline" ; -int size =sizeof (tramp_name); - -if (strncmp (tramp_name, name, size) =0 ) +if (is_kretprobe_trampoline (addr))return "[unknown/kretprobe'd]" ;return name; } -#else -static inline const char *kretprobed (const char *name) -{ -return name; -} -#endif /* CONFIG_KRETPROBES */ void trace_seq_print_sym (struct trace_seq *s,unsigned long address,bool offset)
@@ -374,7 +365,7 @@ trace_seq_print_sym(struct trace_seq *s, unsigned long address, bool offset)sprint_symbol (str, address); elsekallsyms_lookup (address ,NULL ,NULL ,NULL ,str ); - name =kretprobed (str); + name =kretprobed (str, address);if (name &&strlen (name)) {trace_seq_puts (s, name);
Masami Hiramatsu
maintainerPATCH v11 27/27 x86/kprobes: Fixup return address in generic trampoline handler
In reply to Masami HiramatsuIn x86, the fake return address on the stack saved by __kretprobe_trampoline() will be replaced with the real return address after returning from trampoline_handler(). Before fixing the return address, the real return address can be found in the 'current->kretprobe_instances'.
However, since there is a window between updating the 'current->kretprobe_instances' and fixing the address on the stack, if an interrupt happens at that timing and the interrupt handler does stacktrace, it may fail to unwind because it can not get the correct return address from 'current->kretprobe_instances'.
This will eliminate that window by fixing the return address right before updating 'current->kretprobe_instances'.
---
Changes in v9:
- Fixes the changelog. This can eliminate the window.
- Add more comment how it works.
Changes in v7:
- Add a prototype for arch_kretprobe_fixup_return()
--- arch/x86/kernel/kprobes/core.c | 18 ++++++++++++++++-- include/linux/kprobes.h | 3 +++ kernel/kprobes.c | 11 +++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-)
arch/x86/kernel/kprobes/core.c +16 -2
@@ -1065,6 +1065,16 @@ NOKPROBE_SYMBOL(__kretprobe_trampoline);*/ STACK_FRAME_NON_STANDARD_FP (__kretprobe_trampoline); +/* This is called from kretprobe_trampoline_handler(). */ +void arch_kretprobe_fixup_return (struct pt_regs *regs, +kprobe_opcode_t *correct_ret_addr) +{ +unsigned long *frame_pointer = ®s->sp +1 ; + +/* Replace fake return address with real one. */ + *frame_pointer = (unsigned long )correct_ret_addr; +} +/* * Called from __kretprobe_trampoline */
@@ -1082,8 +1092,12 @@ __used __visible void trampoline_handler(struct pt_regs *regs) regs->sp +=sizeof (long ); frame_pointer = ®s->sp +1 ; -/* Replace fake return address with real one. */ - *frame_pointer =kretprobe_trampoline_handler (regs, frame_pointer); +/* +* The return address at 'frame_pointer' is recovered by the +* arch_kretprobe_fixup_return() which called from the +* kretprobe_trampoline_handler(). +*/ +kretprobe_trampoline_handler (regs, frame_pointer);/* * Copy FLAGS to 'pt_regs::sp' so that __kretprobe_trapmoline()
include/linux/kprobes.h +3 -0
@@ -188,6 +188,9 @@ extern void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs);extern int arch_trampoline_kprobe (struct kprobe *p); +void arch_kretprobe_fixup_return (struct pt_regs *regs, +kprobe_opcode_t *correct_ret_addr); +void __kretprobe_trampoline (void );/* * Since some architecture uses structured function pointer,
kernel/kprobes.c +11 -0
@@ -1922,6 +1922,15 @@ unsigned long kretprobe_find_ret_addr(struct task_struct *tsk, void *fp, }NOKPROBE_SYMBOL (kretprobe_find_ret_addr); +void __weak arch_kretprobe_fixup_return (struct pt_regs *regs, +kprobe_opcode_t *correct_ret_addr) +{ +/* +* Do nothing by default. Please fill this to update the fake return +* address on the stack with the correct one on each arch if possible. +*/ +} +unsigned long __kretprobe_trampoline_handler (struct pt_regs *regs,void *frame_pointer) {
@@ -1967,6 +1976,8 @@ unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs, first = first->next; } +arch_kretprobe_fixup_return (regs, correct_ret_addr); +/* Unlink all nodes for this frame. */ first = current->kretprobe_instances.first; current->kretprobe_instances.first = node->next;
Quoted 99 lines · Masami Hiramatsu
Hello,
This is the 11th version of the series to fix the stacktrace with kretprobe on x86.
The previous version is here;
https://lore.kernel.org/all/162756755600.301564.4957591913842010341.stgit@devnote2/
This version is rebased on the latest tip/master branch and includes the kprobe cleanup series[1][2]. No code change.
[1] https://lore.kernel.org/bpf/162748615977.59465.13262421617578791515.stgit@devnote2/
[2] https://lore.kernel.org/linux-csky/[email protected]/With this series, unwinder can unwind stack correctly from ftrace as below;
# cd /sys/kernel/debug/tracing # echo > trace # echo 1 > options/sym-offset # echo r vfs_read >> kprobe_events # echo r full_proxy_read >> kprobe_events # echo traceoff:1 > events/kprobes/r_vfs_read_0/trigger # echo stacktrace:1 > events/kprobes/r_full_proxy_read_0/trigger # echo 1 > events/kprobes/enable # cat /sys/kernel/debug/kprobes/list ffffffff813bedf0 r full_proxy_read+0x0 [FTRACE] ffffffff812c13e0 r vfs_read+0x0 [FTRACE] # echo 0 > events/kprobes/enable # cat trace # tracer: nop # # entries-in-buffer/entries-written: 3/3 #P:8 # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # ||| / _-=> migrate-disable # |||| / delay # TASK-PID CPU# ||||| TIMESTAMP FUNCTION # | | | ||||| | | cat-136 [000] ...1. 14.474966: r_full_proxy_read_0: (vfs_read+0x99/0x190 <- full_proxy_read) cat-136 [000] ...1. 14.474970: <stack trace> => kretprobe_trace_func+0x209/0x300 => kretprobe_dispatcher+0x9d/0xb0 => __kretprobe_trampoline_handler+0xd4/0x1b0 => trampoline_handler+0x43/0x60 => __kretprobe_trampoline+0x2a/0x50 => vfs_read+0x99/0x190 => ksys_read+0x68/0xe0 => do_syscall_64+0x3b/0x90 => entry_SYSCALL_64_after_hwframe+0x44/0xae cat-136 [000] ...1. 14.474971: r_vfs_read_0: (ksys_read+0x68/0xe0 <- vfs_read)This shows the double return probes (
vfs_read()andfull_proxy_read()) on the stack correctly unwinded. (vfs_read()returns to 'ksys_read+0x68' andfull_proxy_read()returns to 'vfs_read+0x99')This also changes the kretprobe behavisor a bit, now the instraction pointer in the '
pt_regs' passed to kretprobe user handler is correctly set the real return address. So user handlers can get it viainstruction_pointer()API, and can usestack_trace_save_regs().You can also get this series from
git://git.kernel.org/pub/scm/linux/kernel/git/mhiramat/linux.gitkprobes/kretprobe-stackfix-v11Thank you,
---
Josh Poimboeuf (3):
objtool: Add frame-pointer-specific function ignore
objtool: Ignore unwind hints for ignored functions x86/kprobes: AddUNWIND_HINT_FUNConkretprobe_trampoline()Masami Hiramatsu (19):
kprobes: treewide: Cleanup the error messages for kprobes
kprobes: Fix coding style issues
kprobes: UseIS_ENABLED()instead ofkprobes_built_in()
kprobes: Add assertions for required lock
kprobes: treewide: Use 'kprobe_opcode_t*' for the code address inget_optimized_kprobe()
kprobes: Use bool type for functions which returns boolean value
ia64: kprobes: Fix to pass correct trampoline address to the handler
kprobes: treewide: Replacearch_deref_entry_point()withdereference_symbol_descriptor()
kprobes: treewide: Removetrampoline_addressfromkretprobe_trampoline_handler()
kprobes: treewide: Make it harder to referkretprobe_trampolinedirectly
kprobes: Addkretprobe_find_ret_addr()for searching return address
ARC: Addinstruction_pointer_set()API
ia64: Addinstruction_pointer_set()API
arm: kprobes: Make space for instruction pointer on stack
kprobes: Enable stacktrace frompt_regsin kretprobe handler
x86/kprobes: Push a fake return address atkretprobe_trampolinex86/unwind: Recover kretprobe trampoline entry
tracing: Show kretprobe unknown indicator only forkretprobe_trampolinex86/kprobes: Fixup return address in generic trampoline handler
Quoted 7 lines
Punit Agrawal (5):
kprobes: Do not use local variable when creating debugfs file
kprobes: Use helper to parse boolean input from userspace
kprobe: Simplifyprepare_kprobe()by dropping redundant version
csky: ftrace: Drop duplicate implementation ofarch_check_ftrace_location()
kprobes: Makearch_check_ftrace_locationstatic
Re-tested with latest BPF selftests and retsnoop tool utilizing kretprobe and capturing stack traces (broken without these changes). Looks good, thank you!
Quoted 51 lines
arch/arc/include/asm/kprobes.h | 2 arch/arc/include/asm/ptrace.h | 5 arch/arc/kernel/kprobes.c | 13 - arch/arm/probes/kprobes/core.c | 15 - arch/arm/probes/kprobes/opt-arm.c | 7 arch/arm64/include/asm/kprobes.h | 2 arch/arm64/kernel/probes/kprobes.c | 10 arch/arm64/kernel/probes/kprobes_trampoline.S | 4 arch/csky/include/asm/kprobes.h | 2 arch/csky/kernel/probes/ftrace.c | 7 arch/csky/kernel/probes/kprobes.c | 14 - arch/csky/kernel/probes/kprobes_trampoline.S | 4 arch/ia64/include/asm/ptrace.h | 5 arch/ia64/kernel/kprobes.c | 15 - arch/mips/kernel/kprobes.c | 26 + arch/parisc/kernel/kprobes.c | 6 arch/powerpc/include/asm/kprobes.h | 2 arch/powerpc/kernel/kprobes.c | 29 - arch/powerpc/kernel/optprobes.c | 8 arch/powerpc/kernel/stacktrace.c | 2 arch/riscv/include/asm/kprobes.h | 2 arch/riscv/kernel/probes/kprobes.c | 15 - arch/riscv/kernel/probes/kprobes_trampoline.S | 4 arch/s390/include/asm/kprobes.h | 2 arch/s390/kernel/kprobes.c | 16 - arch/s390/kernel/stacktrace.c | 2 arch/sh/include/asm/kprobes.h | 2 arch/sh/kernel/kprobes.c | 12 - arch/sparc/include/asm/kprobes.h | 2 arch/sparc/kernel/kprobes.c | 12 - arch/x86/include/asm/kprobes.h | 1 arch/x86/include/asm/unwind.h | 23 + arch/x86/include/asm/unwind_hints.h | 5 arch/x86/kernel/kprobes/core.c | 71 +++- arch/x86/kernel/kprobes/opt.c | 6 arch/x86/kernel/unwind_frame.c | 3 arch/x86/kernel/unwind_guess.c | 3 arch/x86/kernel/unwind_orc.c | 21 + include/linux/kprobes.h | 113 ++++-- include/linux/objtool.h | 12 + kernel/kprobes.c | 502 ++++++++++++++----------- kernel/trace/trace_kprobe.c | 2 kernel/trace/trace_output.c | 17 - lib/error-inject.c | 3 tools/include/linux/objtool.h | 12 + tools/objtool/check.c | 2 46 files changed, 607 insertions(+), 436 deletions(-)--
Masami Hiramatsu (Linaro) <[email protected]>
Masami Hiramatsu
maintainerHi Ingo,
Can you merge this series to -tip tree since if I understand correctly, all kprobes patches still should be merged via -tip tree.
If you don't think so anymore, I would like to handle the kprobe related patches on my tree. Since many kprobes fixes/cleanups have not been merged these months, it seems unhealthy now.
Thank you,
Quoted 156 lines · On Tue, 14 Sep 2021 23:38:27 +0900 Masami Hiramatsu <[email protected]> wrote:
Hello,
This is the 11th version of the series to fix the stacktrace with kretprobe on x86.
The previous version is here;
https://lore.kernel.org/all/162756755600.301564.4957591913842010341.stgit@devnote2/
This version is rebased on the latest tip/master branch and includes the kprobe cleanup series[1][2]. No code change.
[1] https://lore.kernel.org/bpf/162748615977.59465.13262421617578791515.stgit@devnote2/
[2] https://lore.kernel.org/linux-csky/[email protected]/With this series, unwinder can unwind stack correctly from ftrace as below;
# cd /sys/kernel/debug/tracing # echo > trace # echo 1 > options/sym-offset # echo r vfs_read >> kprobe_events # echo r full_proxy_read >> kprobe_events # echo traceoff:1 > events/kprobes/r_vfs_read_0/trigger # echo stacktrace:1 > events/kprobes/r_full_proxy_read_0/trigger # echo 1 > events/kprobes/enable # cat /sys/kernel/debug/kprobes/list ffffffff813bedf0 r full_proxy_read+0x0 [FTRACE] ffffffff812c13e0 r vfs_read+0x0 [FTRACE] # echo 0 > events/kprobes/enable # cat trace # tracer: nop # # entries-in-buffer/entries-written: 3/3 #P:8 # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # ||| / _-=> migrate-disable # |||| / delay # TASK-PID CPU# ||||| TIMESTAMP FUNCTION # | | | ||||| | | cat-136 [000] ...1. 14.474966: r_full_proxy_read_0: (vfs_read+0x99/0x190 <- full_proxy_read) cat-136 [000] ...1. 14.474970: <stack trace> => kretprobe_trace_func+0x209/0x300 => kretprobe_dispatcher+0x9d/0xb0 => __kretprobe_trampoline_handler+0xd4/0x1b0 => trampoline_handler+0x43/0x60 => __kretprobe_trampoline+0x2a/0x50 => vfs_read+0x99/0x190 => ksys_read+0x68/0xe0 => do_syscall_64+0x3b/0x90 => entry_SYSCALL_64_after_hwframe+0x44/0xae cat-136 [000] ...1. 14.474971: r_vfs_read_0: (ksys_read+0x68/0xe0 <- vfs_read)This shows the double return probes (
vfs_read()andfull_proxy_read()) on the stack correctly unwinded. (vfs_read()returns to 'ksys_read+0x68' andfull_proxy_read()returns to 'vfs_read+0x99')This also changes the kretprobe behavisor a bit, now the instraction pointer in the '
pt_regs' passed to kretprobe user handler is correctly set the real return address. So user handlers can get it viainstruction_pointer()API, and can usestack_trace_save_regs().You can also get this series from
git://git.kernel.org/pub/scm/linux/kernel/git/mhiramat/linux.gitkprobes/kretprobe-stackfix-v11Thank you,
---
Josh Poimboeuf (3):
objtool: Add frame-pointer-specific function ignore
objtool: Ignore unwind hints for ignored functions x86/kprobes: AddUNWIND_HINT_FUNConkretprobe_trampoline()Masami Hiramatsu (19):
kprobes: treewide: Cleanup the error messages for kprobes
kprobes: Fix coding style issues
kprobes: UseIS_ENABLED()instead ofkprobes_built_in()
kprobes: Add assertions for required lock
kprobes: treewide: Use 'kprobe_opcode_t*' for the code address inget_optimized_kprobe()
kprobes: Use bool type for functions which returns boolean value
ia64: kprobes: Fix to pass correct trampoline address to the handler
kprobes: treewide: Replacearch_deref_entry_point()withdereference_symbol_descriptor()
kprobes: treewide: Removetrampoline_addressfromkretprobe_trampoline_handler()
kprobes: treewide: Make it harder to referkretprobe_trampolinedirectly
kprobes: Addkretprobe_find_ret_addr()for searching return address
ARC: Addinstruction_pointer_set()API
ia64: Addinstruction_pointer_set()API
arm: kprobes: Make space for instruction pointer on stack
kprobes: Enable stacktrace frompt_regsin kretprobe handler
x86/kprobes: Push a fake return address atkretprobe_trampolinex86/unwind: Recover kretprobe trampoline entry
tracing: Show kretprobe unknown indicator only forkretprobe_trampolinex86/kprobes: Fixup return address in generic trampoline handlerPunit Agrawal (5):
kprobes: Do not use local variable when creating debugfs file
kprobes: Use helper to parse boolean input from userspace
kprobe: Simplifyprepare_kprobe()by dropping redundant version
csky: ftrace: Drop duplicate implementation ofarch_check_ftrace_location()
kprobes: Makearch_check_ftrace_locationstaticarch/arc/include/asm/kprobes.h | 2 arch/arc/include/asm/ptrace.h | 5 arch/arc/kernel/kprobes.c | 13 - arch/arm/probes/kprobes/core.c | 15 - arch/arm/probes/kprobes/opt-arm.c | 7 arch/arm64/include/asm/kprobes.h | 2 arch/arm64/kernel/probes/kprobes.c | 10 arch/arm64/kernel/probes/kprobes_trampoline.S | 4 arch/csky/include/asm/kprobes.h | 2 arch/csky/kernel/probes/ftrace.c | 7 arch/csky/kernel/probes/kprobes.c | 14 - arch/csky/kernel/probes/kprobes_trampoline.S | 4 arch/ia64/include/asm/ptrace.h | 5 arch/ia64/kernel/kprobes.c | 15 - arch/mips/kernel/kprobes.c | 26 + arch/parisc/kernel/kprobes.c | 6 arch/powerpc/include/asm/kprobes.h | 2 arch/powerpc/kernel/kprobes.c | 29 - arch/powerpc/kernel/optprobes.c | 8 arch/powerpc/kernel/stacktrace.c | 2 arch/riscv/include/asm/kprobes.h | 2 arch/riscv/kernel/probes/kprobes.c | 15 - arch/riscv/kernel/probes/kprobes_trampoline.S | 4 arch/s390/include/asm/kprobes.h | 2 arch/s390/kernel/kprobes.c | 16 - arch/s390/kernel/stacktrace.c | 2 arch/sh/include/asm/kprobes.h | 2 arch/sh/kernel/kprobes.c | 12 - arch/sparc/include/asm/kprobes.h | 2 arch/sparc/kernel/kprobes.c | 12 - arch/x86/include/asm/kprobes.h | 1 arch/x86/include/asm/unwind.h | 23 + arch/x86/include/asm/unwind_hints.h | 5 arch/x86/kernel/kprobes/core.c | 71 +++- arch/x86/kernel/kprobes/opt.c | 6 arch/x86/kernel/unwind_frame.c | 3 arch/x86/kernel/unwind_guess.c | 3 arch/x86/kernel/unwind_orc.c | 21 + include/linux/kprobes.h | 113 ++++-- include/linux/objtool.h | 12 + kernel/kprobes.c | 502 ++++++++++++++----------- kernel/trace/trace_kprobe.c | 2 kernel/trace/trace_output.c | 17 - lib/error-inject.c | 3 tools/include/linux/objtool.h | 12 + tools/objtool/check.c | 2 46 files changed, 607 insertions(+), 436 deletions(-)--
Masami Hiramatsu (Linaro) <[email protected]>
Signature · 1 line
Masami Hiramatsu <[email protected]>
Quoted 10 lines · Masami Hiramatsu
Hi Ingo,
Can you merge this series to -tip tree since if I understand correctly, all kprobes patches still should be merged via -tip tree.
If you don't think so anymore, I would like to handle the kprobe related patches on my tree. Since many kprobes fixes/cleanups have not been merged these months, it seems unhealthy now.Thank you,
Linus,
please suggest how to move these patches forward.
We've been waiting for this fix for months now.
Quoted 19 lines
Quoted 16 lines · On Tue, 14 Sep 2021 23:38:27 +0900 Masami Hiramatsu <[email protected]> wrote:
Hello,
This is the 11th version of the series to fix the stacktrace with kretprobe on x86.
The previous version is here;
https://lore.kernel.org/all/162756755600.301564.4957591913842010341.stgit@devnote2/
This version is rebased on the latest tip/master branch and includes the kprobe cleanup series[1][2]. No code change.
[1] https://lore.kernel.org/bpf/162748615977.59465.13262421617578791515.stgit@devnote2/
[2] https://lore.kernel.org/linux-csky/[email protected]/With this series, unwinder can unwind stack correctly from ftrace as below;
Quoted 10 lines · Alexei Starovoitov
Quoted 9 lines · Masami Hiramatsu
Hi Ingo,
Can you merge this series to -tip tree since if I understand correctly, all kprobes patches still should be merged via -tip tree.
If you don't think so anymore, I would like to handle the kprobe related patches on my tree. Since many kprobes fixes/cleanups have not been merged these months, it seems unhealthy now.
Quoted 6 lines
Quoted 1 line
Thank you,
Linus,
please suggest how to move these patches forward.
We've been waiting for this fix for months now.
Sorry, I've not paying attention to those as they are usually handled by Ingo who seems to be lost in space.
Masami, feel free to merge them over your tree. If not, let me know and I'll pick them up tomorrow morning.
Thanks,
tglx
Steven Rostedt
maintainerQuoted 2 lines · On Thu, 30 Sep 2021 21:34:11 +0200 Thomas Gleixner <[email protected]> wrote:
Masami, feel free to merge them over your tree. If not, let me know and I'll pick them up tomorrow morning.
Masami usually goes through my tree. Want me to take it or do you want to?
-- Steve
Quoted 8 lines · Steven Rostedt
Quoted 2 lines · On Thu, 30 Sep 2021 21:34:11 +0200 Thomas Gleixner <[email protected]> wrote:
Masami, feel free to merge them over your tree. If not, let me know and I'll pick them up tomorrow morning.
Masami usually goes through my tree. Want me to take it or do you want to?
Now I'm really confused. Masami poke Ingo to merge stuff which goes usually through your tree !?!
But sure, feel free to pick it up. I have enough stuff on my plate already.
Thanks,
tglx
Masami Hiramatsu
maintainerQuoted 7 lines · On Fri, 01 Oct 2021 01:11:12 +0200 Thomas Gleixner <[email protected]> wrote:
Quoted 6 lines · Steven Rostedt
Quoted 2 lines · On Thu, 30 Sep 2021 21:34:11 +0200 Thomas Gleixner <[email protected]> wrote:
Masami, feel free to merge them over your tree. If not, let me know and I'll pick them up tomorrow morning.
Quoted 8 lines
Quoted 2 lines
Masami usually goes through my tree. Want me to take it or do you want to?
Now I'm really confused. Masami poke Ingo to merge stuff which goes usually through your tree !?!
But sure, feel free to pick it up. I have enough stuff on my plate already.
Let me explain how the patches are usually merged.
- kernel/kprobes.c related patches go through the tip tree.
- kernel/trace/* patches go through the tracing tree.
So traditionally(?) I think this series go through the tip tree, but since the biggest user of kprobes is tracing and the kprobes fix now involves tree-wide fixes as you can see in this series, I think it is a good timing to move kprobes to tracing tree.
Thank you,
Signature · 1 line
Masami Hiramatsu <[email protected]>
Steven Rostedt
maintainerQuoted 4 lines · On Fri, 1 Oct 2021 08:27:33 +0900 Masami Hiramatsu <[email protected]> wrote:
Let me explain how the patches are usually merged.
-
kernel/kprobes.crelated patches go through the tip tree.
-kernel/trace/*patches go through the tracing tree.
And arch/*/kprobe* usually goes through tip as well.
Quoted 5 lines
So traditionally(?) I think this series go through the tip tree, but since the biggest user of kprobes is tracing and the kprobes fix now involves tree-wide fixes as you can see in this series, I think it is a good timing to move kprobes to tracing tree.
I'll pick it up and take the burden off of Thomas.
Just to confirm, this is for the next merge window, right?
-- Steve
Masami Hiramatsu
maintainerQuoted 11 lines · On Thu, 30 Sep 2021 19:37:08 -0400 Steven Rostedt <[email protected]> wrote:
Quoted 4 lines · On Fri, 1 Oct 2021 08:27:33 +0900 Masami Hiramatsu <[email protected]> wrote:
Let me explain how the patches are usually merged.
-
kernel/kprobes.crelated patches go through the tip tree.
-kernel/trace/*patches go through the tracing tree.And
arch/*/kprobe*usually goes through tip as well.Quoted 1 line
Quoted 6 lines
Quoted 4 lines
So traditionally(?) I think this series go through the tip tree, but since the biggest user of kprobes is tracing and the kprobes fix now involves tree-wide fixes as you can see in this series, I think it is a good timing to move kprobes to tracing tree.
I'll pick it up and take the burden off of Thomas.
Thank you very much!
Quoted 2 lines
Just to confirm, this is for the next merge window, right?
Yes, please push it to the next merge window.
Thanks,
Quoted 2 lines
-- Steve
Signature · 1 line
Masami Hiramatsu <[email protected]>
Masami Hiramatsu
maintainerQuoted 16 lines · On Thu, 30 Sep 2021 21:34:11 +0200 Thomas Gleixner <[email protected]> wrote:
Quoted 14 lines · Alexei Starovoitov
Quoted 10 lines · Masami Hiramatsu
Hi Ingo,
Can you merge this series to -tip tree since if I understand correctly, all kprobes patches still should be merged via -tip tree.
If you don't think so anymore, I would like to handle the kprobe related patches on my tree. Since many kprobes fixes/cleanups have not been merged these months, it seems unhealthy now.Thank you,
Linus,
Quoted 8 lines
Quoted 2 lines
please suggest how to move these patches forward.
We've been waiting for this fix for months now.Sorry, I've not paying attention to those as they are usually handled by Ingo who seems to be lost in space.
Masami, feel free to merge them over your tree. If not, let me know and I'll pick them up tomorrow morning.
Thank you Thomas for your proposal. As I send in the other mail, if Steve can pick this as a part of tracing, I think that will be better.
Thanks again,
Quoted 4 lines
Thanks,
tglx
Signature · 1 line
Masami Hiramatsu <[email protected]>