From patchwork Tue Jun 11 11:21:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiri Olsa X-Patchwork-Id: 13693470 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 764F0171644; Tue, 11 Jun 2024 11:22:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718104938; cv=none; b=YgMAy8kc7JBsrBZjUIoQPXTD7Dg+/3jT9b2oF0sH3VmjyvJZqr/RgVXkGN1oocnt4j8GWjyxKFRgzNGspXuSrEhQduOpM+fPvkS6PZPEiWeeavJEvYiM3pENODN12/iCT+v5GH+MQInTY6RbM3yFHRkggSDweHfFgCpcoAulYos= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718104938; c=relaxed/simple; bh=2dJceMDRbDi+uoBltMqlHFK4LRnJUWXXCRkYVwz32Pk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NeR0ZmPu1UQ+dOcfv3hbz4H37mM2PaHpsyi2einCYgf0N15fosNkQt0j4yYMVBs+HPmI8i9cnX7t2GLtWI/L27c7jOAxJVzMWRwk+3pSHM40ycfZmoZl/6urXVNVh226VwgVdQCJZk0xG/fPTRg/K3cRSeu7K4dhJHtBUn7LIiw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Oy3bL/u1; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Oy3bL/u1" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 05D1DC2BD10; Tue, 11 Jun 2024 11:22:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1718104938; bh=2dJceMDRbDi+uoBltMqlHFK4LRnJUWXXCRkYVwz32Pk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Oy3bL/u1jwsH+SWFqeKV+IFnY2fAmS7SAl4abqcP1VLBeMnEW5z2uENWsj64uvKLd GlQuYwRt2zznutKbnas55G+JlkIlMoCctnNehJumVEUk3KzIuPd9noj3do352Du+RO Cpu4k67D1wBIs1xqEQ+zXrCMEZ8l5a6KtsP5akWrfrt/MXNNH0zJvrFDnGkgur3/L5 1Ri+xZWz9kbE59GjCjiEMD7dTR5jz+kFYnBjkRkCLQc7D+eArfb5oXmRmo5+hVfduf yx7tFCIn/NKlbhM3UmhkcAg6qa4YwFbPCcoDyIroSFmOegObyc+8EdLwG0g3V94wz/ 9xGAu3YvwG0cQ== From: Jiri Olsa To: Steven Rostedt , Masami Hiramatsu , Oleg Nesterov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: Rick Edgecombe , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-api@vger.kernel.org, linux-man@vger.kernel.org, x86@kernel.org, bpf@vger.kernel.org, Song Liu , Yonghong Song , John Fastabend , Peter Zijlstra , Thomas Gleixner , "Borislav Petkov (AMD)" , Ingo Molnar , Andy Lutomirski , Deepak Gupta Subject: [PATCHv8 bpf-next 1/9] x86/shstk: Make return uprobe work with shadow stack Date: Tue, 11 Jun 2024 13:21:50 +0200 Message-ID: <20240611112158.40795-2-jolsa@kernel.org> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240611112158.40795-1-jolsa@kernel.org> References: <20240611112158.40795-1-jolsa@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Currently the application with enabled shadow stack will crash if it sets up return uprobe. The reason is the uretprobe kernel code changes the user space task's stack, but does not update shadow stack accordingly. Adding new functions to update values on shadow stack and using them in uprobe code to keep shadow stack in sync with uretprobe changes to user stack. Acked-by: Andrii Nakryiko Acked-by: Rick Edgecombe Reviewed-by: Oleg Nesterov Fixes: 488af8ea7131 ("x86/shstk: Wire in shadow stack interface") Signed-off-by: Jiri Olsa --- arch/x86/include/asm/shstk.h | 2 ++ arch/x86/kernel/shstk.c | 11 +++++++++++ arch/x86/kernel/uprobes.c | 7 ++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/shstk.h b/arch/x86/include/asm/shstk.h index 42fee8959df7..896909f306e3 100644 --- a/arch/x86/include/asm/shstk.h +++ b/arch/x86/include/asm/shstk.h @@ -21,6 +21,7 @@ unsigned long shstk_alloc_thread_stack(struct task_struct *p, unsigned long clon void shstk_free(struct task_struct *p); int setup_signal_shadow_stack(struct ksignal *ksig); int restore_signal_shadow_stack(void); +int shstk_update_last_frame(unsigned long val); #else static inline long shstk_prctl(struct task_struct *task, int option, unsigned long arg2) { return -EINVAL; } @@ -31,6 +32,7 @@ static inline unsigned long shstk_alloc_thread_stack(struct task_struct *p, static inline void shstk_free(struct task_struct *p) {} static inline int setup_signal_shadow_stack(struct ksignal *ksig) { return 0; } static inline int restore_signal_shadow_stack(void) { return 0; } +static inline int shstk_update_last_frame(unsigned long val) { return 0; } #endif /* CONFIG_X86_USER_SHADOW_STACK */ #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/kernel/shstk.c b/arch/x86/kernel/shstk.c index 6f1e9883f074..9797d4cdb78a 100644 --- a/arch/x86/kernel/shstk.c +++ b/arch/x86/kernel/shstk.c @@ -577,3 +577,14 @@ long shstk_prctl(struct task_struct *task, int option, unsigned long arg2) return wrss_control(true); return -EINVAL; } + +int shstk_update_last_frame(unsigned long val) +{ + unsigned long ssp; + + if (!features_enabled(ARCH_SHSTK_SHSTK)) + return 0; + + ssp = get_user_shstk_addr(); + return write_user_shstk_64((u64 __user *)ssp, (u64)val); +} diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index 6c07f6daaa22..6402fb3089d2 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c @@ -1076,8 +1076,13 @@ arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs return orig_ret_vaddr; nleft = copy_to_user((void __user *)regs->sp, &trampoline_vaddr, rasize); - if (likely(!nleft)) + if (likely(!nleft)) { + if (shstk_update_last_frame(trampoline_vaddr)) { + force_sig(SIGSEGV); + return -1; + } return orig_ret_vaddr; + } if (nleft != rasize) { pr_err("return address clobbered: pid=%d, %%sp=%#lx, %%ip=%#lx\n", From patchwork Tue Jun 11 11:21:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiri Olsa X-Patchwork-Id: 13693471 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BD569171644; Tue, 11 Jun 2024 11:22:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718104950; cv=none; b=RiPl3IqQj8huyZ2LbsxuTG92YlBlz0BfgX04Y39p2y83hvdoV00KOLn6KjgIcGz1h+a6Ble5+0sqvwMA14255HFtslyyqoYMrgJtMZcCYuLSfC3i1+StEatvTKW0stndr1gruqWLKkxXb/On7t7RuBLWAzz6nxHXQ5Vt/IEz26Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718104950; c=relaxed/simple; bh=miTQKniStPWOLHCjonpZHPXe/BQEitRNyP42meyvNGU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aMqlMRoKIHI3hxzTMMLL4ocS3jXfz91OiseGZQXV9hsGCBPYxPBswvujpp4rdsjhwB9F8toKcIcAu5cmtnBYNstuC8K6BbpnvL+3u6TyVPhvrD+YimXmv5Ps+Khe5xueYAWa8akesHuPmw5xViNDQjQsp+XBeSrEhWNpOfOvtz8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=hyu3zz8w; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="hyu3zz8w" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1FF67C2BD10; Tue, 11 Jun 2024 11:22:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1718104950; bh=miTQKniStPWOLHCjonpZHPXe/BQEitRNyP42meyvNGU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hyu3zz8w9AzukgR9e59gtFNxVI0sw+TuiiWPgYvOTQ9F7qN83rvOGEYn4/AAKVVyZ jSKoOIHxt35hzBYZwc5pVBsj7hSmlXqFhzranc+pKKo+n5KPybmFc2ZW4ZEFj9Eg9+ 0nEd8BHToi3x4ve5/sqS2pK04sqHQTVGK0d/Al98cYjMEewTi+Ep2xWLoduPzJL/JY Nz4ZOTIMsyoGRdry03VcPLAwIKP/ARjTg4A6F6eoLWzFJB+HHkngnb4NdfT7UGjYXq d09MFwf0Mu7IUI6lj8gZb1o5dKHIRZ4kVrPfjuAufDOAKc+4VgU4lkhybXlnKw8cBr 8Fopa8srj7GFg== From: Jiri Olsa To: Steven Rostedt , Masami Hiramatsu , Oleg Nesterov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-api@vger.kernel.org, linux-man@vger.kernel.org, x86@kernel.org, bpf@vger.kernel.org, Song Liu , Yonghong Song , John Fastabend , Peter Zijlstra , Thomas Gleixner , "Borislav Petkov (AMD)" , Ingo Molnar , Andy Lutomirski , "Edgecombe, Rick P" , Deepak Gupta Subject: [PATCHv8 bpf-next 2/9] uprobe: Wire up uretprobe system call Date: Tue, 11 Jun 2024 13:21:51 +0200 Message-ID: <20240611112158.40795-3-jolsa@kernel.org> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240611112158.40795-1-jolsa@kernel.org> References: <20240611112158.40795-1-jolsa@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Wiring up uretprobe system call, which comes in following changes. We need to do the wiring before, because the uretprobe implementation needs the syscall number. Note at the moment uretprobe syscall is supported only for native 64-bit process. Reviewed-by: Oleg Nesterov Reviewed-by: Masami Hiramatsu (Google) Acked-by: Andrii Nakryiko Signed-off-by: Jiri Olsa --- arch/x86/entry/syscalls/syscall_64.tbl | 1 + include/linux/syscalls.h | 2 ++ include/uapi/asm-generic/unistd.h | 5 ++++- kernel/sys_ni.c | 2 ++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index a396f6e6ab5b..6452c2ec469a 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -384,6 +384,7 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal +463 64 uretprobe sys_uretprobe # # Due to a historical design error, certain syscalls are numbered differently diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 9104952d323d..494f5e0f61f7 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -973,6 +973,8 @@ asmlinkage long sys_lsm_list_modules(u64 *ids, u32 *size, u32 flags); /* x86 */ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); +asmlinkage long sys_uretprobe(void); + /* pciconfig: alpha, arm, arm64, ia64, sparc */ asmlinkage long sys_pciconfig_read(unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len, diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index d983c48a3b6a..2378f88d5ad4 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -845,8 +845,11 @@ __SYSCALL(__NR_lsm_list_modules, sys_lsm_list_modules) #define __NR_mseal 462 __SYSCALL(__NR_mseal, sys_mseal) +#define __NR_uretprobe 463 +__SYSCALL(__NR_uretprobe, sys_uretprobe) + #undef __NR_syscalls -#define __NR_syscalls 463 +#define __NR_syscalls 464 /* * 32 bit systems traditionally used different diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index d7eee421d4bc..5ce9fa0dc195 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -392,3 +392,5 @@ COND_SYSCALL(setuid16); /* restartable sequence */ COND_SYSCALL(rseq); + +COND_SYSCALL(uretprobe); From patchwork Tue Jun 11 11:21:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jiri Olsa X-Patchwork-Id: 13693472 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 33D4D13E8AE; Tue, 11 Jun 2024 11:22:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718104963; cv=none; b=OP0mosUH4uI/bNDAnBdJBYFTvVB4TxnhkAJlibb3cYCuLw70oNLPnme3wB1VPvQiLeMXQQa5o6G9TCYIKHSqKugVi+0bcJ4VUeG8NcZtPPIGvbzJmVMz5zbzSVqblPS8oQ9fvrWdVqWY1vjG6HX64iRq3vdDD71QWA6Kmeeye/U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718104963; c=relaxed/simple; bh=3y99euo6n8eFZJR8v++gmH8KVI8lf89SzvuCaM8aVhU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=rZMCoab79661WczTjkzEiUX/GX77lFpfffKT3qMfxTvtUO5dJlCGLeRB1MxKnQh2Usw7YD1slZj9LjG/vJ9W4knJ2q6gkh8yLCRe1IFUy1AUna7Xh+9RoKtsl/kv0CnqY26z7MYb8Gh94pXnPyvMClf5iI4WNyU1hAAwQ9Ga0aE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZUXZR/tT; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZUXZR/tT" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AAFB5C2BD10; Tue, 11 Jun 2024 11:22:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1718104962; bh=3y99euo6n8eFZJR8v++gmH8KVI8lf89SzvuCaM8aVhU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZUXZR/tTbTFd4TpSl6UZwXultD4I8AccyhIlnKzCiPbnT6T4DxDMp1Jm36STlMqJK Gw/3AX74VuAJ9GiazMt3U56b49c2N6ZBPn78J9ca/Yk8GsU21Gl/t99Uu/jKsLzgGm ycmYr/DwmTr7EDxhCydp+A4i55bhbH7a1b5ChcRHtCXUA4cyUzyBmyLi7Tsg7q7P/Z rYDQ7LP2a1li8O7Cs+5ce8j2/rly3ULS4czaUn5GoK27skwG7cQrjljoPvRQsMB5Wf 3d812uAvKrxZ59bC62hO2TPT2OGyEQUYQYN4RTYf1XRFmD4Q6wf73yQ0DhRcoV8E2P ozUN3IRhw0nEA== From: Jiri Olsa To: Steven Rostedt , Masami Hiramatsu , Oleg Nesterov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-api@vger.kernel.org, linux-man@vger.kernel.org, x86@kernel.org, bpf@vger.kernel.org, Song Liu , Yonghong Song , John Fastabend , Peter Zijlstra , Thomas Gleixner , "Borislav Petkov (AMD)" , Ingo Molnar , Andy Lutomirski , "Edgecombe, Rick P" , Deepak Gupta Subject: [PATCHv8 bpf-next 3/9] uprobe: Add uretprobe syscall to speed up return probe Date: Tue, 11 Jun 2024 13:21:52 +0200 Message-ID: <20240611112158.40795-4-jolsa@kernel.org> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240611112158.40795-1-jolsa@kernel.org> References: <20240611112158.40795-1-jolsa@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Adding uretprobe syscall instead of trap to speed up return probe. At the moment the uretprobe setup/path is: - install entry uprobe - when the uprobe is hit, it overwrites probed function's return address on stack with address of the trampoline that contains breakpoint instruction - the breakpoint trap code handles the uretprobe consumers execution and jumps back to original return address This patch replaces the above trampoline's breakpoint instruction with new ureprobe syscall call. This syscall does exactly the same job as the trap with some more extra work: - syscall trampoline must save original value for rax/r11/rcx registers on stack - rax is set to syscall number and r11/rcx are changed and used by syscall instruction - the syscall code reads the original values of those registers and restore those values in task's pt_regs area - only caller from trampoline exposed in '[uprobes]' is allowed, the process will receive SIGILL signal otherwise Even with some extra work, using the uretprobes syscall shows speed improvement (compared to using standard breakpoint): On Intel (11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz) current: uretprobe-nop : 1.498 ± 0.000M/s uretprobe-push : 1.448 ± 0.001M/s uretprobe-ret : 0.816 ± 0.001M/s with the fix: uretprobe-nop : 1.969 ± 0.002M/s < 31% speed up uretprobe-push : 1.910 ± 0.000M/s < 31% speed up uretprobe-ret : 0.934 ± 0.000M/s < 14% speed up On Amd (AMD Ryzen 7 5700U) current: uretprobe-nop : 0.778 ± 0.001M/s uretprobe-push : 0.744 ± 0.001M/s uretprobe-ret : 0.540 ± 0.001M/s with the fix: uretprobe-nop : 0.860 ± 0.001M/s < 10% speed up uretprobe-push : 0.818 ± 0.001M/s < 10% speed up uretprobe-ret : 0.578 ± 0.000M/s < 7% speed up The performance test spawns a thread that runs loop which triggers uprobe with attached bpf program that increments the counter that gets printed in results above. The uprobe (and uretprobe) kind is determined by which instruction is being patched with breakpoint instruction. That's also important for uretprobes, because uprobe is installed for each uretprobe. The performance test is part of bpf selftests: tools/testing/selftests/bpf/run_bench_uprobes.sh Note at the moment uretprobe syscall is supported only for native 64-bit process, compat process still uses standard breakpoint. Note that when shadow stack is enabled the uretprobe syscall returns via iret, which is slower than return via sysret, but won't cause the shadow stack violation. Suggested-by: Andrii Nakryiko Reviewed-by: Oleg Nesterov Reviewed-by: Masami Hiramatsu (Google) Acked-by: Andrii Nakryiko Signed-off-by: Oleg Nesterov Signed-off-by: Jiri Olsa Tested-by: Nathan Chancellor # build --- arch/x86/include/asm/shstk.h | 2 + arch/x86/kernel/shstk.c | 5 ++ arch/x86/kernel/uprobes.c | 117 +++++++++++++++++++++++++++++++++++ include/linux/uprobes.h | 3 + kernel/events/uprobes.c | 24 ++++--- 5 files changed, 144 insertions(+), 7 deletions(-) diff --git a/arch/x86/include/asm/shstk.h b/arch/x86/include/asm/shstk.h index 896909f306e3..4cb77e004615 100644 --- a/arch/x86/include/asm/shstk.h +++ b/arch/x86/include/asm/shstk.h @@ -22,6 +22,7 @@ void shstk_free(struct task_struct *p); int setup_signal_shadow_stack(struct ksignal *ksig); int restore_signal_shadow_stack(void); int shstk_update_last_frame(unsigned long val); +bool shstk_is_enabled(void); #else static inline long shstk_prctl(struct task_struct *task, int option, unsigned long arg2) { return -EINVAL; } @@ -33,6 +34,7 @@ static inline void shstk_free(struct task_struct *p) {} static inline int setup_signal_shadow_stack(struct ksignal *ksig) { return 0; } static inline int restore_signal_shadow_stack(void) { return 0; } static inline int shstk_update_last_frame(unsigned long val) { return 0; } +static inline bool shstk_is_enabled(void) { return false; } #endif /* CONFIG_X86_USER_SHADOW_STACK */ #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/kernel/shstk.c b/arch/x86/kernel/shstk.c index 9797d4cdb78a..059685612362 100644 --- a/arch/x86/kernel/shstk.c +++ b/arch/x86/kernel/shstk.c @@ -588,3 +588,8 @@ int shstk_update_last_frame(unsigned long val) ssp = get_user_shstk_addr(); return write_user_shstk_64((u64 __user *)ssp, (u64)val); } + +bool shstk_is_enabled(void) +{ + return features_enabled(ARCH_SHSTK_SHSTK); +} diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index 6402fb3089d2..5a952c5ea66b 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -308,6 +309,122 @@ static int uprobe_init_insn(struct arch_uprobe *auprobe, struct insn *insn, bool } #ifdef CONFIG_X86_64 + +asm ( + ".pushsection .rodata\n" + ".global uretprobe_trampoline_entry\n" + "uretprobe_trampoline_entry:\n" + "pushq %rax\n" + "pushq %rcx\n" + "pushq %r11\n" + "movq $" __stringify(__NR_uretprobe) ", %rax\n" + "syscall\n" + ".global uretprobe_syscall_check\n" + "uretprobe_syscall_check:\n" + "popq %r11\n" + "popq %rcx\n" + + /* The uretprobe syscall replaces stored %rax value with final + * return address, so we don't restore %rax in here and just + * call ret. + */ + "retq\n" + ".global uretprobe_trampoline_end\n" + "uretprobe_trampoline_end:\n" + ".popsection\n" +); + +extern u8 uretprobe_trampoline_entry[]; +extern u8 uretprobe_trampoline_end[]; +extern u8 uretprobe_syscall_check[]; + +void *arch_uprobe_trampoline(unsigned long *psize) +{ + static uprobe_opcode_t insn = UPROBE_SWBP_INSN; + struct pt_regs *regs = task_pt_regs(current); + + /* + * At the moment the uretprobe syscall trampoline is supported + * only for native 64-bit process, the compat process still uses + * standard breakpoint. + */ + if (user_64bit_mode(regs)) { + *psize = uretprobe_trampoline_end - uretprobe_trampoline_entry; + return uretprobe_trampoline_entry; + } + + *psize = UPROBE_SWBP_INSN_SIZE; + return &insn; +} + +static unsigned long trampoline_check_ip(void) +{ + unsigned long tramp = uprobe_get_trampoline_vaddr(); + + return tramp + (uretprobe_syscall_check - uretprobe_trampoline_entry); +} + +SYSCALL_DEFINE0(uretprobe) +{ + struct pt_regs *regs = task_pt_regs(current); + unsigned long err, ip, sp, r11_cx_ax[3]; + + if (regs->ip != trampoline_check_ip()) + goto sigill; + + err = copy_from_user(r11_cx_ax, (void __user *)regs->sp, sizeof(r11_cx_ax)); + if (err) + goto sigill; + + /* expose the "right" values of r11/cx/ax/sp to uprobe_consumer/s */ + regs->r11 = r11_cx_ax[0]; + regs->cx = r11_cx_ax[1]; + regs->ax = r11_cx_ax[2]; + regs->sp += sizeof(r11_cx_ax); + regs->orig_ax = -1; + + ip = regs->ip; + sp = regs->sp; + + uprobe_handle_trampoline(regs); + + /* + * Some of the uprobe consumers has changed sp, we can do nothing, + * just return via iret. + * .. or shadow stack is enabled, in which case we need to skip + * return through the user space stack address. + */ + if (regs->sp != sp || shstk_is_enabled()) + return regs->ax; + regs->sp -= sizeof(r11_cx_ax); + + /* for the case uprobe_consumer has changed r11/cx */ + r11_cx_ax[0] = regs->r11; + r11_cx_ax[1] = regs->cx; + + /* + * ax register is passed through as return value, so we can use + * its space on stack for ip value and jump to it through the + * trampoline's ret instruction + */ + r11_cx_ax[2] = regs->ip; + regs->ip = ip; + + err = copy_to_user((void __user *)regs->sp, r11_cx_ax, sizeof(r11_cx_ax)); + if (err) + goto sigill; + + /* ensure sysret, see do_syscall_64() */ + regs->r11 = regs->flags; + regs->cx = regs->ip; + + return regs->ax; + +sigill: + force_sig(SIGILL); + return -1; +} + /* * If arch_uprobe->insn doesn't use rip-relative addressing, return * immediately. Otherwise, rewrite the instruction so that it accesses diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index f46e0ca0169c..b503fafb7fb3 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h @@ -138,6 +138,9 @@ extern bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check c extern bool arch_uprobe_ignore(struct arch_uprobe *aup, struct pt_regs *regs); extern void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, void *src, unsigned long len); +extern void uprobe_handle_trampoline(struct pt_regs *regs); +extern void *arch_uprobe_trampoline(unsigned long *psize); +extern unsigned long uprobe_get_trampoline_vaddr(void); #else /* !CONFIG_UPROBES */ struct uprobes_state { }; diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 2c83ba776fc7..2816e65729ac 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -1474,11 +1474,20 @@ static int xol_add_vma(struct mm_struct *mm, struct xol_area *area) return ret; } +void * __weak arch_uprobe_trampoline(unsigned long *psize) +{ + static uprobe_opcode_t insn = UPROBE_SWBP_INSN; + + *psize = UPROBE_SWBP_INSN_SIZE; + return &insn; +} + static struct xol_area *__create_xol_area(unsigned long vaddr) { struct mm_struct *mm = current->mm; - uprobe_opcode_t insn = UPROBE_SWBP_INSN; + unsigned long insns_size; struct xol_area *area; + void *insns; area = kmalloc(sizeof(*area), GFP_KERNEL); if (unlikely(!area)) @@ -1502,7 +1511,8 @@ static struct xol_area *__create_xol_area(unsigned long vaddr) /* Reserve the 1st slot for get_trampoline_vaddr() */ set_bit(0, area->bitmap); atomic_set(&area->slot_count, 1); - arch_uprobe_copy_ixol(area->pages[0], 0, &insn, UPROBE_SWBP_INSN_SIZE); + insns = arch_uprobe_trampoline(&insns_size); + arch_uprobe_copy_ixol(area->pages[0], 0, insns, insns_size); if (!xol_add_vma(mm, area)) return area; @@ -1827,7 +1837,7 @@ void uprobe_copy_process(struct task_struct *t, unsigned long flags) * * Returns -1 in case the xol_area is not allocated. */ -static unsigned long get_trampoline_vaddr(void) +unsigned long uprobe_get_trampoline_vaddr(void) { struct xol_area *area; unsigned long trampoline_vaddr = -1; @@ -1878,7 +1888,7 @@ static void prepare_uretprobe(struct uprobe *uprobe, struct pt_regs *regs) if (!ri) return; - trampoline_vaddr = get_trampoline_vaddr(); + trampoline_vaddr = uprobe_get_trampoline_vaddr(); orig_ret_vaddr = arch_uretprobe_hijack_return_addr(trampoline_vaddr, regs); if (orig_ret_vaddr == -1) goto fail; @@ -2123,7 +2133,7 @@ static struct return_instance *find_next_ret_chain(struct return_instance *ri) return ri; } -static void handle_trampoline(struct pt_regs *regs) +void uprobe_handle_trampoline(struct pt_regs *regs) { struct uprobe_task *utask; struct return_instance *ri, *next; @@ -2187,8 +2197,8 @@ static void handle_swbp(struct pt_regs *regs) int is_swbp; bp_vaddr = uprobe_get_swbp_addr(regs); - if (bp_vaddr == get_trampoline_vaddr()) - return handle_trampoline(regs); + if (bp_vaddr == uprobe_get_trampoline_vaddr()) + return uprobe_handle_trampoline(regs); uprobe = find_active_uprobe(bp_vaddr, &is_swbp); if (!uprobe) { From patchwork Tue Jun 11 11:21:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiri Olsa X-Patchwork-Id: 13693473 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 352F617B406; Tue, 11 Jun 2024 11:22:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718104975; cv=none; b=RydroMzldWIiLkikdjdhE7Eif66Ta/czf7zfMkfn5LSQFaR2kZc8h+JZgg+DQqwBSC/FKBQUNSypGNQBnRKgPnoSmoJdm5X6kUBt8TCgKMEqeV6oG69Gjox8/7ZnC8uCL0RCMZL4gNW/zeNwEUF8T1OjwHw2MwKgHpHrfuwGW8k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718104975; c=relaxed/simple; bh=uOz/aMSFQPquNtZuA2x4QffKF4wgRighKr2eGEBffRo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ad1Q2GrtOAj+oUElJUxmS8RRp78TNnXhxWhSmypO0t/nvl+z8iXst8gnFILhEucxjzGSejAvH43lkvXaGgmT5MlfykOLRW8KGbJSLFRHUBJsK2KT5hI9g5wGoX+KOpiy/CqLig79HoeFaBznrDIUlRDOSfbDtyNUlTNcJQzoxgg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=C6PPmhS0; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="C6PPmhS0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id F32E6C2BD10; Tue, 11 Jun 2024 11:22:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1718104975; bh=uOz/aMSFQPquNtZuA2x4QffKF4wgRighKr2eGEBffRo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=C6PPmhS0yMaw7TLJPy9/H9OLmF9VRJXlwCsSO7AS4NCWNlsWUHqqX+g/LWbOAwxuo spgegUBvy270a4/PpV2jDFb/n0thCGeuRos8dTBpScXqQs6Gz30aT8ze7fuQSe0JtD jf99lYJDf4+LzDQRmZzAY5/J5wg7nsgz3dciYCSWE+BUTe2A5X0btuEyotNfdJxzzw YhUe9hoiGDB5yV1z9SzQFD6xQHT4ug6lAqhUlwYcKYk5L6XaQHHPgynGH8EJzX+j+Q OFGcWuByCNCyO3rkgvLbnzbGFUgAg912Z0Y51ZsmqbSyEQVmBGODJqj7+DQPxrgYTo 64msYDsQiioiQ== From: Jiri Olsa To: Steven Rostedt , Masami Hiramatsu , Oleg Nesterov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-api@vger.kernel.org, linux-man@vger.kernel.org, x86@kernel.org, bpf@vger.kernel.org, Song Liu , Yonghong Song , John Fastabend , Peter Zijlstra , Thomas Gleixner , "Borislav Petkov (AMD)" , Ingo Molnar , Andy Lutomirski , "Edgecombe, Rick P" , Deepak Gupta Subject: [PATCHv8 bpf-next 4/9] selftests/x86: Add return uprobe shadow stack test Date: Tue, 11 Jun 2024 13:21:53 +0200 Message-ID: <20240611112158.40795-5-jolsa@kernel.org> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240611112158.40795-1-jolsa@kernel.org> References: <20240611112158.40795-1-jolsa@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Adding return uprobe test for shadow stack and making sure it's working properly. Borrowed some of the code from bpf selftests. Acked-by: Andrii Nakryiko Signed-off-by: Jiri Olsa --- .../testing/selftests/x86/test_shadow_stack.c | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/tools/testing/selftests/x86/test_shadow_stack.c b/tools/testing/selftests/x86/test_shadow_stack.c index ee909a7927f9..21af54d5f4ea 100644 --- a/tools/testing/selftests/x86/test_shadow_stack.c +++ b/tools/testing/selftests/x86/test_shadow_stack.c @@ -34,6 +34,7 @@ #include #include #include +#include /* * Define the ABI defines if needed, so people can run the tests @@ -734,6 +735,144 @@ int test_32bit(void) return !segv_triggered; } +static int parse_uint_from_file(const char *file, const char *fmt) +{ + int err, ret; + FILE *f; + + f = fopen(file, "re"); + if (!f) { + err = -errno; + printf("failed to open '%s': %d\n", file, err); + return err; + } + err = fscanf(f, fmt, &ret); + if (err != 1) { + err = err == EOF ? -EIO : -errno; + printf("failed to parse '%s': %d\n", file, err); + fclose(f); + return err; + } + fclose(f); + return ret; +} + +static int determine_uprobe_perf_type(void) +{ + const char *file = "/sys/bus/event_source/devices/uprobe/type"; + + return parse_uint_from_file(file, "%d\n"); +} + +static int determine_uprobe_retprobe_bit(void) +{ + const char *file = "/sys/bus/event_source/devices/uprobe/format/retprobe"; + + return parse_uint_from_file(file, "config:%d\n"); +} + +static ssize_t get_uprobe_offset(const void *addr) +{ + size_t start, end, base; + char buf[256]; + bool found = false; + FILE *f; + + f = fopen("/proc/self/maps", "r"); + if (!f) + return -errno; + + while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &base) == 4) { + if (buf[2] == 'x' && (uintptr_t)addr >= start && (uintptr_t)addr < end) { + found = true; + break; + } + } + + fclose(f); + + if (!found) + return -ESRCH; + + return (uintptr_t)addr - start + base; +} + +static __attribute__((noinline)) void uretprobe_trigger(void) +{ + asm volatile (""); +} + +/* + * This test setups return uprobe, which is sensitive to shadow stack + * (crashes without extra fix). After executing the uretprobe we fail + * the test if we receive SIGSEGV, no crash means we're good. + * + * Helper functions above borrowed from bpf selftests. + */ +static int test_uretprobe(void) +{ + const size_t attr_sz = sizeof(struct perf_event_attr); + const char *file = "/proc/self/exe"; + int bit, fd = 0, type, err = 1; + struct perf_event_attr attr; + struct sigaction sa = {}; + ssize_t offset; + + type = determine_uprobe_perf_type(); + if (type < 0) { + if (type == -ENOENT) + printf("[SKIP]\tUretprobe test, uprobes are not available\n"); + return 0; + } + + offset = get_uprobe_offset(uretprobe_trigger); + if (offset < 0) + return 1; + + bit = determine_uprobe_retprobe_bit(); + if (bit < 0) + return 1; + + sa.sa_sigaction = segv_gp_handler; + sa.sa_flags = SA_SIGINFO; + if (sigaction(SIGSEGV, &sa, NULL)) + return 1; + + /* Setup return uprobe through perf event interface. */ + memset(&attr, 0, attr_sz); + attr.size = attr_sz; + attr.type = type; + attr.config = 1 << bit; + attr.config1 = (__u64) (unsigned long) file; + attr.config2 = offset; + + fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */, -1 /* cpu */, + -1 /* group_fd */, PERF_FLAG_FD_CLOEXEC); + if (fd < 0) + goto out; + + if (sigsetjmp(jmp_buffer, 1)) + goto out; + + ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK); + + /* + * This either segfaults and goes through sigsetjmp above + * or succeeds and we're good. + */ + uretprobe_trigger(); + + printf("[OK]\tUretprobe test\n"); + err = 0; + +out: + ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK); + signal(SIGSEGV, SIG_DFL); + if (fd) + close(fd); + return err; +} + void segv_handler_ptrace(int signum, siginfo_t *si, void *uc) { /* The SSP adjustment caused a segfault. */ @@ -926,6 +1065,12 @@ int main(int argc, char *argv[]) goto out; } + if (test_uretprobe()) { + ret = 1; + printf("[FAIL]\turetprobe test\n"); + goto out; + } + return ret; out: From patchwork Tue Jun 11 11:21:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiri Olsa X-Patchwork-Id: 13693474 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6165817B403; Tue, 11 Jun 2024 11:23:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718104987; cv=none; b=EQcYl7rw9bSEOAmQOxNYHn0227mYPZ9+EhAeJia/qfUpZsdApirmN5DcQtHf+cgB7vD5EVvFs1DSs5P8/orRQUFkARM8cEh29WqVC2dZx5gc5QyN5DlSWGeDaHYtWf+KujDXr6SaSiI3nVDg7jGa/tuR1vG4N/+xnnr2JRlxWvQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718104987; c=relaxed/simple; bh=BpIC4CY6jG2Qh7cRyNfjpwXNpkOKGT8Ien2/8kajnC8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=j5StTqbH5wi6LmmhpkQ4BNGcnRCBnAIAskTccYJgj4FxkNmaieTx93xPcQkquUdvnixBy8QIs3yNzEpa+rS2UmTOrsjyp5ZWgePdZgif21mmlvfdVLEUHiOJVLgPzodIT+EKlvAneuF5E/IhC9VaB9CTgOpGieEwIGD2wWgZ0io= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=XYjy51ls; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="XYjy51ls" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 79F62C2BD10; Tue, 11 Jun 2024 11:23:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1718104987; bh=BpIC4CY6jG2Qh7cRyNfjpwXNpkOKGT8Ien2/8kajnC8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XYjy51lse6g7pKbxc0MnsUb30BSLctC31JCN2EYi3p4hWSWBriDtmtfTiTUZ1PRUz oIvLjX13Y+AHso8G08O6QNpUdrvfZYMz7+LxIc/ew2+u1wdgTxVwtmfmzubmE5nb4I DyAXlZ9XM/+q3HSyF5in8kP2xkzEIBhPArx7kXoSj6QaVT/mu+NOu7rC3RQzJafDmx 5SdFJCJXyL/TvkKlBt9g1iJmXz99TpCUUceAWKDS4scMsMa5/nGvOezCpJImXlgfT/ 7s+fkxoksVBxruRzx6P2SEVQ9M/lxvwzSLkTW+PutyiKyMpKE94qAy57lcC+u529cQ ygFxhHm8DTWhw== From: Jiri Olsa To: Steven Rostedt , Masami Hiramatsu , Oleg Nesterov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-api@vger.kernel.org, linux-man@vger.kernel.org, x86@kernel.org, bpf@vger.kernel.org, Song Liu , Yonghong Song , John Fastabend , Peter Zijlstra , Thomas Gleixner , "Borislav Petkov (AMD)" , Ingo Molnar , Andy Lutomirski , "Edgecombe, Rick P" , Deepak Gupta Subject: [PATCHv8 bpf-next 5/9] selftests/bpf: Add uretprobe syscall test for regs integrity Date: Tue, 11 Jun 2024 13:21:54 +0200 Message-ID: <20240611112158.40795-6-jolsa@kernel.org> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240611112158.40795-1-jolsa@kernel.org> References: <20240611112158.40795-1-jolsa@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add uretprobe syscall test that compares register values before and after the uretprobe is hit. It also compares the register values seen from attached bpf program. Acked-by: Andrii Nakryiko Reviewed-by: Masami Hiramatsu (Google) Signed-off-by: Jiri Olsa --- tools/include/linux/compiler.h | 4 + .../selftests/bpf/prog_tests/uprobe_syscall.c | 163 ++++++++++++++++++ .../selftests/bpf/progs/uprobe_syscall.c | 15 ++ 3 files changed, 182 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c create mode 100644 tools/testing/selftests/bpf/progs/uprobe_syscall.c diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h index 8a63a9913495..6f7f22ac9da5 100644 --- a/tools/include/linux/compiler.h +++ b/tools/include/linux/compiler.h @@ -62,6 +62,10 @@ #define __nocf_check __attribute__((nocf_check)) #endif +#ifndef __naked +#define __naked __attribute__((__naked__)) +#endif + /* Are two types/vars the same type (ignoring qualifiers)? */ #ifndef __same_type # define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c new file mode 100644 index 000000000000..311ac19d8992 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +#ifdef __x86_64__ + +#include +#include +#include +#include "uprobe_syscall.skel.h" + +__naked unsigned long uretprobe_regs_trigger(void) +{ + asm volatile ( + "movq $0xdeadbeef, %rax\n" + "ret\n" + ); +} + +__naked void uretprobe_regs(struct pt_regs *before, struct pt_regs *after) +{ + asm volatile ( + "movq %r15, 0(%rdi)\n" + "movq %r14, 8(%rdi)\n" + "movq %r13, 16(%rdi)\n" + "movq %r12, 24(%rdi)\n" + "movq %rbp, 32(%rdi)\n" + "movq %rbx, 40(%rdi)\n" + "movq %r11, 48(%rdi)\n" + "movq %r10, 56(%rdi)\n" + "movq %r9, 64(%rdi)\n" + "movq %r8, 72(%rdi)\n" + "movq %rax, 80(%rdi)\n" + "movq %rcx, 88(%rdi)\n" + "movq %rdx, 96(%rdi)\n" + "movq %rsi, 104(%rdi)\n" + "movq %rdi, 112(%rdi)\n" + "movq $0, 120(%rdi)\n" /* orig_rax */ + "movq $0, 128(%rdi)\n" /* rip */ + "movq $0, 136(%rdi)\n" /* cs */ + "pushf\n" + "pop %rax\n" + "movq %rax, 144(%rdi)\n" /* eflags */ + "movq %rsp, 152(%rdi)\n" /* rsp */ + "movq $0, 160(%rdi)\n" /* ss */ + + /* save 2nd argument */ + "pushq %rsi\n" + "call uretprobe_regs_trigger\n" + + /* save return value and load 2nd argument pointer to rax */ + "pushq %rax\n" + "movq 8(%rsp), %rax\n" + + "movq %r15, 0(%rax)\n" + "movq %r14, 8(%rax)\n" + "movq %r13, 16(%rax)\n" + "movq %r12, 24(%rax)\n" + "movq %rbp, 32(%rax)\n" + "movq %rbx, 40(%rax)\n" + "movq %r11, 48(%rax)\n" + "movq %r10, 56(%rax)\n" + "movq %r9, 64(%rax)\n" + "movq %r8, 72(%rax)\n" + "movq %rcx, 88(%rax)\n" + "movq %rdx, 96(%rax)\n" + "movq %rsi, 104(%rax)\n" + "movq %rdi, 112(%rax)\n" + "movq $0, 120(%rax)\n" /* orig_rax */ + "movq $0, 128(%rax)\n" /* rip */ + "movq $0, 136(%rax)\n" /* cs */ + + /* restore return value and 2nd argument */ + "pop %rax\n" + "pop %rsi\n" + + "movq %rax, 80(%rsi)\n" + + "pushf\n" + "pop %rax\n" + + "movq %rax, 144(%rsi)\n" /* eflags */ + "movq %rsp, 152(%rsi)\n" /* rsp */ + "movq $0, 160(%rsi)\n" /* ss */ + "ret\n" +); +} + +static void test_uretprobe_regs_equal(void) +{ + struct uprobe_syscall *skel = NULL; + struct pt_regs before = {}, after = {}; + unsigned long *pb = (unsigned long *) &before; + unsigned long *pa = (unsigned long *) &after; + unsigned long *pp; + unsigned int i, cnt; + int err; + + skel = uprobe_syscall__open_and_load(); + if (!ASSERT_OK_PTR(skel, "uprobe_syscall__open_and_load")) + goto cleanup; + + err = uprobe_syscall__attach(skel); + if (!ASSERT_OK(err, "uprobe_syscall__attach")) + goto cleanup; + + uretprobe_regs(&before, &after); + + pp = (unsigned long *) &skel->bss->regs; + cnt = sizeof(before)/sizeof(*pb); + + for (i = 0; i < cnt; i++) { + unsigned int offset = i * sizeof(unsigned long); + + /* + * Check register before and after uretprobe_regs_trigger call + * that triggers the uretprobe. + */ + switch (offset) { + case offsetof(struct pt_regs, rax): + ASSERT_EQ(pa[i], 0xdeadbeef, "return value"); + break; + default: + if (!ASSERT_EQ(pb[i], pa[i], "register before-after value check")) + fprintf(stdout, "failed register offset %u\n", offset); + } + + /* + * Check register seen from bpf program and register after + * uretprobe_regs_trigger call + */ + switch (offset) { + /* + * These values will be different (not set in uretprobe_regs), + * we don't care. + */ + case offsetof(struct pt_regs, orig_rax): + case offsetof(struct pt_regs, rip): + case offsetof(struct pt_regs, cs): + case offsetof(struct pt_regs, rsp): + case offsetof(struct pt_regs, ss): + break; + default: + if (!ASSERT_EQ(pp[i], pa[i], "register prog-after value check")) + fprintf(stdout, "failed register offset %u\n", offset); + } + } + +cleanup: + uprobe_syscall__destroy(skel); +} +#else +static void test_uretprobe_regs_equal(void) +{ + test__skip(); +} +#endif + +void test_uprobe_syscall(void) +{ + if (test__start_subtest("uretprobe_regs_equal")) + test_uretprobe_regs_equal(); +} diff --git a/tools/testing/selftests/bpf/progs/uprobe_syscall.c b/tools/testing/selftests/bpf/progs/uprobe_syscall.c new file mode 100644 index 000000000000..8a4fa6c7ef59 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/uprobe_syscall.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "vmlinux.h" +#include +#include + +struct pt_regs regs; + +char _license[] SEC("license") = "GPL"; + +SEC("uretprobe//proc/self/exe:uretprobe_regs_trigger") +int uretprobe(struct pt_regs *ctx) +{ + __builtin_memcpy(®s, ctx, sizeof(regs)); + return 0; +} From patchwork Tue Jun 11 11:21:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiri Olsa X-Patchwork-Id: 13693475 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D593B17B402; Tue, 11 Jun 2024 11:23:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718105000; cv=none; b=V4LWkRAGeI7tasoNp53Seitpcp5d9VtidLQQZ67GhjcV8iOFPumikVvTBZedS8p8Oir/dfaWSodeQ5qnyT2VMwq04nvGpq2R932CeDs+p7RllUBCAKPnDbW0yoFvlKLX0z+PRRwMoZde0dIZJh15CxeSHXZhk/B2cH3klG5wkAo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718105000; c=relaxed/simple; bh=/rGaUwZojZm+iVZUAVKKmhU9Rybqz7uXbb6C9HW4Hd4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sCedSZyhxhZF9dX/2a91BmZVsezX6ReAMUoCXdJpiaSlFA0iupg6F3QDQTaDuAoZNi+NJkgpXmzk5O2DgDwc3Q04PpqUfiCnZUtB5tbZ+mYEWUee0ddC4U6yVSxpCzI6dn0aLWFEMOulBUHZsJYWzOAMF11kIxXg9mRIHEuixX4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UFIshC4R; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UFIshC4R" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 54AF1C2BD10; Tue, 11 Jun 2024 11:23:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1718104999; bh=/rGaUwZojZm+iVZUAVKKmhU9Rybqz7uXbb6C9HW4Hd4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UFIshC4RaZsaVk6NxvqntoUH/QDMZb7MMrx2y8FviPRHMaR6qKP0WPtyNeofoOe4U m8PEeeu6fHmAGJlSmC/PBjwDh+cLZvb03GPz+rzDGGRcaks3zaDraQOMfnToq1u1NS rKFyTj408jJ8MRTrnhhuXDT9f88kNe+BQkSvQqHj/Q5KzojtyrnMyq9ukM4JYldutB SF0G2tmrTJLVmDg8fOSwrXaEJYbfzCqOLFMgKDR4sH4XpAlJhQwSxy1c908yo63WYS ALVUDADa/XxJ1pMvR0VN4Cf3CHdOtN8KJcmmwPEz6K5sRpnrQZLLPylUdaFxkbVVpS vIGAtT1a/JTvQ== From: Jiri Olsa To: Steven Rostedt , Masami Hiramatsu , Oleg Nesterov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-api@vger.kernel.org, linux-man@vger.kernel.org, x86@kernel.org, bpf@vger.kernel.org, Song Liu , Yonghong Song , John Fastabend , Peter Zijlstra , Thomas Gleixner , "Borislav Petkov (AMD)" , Ingo Molnar , Andy Lutomirski , "Edgecombe, Rick P" , Deepak Gupta Subject: [PATCHv8 bpf-next 6/9] selftests/bpf: Add uretprobe syscall test for regs changes Date: Tue, 11 Jun 2024 13:21:55 +0200 Message-ID: <20240611112158.40795-7-jolsa@kernel.org> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240611112158.40795-1-jolsa@kernel.org> References: <20240611112158.40795-1-jolsa@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Adding test that creates uprobe consumer on uretprobe which changes some of the registers. Making sure the changed registers are propagated to the user space when the ureptobe syscall trampoline is used on x86_64. To be able to do this, adding support to bpf_testmod to create uprobe via new attribute file: /sys/kernel/bpf_testmod_uprobe This file is expecting file offset and creates related uprobe on current process exe file and removes existing uprobe if offset is 0. The can be only single uprobe at any time. The uprobe has specific consumer that changes registers used in ureprobe syscall trampoline and which are later checked in the test. Acked-by: Andrii Nakryiko Reviewed-by: Masami Hiramatsu (Google) Signed-off-by: Jiri Olsa --- .../selftests/bpf/bpf_testmod/bpf_testmod.c | 123 +++++++++++++++++- .../selftests/bpf/prog_tests/uprobe_syscall.c | 67 ++++++++++ 2 files changed, 189 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c index 0a09732cde4b..6cbbecb1e23c 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "bpf_testmod.h" #include "bpf_testmod_kfunc.h" @@ -358,6 +359,119 @@ static struct bin_attribute bin_attr_bpf_testmod_file __ro_after_init = { .write = bpf_testmod_test_write, }; +/* bpf_testmod_uprobe sysfs attribute is so far enabled for x86_64 only, + * please see test_uretprobe_regs_change test + */ +#ifdef __x86_64__ + +static int +uprobe_ret_handler(struct uprobe_consumer *self, unsigned long func, + struct pt_regs *regs) + +{ + regs->ax = 0x12345678deadbeef; + regs->cx = 0x87654321feebdaed; + regs->r11 = (u64) -1; + return true; +} + +struct testmod_uprobe { + struct path path; + loff_t offset; + struct uprobe_consumer consumer; +}; + +static DEFINE_MUTEX(testmod_uprobe_mutex); + +static struct testmod_uprobe uprobe = { + .consumer.ret_handler = uprobe_ret_handler, +}; + +static int testmod_register_uprobe(loff_t offset) +{ + int err = -EBUSY; + + if (uprobe.offset) + return -EBUSY; + + mutex_lock(&testmod_uprobe_mutex); + + if (uprobe.offset) + goto out; + + err = kern_path("/proc/self/exe", LOOKUP_FOLLOW, &uprobe.path); + if (err) + goto out; + + err = uprobe_register_refctr(d_real_inode(uprobe.path.dentry), + offset, 0, &uprobe.consumer); + if (err) + path_put(&uprobe.path); + else + uprobe.offset = offset; + +out: + mutex_unlock(&testmod_uprobe_mutex); + return err; +} + +static void testmod_unregister_uprobe(void) +{ + mutex_lock(&testmod_uprobe_mutex); + + if (uprobe.offset) { + uprobe_unregister(d_real_inode(uprobe.path.dentry), + uprobe.offset, &uprobe.consumer); + uprobe.offset = 0; + } + + mutex_unlock(&testmod_uprobe_mutex); +} + +static ssize_t +bpf_testmod_uprobe_write(struct file *file, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t len) +{ + unsigned long offset = 0; + int err = 0; + + if (kstrtoul(buf, 0, &offset)) + return -EINVAL; + + if (offset) + err = testmod_register_uprobe(offset); + else + testmod_unregister_uprobe(); + + return err ?: strlen(buf); +} + +static struct bin_attribute bin_attr_bpf_testmod_uprobe_file __ro_after_init = { + .attr = { .name = "bpf_testmod_uprobe", .mode = 0666, }, + .write = bpf_testmod_uprobe_write, +}; + +static int register_bpf_testmod_uprobe(void) +{ + return sysfs_create_bin_file(kernel_kobj, &bin_attr_bpf_testmod_uprobe_file); +} + +static void unregister_bpf_testmod_uprobe(void) +{ + testmod_unregister_uprobe(); + sysfs_remove_bin_file(kernel_kobj, &bin_attr_bpf_testmod_uprobe_file); +} + +#else +static int register_bpf_testmod_uprobe(void) +{ + return 0; +} + +static void unregister_bpf_testmod_uprobe(void) { } +#endif + BTF_KFUNCS_START(bpf_testmod_common_kfunc_ids) BTF_ID_FLAGS(func, bpf_iter_testmod_seq_new, KF_ITER_NEW) BTF_ID_FLAGS(func, bpf_iter_testmod_seq_next, KF_ITER_NEXT | KF_RET_NULL) @@ -912,7 +1026,13 @@ static int bpf_testmod_init(void) return -EINVAL; sock = NULL; mutex_init(&sock_lock); - return sysfs_create_bin_file(kernel_kobj, &bin_attr_bpf_testmod_file); + ret = sysfs_create_bin_file(kernel_kobj, &bin_attr_bpf_testmod_file); + if (ret < 0) + return ret; + ret = register_bpf_testmod_uprobe(); + if (ret < 0) + return ret; + return 0; } static void bpf_testmod_exit(void) @@ -927,6 +1047,7 @@ static void bpf_testmod_exit(void) bpf_kfunc_close_sock(); sysfs_remove_bin_file(kernel_kobj, &bin_attr_bpf_testmod_file); + unregister_bpf_testmod_uprobe(); } module_init(bpf_testmod_init); diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c index 311ac19d8992..1a50cd35205d 100644 --- a/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c @@ -149,15 +149,82 @@ static void test_uretprobe_regs_equal(void) cleanup: uprobe_syscall__destroy(skel); } + +#define BPF_TESTMOD_UPROBE_TEST_FILE "/sys/kernel/bpf_testmod_uprobe" + +static int write_bpf_testmod_uprobe(unsigned long offset) +{ + size_t n, ret; + char buf[30]; + int fd; + + n = sprintf(buf, "%lu", offset); + + fd = open(BPF_TESTMOD_UPROBE_TEST_FILE, O_WRONLY); + if (fd < 0) + return -errno; + + ret = write(fd, buf, n); + close(fd); + return ret != n ? (int) ret : 0; +} + +static void test_uretprobe_regs_change(void) +{ + struct pt_regs before = {}, after = {}; + unsigned long *pb = (unsigned long *) &before; + unsigned long *pa = (unsigned long *) &after; + unsigned long cnt = sizeof(before)/sizeof(*pb); + unsigned int i, err, offset; + + offset = get_uprobe_offset(uretprobe_regs_trigger); + + err = write_bpf_testmod_uprobe(offset); + if (!ASSERT_OK(err, "register_uprobe")) + return; + + uretprobe_regs(&before, &after); + + err = write_bpf_testmod_uprobe(0); + if (!ASSERT_OK(err, "unregister_uprobe")) + return; + + for (i = 0; i < cnt; i++) { + unsigned int offset = i * sizeof(unsigned long); + + switch (offset) { + case offsetof(struct pt_regs, rax): + ASSERT_EQ(pa[i], 0x12345678deadbeef, "rax"); + break; + case offsetof(struct pt_regs, rcx): + ASSERT_EQ(pa[i], 0x87654321feebdaed, "rcx"); + break; + case offsetof(struct pt_regs, r11): + ASSERT_EQ(pa[i], (__u64) -1, "r11"); + break; + default: + if (!ASSERT_EQ(pa[i], pb[i], "register before-after value check")) + fprintf(stdout, "failed register offset %u\n", offset); + } + } +} + #else static void test_uretprobe_regs_equal(void) { test__skip(); } + +static void test_uretprobe_regs_change(void) +{ + test__skip(); +} #endif void test_uprobe_syscall(void) { if (test__start_subtest("uretprobe_regs_equal")) test_uretprobe_regs_equal(); + if (test__start_subtest("uretprobe_regs_change")) + test_uretprobe_regs_change(); } From patchwork Tue Jun 11 11:21:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiri Olsa X-Patchwork-Id: 13693476 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7D48417B43C; Tue, 11 Jun 2024 11:23:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718105011; cv=none; b=U5AbgSwEK9MtG+vpYXkMEz2F30Wd7q8dGSzAT398AhzaAF9MwhsjfqMo9WK9hSrEWz1b4h/qgtUlKLeggKTee676ugJLrJZK/Lqhnmj27AqyMNAC8CB5zekacaUaxFI9w8qsGQIHDnQ2Z4V3cp503bDjBvBG57Ay6TqE1k7tSe0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718105011; c=relaxed/simple; bh=DS7+Hm0OTr8osb55SvuyMe5tP8h/Tdu7u34TgYWZPvY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=F62dBn8OSxiMJydSxHqJ7jIp852aGfQEW9DV4lXFKH06dtUcC3PicPUkWCz+Y8tCB2f6kqA+PPVvhzkFR4jv7LCQiPvpFdyviJqyyd6WDE1FkIFg/OMr5uKsTHsP4N8HpGeYobgb3szzIRkPGc3CggpNErJ/n5DWip/VopYzefo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZDPpeosE; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZDPpeosE" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 96188C2BD10; Tue, 11 Jun 2024 11:23:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1718105011; bh=DS7+Hm0OTr8osb55SvuyMe5tP8h/Tdu7u34TgYWZPvY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZDPpeosE+xJNrxZxbqf+GIQzdu1azY0JaPfrO+WFsnebOBCD9J+ZdvlkdKE1GZ3kY x1FEJB0f2M4nTLyuQ991TK1EDwlRq0YWSvX1clzNuRqV+li1OGR7mx4B0Ay8X9NxxJ x3FR3iiAN3IK8MzqPU83AXPyX7S2IIU2UZXuy4Y4TvhE2Ii6afukrdAGFTlExSzK30 cAJRsBiNBhWkkP3XrVC98aUxQHAsH6Ji5mZlaf7McUjoBpdvGy+4ZhnFPB+ASP3y4t SQbCFiWbuI+Ddr1ibAQ5akPC3T6VWPaPmXkcHSJyDQifFMqh3AkG9jEpjwPuOA9Oa0 lINLeKphbq8vQ== From: Jiri Olsa To: Steven Rostedt , Masami Hiramatsu , Oleg Nesterov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-api@vger.kernel.org, linux-man@vger.kernel.org, x86@kernel.org, bpf@vger.kernel.org, Song Liu , Yonghong Song , John Fastabend , Peter Zijlstra , Thomas Gleixner , "Borislav Petkov (AMD)" , Ingo Molnar , Andy Lutomirski , "Edgecombe, Rick P" , Deepak Gupta Subject: [PATCHv8 bpf-next 7/9] selftests/bpf: Add uretprobe syscall call from user space test Date: Tue, 11 Jun 2024 13:21:56 +0200 Message-ID: <20240611112158.40795-8-jolsa@kernel.org> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240611112158.40795-1-jolsa@kernel.org> References: <20240611112158.40795-1-jolsa@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Adding test to verify that when called from outside of the trampoline provided by kernel, the uretprobe syscall will cause calling process to receive SIGILL signal and the attached bpf program is not executed. Acked-by: Andrii Nakryiko Reviewed-by: Masami Hiramatsu (Google) Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/uprobe_syscall.c | 95 +++++++++++++++++++ .../bpf/progs/uprobe_syscall_executed.c | 17 ++++ 2 files changed, 112 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/uprobe_syscall_executed.c diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c index 1a50cd35205d..11ccd693ef73 100644 --- a/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c @@ -7,7 +7,10 @@ #include #include #include +#include +#include #include "uprobe_syscall.skel.h" +#include "uprobe_syscall_executed.skel.h" __naked unsigned long uretprobe_regs_trigger(void) { @@ -209,6 +212,91 @@ static void test_uretprobe_regs_change(void) } } +#ifndef __NR_uretprobe +#define __NR_uretprobe 463 +#endif + +__naked unsigned long uretprobe_syscall_call_1(void) +{ + /* + * Pretend we are uretprobe trampoline to trigger the return + * probe invocation in order to verify we get SIGILL. + */ + asm volatile ( + "pushq %rax\n" + "pushq %rcx\n" + "pushq %r11\n" + "movq $" __stringify(__NR_uretprobe) ", %rax\n" + "syscall\n" + "popq %r11\n" + "popq %rcx\n" + "retq\n" + ); +} + +__naked unsigned long uretprobe_syscall_call(void) +{ + asm volatile ( + "call uretprobe_syscall_call_1\n" + "retq\n" + ); +} + +static void test_uretprobe_syscall_call(void) +{ + LIBBPF_OPTS(bpf_uprobe_multi_opts, opts, + .retprobe = true, + ); + struct uprobe_syscall_executed *skel; + int pid, status, err, go[2], c; + + if (ASSERT_OK(pipe(go), "pipe")) + return; + + skel = uprobe_syscall_executed__open_and_load(); + if (!ASSERT_OK_PTR(skel, "uprobe_syscall_executed__open_and_load")) + goto cleanup; + + pid = fork(); + if (!ASSERT_GE(pid, 0, "fork")) + goto cleanup; + + /* child */ + if (pid == 0) { + close(go[1]); + + /* wait for parent's kick */ + err = read(go[0], &c, 1); + if (err != 1) + exit(-1); + + uretprobe_syscall_call(); + _exit(0); + } + + skel->links.test = bpf_program__attach_uprobe_multi(skel->progs.test, pid, + "/proc/self/exe", + "uretprobe_syscall_call", &opts); + if (!ASSERT_OK_PTR(skel->links.test, "bpf_program__attach_uprobe_multi")) + goto cleanup; + + /* kick the child */ + write(go[1], &c, 1); + err = waitpid(pid, &status, 0); + ASSERT_EQ(err, pid, "waitpid"); + + /* verify the child got killed with SIGILL */ + ASSERT_EQ(WIFSIGNALED(status), 1, "WIFSIGNALED"); + ASSERT_EQ(WTERMSIG(status), SIGILL, "WTERMSIG"); + + /* verify the uretprobe program wasn't called */ + ASSERT_EQ(skel->bss->executed, 0, "executed"); + +cleanup: + uprobe_syscall_executed__destroy(skel); + close(go[1]); + close(go[0]); +} #else static void test_uretprobe_regs_equal(void) { @@ -219,6 +307,11 @@ static void test_uretprobe_regs_change(void) { test__skip(); } + +static void test_uretprobe_syscall_call(void) +{ + test__skip(); +} #endif void test_uprobe_syscall(void) @@ -227,4 +320,6 @@ void test_uprobe_syscall(void) test_uretprobe_regs_equal(); if (test__start_subtest("uretprobe_regs_change")) test_uretprobe_regs_change(); + if (test__start_subtest("uretprobe_syscall_call")) + test_uretprobe_syscall_call(); } diff --git a/tools/testing/selftests/bpf/progs/uprobe_syscall_executed.c b/tools/testing/selftests/bpf/progs/uprobe_syscall_executed.c new file mode 100644 index 000000000000..0d7f1a7db2e2 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/uprobe_syscall_executed.c @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "vmlinux.h" +#include +#include + +struct pt_regs regs; + +char _license[] SEC("license") = "GPL"; + +int executed = 0; + +SEC("uretprobe.multi") +int test(struct pt_regs *regs) +{ + executed = 1; + return 0; +} From patchwork Tue Jun 11 11:21:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiri Olsa X-Patchwork-Id: 13693477 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7130D17B435; Tue, 11 Jun 2024 11:23:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718105023; cv=none; b=CHkUjUiu8uekNw6DkjSfChXCttKipV5pM6x7Mv7CUPBaTQpaAHiGSYwz+9KG0b6wDff4TgMndv3o2mzyX2n9rsGRx1c8g0o2t8smqLtJ2m1aMXbL6X8CXTGIkRiBqqppaBdUUyi6TE1ZebzsKYQj9aaDZv1VfgjIRtqKsin4vpI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718105023; c=relaxed/simple; bh=kBK6B58Bhm3uiXQkslA98Oc+NYgflR4HydITuxmbZ60=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=diYo6hBN1JIJzH7quvbGzC+rbcegadsJA7+PAqmVYsf124iZQrdFNUspsQyUKo4taT2mPPQh13RmZdyfydnnygXLYtOMUkr7EJ61/nFTK49RMF7T9E6CWiF6X+hRUvyNmBO3WsL1xmttqdE9t5FQ5+NvqYHsWk2DhfcvXQduIOM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UURsNnVW; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UURsNnVW" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5A6F7C2BD10; Tue, 11 Jun 2024 11:23:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1718105023; bh=kBK6B58Bhm3uiXQkslA98Oc+NYgflR4HydITuxmbZ60=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UURsNnVWR31opOrXriepN03nD8Dx7jAHOlXVkSYgqBXCFb01g6w2wAa3LuhYaRYy1 iU39oQCu2vyWqOsw/u87i49jFQW9Nb26HKhj72NwVlXJvPa6PwospB/bxBfTsN7i/R BHA7GQlgoPLrqqg3/WVq/AEJ/exYqwhn7NMhdcHu+LIsTvMmxgKw6ja3OMFrMOz4/L 9hihFD9BAnCbedRRjYKRFmAgl4YX5Xftxbqd3U30G8DMLLKmeCtCeQdyyXh4A7EwCT cE2L0SBeID3yXlK3ZCRI4D2/ao74Dj0KR/Vv0owVvdUQu02EyyX7a1fYSZclhTSjnW qjyjhkqgBV+2g== From: Jiri Olsa To: Steven Rostedt , Masami Hiramatsu , Oleg Nesterov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-api@vger.kernel.org, linux-man@vger.kernel.org, x86@kernel.org, bpf@vger.kernel.org, Song Liu , Yonghong Song , John Fastabend , Peter Zijlstra , Thomas Gleixner , "Borislav Petkov (AMD)" , Ingo Molnar , Andy Lutomirski , "Edgecombe, Rick P" , Deepak Gupta Subject: [PATCHv8 bpf-next 8/9] selftests/bpf: Add uretprobe shadow stack test Date: Tue, 11 Jun 2024 13:21:57 +0200 Message-ID: <20240611112158.40795-9-jolsa@kernel.org> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240611112158.40795-1-jolsa@kernel.org> References: <20240611112158.40795-1-jolsa@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Adding uretprobe shadow stack test that runs all existing uretprobe tests with shadow stack enabled if it's available. Acked-by: Andrii Nakryiko Reviewed-by: Masami Hiramatsu (Google) Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/uprobe_syscall.c | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c index 11ccd693ef73..c8517c8f5313 100644 --- a/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include #include "uprobe_syscall.skel.h" #include "uprobe_syscall_executed.skel.h" @@ -297,6 +300,56 @@ static void test_uretprobe_syscall_call(void) close(go[1]); close(go[0]); } + +/* + * Borrowed from tools/testing/selftests/x86/test_shadow_stack.c. + * + * For use in inline enablement of shadow stack. + * + * The program can't return from the point where shadow stack gets enabled + * because there will be no address on the shadow stack. So it can't use + * syscall() for enablement, since it is a function. + * + * Based on code from nolibc.h. Keep a copy here because this can't pull + * in all of nolibc.h. + */ +#define ARCH_PRCTL(arg1, arg2) \ +({ \ + long _ret; \ + register long _num asm("eax") = __NR_arch_prctl; \ + register long _arg1 asm("rdi") = (long)(arg1); \ + register long _arg2 asm("rsi") = (long)(arg2); \ + \ + asm volatile ( \ + "syscall\n" \ + : "=a"(_ret) \ + : "r"(_arg1), "r"(_arg2), \ + "0"(_num) \ + : "rcx", "r11", "memory", "cc" \ + ); \ + _ret; \ +}) + +#ifndef ARCH_SHSTK_ENABLE +#define ARCH_SHSTK_ENABLE 0x5001 +#define ARCH_SHSTK_DISABLE 0x5002 +#define ARCH_SHSTK_SHSTK (1ULL << 0) +#endif + +static void test_uretprobe_shadow_stack(void) +{ + if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK)) { + test__skip(); + return; + } + + /* Run all of the uretprobe tests. */ + test_uretprobe_regs_equal(); + test_uretprobe_regs_change(); + test_uretprobe_syscall_call(); + + ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK); +} #else static void test_uretprobe_regs_equal(void) { @@ -312,6 +365,11 @@ static void test_uretprobe_syscall_call(void) { test__skip(); } + +static void test_uretprobe_shadow_stack(void) +{ + test__skip(); +} #endif void test_uprobe_syscall(void) @@ -322,4 +380,6 @@ void test_uprobe_syscall(void) test_uretprobe_regs_change(); if (test__start_subtest("uretprobe_syscall_call")) test_uretprobe_syscall_call(); + if (test__start_subtest("uretprobe_shadow_stack")) + test_uretprobe_shadow_stack(); } From patchwork Tue Jun 11 11:21:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiri Olsa X-Patchwork-Id: 13693478 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 295C117A93A; Tue, 11 Jun 2024 11:23:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718105036; cv=none; b=qB35osB5FDT1lFB9hZOnmkr7/TewKob2NFR+GaCsCehWfD3tcvvWN6FtfLb/kGGAloS+4fE/pJhDwC4cqJv7ZnYW5hz8RFFE09WxUSRbQFjd12nvpG6PM1L83hhbnbbR1ppPFS7x6dpzcJym9nzB4Soc70uVPUQVHPCcxo4A9BI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718105036; c=relaxed/simple; bh=/8nbAp1OS2X1ovAw089c1Fq7pMcHWVM163XH0tCI8M0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kXR8+H8ANGn4llM9AH74FTAH00rOAuPwg1VrBRtvrwHhyG92sUCDD6McaS9EXVbsCblMWaBsu9a5vWB+NlOAMKy6WpDDfnpFZgHjhiMGWbGA9zEF2Q5o4KI109YOOnKtd5HgSSWIkIdDS537mHlrXpkAif1H27akKCV9RVeEmXY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=L8D2OKRs; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="L8D2OKRs" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9361EC2BD10; Tue, 11 Jun 2024 11:23:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1718105035; bh=/8nbAp1OS2X1ovAw089c1Fq7pMcHWVM163XH0tCI8M0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=L8D2OKRsMCOkyWAJXAdC5j6d8MlciLvsnlc0yB2gnuY7N4CrjOoZrm9ZVr1CP45FJ oob9F2O+eRZpmi+MvB/dHJem9Sx3Rd412NZ7zGDqU7zfUsO2B9JCnyjWcaQCmI/mPc CckGizsqCttV0oFQX6qDE6MlUjiBEDAJOSwmGTtHptiDsOWm7L3IknfMVtGhXkj+Hd pQHjTqoPnR2DVp/bj6IIreeMAdRtM7dI7LEnNTR4F0DHzKt4rDJ4svOnDvtN+AxBLI 5R8h5P6bg9pXo7KIjTjjjOYslRO3UGf5r3Mg2ydCXFRuUT6FJYrjvb39fxLO1dOjgl +aHb3gK1FZOBg== From: Jiri Olsa To: Steven Rostedt , Masami Hiramatsu , Oleg Nesterov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: Alejandro Colomar , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-api@vger.kernel.org, linux-man@vger.kernel.org, x86@kernel.org, bpf@vger.kernel.org, Song Liu , Yonghong Song , John Fastabend , Peter Zijlstra , Thomas Gleixner , "Borislav Petkov (AMD)" , Ingo Molnar , Andy Lutomirski , "Edgecombe, Rick P" , Deepak Gupta Subject: [PATCHv8 9/9] man2: Add uretprobe syscall page Date: Tue, 11 Jun 2024 13:21:58 +0200 Message-ID: <20240611112158.40795-10-jolsa@kernel.org> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240611112158.40795-1-jolsa@kernel.org> References: <20240611112158.40795-1-jolsa@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Adding man page for new uretprobe syscall. Acked-by: Andrii Nakryiko Reviewed-by: Alejandro Colomar Signed-off-by: Jiri Olsa Reviewed-by: Masami Hiramatsu (Google) Acked-by: From: Jiri Olsa --- man/man2/uretprobe.2 | 56 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 man/man2/uretprobe.2 diff --git a/man/man2/uretprobe.2 b/man/man2/uretprobe.2 new file mode 100644 index 000000000000..cf1c2b0d852e --- /dev/null +++ b/man/man2/uretprobe.2 @@ -0,0 +1,56 @@ +.\" Copyright (C) 2024, Jiri Olsa +.\" +.\" SPDX-License-Identifier: Linux-man-pages-copyleft +.\" +.TH uretprobe 2 (date) "Linux man-pages (unreleased)" +.SH NAME +uretprobe \- execute pending return uprobes +.SH SYNOPSIS +.nf +.B int uretprobe(void) +.fi +.SH DESCRIPTION +The +.BR uretprobe () +system call is an alternative to breakpoint instructions for triggering return +uprobe consumers. +.P +Calls to +.BR uretprobe () +system call are only made from the user-space trampoline provided by the kernel. +Calls from any other place result in a +.BR SIGILL . +.SH RETURN VALUE +The +.BR uretprobe () +system call return value is architecture-specific. +.SH ERRORS +.TP +.B SIGILL +The +.BR uretprobe () +system call was called by a user-space program. +.SH VERSIONS +Details of the +.BR uretprobe () +system call behavior vary across systems. +.SH STANDARDS +None. +.SH HISTORY +TBD +.SH NOTES +The +.BR uretprobe () +system call was initially introduced for the x86_64 architecture +where it was shown to be faster than breakpoint traps. +It might be extended to other architectures. +.P +The +.BR uretprobe () +system call exists only to allow the invocation of return uprobe consumers. +It should +.B never +be called directly. +Details of the arguments (if any) passed to +.BR uretprobe () +and the return value are architecture-specific.