tracing: Updates for 5.16
Subsystems (20)
Steven Rostedt
maintainercover tracing: Updates for 5.16
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
for-next
Head SHA1: bf094cffea2a6503ce84062f9f0243bef77c58f9
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(-)
Steven Rostedt
maintainerPATCH 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);
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 2/27 kprobes: Use helper to parse boolean input from userspace
In reply to Steven RostedtFrom: 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;
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 3/27 kprobe: Simplify prepare_kprobe() by dropping redundant version
In reply to Steven RostedtFrom: 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) {
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 4/27 csky: ftrace: Drop duplicate implementation of arch_check_ftrace_location()
In reply to Steven RostedtFrom: 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)
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 5/27 kprobes: Make arch_check_ftrace_location static
In reply to Steven RostedtFrom: 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 ();
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 6/27 kprobes: treewide: Cleanup the error messages for kprobes
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
This 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" );
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 7/27 kprobes: Fix coding style issues
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Fix 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
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 8/27 kprobes: Use IS_ENABLED() instead of kprobes_built_in()
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Use 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;
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 9/27 kprobes: Add assertions for required lock
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Add 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 ))
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 10/27 kprobes: treewide: Use kprobe_opcode_t * for the code address in get_optimized_kprobe()
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Since 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); }
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 11/27 kprobes: Use bool type for functions which returns boolean value
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Use 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.
--- 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,
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 12/27 ia64: kprobes: Fix to pass correct trampoline address to the handler
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
The 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.
--- arch/ia64/kernel/kprobes.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
arch/ia64/kernel/kprobes.c +5 -4
@@ -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 ;
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 13/27 kprobes: treewide: Replace arch_deref_entry_point() with dereference_symbol_descriptor()
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
~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().
--- 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)) {
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 14/27 kprobes: treewide: Remove trampoline_address from kretprobe_trampoline_handler()
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
The __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.
--- 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
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 15/27 kprobes: treewide: Make it harder to refer kretprobe_trampoline directly
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Since 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 -4
@@ -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 -5
@@ -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 )
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 16/27 kprobes: Add kretprobe_find_ret_addr() for searching return address
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Introduce 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.
--- 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
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 17/27 objtool: Add frame-pointer-specific function ignore
In reply to Steven RostedtFrom: 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.
--- 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
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 18/27 objtool: Ignore unwind hints for ignored functions
In reply to Steven RostedtFrom: 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);
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 19/27 x86/kprobes: Add UNWIND_HINT_FUNC on kretprobe_trampoline()
In reply to Steven RostedtFrom: 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().
--- 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
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 20/27 ARC: Add instruction_pointer_set() API
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Add 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 */
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 21/27 ia64: Add instruction_pointer_set() API
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Add instruction_pointer_set() API for ia64.
--- 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) {
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 22/27 arm: kprobes: Make space for instruction pointer on stack
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Since 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.
--- 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
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 23/27 kprobes: Enable stacktrace from pt_regs in kretprobe handler
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Since 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).
--- 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) {
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 24/27 x86/kprobes: Push a fake return address at kretprobe_trampoline
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Change __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.
--- 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);
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 25/27 x86/unwind: Recover kretprobe trampoline entry
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Since 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
--- 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;
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 26/27 tracing: Show kretprobe unknown indicator only for kretprobe_trampoline
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
ftrace 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);
Signature · 1 line
2.32.0
Steven Rostedt
maintainerPATCH 27/27 x86/kprobes: Fixup return address in generic trampoline handler
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
In 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'.
--- 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;
Signature · 1 line
2.32.0
Steven Rostedt
maintainerQuoted 6 lines · On Tue, 05 Oct 2021 09:57:33 -0400 Steven Rostedt <[email protected]> wrote:
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
for-nextHead SHA1:
bf094cffea2a6503ce84062f9f0243bef77c58f9
I just realized I used the wrong subject tag. This was suppose to be "[for-next]" not "[for-linus]".
-- Steve