ARM64: Uprobe support added
Subsystems (3)
cover ARM64: Uprobe support added
ARM64 kprobe support is lying in torvalds/linux.git:master now. Therefore sending my uprobe patches which were dependent on decode-insn code of kprobe patches.
Unit tests for following have been done so far and they have been found working.
1. Step-able instructions, like sub, ldr, add etc.
2. Simulation-able like ret, cbnz, cbz etc.
3. uretprobe
4. Reject-able instructions like sev, wfe etc.
5. trapped and abort xol path
6. probe at unaligned user address.
7. longjump test cases
Currently it does not support aarch32 instruction probing.
RFC patches were sent long back, and all review comments for RFCs have been incorporated. RFCs were here: https://lwn.net/Articles/648514/
Pratyush Anand (5):
arm64: kprobe: protect/rename few definitions to be reused by uprobe
arm64: kgdb_step_brk_fn: ignore other's exception
arm64: Handle TRAP_HWBRKPT for user mode as well
arm64: Handle TRAP_BRKPT for user mode as well
arm64: Add uprobe support
arch/arm64/Kconfig | 3 + arch/arm64/include/asm/debug-monitors.h | 3 + arch/arm64/include/asm/probes.h | 23 ++-- arch/arm64/include/asm/ptrace.h | 8 ++ arch/arm64/include/asm/thread_info.h | 5 +- arch/arm64/include/asm/uprobes.h | 37 ++++++ arch/arm64/kernel/debug-monitors.c | 40 +++--- arch/arm64/kernel/entry.S | 6 +- arch/arm64/kernel/kgdb.c | 3 + arch/arm64/kernel/probes/Makefile | 2 + arch/arm64/kernel/probes/decode-insn.c | 31 ++--- arch/arm64/kernel/probes/decode-insn.h | 8 +- arch/arm64/kernel/probes/kprobes.c | 36 ++--- arch/arm64/kernel/probes/uprobes.c | 227 ++++++++++++++++++++++++++++++++ arch/arm64/kernel/signal.c | 4 +- arch/arm64/mm/flush.c | 6 + 16 files changed, 378 insertions(+), 64 deletions(-) create mode 100644 arch/arm64/include/asm/uprobes.h create mode 100644 arch/arm64/kernel/probes/uprobes.c
Signature · 1 line
2.5.5
PATCH 1/5 arm64: kprobe: protect/rename few definitions to be reused by uprobe
decode-insn code has to be reused by arm64 uprobe implementation as well. Therefore, this patch protects some portion of kprobe code and renames few other, so that decode-insn functionality can be reused by uprobe even when CONFIG_KPROBES is not defined.
kprobe_opcode_t and struct arch_specific_insn are also defined by linux/kprobes.h, when CONFIG_KPROBES is not defined. So, protect these definitions in asm/probes.h.
linux/kprobes.h already includes asm/kprobes.h. Therefore, remove inclusion of asm/kprobes.h from decode-insn.c.
There are some definitions like kprobe_insn and kprobes_handler_t etc can be re-used by uprobe. So, it would be better to remove 'k' from their names.
struct arch_specific_insn is specific to kprobe. Therefore, introduce a new struct arch_probe_insn which will be common for both kprobe and uprobe, so that decode-insn code can be shared. Modify kprobe code accordingly.
Function arm_probe_decode_insn() will be needed by uprobe as well. So make it global.
--- arch/arm64/include/asm/probes.h | 19 ++++++++++-------- arch/arm64/kernel/probes/decode-insn.c | 31 +++++++++++++++-------------- arch/arm64/kernel/probes/decode-insn.h | 8 ++++++-- arch/arm64/kernel/probes/kprobes.c | 36 +++++++++++++++++----------------- 4 files changed, 51 insertions(+), 43 deletions(-)
arch/arm64/include/asm/probes.h +11 -8
@@ -17,19 +17,22 @@#include <asm/opcodes.h> -struct kprobe ; -struct arch_specific_insn ; - -typedef u32 kprobe_opcode_t ; -typedef void (kprobes_handler_t ) (u32 opcode,long addr,struct pt_regs *); +typedef u32 probe_opcode_t ; +typedef void (probes_handler_t ) (u32 opcode,long addr,struct pt_regs *);/* architecture specific copy of original instruction */ -struct arch_specific_insn { -kprobe_opcode_t *insn; +struct arch_probe_insn { +probe_opcode_t *insn;pstate_check_t *pstate_cc; -kprobes_handler_t *handler; +probes_handler_t *handler;/* restore address after step xol */ unsigned long restore; }; +#ifdef CONFIG_KPROBES +typedef u32 kprobe_opcode_t ; +struct arch_specific_insn { +struct arch_probe_insn api; +}; +#endif #endif
arch/arm64/kernel/probes/decode-insn.c +16 -15
@@ -16,7 +16,6 @@#include <linux/kernel.h> #include <linux/kprobes.h> #include <linux/module.h> -#include <asm/kprobes.h> #include <asm/insn.h> #include <asm/sections.h>
@@ -77,8 +76,8 @@ static bool __kprobes aarch64_insn_is_steppable(u32 insn)* INSN_GOOD If instruction is supported and uses instruction slot, * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. */ -static enum kprobe_insn __kprobes -arm_probe_decode_insn (kprobe_opcode_t insn,struct arch_specific_insn *asi) +enum probe_insn __kprobes +arm_probe_decode_insn (probe_opcode_t insn,struct arch_probe_insn *api) {/* * Instructions reading or modifying the PC won't work from the XOL
@@ -88,26 +87,26 @@ arm_probe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)return INSN_GOOD ;if (aarch64_insn_is_bcond (insn)) { - asi->handler = simulate_b_cond; + api->handler = simulate_b_cond; }else if (aarch64_insn_is_cbz (insn) ||aarch64_insn_is_cbnz (insn)) { - asi->handler = simulate_cbz_cbnz; + api->handler = simulate_cbz_cbnz; }else if (aarch64_insn_is_tbz (insn) ||aarch64_insn_is_tbnz (insn)) { - asi->handler = simulate_tbz_tbnz; + api->handler = simulate_tbz_tbnz; }else if (aarch64_insn_is_adr_adrp (insn)) { - asi->handler = simulate_adr_adrp; + api->handler = simulate_adr_adrp; }else if (aarch64_insn_is_b (insn) ||aarch64_insn_is_bl (insn)) { - asi->handler = simulate_b_bl; + api->handler = simulate_b_bl; }else if (aarch64_insn_is_br (insn) ||aarch64_insn_is_blr (insn) ||aarch64_insn_is_ret (insn)) { - asi->handler = simulate_br_blr_ret; + api->handler = simulate_br_blr_ret; }else if (aarch64_insn_is_ldr_lit (insn)) { - asi->handler = simulate_ldr_literal; + api->handler = simulate_ldr_literal; }else if (aarch64_insn_is_ldrsw_lit (insn)) { - asi->handler = simulate_ldrsw_literal; + api->handler = simulate_ldrsw_literal; }else {/* * Instruction cannot be stepped out-of-line and we don't
@@ -119,6 +118,7 @@ arm_probe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)return INSN_GOOD_NO_SLOT ; } +#ifdef CONFIG_KPROBES static bool __kprobes is_probed_address_atomic (kprobe_opcode_t *scan_start,kprobe_opcode_t *scan_end) {
@@ -137,11 +137,11 @@ is_probed_address_atomic(kprobe_opcode_t *scan_start, kprobe_opcode_t *scan_end)return false; } -enum kprobe_insn __kprobes +enum probe_insn __kprobes arm_kprobe_decode_insn (kprobe_opcode_t *addr,struct arch_specific_insn *asi) { -enum kprobe_insn decoded; -kprobe_opcode_t insn =le32_to_cpu (*addr); +enum probe_insn decoded; +probe_opcode_t insn =le32_to_cpu (*addr);kprobe_opcode_t *scan_start = addr -1 ;kprobe_opcode_t *scan_end = addr -MAX_ATOMIC_CONTEXT_SIZE ;#if defined(CONFIG_MODULES ) && defined(MODULES_VADDR )
@@ -164,7 +164,7 @@ arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi) preempt_enable(); }#endif - decoded =arm_probe_decode_insn (insn, asi); + decoded =arm_probe_decode_insn (insn, &asi->api);if (decoded ==INSN_REJECTED ||is_probed_address_atomic (scan_start, scan_end))
@@ -172,3 +172,4 @@ arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi) return decoded; } +#endif
arch/arm64/kernel/probes/decode-insn.h +6 -2
@@ -23,13 +23,17 @@*/ #define MAX_ATOMIC_CONTEXT_SIZE (128 / sizeof(kprobe_opcode_t)) -enum kprobe_insn { +enum probe_insn {INSN_REJECTED ,INSN_GOOD_NO_SLOT ,INSN_GOOD , }; -enum kprobe_insn __kprobes +#ifdef CONFIG_KPROBES +enum probe_insn __kprobes arm_kprobe_decode_insn (kprobe_opcode_t *addr,struct arch_specific_insn *asi); +#endif +enum probe_insn __kprobes +arm_probe_decode_insn (probe_opcode_t insn,struct arch_probe_insn *asi);#endif /* _ARM_KERNEL_KPROBES_ARM64_H */
arch/arm64/kernel/probes/kprobes.c +18 -18
@@ -56,31 +56,31 @@ static inline unsigned long min_stack_size(unsigned long addr)static void __kprobes arch_prepare_ss_slot (struct kprobe *p) {/* prepare insn slot */ - p->ainsn.insn[0 ] =cpu_to_le32 (p->opcode); + p->ainsn.api.insn[0 ] =cpu_to_le32 (p->opcode); -flush_icache_range ((uintptr_t ) (p->ainsn.insn), - (uintptr_t ) (p->ainsn.insn) + +flush_icache_range ((uintptr_t ) (p->ainsn.api.insn), + (uintptr_t ) (p->ainsn.api.insn) +MAX_INSN_SIZE *sizeof (kprobe_opcode_t));/* * Needs restoring of return address after stepping xol. */ - p->ainsn.restore = (unsigned long ) p->addr + + p->ainsn.api.restore = (unsigned long ) p->addr +sizeof (kprobe_opcode_t); }static void __kprobes arch_prepare_simulate (struct kprobe *p) {/* This instructions is not executed xol. No need to adjust the PC */ - p->ainsn.restore =0 ; + p->ainsn.api.restore =0 ; }static void __kprobes arch_simulate_insn (struct kprobe *p,struct pt_regs *regs) {struct kprobe_ctlblk *kcb =get_kprobe_ctlblk (); -if (p->ainsn.handler) - p->ainsn.handler ((u32 )p->opcode, (long )p->addr, regs); +if (p->ainsn.api.handler) + p->ainsn.api.handler ((u32 )p->opcode, (long )p->addr, regs);/* single step simulated, now go for post processing */ post_kprobe_handler (kcb, regs);
@@ -110,18 +110,18 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)return -EINVAL ;case INSN_GOOD_NO_SLOT :/* insn need simulation */ - p->ainsn.insn =NULL ; + p->ainsn.api.insn =NULL ;break ;case INSN_GOOD :/* instruction uses slot */ - p->ainsn.insn =get_insn_slot (); -if (!p->ainsn.insn) + p->ainsn.api.insn =get_insn_slot (); +if (!p->ainsn.api.insn)return -ENOMEM ;break ; };/* prepare the instruction */ -if (p->ainsn.insn) +if (p->ainsn.api.insn)arch_prepare_ss_slot (p);else arch_prepare_simulate (p);
@@ -154,9 +154,9 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p)void __kprobes arch_remove_kprobe (struct kprobe *p) { -if (p->ainsn.insn) { -free_insn_slot (p->ainsn.insn,0 ); - p->ainsn.insn =NULL ; +if (p->ainsn.api.insn) { +free_insn_slot (p->ainsn.api.insn,0 ); + p->ainsn.api.insn =NULL ; } }
@@ -251,9 +251,9 @@ static void __kprobes setup_singlestep(struct kprobe *p, } -if (p->ainsn.insn) { +if (p->ainsn.api.insn) {/* prepare for single stepping */ - slot = (unsigned long )p->ainsn.insn; + slot = (unsigned long )p->ainsn.api.insn;set_ss_context (kcb, slot);/* mark pending ss */
@@ -305,8 +305,8 @@ post_kprobe_handler(struct kprobe_ctlblk *kcb, struct pt_regs *regs)return ;/* return addr restore if non-branching insn */ -if (cur->ainsn.restore !=0 ) -instruction_pointer_set (regs, cur->ainsn.restore); +if (cur->ainsn.api.restore !=0 ) +instruction_pointer_set (regs, cur->ainsn.api.restore);/* restore back original saved kprobe variables and continue */ if (kcb->kprobe_status ==KPROBE_REENTER ) {
Signature · 1 line
2.5.5
PATCH 2/5 arm64: kgdb_step_brk_fn: ignore other's exception
In reply to Pratyush AnandARM64 step exception does not have any syndrome information. So, it is responsibility of exception handler to take care that they handle it only if exception was raised for them.
Since kgdb_step_brk_fn() always returns 0, therefore we might have problem when we will have other step handler registered as well.
This patch fixes kgdb_step_brk_fn() to return error in case of step handler was not meant for kgdb.
--- arch/arm64/kernel/kgdb.c | 3 +++ 1 file changed, 3 insertions(+)
arch/arm64/kernel/kgdb.c +3 -0
@@ -244,6 +244,9 @@ NOKPROBE_SYMBOL(kgdb_compiled_brk_fn);static int kgdb_step_brk_fn (struct pt_regs *regs,unsigned int esr) { +if (!kgdb_single_step) +return DBG_HOOK_ERROR ; +kgdb_handle_exception (1 ,SIGTRAP ,0 , regs);return 0 ; }
Signature · 1 line
2.5.5
PATCH 3/5 arm64: Handle TRAP_HWBRKPT for user mode as well
In reply to Pratyush Ananduprobe registers a handler at step_hook. So, single_step_handler now checks for user mode as well if there is a valid hook.
--- arch/arm64/kernel/debug-monitors.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-)
arch/arm64/kernel/debug-monitors.c +12 -10
@@ -246,6 +246,8 @@ static void send_user_sigtrap(int si_code)static int single_step_handler (unsigned long addr,unsigned int esr,struct pt_regs *regs) { +bool handler_found = false; +/* * If we are stepping a pending breakpoint, call the hw_breakpoint * handler first.
@@ -253,7 +255,14 @@ static int single_step_handler(unsigned long addr, unsigned int esr,if (!reinstall_suspended_bps (regs))return 0 ; -if (user_mode (regs)) { +#ifdef CONFIG_KPROBES +if (kprobe_single_step_handler (regs, esr) ==DBG_HOOK_HANDLED ) + handler_found = true; +#endif +if (!handler_found &&call_step_hook (regs, esr) ==DBG_HOOK_HANDLED ) + handler_found = true; + +if (!handler_found &&user_mode (regs)) {send_user_sigtrap (TRAP_HWBKPT );/*
@@ -263,15 +272,8 @@ static int single_step_handler(unsigned long addr, unsigned int esr,* to the active-not-pending state). */ user_rewind_single_step (current); - }else { -#ifdef CONFIG_KPROBES -if (kprobe_single_step_handler (regs, esr) ==DBG_HOOK_HANDLED ) -return 0 ; -#endif -if (call_step_hook (regs, esr) ==DBG_HOOK_HANDLED ) -return 0 ; - -pr_warning ("Unexpected kernel single-step exception at EL1\n" ); + }else if (!handler_found) { +pr_warn ("Unexpected kernel single-step exception at EL1\n" );/* * Re-enable stepping since we know that we will be * returning to regs.
Signature · 1 line
2.5.5
Catalin Marinas
maintainerRe: [PATCH 3/5] arm64: Handle TRAP_HWBRKPT for user mode as well
Quoted 15 lines · Pratyush Anand
arch/arm64/kernel/debug-monitors.c +2
-0@@ -246,6 +246,8 @@ static void send_user_sigtrap(int si_code)static int single_step_handler (unsigned long addr,unsigned int esr,struct pt_regs *regs) { +bool handler_found = false; +/* * If we are stepping a pending breakpoint, call the hw_breakpoint * handler first. @@ -253,7 +255,14 @@ static int single_step_handler(unsigned long addr, unsigned int esr,if (!reinstall_suspended_bps (regs))return 0 ;
arch/arm64/kernel/debug-monitors.c static int single_step_handler(unsigned long addr, unsigned int esr, · line 266
Quoted 10 lines
arch/arm64/kernel/debug-monitors.c +8
-1-if (user_mode (regs)) { +#ifdef CONFIG_KPROBES +if (kprobe_single_step_handler (regs, esr) ==DBG_HOOK_HANDLED ) + handler_found = true; +#endif +if (!handler_found &&call_step_hook (regs, esr) ==DBG_HOOK_HANDLED ) + handler_found = true; + +if (!handler_found &&user_mode (regs)) {send_user_sigtrap (TRAP_HWBKPT );
Could we register kprobe_single_step_handler() via register_set_hook() and only invoke call_step_hook() above?
Signature · 1 line
Catalin
Re: [PATCH 3/5] arm64: Handle TRAP_HWBRKPT for user mode as well
Quoted 16 lines · Catalin Marinas
Quoted 15 lines · Pratyush Anand
arch/arm64/kernel/debug-monitors.c +2
-0@@ -246,6 +246,8 @@ static void send_user_sigtrap(int si_code)static int single_step_handler (unsigned long addr,unsigned int esr,struct pt_regs *regs) { +bool handler_found = false; +/* * If we are stepping a pending breakpoint, call the hw_breakpoint * handler first. @@ -253,7 +255,14 @@ static int single_step_handler(unsigned long addr, unsigned int esr,if (!reinstall_suspended_bps (regs))return 0 ;
Quoted 14 lines
arch/arm64/kernel/debug-monitors.c static int single_step_handler(unsigned long addr, unsigned int esr, · line 266
Quoted 10 lines
arch/arm64/kernel/debug-monitors.c +8
-1-if (user_mode (regs)) { +#ifdef CONFIG_KPROBES +if (kprobe_single_step_handler (regs, esr) ==DBG_HOOK_HANDLED ) + handler_found = true; +#endif +if (!handler_found &&call_step_hook (regs, esr) ==DBG_HOOK_HANDLED ) + handler_found = true; + +if (!handler_found &&user_mode (regs)) {send_user_sigtrap (TRAP_HWBKPT );Could we register
kprobe_single_step_handler()viaregister_set_hook()and only invokecall_step_hook()above?
I seem to recall a criticism of doing that in a much earlier kprobes64 patch of mine. The concern was that it would cause unnecessarily more kernel functions to be kprobes-blacklisted. Hence the hardcoded check and call.
-dl
Re: [PATCH 3/5] arm64: Handle TRAP_HWBRKPT for user mode as well
Quoted 32 lines · David Long
Quoted 16 lines · Catalin Marinas
Quoted 15 lines · Pratyush Anand
arch/arm64/kernel/debug-monitors.c +2
-0@@ -246,6 +246,8 @@ static void send_user_sigtrap(int si_code)static int single_step_handler (unsigned long addr,unsigned int esr,struct pt_regs *regs) { +bool handler_found = false; +/* * If we are stepping a pending breakpoint, call the hw_breakpoint * handler first. @@ -253,7 +255,14 @@ static int single_step_handler(unsigned long addr, unsigned int esr,if (!reinstall_suspended_bps (regs))return 0 ;Quoted 14 lines
arch/arm64/kernel/debug-monitors.c static int single_step_handler(unsigned long addr, unsigned int esr, · line 266
Quoted 10 lines
arch/arm64/kernel/debug-monitors.c +8
-1-if (user_mode (regs)) { +#ifdef CONFIG_KPROBES +if (kprobe_single_step_handler (regs, esr) ==DBG_HOOK_HANDLED ) + handler_found = true; +#endif +if (!handler_found &&call_step_hook (regs, esr) ==DBG_HOOK_HANDLED ) + handler_found = true; + +if (!handler_found &&user_mode (regs)) {send_user_sigtrap (TRAP_HWBKPT );Could we register
kprobe_single_step_handler()viaregister_set_hook()and only invokecall_step_hook()above?
Quoted 3 lines
I seem to recall a criticism of doing that in a much earlier kprobes64 patch of mine. The concern was that it would cause unnecessarily more kernel functions to be kprobes-blacklisted. Hence the hardcoded check and call.
Yes, all the code regions are kprobe unsafe which lie within the moment we receive a break/single step exception to the point where it is handled for kprobe. Therefore we must call kprobe_single_step/breakpoint_handler() before other handlers. Otherwise, we would not be able to trace other handlers and the functions called from those handlers.
~Pratyush
Catalin Marinas
maintainerRe: [PATCH 3/5] arm64: Handle TRAP_HWBRKPT for user mode as well
In reply to David LongQuoted 31 lines · David Long
Quoted 16 lines · Catalin Marinas
Quoted 15 lines · Pratyush Anand
arch/arm64/kernel/debug-monitors.c +2
-0@@ -246,6 +246,8 @@ static void send_user_sigtrap(int si_code)static int single_step_handler (unsigned long addr,unsigned int esr,struct pt_regs *regs) { +bool handler_found = false; +/* * If we are stepping a pending breakpoint, call the hw_breakpoint * handler first. @@ -253,7 +255,14 @@ static int single_step_handler(unsigned long addr, unsigned int esr,if (!reinstall_suspended_bps (regs))return 0 ;Quoted 13 lines
arch/arm64/kernel/debug-monitors.c static int single_step_handler(unsigned long addr, unsigned int esr, · line 266
Quoted 10 lines
arch/arm64/kernel/debug-monitors.c +8
-1-if (user_mode (regs)) { +#ifdef CONFIG_KPROBES +if (kprobe_single_step_handler (regs, esr) ==DBG_HOOK_HANDLED ) + handler_found = true; +#endif +if (!handler_found &&call_step_hook (regs, esr) ==DBG_HOOK_HANDLED ) + handler_found = true; + +if (!handler_found &&user_mode (regs)) {send_user_sigtrap (TRAP_HWBKPT );Could we register
kprobe_single_step_handler()viaregister_set_hook()and only invokecall_step_hook()above?
Quoted 3 lines
I seem to recall a criticism of doing that in a much earlier kprobes64 patch of mine. The concern was that it would cause unnecessarily more kernel functions to be kprobes-blacklisted. Hence the hardcoded check and call.
Ah, ok. I missed this aspect.
Signature · 1 line
Catalin
PATCH 4/5 arm64: Handle TRAP_BRKPT for user mode as well
In reply to Pratyush Ananduprobe is registered at break_hook with a unique ESR code. So, when a TRAP_BRKPT occurs, call_break_hook checks if it was for uprobe. If not, then send a SIGTRAP to user.
--- arch/arm64/kernel/debug-monitors.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-)
arch/arm64/kernel/debug-monitors.c +11 -7
@@ -326,16 +326,20 @@ NOKPROBE_SYMBOL(call_break_hook);static int brk_handler (unsigned long addr,unsigned int esr,struct pt_regs *regs) { -if (user_mode (regs)) { -send_user_sigtrap (TRAP_BRKPT ); - } +bool handler_found = false; +#ifdef CONFIG_KPROBES - else if ((esr & BRK64_ESR_MASK) == BRK64_ESR_KPROBES) { -if (kprobe_breakpoint_handler (regs, esr) !=DBG_HOOK_HANDLED ) -return -EFAULT ; +if ((esr &BRK64_ESR_MASK ) ==BRK64_ESR_KPROBES ) { +if (kprobe_breakpoint_handler (regs, esr) ==DBG_HOOK_HANDLED ) + handler_found = true; }#endif - else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) { +if (!handler_found &&call_break_hook (regs, esr) ==DBG_HOOK_HANDLED ) + handler_found = true; + +if (!handler_found &&user_mode (regs)) { +send_user_sigtrap (TRAP_BRKPT ); + }else if (!handler_found) {pr_warn ("Unexpected kernel BRK exception at EL1\n" );return -EFAULT ; }
Signature · 1 line
2.5.5
Catalin Marinas
maintainerRe: [PATCH 4/5] arm64: Handle TRAP_BRKPT for user mode as well
Quoted 20 lines · Pratyush Anand
arch/arm64/kernel/debug-monitors.c +5
-6@@ -326,16 +326,20 @@ NOKPROBE_SYMBOL(call_break_hook);static int brk_handler (unsigned long addr,unsigned int esr,struct pt_regs *regs) { -if (user_mode (regs)) { -send_user_sigtrap (TRAP_BRKPT ); - } +bool handler_found = false; +#ifdef CONFIG_KPROBES - else if ((esr & BRK64_ESR_MASK) == BRK64_ESR_KPROBES) { -if (kprobe_breakpoint_handler (regs, esr) !=DBG_HOOK_HANDLED ) -return -EFAULT ; +if ((esr &BRK64_ESR_MASK ) ==BRK64_ESR_KPROBES ) { +if (kprobe_breakpoint_handler (regs, esr) ==DBG_HOOK_HANDLED ) + handler_found = true; }#endif
arch/arm64/kernel/debug-monitors.c NOKPROBE_SYMBOL(call_break_hook); · line 345
Quoted 10 lines
arch/arm64/kernel/debug-monitors.c +6
-1-else if (call_break_hook (regs, esr) !=DBG_HOOK_HANDLED ) { +if (!handler_found &&call_break_hook (regs, esr) ==DBG_HOOK_HANDLED ) + handler_found = true; + +if (!handler_found &&user_mode (regs)) { +send_user_sigtrap (TRAP_BRKPT ); + }else if (!handler_found) {pr_warn ("Unexpected kernel BRK exception at EL1\n" );return -EFAULT ; }
I think we could do the same here with a single call_break_hook() and making sure that the corresponding handlers check the esr for the corresponding BRK encoding.
Signature · 1 line
Catalin
PATCH 5/5 arm64: Add uprobe support
In reply to Pratyush AnandThis patch adds support for uprobe on ARM64 architecture.
Unit test for following has been done so far and they have been found working
1. Step-able instructions, like sub, ldr, add etc.
2. Simulation-able like ret, cbnz, cbz etc.
3. uretprobe
4. Reject-able instructions like sev, wfe etc.
5. trapped and abort xol path
6. probe at unaligned user address.
7. longjump test cases
Currently it does not support aarch32 instruction probing.
Thanks to Shi Yang <yang.shi at linaro.org, for suggesting to define TIF_UPROBE as 5 in stead of 4, since 4 has already been used in -rt kernel.
--- arch/arm64/Kconfig | 3 + arch/arm64/include/asm/debug-monitors.h | 3 + arch/arm64/include/asm/probes.h | 4 + arch/arm64/include/asm/ptrace.h | 8 ++ arch/arm64/include/asm/thread_info.h | 5 +- arch/arm64/include/asm/uprobes.h | 37 ++++++ arch/arm64/kernel/entry.S | 6 +- arch/arm64/kernel/probes/Makefile | 2 + arch/arm64/kernel/probes/uprobes.c | 227 ++++++++++++++++++++++++++++++++ arch/arm64/kernel/signal.c | 4 +- arch/arm64/mm/flush.c | 6 + 11 files changed, 301 insertions(+), 4 deletions(-) create mode 100644 arch/arm64/include/asm/uprobes.h create mode 100644 arch/arm64/kernel/probes/uprobes.c
arch/arm64/Kconfig +3 -0
@@ -232,6 +232,9 @@ config PGTABLE_LEVELS default 3 if ARM64_16K_PAGES && ARM64_VA_BITS_47 default 4 if !ARM64_64K_PAGES && ARM64_VA_BITS_48 +config ARCH_SUPPORTS_UPROBES + def_bool y + source "init/Kconfig" source "kernel/Kconfig.freezer"
arch/arm64/include/asm/debug-monitors.h +3 -0
@@ -70,6 +70,9 @@#define BRK64_ESR_MASK 0xFFFF#define BRK64_ESR_KPROBES 0x0004#define BRK64_OPCODE_KPROBES (AARCH64_BREAK_MON | (BRK64_ESR_KPROBES << 5)) +/* uprobes BRK opcodes with ESR encoding */ +#define BRK64_ESR_UPROBES 0x0008 +#define BRK64_OPCODE_UPROBES (AARCH64_BREAK_MON | (BRK64_ESR_UPROBES << 5))/* AArch32 */ #define DBG_ESR_EVT_BKPT 0x4
arch/arm64/include/asm/probes.h +4 -0
@@ -35,4 +35,8 @@ struct arch_specific_insn { };#endif +#ifdef CONFIG_UPROBES +typedef u32 uprobe_opcode_t ; +#endif +#endif
arch/arm64/include/asm/ptrace.h +8 -0
@@ -217,6 +217,14 @@ int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task);#include <asm-generic/ptrace.h> +#define procedure_link_pointer (regs) ((regs)->regs[30]) + +static inline void procedure_link_pointer_set (struct pt_regs *regs, +unsigned long val) +{ +procedure_link_pointer (regs) = val; +} +#undef profile_pcextern unsigned long profile_pc (struct pt_regs *regs);
arch/arm64/include/asm/thread_info.h +4 -1
@@ -109,6 +109,7 @@ static inline struct thread_info *current_thread_info(void)#define TIF_NEED_RESCHED 1#define TIF_NOTIFY_RESUME 2/* callback before returning to user */ #define TIF_FOREIGN_FPSTATE 3/* CPU's FP state is not current's */ +#define TIF_UPROBE 5/* uprobe breakpoint or singlestep */ #define TIF_NOHZ 7#define TIF_SYSCALL_TRACE 8#define TIF_SYSCALL_AUDIT 9
@@ -129,10 +130,12 @@ static inline struct thread_info *current_thread_info(void)#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)#define _TIF_SECCOMP (1 << TIF_SECCOMP) +#define _TIF_UPROBE (1 << TIF_UPROBE)#define _TIF_32BIT (1 << TIF_32BIT)#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ - _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE) + _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \ + _TIF_UPROBE)#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
arch/arm64/include/asm/uprobes.h new file +37 -0
@@ -0,0 +1,37 @@ +/* +* Copyright (C) 2014-2015 Pratyush Anand <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#ifndef _ASM_UPROBES_H +#define _ASM_UPROBES_H + +#include <asm/debug-monitors.h> +#include <asm/insn.h> +#include <asm/probes.h> + +#define MAX_UINSN_BYTES AARCH64_INSN_SIZE + +#define UPROBE_SWBP_INSN BRK64_OPCODE_UPROBES +#define UPROBE_SWBP_INSN_SIZE 4 +#define UPROBE_XOL_SLOT_BYTES MAX_UINSN_BYTES + +struct arch_uprobe_task { +unsigned long saved_fault_code; +}; + +struct arch_uprobe { +union { +u8 insn[MAX_UINSN_BYTES ]; +u8 ixol[MAX_UINSN_BYTES ]; + }; +struct arch_probe_insn api; +bool simulate; +}; + +extern void flush_uprobe_xol_access (struct page *page,unsigned long uaddr, +void *kaddr,unsigned long len); +#endif
arch/arm64/kernel/entry.S +4 -2
@@ -688,7 +688,8 @@ ret_fast_syscall: ldr x1, [tsk, #TI_FLAGS] // re-check for syscall tracing and x2, x1, #_TIF_SYSCALL_WORK cbnz x2, ret_fast_syscall_trace - and x2, x1, #_TIF_WORK_MASK + mov x2, #_TIF_WORK_MASK + and x2, x1, x2 cbnz x2, work_pending enable_step_tsk x1, x2 kernel_exit 0
@@ -718,7 +719,8 @@ work_resched: ret_to_user: disable_irq // disable interrupts ldr x1, [tsk, #TI_FLAGS] - and x2, x1, #_TIF_WORK_MASK + mov x2, #_TIF_WORK_MASK + and x2, x1, x2 cbnz x2, work_pending enable_step_tsk x1, x2 kernel_exit 0
arch/arm64/kernel/probes/Makefile +2 -0
@@ -1,3 +1,5 @@ obj-$(CONFIG_KPROBES) += kprobes.o decode-insn.o \ kprobes_trampoline.o \ simulate-insn.o +obj-$(CONFIG_UPROBES) += uprobes.o decode-insn.o \ + simulate-insn.o
arch/arm64/kernel/probes/uprobes.c new file +227 -0
227 lines not on this page · raw message
arch/arm64/kernel/signal.c +3 -1
@@ -402,6 +402,9 @@ static void do_signal(struct pt_regs *regs) asmlinkage void do_notify_resume(struct pt_regs *regs,unsigned int thread_flags) { +if (thread_flags & _TIF_UPROBE) +uprobe_notify_resume (regs); +if (thread_flags & _TIF_SIGPENDING)do_signal (regs);
@@ -412,5 +415,4 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,if (thread_flags & _TIF_FOREIGN_FPSTATE)fpsimd_restore_current_state (); - }
arch/arm64/mm/flush.c +6 -0
@@ -54,6 +54,12 @@ static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,sync_icache_aliases (kaddr, len); } +void flush_uprobe_xol_access (struct page *page,unsigned long uaddr, +void *kaddr,unsigned long len) +{ +sync_icache_aliases (kaddr, len); +} +/* * Copy user data from/to a page which is mapped into a different processes * address space. Really, we want to allow our "user space" model to handle
Signature · 1 line
2.5.5
Oleg Nesterov
maintainerRe: [PATCH 5/5] arm64: Add uprobe support
Quoted 2 lines · Pratyush Anand
This patch adds support for uprobe on ARM64 architecture.
I know nothing about ARM, so I can't actually review this change. But it looks good to me ;)
Just one note,
Quoted 4 lines
arch/arm64/kernel/probes/uprobes.c new file +4
-0+int arch_uprobe_pre_xol (struct arch_uprobe *auprobe,struct pt_regs *regs) +{ +struct uprobe_task *utask = current->utask; +
arch/arm64/kernel/probes/uprobes.c line 81
Quoted 10 lines
arch/arm64/kernel/probes/uprobes.c new file +10
-0+/* saved fault code is restored in post_xol */ + utask->autask.saved_fault_code = current->thread.fault_code; + +/* An invalid fault code between pre/post xol event */ + current->thread.fault_code =UPROBE_INV_FAULT_CODE ; + +/* Instruction point to execute ol */ +instruction_pointer_set (regs, utask->xol_vaddr); + +user_enable_single_step (current);
I don't think we want user_{enable,disable{_single_step in the long term, please look at 9bd1190a11c9d2 "uprobes/x86: Do not (ab)use TIF_SINGLESTEP /user_*_single_step() for single-stepping". it seems that ARM64 sets/clears TIF_SINGLESTEP. You can also lool at saved_tf logic, probably ARM64 needs the same.
However, I agree we can do this later and initial version can use these ptrace helpers.
Oleg.
Re: [PATCH 5/5] arm64: Add uprobe support
Hi Oleg,
Thanks a lot for your review, and sorry for delayed response.
Quoted 21 lines · Oleg Nesterov
Quoted 2 lines · Pratyush Anand
This patch adds support for uprobe on ARM64 architecture.
I know nothing about ARM, so I can't actually review this change. But it looks good to me ;)
Just one note,
Quoted 12 lines
arch/arm64/kernel/probes/uprobes.c new file +12
-0+int arch_uprobe_pre_xol (struct arch_uprobe *auprobe,struct pt_regs *regs) +{ +struct uprobe_task *utask = current->utask; + +/* saved fault code is restored in post_xol */ + utask->autask.saved_fault_code = current->thread.fault_code; + +/* An invalid fault code between pre/post xol event */ + current->thread.fault_code =UPROBE_INV_FAULT_CODE ; + +/* Instruction point to execute ol */ +instruction_pointer_set (regs, utask->xol_vaddr);
Quoted 8 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ + user_enable_single_step(current);I don't think we want user_{enable,disable{_single_step in the long term, please look at
9bd1190a11c9d2"uprobes/x86: Do not (ab)useTIF_SINGLESTEP/user_*_single_step() for single-stepping". it seems that ARM64 sets/clearsTIF_SINGLESTEP. You can also lool atsaved_tflogic, probably ARM64 needs the same.
IIUC, then you mean that TIF_SINGLESTEP is a per task flag, while arch_uprobe_pre/post_xol() should enable/disable single stepping using a per uprobe_task, and we should have a flag in "struct arch_uprobe_task" to handle this, right?
Quoted 3 lines
However, I agree we can do this later and initial version can use these ptrace helpers.
Yes, I would also like to do that change latter, because these set of patches have already been tested heavily with systemtap, so it would be better to go with an incremental changes latter on.
~Pratyush
Oleg Nesterov
maintainerRe: [PATCH 5/5] arm64: Add uprobe support
Hi Pratyush,
Quoted 8 lines · Pratyush Anand
Quoted 6 lines
I don't think we want user_{enable,disable{_single_step in the long term, please look at
9bd1190a11c9d2"uprobes/x86: Do not (ab)useTIF_SINGLESTEP/user_*_single_step() for single-stepping". it seems that ARM64 sets/clearsTIF_SINGLESTEP. You can also lool atsaved_tflogic, probably ARM64 needs the same.IIUC, then you mean that
TIF_SINGLESTEPis a per task flag,
Yes, and nobody but ptrace should use it, otherwise ptrace/uprobes can confuse each other. And uprobes simply doesn't need to set/clear it.
Quoted 3 lines
while
arch_uprobe_pre/post_xol() should enable/disable single stepping using a peruprobe_task,
I can't really answer since I know nothing about arm. x86 just needs to set X86_EFLAGS_TF, I guess arm needs to modify some register too?
Quoted 2 lines
and we should have a flag in "struct
arch_uprobe_task" to handle this, right?
Probably yes, because we need to record/restore X86_EFLAGS_TF in case it was already set by ptrace or something else.
Quoted 6 lines
Quoted 2 lines
However, I agree we can do this later and initial version can use these ptrace helpers.
Yes, I would also like to do that change latter, because these set of patches have already been tested heavily with systemtap, so it would be better to go with an incremental changes latter on.
Yes, yes, I agree. Let me repeat that this patch looks good to me as initial version, but obviously I can't really revit it and/or ack.
Oleg.
Re: [PATCH 5/5] arm64: Add uprobe support
Quoted 8 lines · Oleg Nesterov
Quoted 7 lines · Pratyush Anand
Quoted 6 lines
I don't think we want user_{enable,disable{_single_step in the long term, please look at
9bd1190a11c9d2"uprobes/x86: Do not (ab)useTIF_SINGLESTEP/user_*_single_step() for single-stepping". it seems that ARM64 sets/clearsTIF_SINGLESTEP. You can also lool atsaved_tflogic, probably ARM64 needs the same.
Quoted 4 lines
Quoted 1 line
IIUC, then you mean that
TIF_SINGLESTEPis a per task flag,Yes, and nobody but ptrace should use it, otherwise ptrace/uprobes can confuse each other. And uprobes simply doesn't need to set/clear it.
We're already using it for kprobes, hw_breakpoint and kgdb as well as ptrace, so I'd rather uprobes either followed existing practice, or we converted everybody off the current code.
In what way do things get confused?
Quoted 6 lines
Quoted 3 lines
while
arch_uprobe_pre/post_xol() should enable/disable single stepping using a peruprobe_task,I can't really answer since I know nothing about arm. x86 just needs to set
X86_EFLAGS_TF, I guess arm needs to modify some register too?
We have {user,kernel}_{enable,disable}_single_step for managing the various registers controlling the single-step state machine on arm64.
Will
Oleg Nesterov
maintainerRe: [PATCH 5/5] arm64: Add uprobe support
Quoted 10 lines · Will Deacon
Quoted 8 lines · Oleg Nesterov
Quoted 7 lines · Pratyush Anand
Quoted 6 lines
I don't think we want user_{enable,disable{_single_step in the long term, please look at
9bd1190a11c9d2"uprobes/x86: Do not (ab)useTIF_SINGLESTEP/user_*_single_step() for single-stepping". it seems that ARM64 sets/clearsTIF_SINGLESTEP. You can also lool atsaved_tflogic, probably ARM64 needs the same.
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
IIUC, then you mean that
TIF_SINGLESTEPis a per task flag,Yes, and nobody but ptrace should use it, otherwise ptrace/uprobes can confuse each other. And uprobes simply doesn't need to set/clear it.
We're already using it for kprobes,
hw_breakpointand kgdb as well as ptrace, so I'd rather uprobes either followed existing practice, or we converted everybody off the current code.
And perhaps this is fine for arm64, I do not know.
Quoted 1 line
In what way do things get confused?
Say, arch_uprobe_post_xol() should not blindly do user_disable_single_step(), this can confuse ptrace if TIF_SINGLESTEP was set by debugger which wants to step over the probed insn.
Quoted 5 lines
Quoted 2 lines
I can't really answer since I know nothing about arm. x86 just needs to set
X86_EFLAGS_TF, I guess arm needs to modify some register too?We have {user,kernel}_{enable,disable}_single_step for managing the various registers controlling the single-step state machine on arm64.
Yes, and perhaps uprobes can just do set_regs_spsr_ss() ? I never looked into arch/arm64/, but it seems that we only need to ensure that call_step_hook() will be called even if user_mode() == T, why do we need TIF_SINGLESTEP ?
Nevermind. I can be easily wrong and let me repeat that I agree with user_{enable,disable}_single_step in the initial version in any case.
Oleg.
Catalin Marinas
maintainerRe: [PATCH 5/5] arm64: Add uprobe support
In reply to Pratyush AnandHi Pratyush,
arch/arm64/include/asm/debug-monitors.h line 75
Quoted 9 lines · Pratyush Anand
arch/arm64/include/asm/debug-monitors.h +3
-0@@ -70,6 +70,9 @@#define BRK64_ESR_MASK 0xFFFF#define BRK64_ESR_KPROBES 0x0004#define BRK64_OPCODE_KPROBES (AARCH64_BREAK_MON | (BRK64_ESR_KPROBES << 5)) +/* uprobes BRK opcodes with ESR encoding */ +#define BRK64_ESR_UPROBES 0x0008 +#define BRK64_OPCODE_UPROBES (AARCH64_BREAK_MON | (BRK64_ESR_UPROBES << 5))
You can use 0x0005 as immediate, we don't need individual bits here.
arch/arm64/include/asm/probes.h struct arch_specific_insn { · line 40
Quoted 9 lines
arch/arm64/include/asm/probes.h +3
-0@@ -35,4 +35,8 @@ struct arch_specific_insn { };#endif +#ifdef CONFIG_UPROBES +typedef u32 uprobe_opcode_t ; +#endif
We don't need #ifdef around this typedef. Also, all the other architectures seem to have this typedef in asm/uprobes.h.
arch/arm64/include/asm/ptrace.h int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task); · line 226
Quoted 13 lines
arch/arm64/include/asm/ptrace.h +7
-0@@ -217,6 +217,14 @@ int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task);#include <asm-generic/ptrace.h> +#define procedure_link_pointer (regs) ((regs)->regs[30]) + +static inline void procedure_link_pointer_set (struct pt_regs *regs, +unsigned long val) +{ +procedure_link_pointer (regs) = val; +}
Do you need these macro and function here? It seems that they are only used in arch_uretprobe_hijack_return_addr(), so you can just expand them in there, no need for additional definitions.
arch/arm64/include/asm/thread_info.h static inline struct thread_info *current_thread_info(void) · line 112
Quoted 7 lines
arch/arm64/include/asm/thread_info.h +1
-0@@ -109,6 +109,7 @@ static inline struct thread_info *current_thread_info(void)#define TIF_NEED_RESCHED 1#define TIF_NOTIFY_RESUME 2/* callback before returning to user */ #define TIF_FOREIGN_FPSTATE 3/* CPU's FP state is not current's */ +#define TIF_UPROBE 5/* uprobe breakpoint or singlestep */
Nitpick: you can just use 4 until we cover this gap.
Quoted 12 lines
arch/arm64/include/asm/uprobes.h new file +9
-0@@ -0,0 +1,37 @@ +/* +* Copyright (C) 2014-2015 Pratyush Anand <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#ifndef _ASM_UPROBES_H
arch/arm64/include/asm/uprobes.h line 19
Quoted 10 lines
arch/arm64/include/asm/uprobes.h new file +10
-0+#define _ASM_UPROBES_H + +#include <asm/debug-monitors.h> +#include <asm/insn.h> +#include <asm/probes.h> + +#define MAX_UINSN_BYTES AARCH64_INSN_SIZE + +#define UPROBE_SWBP_INSN BRK64_OPCODE_UPROBES +#define UPROBE_SWBP_INSN_SIZE 4
Nitpick: for consistency, just use AARCH64_INSN_SIZE.
Quoted 7 lines
arch/arm64/include/asm/uprobes.h new file +7
-0+#define UPROBE_XOL_SLOT_BYTES MAX_UINSN_BYTES + +struct arch_uprobe_task { +unsigned long saved_fault_code; +}; + +struct arch_uprobe {
arch/arm64/include/asm/uprobes.h line 36
Quoted 10 lines
arch/arm64/include/asm/uprobes.h new file +10
-0+union { +u8 insn[MAX_UINSN_BYTES ]; +u8 ixol[MAX_UINSN_BYTES ]; + }; +struct arch_probe_insn api; +bool simulate; +}; + +extern void flush_uprobe_xol_access (struct page *page,unsigned long uaddr, +void *kaddr,unsigned long len);
I don't think we need this. It doesn't seem to be used anywhere other than the arm64 uprobes.c file. So I would rather expose sync_icache_aliases(), similarly to __sync_icache_dcache().
arch/arm64/kernel/entry.S ret_fast_syscall: · line 692
Quoted 9 lines
arch/arm64/kernel/entry.S +2
-1@@ -688,7 +688,8 @@ ret_fast_syscall: ldr x1, [tsk, #TI_FLAGS] // re-check for syscall tracing and x2, x1, #_TIF_SYSCALL_WORK cbnz x2, ret_fast_syscall_trace - and x2, x1, #_TIF_WORK_MASK + mov x2, #_TIF_WORK_MASK + and x2, x1, x2
Is this needed because _TIF_WORK_MASK cannot work as an immediate value to 'and'? We could reorder the TIF bits, they are not exposed to user to have ABI implications.
arch/arm64/kernel/entry.S work_resched: · line 726
Quoted 13 lines
arch/arm64/kernel/entry.S +2
-1cbnz x2, work_pending enable_step_tsk x1, x2 kernel_exit 0@@ -718,7 +719,8 @@ work_resched: ret_to_user: disable_irq // disable interrupts ldr x1, [tsk, #TI_FLAGS] - and x2, x1, #_TIF_WORK_MASK + mov x2, #_TIF_WORK_MASK + and x2, x1, x2 cbnz x2, work_pending enable_step_tsk x1, x2 kernel_exit 0
Same here.
Quoted 15 lines
arch/arm64/kernel/probes/uprobes.c new file +12
-0@@ -0,0 +1,227 @@ +/* +* Copyright (C) 2014-2015 Pratyush Anand <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ +#include <linux/highmem.h> +#include <linux/ptrace.h> +#include <linux/uprobes.h> + +#include "decode-insn.h"
arch/arm64/kernel/probes/uprobes.c line 22
Quoted 10 lines
arch/arm64/kernel/probes/uprobes.c new file +10
-0+ +#define UPROBE_INV_FAULT_CODE UINT_MAX + +void arch_uprobe_copy_ixol (struct page *page,unsigned long vaddr, +void *src,unsigned long len) +{ +void *xol_page_kaddr =kmap_atomic (page); +void *dst = xol_page_kaddr + (vaddr & ~PAGE_MASK ); + +preempt_disable ();
kmap_atomic() already disabled preemption.
arch/arm64/kernel/probes/uprobes.c line 28
Quoted 6 lines
arch/arm64/kernel/probes/uprobes.c new file +6
-0+ +/* Initialize the slot */ +memcpy (dst, src, len); + +/* flush caches (dcache/icache) */ +flush_uprobe_xol_access (page, vaddr, dst, len);
Just use sync_icache_aliases() here (once exposed in an arm64 header).
Quoted 7 lines
arch/arm64/kernel/probes/uprobes.c new file +7
-0+ +preempt_enable (); + +kunmap_atomic (xol_page_kaddr); +} + +unsigned long uprobe_get_swbp_addr (struct pt_regs *regs)
arch/arm64/kernel/probes/uprobes.c line 45
Quoted 10 lines
arch/arm64/kernel/probes/uprobes.c new file +10
-0+{ +return instruction_pointer (regs); +} + +int arch_uprobe_analyze_insn (struct arch_uprobe *auprobe,struct mm_struct *mm, +unsigned long addr) +{ +probe_opcode_t insn; + +/* TODO: Currently we do not support AARCH32 instruction probing */
Is there a way to check (not necessarily in this file) that we don't probe 32-bit tasks?
Quoted 6 lines
arch/arm64/kernel/probes/uprobes.c new file +6
-0+if (!IS_ALIGNED (addr,AARCH64_INSN_SIZE )) +return -EINVAL ; + + insn = *(probe_opcode_t *)(&auprobe->insn[0 ]); + +switch (arm_probe_decode_insn (insn, &auprobe->api)) {
arch/arm64/kernel/probes/uprobes.c line 62
Quoted 10 lines
arch/arm64/kernel/probes/uprobes.c new file +10
-0+case INSN_REJECTED : +return -EINVAL ; + +case INSN_GOOD_NO_SLOT : + auprobe->simulate = true; +break ; + +case INSN_GOOD : +default : +break ;
Nitpick, we don't need case INSN_GOOD as well since default would cover it (that's unless you want to change default to BUG()).
arch/arm64/kernel/probes/uprobes.c line 73
Quoted 11 lines
arch/arm64/kernel/probes/uprobes.c new file +11
-0+ } + +return 0 ; +} + +int arch_uprobe_pre_xol (struct arch_uprobe *auprobe,struct pt_regs *regs) +{ +struct uprobe_task *utask = current->utask; + +/* saved fault code is restored in post_xol */ + utask->autask.saved_fault_code = current->thread.fault_code;
Does the current->thread.fault_code has any meaning here? We use it in the arm64 code when delivering a signal to user but I don't think that's the case here, we are handling a breakpoint instruction and there isn't anything that set the fault_code.
Quoted 10 lines
arch/arm64/kernel/probes/uprobes.c new file +10
-0+ +/* An invalid fault code between pre/post xol event */ + current->thread.fault_code =UPROBE_INV_FAULT_CODE ; + +/* Instruction point to execute ol */ +instruction_pointer_set (regs, utask->xol_vaddr); + +user_enable_single_step (current); + +return 0 ;
arch/arm64/kernel/probes/uprobes.c line 93
Quoted 10 lines
arch/arm64/kernel/probes/uprobes.c new file +10
-0+} + +int arch_uprobe_post_xol (struct arch_uprobe *auprobe,struct pt_regs *regs) +{ +struct uprobe_task *utask = current->utask; + +WARN_ON_ONCE (current->thread.fault_code !=UPROBE_INV_FAULT_CODE ); + +/* restore fault code */ + current->thread.fault_code = utask->autask.saved_fault_code;
Same here, I don't think this needs restoring if it wasn't meaningful in the first place.
Signature · 1 line
Catalin
Re: [PATCH 5/5] arm64: Add uprobe support
Hi Catalin,
Thanks for your review.
Quoted 14 lines · Catalin Marinas
Hi Pratyush,
arch/arm64/include/asm/debug-monitors.h line 75
Quoted 9 lines · Pratyush Anand
arch/arm64/include/asm/debug-monitors.h +3
-0@@ -70,6 +70,9 @@#define BRK64_ESR_MASK 0xFFFF#define BRK64_ESR_KPROBES 0x0004#define BRK64_OPCODE_KPROBES (AARCH64_BREAK_MON | (BRK64_ESR_KPROBES << 5)) +/* uprobes BRK opcodes with ESR encoding */ +#define BRK64_ESR_UPROBES 0x0008 +#define BRK64_OPCODE_UPROBES (AARCH64_BREAK_MON | (BRK64_ESR_UPROBES << 5))You can use
0x0005as immediate, we don't need individual bits here.
OK. will define BRK64_ESR_UPROBES as 0x0005
Quoted 7 lines
Quoted 7 lines
arch/arm64/include/asm/probes.h +0
-0@@ -35,4 +35,8 @@ struct arch_specific_insn { };#endif
Quoted 6 lines
arch/arm64/include/asm/probes.h struct arch_specific_insn { · line 40
Quoted 3 lines
arch/arm64/include/asm/probes.h +3
-0+#ifdef CONFIG_UPROBES +typedef u32 uprobe_opcode_t ; +#endif We don't need #ifdef around this typedef. Also, all the other architectures seem to have this typedef in
asm/uprobes.h.
kprobe_opcode_t was defined here, so I defined it here as well. But yes, it would be good to move it to asm/uprobes.h to keep in sync with other arch.
Quoted 7 lines
Quoted 7 lines
arch/arm64/include/asm/ptrace.h +0
-0@@ -217,6 +217,14 @@ int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task);#include <asm-generic/ptrace.h>
Quoted 11 lines
arch/arm64/include/asm/ptrace.h int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task); · line 226
Quoted 7 lines
arch/arm64/include/asm/ptrace.h +7
-0+#define procedure_link_pointer (regs) ((regs)->regs[30]) + +static inline void procedure_link_pointer_set (struct pt_regs *regs, +unsigned long val) +{ +procedure_link_pointer (regs) = val; +}Do you need these macro and function here? It seems that they are only used in
arch_uretprobe_hijack_return_addr(), so you can just expand them in there, no need for additional definitions.
I introduced it to keep sync with other register usage like instruction_pointer_set().
I have used it in uprobe code only, but I think, we can have a patch to modify following code, which can use them as well.
arch/arm64/kernel/probes/kprobes.c: ri->ret_addr = (kprobe_opcode_t *)regs->regs[30]; arch/arm64/kernel/probes/kprobes.c: regs->regs[30] = (long)&kretprobe_trampoline; arch/arm64/kernel/process.c: lr = regs->regs[30]; arch/arm64/kernel/signal.c: __put_user_error(regs->regs[30], &sf->lr, err); arch/arm64/kernel/signal.c: regs->regs[30] = (unsigned long)sigtramp;
Quoted 10 lines
arch/arm64/include/asm/thread_info.h static inline struct thread_info *current_thread_info(void) · line 112
Quoted 8 lines
arch/arm64/include/asm/thread_info.h +1
-0@@ -109,6 +109,7 @@ static inline struct thread_info *current_thread_info(void)#define TIF_NEED_RESCHED 1#define TIF_NOTIFY_RESUME 2/* callback before returning to user */ #define TIF_FOREIGN_FPSTATE 3/* CPU's FP state is not current's */ +#define TIF_UPROBE 5/* uprobe breakpoint or singlestep */ Nitpick: you can just use 4 until we cover this gap.
Hummm..as stated in commit log, Shi Yang suggested to define TIF_UPROBE as 5 in stead of 4, since 4 has already been used in -rt kernel. May be, I can put a comment in code as well.
Or, keep it 4 and -rt kernel will change their definitions. I am OK with both. let me know.
Quoted 17 lines
Quoted 17 lines
arch/arm64/include/asm/uprobes.h new file +13
-0@@ -0,0 +1,37 @@ +/* +* Copyright (C) 2014-2015 Pratyush Anand <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#ifndef _ASM_UPROBES_H +#define _ASM_UPROBES_H + +#include <asm/debug-monitors.h> +#include <asm/insn.h>
Quoted 8 lines
arch/arm64/include/asm/uprobes.h line 19
Quoted 6 lines
arch/arm64/include/asm/uprobes.h new file +6
-0+#include <asm/probes.h> + +#define MAX_UINSN_BYTES AARCH64_INSN_SIZE + +#define UPROBE_SWBP_INSN BRK64_OPCODE_UPROBES +#define UPROBE_SWBP_INSN_SIZE 4Nitpick: for consistency, just use
AARCH64_INSN_SIZE.
OK
Quoted 14 lines
Quoted 14 lines
arch/arm64/include/asm/uprobes.h new file +13
-0+#define UPROBE_XOL_SLOT_BYTES MAX_UINSN_BYTES + +struct arch_uprobe_task { +unsigned long saved_fault_code; +}; + +struct arch_uprobe { +union { +u8 insn[MAX_UINSN_BYTES ]; +u8 ixol[MAX_UINSN_BYTES ]; + }; +struct arch_probe_insn api; +bool simulate;
Quoted 8 lines
arch/arm64/include/asm/uprobes.h line 36
Quoted 4 lines
arch/arm64/include/asm/uprobes.h new file +4
-0+}; + +extern void flush_uprobe_xol_access (struct page *page,unsigned long uaddr, +void *kaddr,unsigned long len);I don't think we need this. It doesn't seem to be used anywhere other than the arm64
uprobes.cfile. So I would rather exposesync_icache_aliases(), similarly to__sync_icache_dcache().
OK.
Quoted 14 lines
arch/arm64/kernel/entry.S ret_fast_syscall: · line 692
Quoted 10 lines
arch/arm64/kernel/entry.S +2
-1@@ -688,7 +688,8 @@ ret_fast_syscall: ldr x1, [tsk, #TI_FLAGS] // re-check for syscall tracing and x2, x1, #_TIF_SYSCALL_WORK cbnz x2, ret_fast_syscall_trace - and x2, x1, #_TIF_WORK_MASK + mov x2, #_TIF_WORK_MASK + and x2, x1, x2Is this needed because
_TIF_WORK_MASKcannot work as an immediate value to 'and'? We could reorder the TIF bits, they are not exposed to user to have ABI implications.
_TIF_WORK_MASK is defined as follows:
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
_TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \
_TIF_UPROBE)Re-ordering will not help, because 0-3 have already been used by previous definitions. Only way to use immediate value could be if, TIF_UPROBE is defined as 4.
Quoted 36 lines
Quoted 5 lines
arch/arm64/kernel/entry.S +0
-0cbnz x2, work_pending enable_step_tsk x1, x2 kernel_exit 0arch/arm64/kernel/entry.S work_resched: · line 726
Quoted 9 lines
arch/arm64/kernel/entry.S +2
-1@@ -718,7 +719,8 @@ work_resched: ret_to_user: disable_irq // disable interrupts ldr x1, [tsk, #TI_FLAGS] - and x2, x1, #_TIF_WORK_MASK + mov x2, #_TIF_WORK_MASK + and x2, x1, x2 cbnz x2, work_pending enable_step_tsk x1, x2 kernel_exit 0Same here.
Quoted 19 lines
arch/arm64/kernel/probes/uprobes.c new file +16
-0@@ -0,0 +1,227 @@ +/* +* Copyright (C) 2014-2015 Pratyush Anand <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ +#include <linux/highmem.h> +#include <linux/ptrace.h> +#include <linux/uprobes.h> + +#include "decode-insn.h" + +#define UPROBE_INV_FAULT_CODE UINT_MAX + +void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
Quoted 8 lines
arch/arm64/kernel/probes/uprobes.c line 22
Quoted 6 lines
arch/arm64/kernel/probes/uprobes.c new file +6
-0+ void *src, unsigned long len) +{ + void *xol_page_kaddr = kmap_atomic(page); +void *dst = xol_page_kaddr + (vaddr & ~PAGE_MASK ); + +preempt_disable ();
kmap_atomic()already disabled preemption.
Yes..will remove.
Quoted 9 lines
arch/arm64/kernel/probes/uprobes.c line 28
Quoted 7 lines
arch/arm64/kernel/probes/uprobes.c new file +6
-0+ +/* Initialize the slot */ +memcpy (dst, src, len); + +/* flush caches (dcache/icache) */ +flush_uprobe_xol_access (page, vaddr, dst, len);Just use
sync_icache_aliases()here (once exposed in an arm64 header).
OK.
Quoted 13 lines
Quoted 13 lines
arch/arm64/kernel/probes/uprobes.c new file +12
-0+ +preempt_enable (); + +kunmap_atomic (xol_page_kaddr); +} + +unsigned long uprobe_get_swbp_addr (struct pt_regs *regs) +{ +return instruction_pointer (regs); +} + +int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
Quoted 8 lines
arch/arm64/kernel/probes/uprobes.c line 45
Quoted 5 lines
arch/arm64/kernel/probes/uprobes.c new file +5
-0+ unsigned long addr) +{ +probe_opcode_t insn; + +/* TODO: Currently we do not support AARCH32 instruction probing */ Is there a way to check (not necessarily in this file) that we don't probe 32-bit tasks?
- Well, I do not have complete idea about it that, how it can be done. I think we can not check that just by looking a single bit in an instruction. My understanding is that, we can only know about it when we are executing the instruction, by reading pstate, but that would not be useful for uprobe instruction analysis.
I hope, instruction encoding for aarch32 and aarch64 are different, and by analyzing for all types of aarch32 instructions, we will be able to decide that whether instruction is 32 bit trace-able or not. Accordingly, we can use either BRK or BKPT instruction for breakpoint generation.
Quoted 12 lines
Quoted 12 lines
arch/arm64/kernel/probes/uprobes.c new file +11
-0+if (!IS_ALIGNED (addr,AARCH64_INSN_SIZE )) +return -EINVAL ; + + insn = *(probe_opcode_t *)(&auprobe->insn[0 ]); + +switch (arm_probe_decode_insn (insn, &auprobe->api)) { +case INSN_REJECTED : +return -EINVAL ; + +case INSN_GOOD_NO_SLOT : + auprobe->simulate = true;
Quoted 8 lines
arch/arm64/kernel/probes/uprobes.c line 62
Quoted 5 lines
arch/arm64/kernel/probes/uprobes.c new file +5
-0+break ; + +case INSN_GOOD : +default : +break ;Nitpick, we don't need case
INSN_GOODas well since default would cover it (that's unless you want to change default toBUG()).
we will not have other than these 3, so need to introduce BUG(). I will remove INSN_GOOD.
Quoted 17 lines
arch/arm64/kernel/probes/uprobes.c line 73
Quoted 12 lines
arch/arm64/kernel/probes/uprobes.c new file +11
-0+ } + +return 0 ; +} + +int arch_uprobe_pre_xol (struct arch_uprobe *auprobe,struct pt_regs *regs) +{ +struct uprobe_task *utask = current->utask; + +/* saved fault code is restored in post_xol */ + utask->autask.saved_fault_code = current->thread.fault_code;Does the
current->thread.fault_codehas any meaning here? We use it in the arm64 code when delivering a signal to user but I don't think that's the case here, we are handling a breakpoint instruction and there isn't anything that set thefault_code.
Correct, they will just having garbage values. will remove.
Quoted 16 lines
Quoted 16 lines
arch/arm64/kernel/probes/uprobes.c new file +15
-0+ +/* An invalid fault code between pre/post xol event */ + current->thread.fault_code =UPROBE_INV_FAULT_CODE ; + +/* Instruction point to execute ol */ +instruction_pointer_set (regs, utask->xol_vaddr); + +user_enable_single_step (current); + +return 0 ; +} + +int arch_uprobe_post_xol (struct arch_uprobe *auprobe,struct pt_regs *regs) +{ +struct uprobe_task *utask = current->utask;
Quoted 8 lines
arch/arm64/kernel/probes/uprobes.c line 93
Quoted 5 lines
arch/arm64/kernel/probes/uprobes.c new file +5
-0+ +WARN_ON_ONCE (current->thread.fault_code !=UPROBE_INV_FAULT_CODE ); + +/* restore fault code */ + current->thread.fault_code = utask->autask.saved_fault_code;Same here, I don't think this needs restoring if it wasn't meaningful in the first place.
OK.
~Pratyush
Catalin Marinas
maintainerRe: [PATCH 5/5] arm64: Add uprobe support
Quoted 12 lines · Pratyush Anand
Quoted 10 lines · Catalin Marinas
arch/arm64/include/asm/thread_info.h static inline struct thread_info *current_thread_info(void) · line 112
Quoted 7 lines · Pratyush Anand
arch/arm64/include/asm/thread_info.h +1
-0@@ -109,6 +109,7 @@ static inline struct thread_info *current_thread_info(void)#define TIF_NEED_RESCHED 1#define TIF_NOTIFY_RESUME 2/* callback before returning to user */ #define TIF_FOREIGN_FPSTATE 3/* CPU's FP state is not current's */ +#define TIF_UPROBE 5/* uprobe breakpoint or singlestep */ Nitpick: you can just use 4 until we cover this gap.
Quoted 5 lines
Hummm..as stated in commit log, Shi Yang suggested to define
TIF_UPROBEas 5 in stead of 4, since 4 has already been used in -rt kernel. May be, I can put a comment in code as well.
Or, keep it 4 and -rt kernel will change their definitions. I am OK with both. let me know.
I forgot about the -rt kernel. I guess the -rt guys need to rebase the patches anyway on top of mainline, so it's just a matter of sorting out a minor conflict (as I already said, these bits are internal to the kernel, so no ABI affected). For now, just use 4 so that we avoid additional asm changes.
Quoted 14 lines
Quoted 5 lines
Quoted 5 lines
arch/arm64/kernel/entry.S +0
-0@@ -688,7 +688,8 @@ ret_fast_syscall: ldr x1, [tsk, #TI_FLAGS] // re-check for syscall tracing and x2, x1, #_TIF_SYSCALL_WORKQuoted 8 lines
arch/arm64/kernel/entry.S ret_fast_syscall: · line 692
Quoted 4 lines
arch/arm64/kernel/entry.S +2
-1cbnz x2, ret_fast_syscall_trace - and x2, x1, #_TIF_WORK_MASK + mov x2, #_TIF_WORK_MASK + and x2, x1, x2Is this needed because
_TIF_WORK_MASKcannot work as an immediate value to 'and'? We could reorder the TIF bits, they are not exposed to user to have ABI implications.
Quoted 8 lines
_TIF_WORK_MASKis defined as follows:#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \ _TIF_UPROBE)Re-ordering will not help, because 0-3 have already been used by previous definitions. Only way to use immediate value could be if,
TIF_UPROBEis defined as 4.
Yes, see above.
Quoted 21 lines
Quoted 6 lines
Quoted 6 lines
arch/arm64/kernel/entry.S +6
-0+unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) +{ + return instruction_pointer(regs); +} + +int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,Quoted 8 lines
arch/arm64/kernel/entry.S
Quoted 5 lines
arch/arm64/kernel/entry.S +5
-0+ unsigned long addr) +{ + probe_opcode_t insn; + + /* TODO: Currently we do not support AARCH32 instruction probing */Is there a way to check (not necessarily in this file) that we don't probe 32-bit tasks?
- Well, I do not have complete idea about it that, how it can be done. I think we can not check that just by looking a single bit in an instruction. My understanding is that, we can only know about it when we are executing the instruction, by reading pstate, but that would not be useful for uprobe instruction analysis.
Quoted 4 lines
I hope, instruction encoding for aarch32 and aarch64 are different, and by analyzing for all types of aarch32 instructions, we will be able to decide that whether instruction is 32 bit trace-able or not. Accordingly, we can use either BRK or BKPT instruction for breakpoint generation.
We may have some unrelated instruction encoding overlapping but I haven't checked. I was more thinking about whether we know which task is being probed and check is_compat_task() or maybe using compat_user_mode(regs).
Signature · 1 line
Catalin
Re: [PATCH 5/5] arm64: Add uprobe support
Quoted 23 lines · Catalin Marinas
Quoted 17 lines · Pratyush Anand
Quoted 9 lines · Catalin Marinas
arch/arm64/kernel/probes/uprobes.c line 45
Quoted 6 lines
arch/arm64/kernel/probes/uprobes.c new file +6
-0+int arch_uprobe_analyze_insn (struct arch_uprobe *auprobe,struct mm_struct *mm, +unsigned long addr) +{ +probe_opcode_t insn; + +/* TODO: Currently we do not support AARCH32 instruction probing */ Is there a way to check (not necessarily in this file) that we don't probe 32-bit tasks?
- Well, I do not have complete idea about it that, how it can be done. I think we can not check that just by looking a single bit in an instruction. My understanding is that, we can only know about it when we are executing the instruction, by reading pstate, but that would not be useful for uprobe instruction analysis.
Quoted 4 lines
I hope, instruction encoding for aarch32 and aarch64 are different, and by analyzing for all types of aarch32 instructions, we will be able to decide that whether instruction is 32 bit trace-able or not. Accordingly, we can use either BRK or BKPT instruction for breakpoint generation.
Quoted 4 lines
We may have some unrelated instruction encoding overlapping but I haven't checked. I was more thinking about whether we know which task is being probed and check
is_compat_task()or maybe usingcompat_user_mode(regs).
I had thought of this, but problem is that we might not have task in existence when we enable uprobes. For example: Lets say we are inserting a trace probe at offset 0x690 in a executable binary.
echo "p test:0x690" > /sys/kernel/debug/tracing/uprobe_events echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable
In the 'enable' step, it is decided that whether instruction is traceable or not.
(1) But at this point 'test' executable might not be running.
(2) Even if it is running, is_compat_task() or compat_user_mode() might not be usable, as they work with 'current' task.
What I was thinking that, let it go with 'TODO' as of now.
Later on, we propose some changes in core layer, so that we can read the elf headers of executable binary. ELFCLASS will be able to tell us, whether its a 32 bit or 64 bit executable. I think, moving "struct uprobe" from kernel/events/uprobes.c to a include/linux header file will do the job. "struct arch_uprobe" is part of "struct uprobe". "struct arch_uprobe" is passed in arch_uprobe_analyze_insn(). So, we can access struct uprobe's "inode" element with this change.
~Pratyush
Catalin Marinas
maintainerRe: [PATCH 5/5] arm64: Add uprobe support
Quoted 36 lines · Pratyush Anand
Quoted 23 lines · Catalin Marinas
Quoted 17 lines · Pratyush Anand
Quoted 9 lines · Catalin Marinas
arch/arm64/kernel/probes/uprobes.c line 45
Quoted 6 lines
arch/arm64/kernel/probes/uprobes.c new file +6
-0+int arch_uprobe_analyze_insn (struct arch_uprobe *auprobe,struct mm_struct *mm, +unsigned long addr) +{ +probe_opcode_t insn; + +/* TODO: Currently we do not support AARCH32 instruction probing */ Is there a way to check (not necessarily in this file) that we don't probe 32-bit tasks?
- Well, I do not have complete idea about it that, how it can be done. I think we can not check that just by looking a single bit in an instruction. My understanding is that, we can only know about it when we are executing the instruction, by reading pstate, but that would not be useful for uprobe instruction analysis.
Quoted 4 lines
I hope, instruction encoding for aarch32 and aarch64 are different, and by analyzing for all types of aarch32 instructions, we will be able to decide that whether instruction is 32 bit trace-able or not. Accordingly, we can use either BRK or BKPT instruction for breakpoint generation.
Quoted 4 lines
We may have some unrelated instruction encoding overlapping but I haven't checked. I was more thinking about whether we know which task is being probed and check
is_compat_task()or maybe usingcompat_user_mode(regs).I had thought of this, but problem is that we might not have task in existence when we enable uprobes. For example: Lets say we are inserting a trace probe at offset
0x690in a executable binary.echo "p test:0x690" >
/sys/kernel/debug/tracing/uprobe_eventsecho 1 >/sys/kernel/debug/tracing/events/uprobes/enable
Quoted 6 lines
In the 'enable' step, it is decided that whether instruction is traceable or not.
(1) But at this point 'test' executable might not be running.
(2) Even if it is running,is_compat_task()orcompat_user_mode()might not be usable, as they work with 'current' task.
What I find strange is that uprobes allows you to insert a breakpoint instruction that's not even compatible with the task (so it would SIGILL rather than generate a debug exception).
Quoted 1 line
What I was thinking that, let it go with 'TODO' as of now.
Only that I don't have any guarantee that someone is going to fix it ;).
As a quick workaround you could check mm->task_size > TASK_SIZE_32 in the arch_uprobe_analyze_insn() function.
Quoted 7 lines
Later on, we propose some changes in core layer, so that we can read the elf headers of executable binary. ELFCLASS will be able to tell us, whether its a 32 bit or 64 bit executable. I think, moving "struct uprobe" from
kernel/events/uprobes.cto ainclude/linuxheader file will do the job. "structarch_uprobe" is part of "struct uprobe". "structarch_uprobe" is passed inarch_uprobe_analyze_insn(). So, we can access struct uprobe's "inode" element with this change.
You can get access to struct linux_binfmt via mm_struct but it doesn't currently help much since all the members of this structure point to static functions. Maybe an enum in struct linux_binfmt with format types exposed to the rest of the kernel?
Signature · 1 line
Catalin
Re: [PATCH 5/5] arm64: Add uprobe support
Quoted 34 lines · Catalin Marinas
Quoted 33 lines · Pratyush Anand
Quoted 23 lines · Catalin Marinas
Quoted 17 lines · Pratyush Anand
Quoted 9 lines · Catalin Marinas
arch/arm64/kernel/probes/uprobes.c line 45
Quoted 6 lines
arch/arm64/kernel/probes/uprobes.c new file +6
-0+int arch_uprobe_analyze_insn (struct arch_uprobe *auprobe,struct mm_struct *mm, +unsigned long addr) +{ +probe_opcode_t insn; + +/* TODO: Currently we do not support AARCH32 instruction probing */ Is there a way to check (not necessarily in this file) that we don't probe 32-bit tasks?
- Well, I do not have complete idea about it that, how it can be done. I think we can not check that just by looking a single bit in an instruction. My understanding is that, we can only know about it when we are executing the instruction, by reading pstate, but that would not be useful for uprobe instruction analysis.
Quoted 4 lines
I hope, instruction encoding for aarch32 and aarch64 are different, and by analyzing for all types of aarch32 instructions, we will be able to decide that whether instruction is 32 bit trace-able or not. Accordingly, we can use either BRK or BKPT instruction for breakpoint generation.
Quoted 4 lines
We may have some unrelated instruction encoding overlapping but I haven't checked. I was more thinking about whether we know which task is being probed and check
is_compat_task()or maybe usingcompat_user_mode(regs).I had thought of this, but problem is that we might not have task in existence when we enable uprobes. For example: Lets say we are inserting a trace probe at offset
0x690in a executable binary.
Quoted 7 lines
Quoted 7 lines
echo "p test:0x690" >
/sys/kernel/debug/tracing/uprobe_eventsecho 1 >/sys/kernel/debug/tracing/events/uprobes/enableIn the 'enable' step, it is decided that whether instruction is traceable or not.
(1) But at this point 'test' executable might not be running.
Let me correct myself first here. When executable is not running, then, arch_uprobe_analyze_insn() is not called while uprobes enabling (ie writing '1' to 'enable'). In that case, it is called when binary is executed and task is created.
Quoted 7 lines
Quoted 2 lines
(2) Even if it is running,
is_compat_task()orcompat_user_mode()might not be usable, as they work with 'current' task.What I find strange is that uprobes allows you to insert a breakpoint instruction that's not even compatible with the task (so it would SIGILL rather than generate a debug exception).
Quoted 6 lines
Quoted 1 line
What I was thinking that, let it go with 'TODO' as of now.
Only that I don't have any guarantee that someone is going to fix it ;).
As a quick workaround you could check
mm->task_size>TASK_SIZE_32in thearch_uprobe_analyze_insn()function.
It would be doable. TASK_SIZE_32 is defined only for COMPAT. So, may be I can return -EINVAL when mm->task_size < TASK_SIZE_64.
Thanks for your input.
~Pratyush
Catalin Marinas
maintainerRe: [PATCH 5/5] arm64: Add uprobe support
Quoted 41 lines · Pratyush Anand
Quoted 40 lines · Catalin Marinas
Quoted 39 lines · Pratyush Anand
Quoted 23 lines · Catalin Marinas
Quoted 17 lines · Pratyush Anand
Quoted 9 lines · Catalin Marinas
Review
Quoted 6 lines
(quoted diff) +6
-0+int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, + unsigned long addr) +{ + probe_opcode_t insn; + + /* TODO: Currently we do not support AARCH32 instruction probing */Is there a way to check (not necessarily in this file) that we don't probe 32-bit tasks?
- Well, I do not have complete idea about it that, how it can be done. I think we can not check that just by looking a single bit in an instruction. My understanding is that, we can only know about it when we are executing the instruction, by reading pstate, but that would not be useful for uprobe instruction analysis.
Quoted 4 lines
I hope, instruction encoding for aarch32 and aarch64 are different, and by analyzing for all types of aarch32 instructions, we will be able to decide that whether instruction is 32 bit trace-able or not. Accordingly, we can use either BRK or BKPT instruction for breakpoint generation.
Quoted 4 lines
We may have some unrelated instruction encoding overlapping but I haven't checked. I was more thinking about whether we know which task is being probed and check
is_compat_task()or maybe usingcompat_user_mode(regs).I had thought of this, but problem is that we might not have task in existence when we enable uprobes. For example: Lets say we are inserting a trace probe at offset
0x690in a executable binary.echo "p test:0x690" >
/sys/kernel/debug/tracing/uprobe_eventsecho 1 >/sys/kernel/debug/tracing/events/uprobes/enableIn the 'enable' step, it is decided that whether instruction is traceable or not.
Quoted 6 lines
Quoted 1 line
Quoted 1 line
(1) But at this point 'test' executable might not be running.
Let me correct myself first here. When executable is not running, then,
arch_uprobe_analyze_insn()is not called while uprobes enabling (ie writing '1' to 'enable'). In that case, it is called when binary is executed and task is created.
I kind of figured this out. This function needs to read the actual instruction from memory, so that won't be possible until at least the executable file has an address_space in the kernel. What's not clear to me is how early this is done, do we have the mm_struct fully populated?
Quoted 9 lines
Quoted 9 lines
Quoted 2 lines
(2) Even if it is running,
is_compat_task()orcompat_user_mode()might not be usable, as they work with 'current' task.What I find strange is that uprobes allows you to insert a breakpoint instruction that's not even compatible with the task (so it would SIGILL rather than generate a debug exception).
Quoted 1 line
What I was thinking that, let it go with 'TODO' as of now.
Quoted 7 lines
Quoted 4 lines
Only that I don't have any guarantee that someone is going to fix it ;).
As a quick workaround you could check
mm->task_size>TASK_SIZE_32in thearch_uprobe_analyze_insn()function.It would be doable.
TASK_SIZE_32is defined only for COMPAT. So, may be I can return-EINVALwhenmm->task_size<TASK_SIZE_64.
That's just a temporary workaround. If we ever merge ILP32, this test would no longer be enough (as the ISA is AArch64 but with TASK_SIZE_32).
Looking@prepare_uprobe(), we have a weak is_trap_insn() function. This check is meaningless without knowing which instruction set we target. A false positive here, however, is not that bad as we wouldn't end up inserting the wrong breakpoint in the executable. But it looks to me like the core uprobe code needs to pass some additional information like the type of task or ELF format to the arch code to make a useful choice of breakpoint type.
Signature · 1 line
Catalin
Re: [PATCH 5/5] arm64: Add uprobe support
Quoted 5 lines · Catalin Marinas
Quoted 3 lines · Pratyush Anand
Quoted 2 lines · Catalin Marinas
Quoted 1 line · Pratyush Anand
On 21/09/2016:06:04:04 PM, Catalin Marinas wrote:
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
As a quick workaround you could check
mm->task_size>TASK_SIZE_32in thearch_uprobe_analyze_insn()function.It would be doable.
TASK_SIZE_32is defined only for COMPAT. So, may be I can return-EINVALwhenmm->task_size<TASK_SIZE_64.That's just a temporary workaround. If we ever merge ILP32, this test would no longer be enough (as the ISA is AArch64 but with
TASK_SIZE_32).
OK.. So what about doing something similar what x86 is doing. We can have a flag for task Type in arch specific mm_context_t. We also set this flag in COMPAT_SET_PERSONALITY() along with setting thread_info flag, and we clear them in SET_PERSONALITY().
Quoted 8 lines
Looking at
prepare_uprobe(), we have a weakis_trap_insn()function. This check is meaningless without knowing which instruction set we target. A false positive here, however, is not that bad as we wouldn't end up inserting the wrong breakpoint in the executable. But it looks to me like the core uprobe code needs to pass some additional information like the type of task or ELF format to the arch code to make a useful choice of breakpoint type.
It seems that 'strtle r0, [r0], #160' would have the closest matching aarch32 instruction wrt BRK64_OPCODE_UPROBES(0xd42000A0). But that too seems a bad instruction. So, may be we can use still weak is_trap_insn().
~Pratyush
Catalin Marinas
maintainerRe: [PATCH 5/5] arm64: Add uprobe support
Quoted 13 lines · Pratyush Anand
Quoted 11 lines · Catalin Marinas
Quoted 9 lines · Pratyush Anand
Quoted 5 lines · Catalin Marinas
Quoted 1 line · Pratyush Anand
On 21/09/2016:06:04:04 PM, Catalin Marinas wrote:
As a quick workaround you could check
mm->task_size>TASK_SIZE_32in thearch_uprobe_analyze_insn()function.It would be doable.
TASK_SIZE_32is defined only for COMPAT. So, may be I can return-EINVALwhenmm->task_size<TASK_SIZE_64.
Quoted 7 lines
Quoted 2 lines
That's just a temporary workaround. If we ever merge ILP32, this test would no longer be enough (as the ISA is AArch64 but with
TASK_SIZE_32).OK.. So what about doing something similar what x86 is doing. We can have a flag for task Type in arch specific
mm_context_t. We also set this flag inCOMPAT_SET_PERSONALITY()along with settingthread_infoflag, and we clear them inSET_PERSONALITY().
This looks like a better approach.
Quoted 8 lines
Quoted 7 lines
Looking at
prepare_uprobe(), we have a weakis_trap_insn()function. This check is meaningless without knowing which instruction set we target. A false positive here, however, is not that bad as we wouldn't end up inserting the wrong breakpoint in the executable. But it looks to me like the core uprobe code needs to pass some additional information like the type of task or ELF format to the arch code to make a useful choice of breakpoint type.
Quoted 4 lines
It seems that 'strtle r0, [r0], #160' would have the closest matching aarch32 instruction wrt
BRK64_OPCODE_UPROBES(0xd42000A0). But that too seems a bad instruction. So, may be we can use still weakis_trap_insn().
Even if the is_trap_insn() check passes, we would reject the probe in arch_uprobe_analyze_insn() immediately after based on the mm type check, so not too bad.
If we add support for probing 32-bit tasks, I would rather have is_trap_insn() take the mm_struct as argument so that a non-weak implementation can check for the correct encoding.
Signature · 1 line
Catalin
Re: [PATCH 5/5] arm64: Add uprobe support
Quoted 32 lines · Catalin Marinas
Quoted 13 lines · Pratyush Anand
Quoted 11 lines · Catalin Marinas
Quoted 9 lines · Pratyush Anand
Quoted 5 lines · Catalin Marinas
Quoted 1 line · Pratyush Anand
On 21/09/2016:06:04:04 PM, Catalin Marinas wrote:
As a quick workaround you could check
mm->task_size>TASK_SIZE_32in thearch_uprobe_analyze_insn()function.It would be doable.
TASK_SIZE_32is defined only for COMPAT. So, may be I can return-EINVALwhenmm->task_size<TASK_SIZE_64.Quoted 7 lines
Quoted 2 lines
That's just a temporary workaround. If we ever merge ILP32, this test would no longer be enough (as the ISA is AArch64 but with
TASK_SIZE_32).OK.. So what about doing something similar what x86 is doing. We can have a flag for task Type in arch specific
mm_context_t. We also set this flag inCOMPAT_SET_PERSONALITY()along with settingthread_infoflag, and we clear them inSET_PERSONALITY().This looks like a better approach.
Quoted 8 lines
Quoted 7 lines
Looking at
prepare_uprobe(), we have a weakis_trap_insn()function. This check is meaningless without knowing which instruction set we target. A false positive here, however, is not that bad as we wouldn't end up inserting the wrong breakpoint in the executable. But it looks to me like the core uprobe code needs to pass some additional information like the type of task or ELF format to the arch code to make a useful choice of breakpoint type.
Quoted 8 lines
Quoted 4 lines
It seems that 'strtle r0, [r0], #160' would have the closest matching aarch32 instruction wrt
BRK64_OPCODE_UPROBES(0xd42000A0). But that too seems a bad instruction. So, may be we can use still weakis_trap_insn().Even if the
is_trap_insn()check passes, we would reject the probe inarch_uprobe_analyze_insn()immediately after based on the mm type check, so not too bad.
OK..I will have an always returning false from arm64 is_trap_insn() in v2.
Quoted 4 lines
If we add support for probing 32-bit tasks, I would rather have
is_trap_insn()take themm_structas argument so that a non-weak implementation can check for the correct encoding.
Yes, for 32 bit task we would need mm_struct as arg in is_trap_insn() as well as in is_swbp_insn(). We would also need to have arm64 specific set_swbp().
Thanks for all your input. It was helpful. I will send V2 soon.
~Pratyush
Catalin Marinas
maintainerRe: [PATCH 5/5] arm64: Add uprobe support
Quoted 38 lines · Pratyush Anand
Quoted 37 lines · Catalin Marinas
Quoted 13 lines · Pratyush Anand
Quoted 11 lines · Catalin Marinas
Quoted 9 lines · Pratyush Anand
Quoted 5 lines · Catalin Marinas
Quoted 1 line · Pratyush Anand
On 21/09/2016:06:04:04 PM, Catalin Marinas wrote:
As a quick workaround you could check
mm->task_size>TASK_SIZE_32in thearch_uprobe_analyze_insn()function.It would be doable.
TASK_SIZE_32is defined only for COMPAT. So, may be I can return-EINVALwhenmm->task_size<TASK_SIZE_64.Quoted 7 lines
Quoted 2 lines
That's just a temporary workaround. If we ever merge ILP32, this test would no longer be enough (as the ISA is AArch64 but with
TASK_SIZE_32).OK.. So what about doing something similar what x86 is doing. We can have a flag for task Type in arch specific
mm_context_t. We also set this flag inCOMPAT_SET_PERSONALITY()along with settingthread_infoflag, and we clear them inSET_PERSONALITY().This looks like a better approach.
Quoted 12 lines
Quoted 7 lines
Looking at
prepare_uprobe(), we have a weakis_trap_insn()function. This check is meaningless without knowing which instruction set we target. A false positive here, however, is not that bad as we wouldn't end up inserting the wrong breakpoint in the executable. But it looks to me like the core uprobe code needs to pass some additional information like the type of task or ELF format to the arch code to make a useful choice of breakpoint type.It seems that 'strtle r0, [r0], #160' would have the closest matching aarch32 instruction wrt
BRK64_OPCODE_UPROBES(0xd42000A0). But that too seems a bad instruction. So, may be we can use still weakis_trap_insn().
Quoted 5 lines
Quoted 3 lines
Even if the
is_trap_insn()check passes, we would reject the probe inarch_uprobe_analyze_insn()immediately after based on the mm type check, so not too bad.OK..I will have an always returning false from arm64
is_trap_insn()in v2.
For the time being, I think the default is_trap_insn() check is still useful on arm64. The problem gets trickier when we add AArch32 support as it may return 'true' on an AArch32 instruction that matches the AArch64 BRK (or vice-versa). That's when we need to either pass the mm to is_trap_insn() or simply return false and always perform the check in the arch_uprobe_analyze_insn() (which should, in addition, check for the trap instruction).
There is also the is_trap_at_addr() function which uses is_trap_insn(). I haven't checked the call paths here, are there any implications if is_trap_insn() always returns false?
Signature · 1 line
Catalin
Re: [PATCH 5/5] arm64: Add uprobe support
Quoted 13 lines · Catalin Marinas
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Looking at
prepare_uprobe(), we have a weakis_trap_insn()function.Quoted 11 lines
Quoted 11 lines
Quoted 6 lines
Quoted 6 lines
This check is meaningless without knowing which instruction set we target. A false positive here, however, is not that bad as we wouldn't end up inserting the wrong breakpoint in the executable. But it looks to me like the core uprobe code needs to pass some additional information like the type of task or ELF format to the arch code to make a useful choice of breakpoint type.
It seems that 'strtle r0, [r0], #160' would have the closest matching aarch32 instruction wrt
BRK64_OPCODE_UPROBES(0xd42000A0). But that too seems a bad instruction. So, may be we can use still weakis_trap_insn().
Quoted 7 lines
Quoted 5 lines
Quoted 5 lines
Quoted 3 lines
Quoted 3 lines
Even if the
is_trap_insn()check passes, we would reject the probe inarch_uprobe_analyze_insn()immediately after based on the mm type check, so not too bad.OK..I will have an always returning false from arm64
is_trap_insn()in v2.For the time being, I think the default
is_trap_insn()check is still useful on arm64.
I have already sent V2 with arm64 is_trap_insn() :(
Quoted 6 lines
The problem gets trickier when we add AArch32 support
as it may return 'true' on an AArch32 instruction that matches the AArch64 BRK (or vice-versa). That's when we need to either pass the mm tois_trap_insn()or simply return false and always perform the check in thearch_uprobe_analyze_insn()(which should, in addition, check for the trap instruction).
Yes, I agree that we will have to modify is_trap_insn() for supporting aarch32 task tracing.
Quoted 4 lines
There is also the
is_trap_at_addr()function which usesis_trap_insn(). I haven't checked the call paths here, are there any implications ifis_trap_insn()always returns false?
I had looked into it and also tested that a tracepoint at an application having a same instruction as that of "uprobe break instruction" ie "BRK #0x5" is rejected. So, I think a false positive return from is_tarp_insn() is still OK.
~Pratyush
Catalin Marinas
maintainerRe: [PATCH 5/5] arm64: Add uprobe support
Quoted 9 lines · Pratyush Anand
Quoted 3 lines · Catalin Marinas
There is also the
is_trap_at_addr()function which usesis_trap_insn(). I haven't checked the call paths here, are there any implications ifis_trap_insn()always returns false?I had looked into it and also tested that a tracepoint at an application having a same instruction as that of "uprobe break instruction" ie "BRK #0x5" is rejected. So, I think a false positive return from
is_tarp_insn()is still OK.
Looking at handle_swbp(), if we hit a breakpoint for which we don't have a valid uprobe, this function currently sends a SIGTRAP. But if is_trap_insn() returns false always, is_trap_at_addr() would return 0 in this case so the SIGTRAP is never issued.
Signature · 1 line
Catalin
Hi Will/Catalin,
Do you have any specific comment for this patch set?
~Pratyush
[1] https://lkml.org/lkml/2016/8/22/69
Quoted 48 lines · Pratyush Anand
ARM64 kprobe support is lying in torvalds/linux.git:master now. Therefore sending my uprobe patches which were dependent on decode-insn code of kprobe patches.
Unit tests for following have been done so far and they have been found working.
1. Step-able instructions, like sub, ldr, add etc.
2. Simulation-able like ret, cbnz, cbz etc.
3. uretprobe
4. Reject-able instructions like sev, wfe etc.
5. trapped and abort xol path
6. probe at unaligned user address.
7. longjump test casesCurrently it does not support aarch32 instruction probing.
RFC patches were sent long back, and all review comments for RFCs have been incorporated. RFCs were here: https://lwn.net/Articles/648514/
Pratyush Anand (5):
arm64: kprobe: protect/rename few definitions to be reused by uprobe
arm64:kgdb_step_brk_fn: ignore other's exception
arm64: HandleTRAP_HWBRKPTfor user mode as well
arm64: HandleTRAP_BRKPTfor user mode as well
arm64: Add uprobe supportarch/arm64/Kconfig | 3 + arch/arm64/include/asm/debug-monitors.h | 3 + arch/arm64/include/asm/probes.h | 23 ++-- arch/arm64/include/asm/ptrace.h | 8 ++ arch/arm64/include/asm/thread_info.h | 5 +- arch/arm64/include/asm/uprobes.h | 37 ++++++ arch/arm64/kernel/debug-monitors.c | 40 +++--- arch/arm64/kernel/entry.S | 6 +- arch/arm64/kernel/kgdb.c | 3 + arch/arm64/kernel/probes/Makefile | 2 + arch/arm64/kernel/probes/decode-insn.c | 31 ++--- arch/arm64/kernel/probes/decode-insn.h | 8 +- arch/arm64/kernel/probes/kprobes.c | 36 ++--- arch/arm64/kernel/probes/uprobes.c | 227 ++++++++++++++++++++++++++++++++ arch/arm64/kernel/signal.c | 4 +- arch/arm64/mm/flush.c | 6 + 16 files changed, 378 insertions(+), 64 deletions(-) create mode 100644 arch/arm64/include/asm/uprobes.h create mode 100644 arch/arm64/kernel/probes/uprobes.cSignature · 1 line
2.5.5
Hi Will/Catalin,
So far there is no comment which would require any modification in this patch set. However, a rebase would be required, because we have a fixup "arm64: Improve kprobes test for atomic sequence" in the next now. Also, since we have "arm64: kprobe: Always clear pstate.D in breakpoint exception handler" in next, so I can remove __kprobes tag from uprobe_breakpoint_handler() and uprobe_single_step_handler().
Do you think that these patches are good to be taken for 4.9? If yes, then I will send a quick V2 with above modifications.
~Pratyush
Quoted 57 lines · Pratyush Anand
Hi Will/Catalin,
Do you have any specific comment for this patch set?
~Pratyush
[1] https://lkml.org/lkml/2016/8/22/69
Quoted 48 lines · Pratyush Anand
ARM64 kprobe support is lying in torvalds/linux.git:master now. Therefore sending my uprobe patches which were dependent on decode-insn code of kprobe patches.
Unit tests for following have been done so far and they have been found working.
1. Step-able instructions, like sub, ldr, add etc.
2. Simulation-able like ret, cbnz, cbz etc.
3. uretprobe
4. Reject-able instructions like sev, wfe etc.
5. trapped and abort xol path
6. probe at unaligned user address.
7. longjump test casesCurrently it does not support aarch32 instruction probing.
RFC patches were sent long back, and all review comments for RFCs have been incorporated. RFCs were here: https://lwn.net/Articles/648514/
Pratyush Anand (5):
arm64: kprobe: protect/rename few definitions to be reused by uprobe
arm64:kgdb_step_brk_fn: ignore other's exception
arm64: HandleTRAP_HWBRKPTfor user mode as well
arm64: HandleTRAP_BRKPTfor user mode as well
arm64: Add uprobe supportarch/arm64/Kconfig | 3 + arch/arm64/include/asm/debug-monitors.h | 3 + arch/arm64/include/asm/probes.h | 23 ++-- arch/arm64/include/asm/ptrace.h | 8 ++ arch/arm64/include/asm/thread_info.h | 5 +- arch/arm64/include/asm/uprobes.h | 37 ++++++ arch/arm64/kernel/debug-monitors.c | 40 +++--- arch/arm64/kernel/entry.S | 6 +- arch/arm64/kernel/kgdb.c | 3 + arch/arm64/kernel/probes/Makefile | 2 + arch/arm64/kernel/probes/decode-insn.c | 31 ++--- arch/arm64/kernel/probes/decode-insn.h | 8 +- arch/arm64/kernel/probes/kprobes.c | 36 ++--- arch/arm64/kernel/probes/uprobes.c | 227 ++++++++++++++++++++++++++++++++ arch/arm64/kernel/signal.c | 4 +- arch/arm64/mm/flush.c | 6 + 16 files changed, 378 insertions(+), 64 deletions(-) create mode 100644 arch/arm64/include/asm/uprobes.h create mode 100644 arch/arm64/kernel/probes/uprobes.c--
2.5.5