Merge branch 'Fix accessing syscall arguments'
Ilya Leoshkevich says: ==================== libbpf now has macros to access syscall arguments in an architecture-agnostic manner, but unfortunately they have a number of issues on non-Intel arches, which this series aims to fix. v1: https://lore.kernel.org/bpf/20220201234200.1836443-1-iii@linux.ibm.com/ v1 -> v2: * Put orig_gpr2 in place of args[1] on s390 (Vasily). * Fix arm64, powerpc and riscv (Heiko). v2: https://lore.kernel.org/bpf/20220204041955.1958263-1-iii@linux.ibm.com/ v2 -> v3: * Undo args[1] change (Andrii). * Rename PT_REGS_SYSCALL to PT_REGS_SYSCALL_REGS (Andrii). * Split the riscv patch (Andrii). v3: https://lore.kernel.org/bpf/20220204145018.1983773-1-iii@linux.ibm.com/ v3 -> v4: * Undo arm64's and s390's user_pt_regs changes. * Use struct pt_regs when vmlinux.h is available (Andrii). * Use offsetofend for accessing orig_gpr2 and orig_x0 (Andrii). * Move libbpf's copy of offsetofend to a new header. * Fix riscv's __PT_FP_REG. * Use PT_REGS_SYSCALL_REGS in test_probe_user.c. * Test bpf_syscall_macro with userspace headers. * Use Naveen's suggestions and code in patches 5 and 6. * Add warnings to arm64's and s390's ptrace.h (Andrii). v4: https://lore.kernel.org/bpf/20220208051635.2160304-1-iii@linux.ibm.com/ v4 -> v5: * Go back to v3. * Do not touch arch headers. * Use CO-RE struct flavors to access orig_x0 and orig_gpr2. * Fail compilation if non-CO-RE macros are used to access the first syscall parameter on arm64 and s390. * Fix accessing frame pointer on riscv. ==================== Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
This commit is contained in:
commit
8dd039a6fc
|
@ -70,13 +70,15 @@
|
|||
#define __PT_PARM2_REG si
|
||||
#define __PT_PARM3_REG dx
|
||||
#define __PT_PARM4_REG cx
|
||||
#define __PT_PARM4_REG_SYSCALL r10 /* syscall uses r10 */
|
||||
#define __PT_PARM5_REG r8
|
||||
#define __PT_RET_REG sp
|
||||
#define __PT_FP_REG bp
|
||||
#define __PT_RC_REG ax
|
||||
#define __PT_SP_REG sp
|
||||
#define __PT_IP_REG ip
|
||||
/* syscall uses r10 for PARM4 */
|
||||
#define PT_REGS_PARM4_SYSCALL(x) ((x)->r10)
|
||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) BPF_CORE_READ(x, r10)
|
||||
|
||||
#else
|
||||
|
||||
|
@ -100,13 +102,15 @@
|
|||
#define __PT_PARM2_REG rsi
|
||||
#define __PT_PARM3_REG rdx
|
||||
#define __PT_PARM4_REG rcx
|
||||
#define __PT_PARM4_REG_SYSCALL r10 /* syscall uses r10 */
|
||||
#define __PT_PARM5_REG r8
|
||||
#define __PT_RET_REG rsp
|
||||
#define __PT_FP_REG rbp
|
||||
#define __PT_RC_REG rax
|
||||
#define __PT_SP_REG rsp
|
||||
#define __PT_IP_REG rip
|
||||
/* syscall uses r10 for PARM4 */
|
||||
#define PT_REGS_PARM4_SYSCALL(x) ((x)->r10)
|
||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) BPF_CORE_READ(x, r10)
|
||||
|
||||
#endif /* __i386__ */
|
||||
|
||||
|
@ -114,6 +118,10 @@
|
|||
|
||||
#elif defined(bpf_target_s390)
|
||||
|
||||
struct pt_regs___s390 {
|
||||
unsigned long orig_gpr2;
|
||||
};
|
||||
|
||||
/* s390 provides user_pt_regs instead of struct pt_regs to userspace */
|
||||
#define __PT_REGS_CAST(x) ((const user_pt_regs *)(x))
|
||||
#define __PT_PARM1_REG gprs[2]
|
||||
|
@ -126,6 +134,8 @@
|
|||
#define __PT_RC_REG gprs[2]
|
||||
#define __PT_SP_REG gprs[15]
|
||||
#define __PT_IP_REG psw.addr
|
||||
#define PT_REGS_PARM1_SYSCALL(x) ({ _Pragma("GCC error \"use PT_REGS_PARM1_CORE_SYSCALL() instead\""); 0l; })
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) BPF_CORE_READ((const struct pt_regs___s390 *)(x), orig_gpr2)
|
||||
|
||||
#elif defined(bpf_target_arm)
|
||||
|
||||
|
@ -142,6 +152,10 @@
|
|||
|
||||
#elif defined(bpf_target_arm64)
|
||||
|
||||
struct pt_regs___arm64 {
|
||||
unsigned long orig_x0;
|
||||
};
|
||||
|
||||
/* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */
|
||||
#define __PT_REGS_CAST(x) ((const struct user_pt_regs *)(x))
|
||||
#define __PT_PARM1_REG regs[0]
|
||||
|
@ -154,6 +168,8 @@
|
|||
#define __PT_RC_REG regs[0]
|
||||
#define __PT_SP_REG sp
|
||||
#define __PT_IP_REG pc
|
||||
#define PT_REGS_PARM1_SYSCALL(x) ({ _Pragma("GCC error \"use PT_REGS_PARM1_CORE_SYSCALL() instead\""); 0l; })
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) BPF_CORE_READ((const struct pt_regs___arm64 *)(x), orig_x0)
|
||||
|
||||
#elif defined(bpf_target_mips)
|
||||
|
||||
|
@ -180,6 +196,8 @@
|
|||
#define __PT_RC_REG gpr[3]
|
||||
#define __PT_SP_REG sp
|
||||
#define __PT_IP_REG nip
|
||||
/* powerpc does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
||||
#define PT_REGS_SYSCALL_REGS(ctx) ctx
|
||||
|
||||
#elif defined(bpf_target_sparc)
|
||||
|
||||
|
@ -208,10 +226,12 @@
|
|||
#define __PT_PARM4_REG a3
|
||||
#define __PT_PARM5_REG a4
|
||||
#define __PT_RET_REG ra
|
||||
#define __PT_FP_REG fp
|
||||
#define __PT_FP_REG s0
|
||||
#define __PT_RC_REG a5
|
||||
#define __PT_SP_REG sp
|
||||
#define __PT_IP_REG epc
|
||||
#define __PT_IP_REG pc
|
||||
/* riscv does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
||||
#define PT_REGS_SYSCALL_REGS(ctx) ctx
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -265,22 +285,22 @@ struct pt_regs;
|
|||
|
||||
#endif
|
||||
|
||||
#ifndef PT_REGS_PARM1_SYSCALL
|
||||
#define PT_REGS_PARM1_SYSCALL(x) PT_REGS_PARM1(x)
|
||||
#endif
|
||||
#define PT_REGS_PARM2_SYSCALL(x) PT_REGS_PARM2(x)
|
||||
#define PT_REGS_PARM3_SYSCALL(x) PT_REGS_PARM3(x)
|
||||
#ifdef __PT_PARM4_REG_SYSCALL
|
||||
#define PT_REGS_PARM4_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM4_REG_SYSCALL)
|
||||
#else /* __PT_PARM4_REG_SYSCALL */
|
||||
#ifndef PT_REGS_PARM4_SYSCALL
|
||||
#define PT_REGS_PARM4_SYSCALL(x) PT_REGS_PARM4(x)
|
||||
#endif
|
||||
#define PT_REGS_PARM5_SYSCALL(x) PT_REGS_PARM5(x)
|
||||
|
||||
#ifndef PT_REGS_PARM1_CORE_SYSCALL
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) PT_REGS_PARM1_CORE(x)
|
||||
#endif
|
||||
#define PT_REGS_PARM2_CORE_SYSCALL(x) PT_REGS_PARM2_CORE(x)
|
||||
#define PT_REGS_PARM3_CORE_SYSCALL(x) PT_REGS_PARM3_CORE(x)
|
||||
#ifdef __PT_PARM4_REG_SYSCALL
|
||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM4_REG_SYSCALL)
|
||||
#else /* __PT_PARM4_REG_SYSCALL */
|
||||
#ifndef PT_REGS_PARM4_CORE_SYSCALL
|
||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) PT_REGS_PARM4_CORE(x)
|
||||
#endif
|
||||
#define PT_REGS_PARM5_CORE_SYSCALL(x) PT_REGS_PARM5_CORE(x)
|
||||
|
@ -326,6 +346,16 @@ struct pt_regs;
|
|||
|
||||
#endif /* defined(bpf_target_defined) */
|
||||
|
||||
/*
|
||||
* When invoked from a syscall handler kprobe, returns a pointer to a
|
||||
* struct pt_regs containing syscall arguments and suitable for passing to
|
||||
* PT_REGS_PARMn_SYSCALL() and PT_REGS_PARMn_CORE_SYSCALL().
|
||||
*/
|
||||
#ifndef PT_REGS_SYSCALL_REGS
|
||||
/* By default, assume that the arch selects ARCH_HAS_SYSCALL_WRAPPER. */
|
||||
#define PT_REGS_SYSCALL_REGS(ctx) ((struct pt_regs *)PT_REGS_PARM1(ctx))
|
||||
#endif
|
||||
|
||||
#ifndef ___bpf_concat
|
||||
#define ___bpf_concat(a, b) a ## b
|
||||
#endif
|
||||
|
|
|
@ -33,7 +33,11 @@ void test_bpf_syscall_macro(void)
|
|||
|
||||
/* check whether args of syscall are copied correctly */
|
||||
prctl(exp_arg1, exp_arg2, exp_arg3, exp_arg4, exp_arg5);
|
||||
#if defined(__aarch64__) || defined(__s390__)
|
||||
ASSERT_NEQ(skel->bss->arg1, exp_arg1, "syscall_arg1");
|
||||
#else
|
||||
ASSERT_EQ(skel->bss->arg1, exp_arg1, "syscall_arg1");
|
||||
#endif
|
||||
ASSERT_EQ(skel->bss->arg2, exp_arg2, "syscall_arg2");
|
||||
ASSERT_EQ(skel->bss->arg3, exp_arg3, "syscall_arg3");
|
||||
/* it cannot copy arg4 when uses PT_REGS_PARM4 on x86_64 */
|
||||
|
|
|
@ -28,14 +28,19 @@ int BPF_KPROBE(handle_sys_prctl)
|
|||
{
|
||||
struct pt_regs *real_regs;
|
||||
pid_t pid = bpf_get_current_pid_tgid() >> 32;
|
||||
unsigned long tmp = 0;
|
||||
|
||||
if (pid != filter_pid)
|
||||
return 0;
|
||||
|
||||
real_regs = (struct pt_regs *)PT_REGS_PARM1(ctx);
|
||||
real_regs = PT_REGS_SYSCALL_REGS(ctx);
|
||||
|
||||
/* test for PT_REGS_PARM */
|
||||
bpf_probe_read_kernel(&arg1, sizeof(arg1), &PT_REGS_PARM1_SYSCALL(real_regs));
|
||||
|
||||
#if !defined(bpf_target_arm64) && !defined(bpf_target_s390)
|
||||
bpf_probe_read_kernel(&tmp, sizeof(tmp), &PT_REGS_PARM1_SYSCALL(real_regs));
|
||||
#endif
|
||||
arg1 = tmp;
|
||||
bpf_probe_read_kernel(&arg2, sizeof(arg2), &PT_REGS_PARM2_SYSCALL(real_regs));
|
||||
bpf_probe_read_kernel(&arg3, sizeof(arg3), &PT_REGS_PARM3_SYSCALL(real_regs));
|
||||
bpf_probe_read_kernel(&arg4_cx, sizeof(arg4_cx), &PT_REGS_PARM4(real_regs));
|
||||
|
|
Loading…
Reference in New Issue