xref: /openbmc/linux/arch/arm64/kernel/probes/uprobes.c (revision 09138ba68c1487a42c400485e999386a74911dbc)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
29842ceaeSPratyush Anand /*
39842ceaeSPratyush Anand  * Copyright (C) 2014-2016 Pratyush Anand <panand@redhat.com>
49842ceaeSPratyush Anand  */
59842ceaeSPratyush Anand #include <linux/highmem.h>
69842ceaeSPratyush Anand #include <linux/ptrace.h>
79842ceaeSPratyush Anand #include <linux/uprobes.h>
89842ceaeSPratyush Anand #include <asm/cacheflush.h>
99842ceaeSPratyush Anand 
109842ceaeSPratyush Anand #include "decode-insn.h"
119842ceaeSPratyush Anand 
129842ceaeSPratyush Anand #define UPROBE_INV_FAULT_CODE	UINT_MAX
139842ceaeSPratyush Anand 
arch_uprobe_copy_ixol(struct page * page,unsigned long vaddr,void * src,unsigned long len)149842ceaeSPratyush Anand void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
159842ceaeSPratyush Anand 		void *src, unsigned long len)
169842ceaeSPratyush Anand {
179842ceaeSPratyush Anand 	void *xol_page_kaddr = kmap_atomic(page);
189842ceaeSPratyush Anand 	void *dst = xol_page_kaddr + (vaddr & ~PAGE_MASK);
199842ceaeSPratyush Anand 
209842ceaeSPratyush Anand 	/* Initialize the slot */
219842ceaeSPratyush Anand 	memcpy(dst, src, len);
229842ceaeSPratyush Anand 
239842ceaeSPratyush Anand 	/* flush caches (dcache/icache) */
248c28d52cSFuad Tabba 	sync_icache_aliases((unsigned long)dst, (unsigned long)dst + len);
259842ceaeSPratyush Anand 
269842ceaeSPratyush Anand 	kunmap_atomic(xol_page_kaddr);
279842ceaeSPratyush Anand }
289842ceaeSPratyush Anand 
uprobe_get_swbp_addr(struct pt_regs * regs)299842ceaeSPratyush Anand unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
309842ceaeSPratyush Anand {
319842ceaeSPratyush Anand 	return instruction_pointer(regs);
329842ceaeSPratyush Anand }
339842ceaeSPratyush Anand 
arch_uprobe_analyze_insn(struct arch_uprobe * auprobe,struct mm_struct * mm,unsigned long addr)349842ceaeSPratyush Anand int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
359842ceaeSPratyush Anand 		unsigned long addr)
369842ceaeSPratyush Anand {
379842ceaeSPratyush Anand 	probe_opcode_t insn;
389842ceaeSPratyush Anand 
399842ceaeSPratyush Anand 	/* TODO: Currently we do not support AARCH32 instruction probing */
405ce93ab6SYury Norov 	if (mm->context.flags & MMCF_AARCH32)
41d47422d9SHe Zhe 		return -EOPNOTSUPP;
429842ceaeSPratyush Anand 	else if (!IS_ALIGNED(addr, AARCH64_INSN_SIZE))
439842ceaeSPratyush Anand 		return -EINVAL;
449842ceaeSPratyush Anand 
45*8165bf83SMark Rutland 	insn = le32_to_cpu(auprobe->insn);
469842ceaeSPratyush Anand 
479842ceaeSPratyush Anand 	switch (arm_probe_decode_insn(insn, &auprobe->api)) {
489842ceaeSPratyush Anand 	case INSN_REJECTED:
499842ceaeSPratyush Anand 		return -EINVAL;
509842ceaeSPratyush Anand 
519842ceaeSPratyush Anand 	case INSN_GOOD_NO_SLOT:
529842ceaeSPratyush Anand 		auprobe->simulate = true;
539842ceaeSPratyush Anand 		break;
549842ceaeSPratyush Anand 
559842ceaeSPratyush Anand 	default:
569842ceaeSPratyush Anand 		break;
579842ceaeSPratyush Anand 	}
589842ceaeSPratyush Anand 
599842ceaeSPratyush Anand 	return 0;
609842ceaeSPratyush Anand }
619842ceaeSPratyush Anand 
arch_uprobe_pre_xol(struct arch_uprobe * auprobe,struct pt_regs * regs)629842ceaeSPratyush Anand int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
639842ceaeSPratyush Anand {
649842ceaeSPratyush Anand 	struct uprobe_task *utask = current->utask;
659842ceaeSPratyush Anand 
669842ceaeSPratyush Anand 	/* Initialize with an invalid fault code to detect if ol insn trapped */
679842ceaeSPratyush Anand 	current->thread.fault_code = UPROBE_INV_FAULT_CODE;
689842ceaeSPratyush Anand 
699842ceaeSPratyush Anand 	/* Instruction points to execute ol */
709842ceaeSPratyush Anand 	instruction_pointer_set(regs, utask->xol_vaddr);
719842ceaeSPratyush Anand 
729842ceaeSPratyush Anand 	user_enable_single_step(current);
739842ceaeSPratyush Anand 
749842ceaeSPratyush Anand 	return 0;
759842ceaeSPratyush Anand }
769842ceaeSPratyush Anand 
arch_uprobe_post_xol(struct arch_uprobe * auprobe,struct pt_regs * regs)779842ceaeSPratyush Anand int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
789842ceaeSPratyush Anand {
799842ceaeSPratyush Anand 	struct uprobe_task *utask = current->utask;
809842ceaeSPratyush Anand 
819842ceaeSPratyush Anand 	WARN_ON_ONCE(current->thread.fault_code != UPROBE_INV_FAULT_CODE);
829842ceaeSPratyush Anand 
839842ceaeSPratyush Anand 	/* Instruction points to execute next to breakpoint address */
849842ceaeSPratyush Anand 	instruction_pointer_set(regs, utask->vaddr + 4);
859842ceaeSPratyush Anand 
869842ceaeSPratyush Anand 	user_disable_single_step(current);
879842ceaeSPratyush Anand 
889842ceaeSPratyush Anand 	return 0;
899842ceaeSPratyush Anand }
arch_uprobe_xol_was_trapped(struct task_struct * t)909842ceaeSPratyush Anand bool arch_uprobe_xol_was_trapped(struct task_struct *t)
919842ceaeSPratyush Anand {
929842ceaeSPratyush Anand 	/*
939842ceaeSPratyush Anand 	 * Between arch_uprobe_pre_xol and arch_uprobe_post_xol, if an xol
949842ceaeSPratyush Anand 	 * insn itself is trapped, then detect the case with the help of
959842ceaeSPratyush Anand 	 * invalid fault code which is being set in arch_uprobe_pre_xol
969842ceaeSPratyush Anand 	 */
979842ceaeSPratyush Anand 	if (t->thread.fault_code != UPROBE_INV_FAULT_CODE)
989842ceaeSPratyush Anand 		return true;
999842ceaeSPratyush Anand 
1009842ceaeSPratyush Anand 	return false;
1019842ceaeSPratyush Anand }
1029842ceaeSPratyush Anand 
arch_uprobe_skip_sstep(struct arch_uprobe * auprobe,struct pt_regs * regs)1039842ceaeSPratyush Anand bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
1049842ceaeSPratyush Anand {
1059842ceaeSPratyush Anand 	probe_opcode_t insn;
1069842ceaeSPratyush Anand 	unsigned long addr;
1079842ceaeSPratyush Anand 
1089842ceaeSPratyush Anand 	if (!auprobe->simulate)
1099842ceaeSPratyush Anand 		return false;
1109842ceaeSPratyush Anand 
111*8165bf83SMark Rutland 	insn = le32_to_cpu(auprobe->insn);
1129842ceaeSPratyush Anand 	addr = instruction_pointer(regs);
1139842ceaeSPratyush Anand 
1149842ceaeSPratyush Anand 	if (auprobe->api.handler)
1159842ceaeSPratyush Anand 		auprobe->api.handler(insn, addr, regs);
1169842ceaeSPratyush Anand 
1179842ceaeSPratyush Anand 	return true;
1189842ceaeSPratyush Anand }
1199842ceaeSPratyush Anand 
arch_uprobe_abort_xol(struct arch_uprobe * auprobe,struct pt_regs * regs)1209842ceaeSPratyush Anand void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
1219842ceaeSPratyush Anand {
1229842ceaeSPratyush Anand 	struct uprobe_task *utask = current->utask;
1239842ceaeSPratyush Anand 
1249842ceaeSPratyush Anand 	/*
1259842ceaeSPratyush Anand 	 * Task has received a fatal signal, so reset back to probbed
1269842ceaeSPratyush Anand 	 * address.
1279842ceaeSPratyush Anand 	 */
1289842ceaeSPratyush Anand 	instruction_pointer_set(regs, utask->vaddr);
1299842ceaeSPratyush Anand 
1309842ceaeSPratyush Anand 	user_disable_single_step(current);
1319842ceaeSPratyush Anand }
1329842ceaeSPratyush Anand 
arch_uretprobe_is_alive(struct return_instance * ret,enum rp_check ctx,struct pt_regs * regs)1339842ceaeSPratyush Anand bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
1349842ceaeSPratyush Anand 		struct pt_regs *regs)
1359842ceaeSPratyush Anand {
1369842ceaeSPratyush Anand 	/*
1379842ceaeSPratyush Anand 	 * If a simple branch instruction (B) was called for retprobed
1389842ceaeSPratyush Anand 	 * assembly label then return true even when regs->sp and ret->stack
1399842ceaeSPratyush Anand 	 * are same. It will ensure that cleanup and reporting of return
1409842ceaeSPratyush Anand 	 * instances corresponding to callee label is done when
1419842ceaeSPratyush Anand 	 * handle_trampoline for called function is executed.
1429842ceaeSPratyush Anand 	 */
1439842ceaeSPratyush Anand 	if (ctx == RP_CHECK_CHAIN_CALL)
1449842ceaeSPratyush Anand 		return regs->sp <= ret->stack;
1459842ceaeSPratyush Anand 	else
1469842ceaeSPratyush Anand 		return regs->sp < ret->stack;
1479842ceaeSPratyush Anand }
1489842ceaeSPratyush Anand 
1499842ceaeSPratyush Anand unsigned long
arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,struct pt_regs * regs)1509842ceaeSPratyush Anand arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
1519842ceaeSPratyush Anand 				  struct pt_regs *regs)
1529842ceaeSPratyush Anand {
1539842ceaeSPratyush Anand 	unsigned long orig_ret_vaddr;
1549842ceaeSPratyush Anand 
1559842ceaeSPratyush Anand 	orig_ret_vaddr = procedure_link_pointer(regs);
1569842ceaeSPratyush Anand 	/* Replace the return addr with trampoline addr */
1579842ceaeSPratyush Anand 	procedure_link_pointer_set(regs, trampoline_vaddr);
1589842ceaeSPratyush Anand 
1599842ceaeSPratyush Anand 	return orig_ret_vaddr;
1609842ceaeSPratyush Anand }
1619842ceaeSPratyush Anand 
arch_uprobe_exception_notify(struct notifier_block * self,unsigned long val,void * data)1629842ceaeSPratyush Anand int arch_uprobe_exception_notify(struct notifier_block *self,
1639842ceaeSPratyush Anand 				 unsigned long val, void *data)
1649842ceaeSPratyush Anand {
1659842ceaeSPratyush Anand 	return NOTIFY_DONE;
1669842ceaeSPratyush Anand }
1679842ceaeSPratyush Anand 
uprobe_breakpoint_handler(struct pt_regs * regs,unsigned long esr)1689842ceaeSPratyush Anand static int uprobe_breakpoint_handler(struct pt_regs *regs,
1698d56e5c5SAlexandru Elisei 				     unsigned long esr)
1709842ceaeSPratyush Anand {
171fb610f2aSWill Deacon 	if (uprobe_pre_sstep_notifier(regs))
1729842ceaeSPratyush Anand 		return DBG_HOOK_HANDLED;
1739842ceaeSPratyush Anand 
1749842ceaeSPratyush Anand 	return DBG_HOOK_ERROR;
1759842ceaeSPratyush Anand }
1769842ceaeSPratyush Anand 
uprobe_single_step_handler(struct pt_regs * regs,unsigned long esr)1779842ceaeSPratyush Anand static int uprobe_single_step_handler(struct pt_regs *regs,
1788d56e5c5SAlexandru Elisei 				      unsigned long esr)
1799842ceaeSPratyush Anand {
1809842ceaeSPratyush Anand 	struct uprobe_task *utask = current->utask;
1819842ceaeSPratyush Anand 
182fb610f2aSWill Deacon 	WARN_ON(utask && (instruction_pointer(regs) != utask->xol_vaddr + 4));
1839842ceaeSPratyush Anand 	if (uprobe_post_sstep_notifier(regs))
1849842ceaeSPratyush Anand 		return DBG_HOOK_HANDLED;
1859842ceaeSPratyush Anand 
1869842ceaeSPratyush Anand 	return DBG_HOOK_ERROR;
1879842ceaeSPratyush Anand }
1889842ceaeSPratyush Anand 
1899842ceaeSPratyush Anand /* uprobe breakpoint handler hook */
1909842ceaeSPratyush Anand static struct break_hook uprobes_break_hook = {
191453b7740SWill Deacon 	.imm = UPROBES_BRK_IMM,
1929842ceaeSPratyush Anand 	.fn = uprobe_breakpoint_handler,
1939842ceaeSPratyush Anand };
1949842ceaeSPratyush Anand 
1959842ceaeSPratyush Anand /* uprobe single step handler hook */
1969842ceaeSPratyush Anand static struct step_hook uprobes_step_hook = {
1979842ceaeSPratyush Anand 	.fn = uprobe_single_step_handler,
1989842ceaeSPratyush Anand };
1999842ceaeSPratyush Anand 
arch_init_uprobes(void)2009842ceaeSPratyush Anand static int __init arch_init_uprobes(void)
2019842ceaeSPratyush Anand {
20226a04d84SWill Deacon 	register_user_break_hook(&uprobes_break_hook);
20326a04d84SWill Deacon 	register_user_step_hook(&uprobes_step_hook);
2049842ceaeSPratyush Anand 
2059842ceaeSPratyush Anand 	return 0;
2069842ceaeSPratyush Anand }
2079842ceaeSPratyush Anand 
2089842ceaeSPratyush Anand device_initcall(arch_init_uprobes);
209