diff --git a/MANIFEST b/MANIFEST index c9f01b50b..91cb4d7c2 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1190,6 +1190,7 @@ src/exec_monitor.c src/exec_nopty.c src/exec_preload.c src/exec_ptrace.c +src/exec_ptrace.h src/exec_pty.c src/get_pty.c src/hooks.c diff --git a/src/Makefile.in b/src/Makefile.in index f5690449b..22ad985c8 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -615,8 +615,8 @@ exec_ptrace.o: $(srcdir)/exec_ptrace.c $(incdir)/compat/stdbool.h \ $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \ $(incdir)/sudo_util.h $(srcdir)/exec_intercept.h \ - $(srcdir)/sudo.h $(srcdir)/sudo_exec.h $(top_builddir)/config.h \ - $(top_builddir)/pathnames.h + $(srcdir)/exec_ptrace.h $(srcdir)/sudo.h $(srcdir)/sudo_exec.h \ + $(top_builddir)/config.h $(top_builddir)/pathnames.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(HARDENING_CFLAGS) $(srcdir)/exec_ptrace.c exec_ptrace.i: $(srcdir)/exec_ptrace.c $(incdir)/compat/stdbool.h \ $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \ @@ -624,8 +624,8 @@ exec_ptrace.i: $(srcdir)/exec_ptrace.c $(incdir)/compat/stdbool.h \ $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \ $(incdir)/sudo_util.h $(srcdir)/exec_intercept.h \ - $(srcdir)/sudo.h $(srcdir)/sudo_exec.h $(top_builddir)/config.h \ - $(top_builddir)/pathnames.h + $(srcdir)/exec_ptrace.h $(srcdir)/sudo.h $(srcdir)/sudo_exec.h \ + $(top_builddir)/config.h $(top_builddir)/pathnames.h $(CC) -E -o $@ $(CPPFLAGS) $< exec_ptrace.plog: exec_ptrace.i rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/exec_ptrace.c --i-file $< --output-file $@ diff --git a/src/exec_intercept.h b/src/exec_intercept.h index 0b8621530..d2d848e97 100644 --- a/src/exec_intercept.h +++ b/src/exec_intercept.h @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef SUDO_INTERCEPT_H -#define SUDO_INTERCEPT_H +#ifndef SUDO_EXEC_INTERCEPT_H +#define SUDO_EXEC_INTERCEPT_H enum intercept_state { RECV_HELLO_INITIAL, @@ -50,4 +50,4 @@ struct intercept_closure { void intercept_closure_reset(struct intercept_closure *closure); bool intercept_check_policy(const char *command, int argc, char **argv, int envc, char **envp, const char *runcwd, void *closure); -#endif /* SUDO_INTERCEPT_H */ +#endif /* SUDO_EXEC_INTERCEPT_H */ diff --git a/src/exec_ptrace.c b/src/exec_ptrace.c index ab571adb8..3b20d7776 100644 --- a/src/exec_ptrace.c +++ b/src/exec_ptrace.c @@ -37,226 +37,13 @@ #include "sudo.h" #include "sudo_exec.h" -#include "exec_intercept.h" #ifdef HAVE_PTRACE_INTERCEPT -# include -# include -# include -# include -# include -# include -# include -# include -# include - -/* Older systems may not support execveat(2). */ -#ifndef __NR_execveat -# define __NR_execveat -1 -#endif - -/* In case userland doesn't define __X32_SYSCALL_BIT. */ -#if defined(__x86_64__) && !defined(__X32_SYSCALL_BIT) -# define __X32_SYSCALL_BIT 0x40000000 -#endif - -/* Align address to a word boundary. */ -#define WORDALIGN(_a, _l) (((_a) + ((_l) - 1)) & ~((_l) - 1)) - -/* - * See syscall(2) for a list of registers used in system calls. - * For example code, see tools/testing/selftests/seccomp/seccomp_bpf.c - * - * The structs and registers vary among the different platforms. - * We define user_regs_struct as the struct to use for gettings - * and setting the general registers and define accessor - * macros to get/set the individual struct members. - * - * The value of SECCOMP_AUDIT_ARCH is used when matching the architecture - * in the seccomp(2) filter. - */ -#if defined(__x86_64__) -# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_X86_64 -# define X32_execve __X32_SYSCALL_BIT + 520 -# define X32_execveat __X32_SYSCALL_BIT + 545 -# define user_pt_regs user_regs_struct -# define reg_syscall(x) (x).orig_rax -# define reg_retval(x) (x).rax -# define reg_sp(x) (x).rsp -# define reg_arg1(x) (x).rdi -# define reg_arg2(x) (x).rsi -# define reg_arg3(x) (x).rdx -# define reg_arg4(x) (x).r10 -#elif defined(__aarch64__) -# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_AARCH64 -# define reg_syscall(x) (x).regs[8] /* w8 */ -# define reg_retval(x) (x).regs[0] /* x0 */ -# define reg_sp(x) (x).sp /* sp */ -# define reg_arg1(x) (x).regs[0] /* x0 */ -# define reg_arg2(x) (x).regs[1] /* x1 */ -# define reg_arg3(x) (x).regs[2] /* x2 */ -# define reg_arg4(x) (x).regs[3] /* x3 */ -#elif defined(__arm__) -/* Note: assumes arm EABI, not OABI */ -/* Untested */ -# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARM -# define user_pt_regs pt_regs -# define reg_syscall(x) (x).ARM_r7 -# define reg_retval(x) (x).ARM_r0 -# define reg_sp(x) (x).ARM_sp -# define reg_arg1(x) (x).ARM_r0 -# define reg_arg2(x) (x).ARM_r1 -# define reg_arg3(x) (x).ARM_r2 -# define reg_arg4(x) (x).ARM_r3 -#elif defined (__hppa__) -/* Untested (should also support hppa64) */ -# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_PARISC -# define user_pt_regs user_regs_struct -# define reg_syscall(x) (x).gr[20] /* r20 */ -# define reg_retval(x) (x).gr[28] /* r28 */ -# define reg_sp(x) (x).gr[30] /* r30 */ -# define reg_arg1(x) (x).gr[26] /* r26 */ -# define reg_arg2(x) (x).gr[25] /* r25 */ -# define reg_arg3(x) (x).gr[24] /* r24 */ -# define reg_arg4(x) (x).gr[23] /* r23 */ -#elif defined(__i386__) -# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_I386 -# define user_pt_regs user_regs_struct -# define reg_syscall(x) (x).orig_eax -# define reg_retval(x) (x).eax -# define reg_sp(x) (x).esp -# define reg_arg1(x) (x).ebx -# define reg_arg2(x) (x).ecx -# define reg_arg3(x) (x).edx -# define reg_arg4(x) (x).esi -#elif defined(__powerpc64__) -/* Untested */ -# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_PPC64LE -# else -# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_PPC64 -# endif -# define user_pt_regs pt_regs -# define reg_syscall(x) (x).gpr[0] /* r0 */ -# define reg_retval(x) (x).gpr[3] /* r3 */ -# define reg_sp(x) (x).gpr[1] /* r1 */ -# define reg_arg1(x) (x).gpr[3] /* r3 */ -# define reg_arg2(x) (x).gpr[4] /* r4 */ -# define reg_arg3(x) (x).gpr[5] /* r5 */ -# define reg_arg4(x) (x).gpr[6] /* r6 */ -#elif defined(__powerpc__) -/* Untested */ -# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_PPC -# define user_pt_regs pt_regs -# define reg_syscall(x) (x).gpr[0] /* r0 */ -# define reg_retval(x) (x).gpr[3] /* r3 */ -# define reg_sp(x) (x).gpr[1] /* r1 */ -# define reg_arg1(x) (x).gpr[3] /* r3 */ -# define reg_arg2(x) (x).gpr[4] /* r4 */ -# define reg_arg3(x) (x).gpr[5] /* r5 */ -# define reg_arg4(x) (x).gpr[6] /* r6 */ -#elif defined(__riscv) && __riscv_xlen == 64 -/* Untested */ -# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_RISCV64 -# define user_pt_regs user_regs_struct -# define reg_syscall(x) (x).a7 -# define reg_retval(x) (x).a0 -# define reg_sp(x) (x).sp -# define reg_arg1(x) (x).a0 -# define reg_arg2(x) (x).a1 -# define reg_arg3(x) (x).a2 -# define reg_arg4(x) (x).a3 -#elif defined(__s390x__) -# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_S390X -# define user_pt_regs s390_regs -# define reg_syscall(x) (x).gprs[1] /* r1 */ -# define reg_retval(x) (x).gprs[2] /* r2 */ -# define reg_sp(x) (x).gprs[15] /* r15 */ -# define reg_arg1(x) (x).gprs[2] /* r2 */ -# define reg_arg2(x) (x).gprs[3] /* r3 */ -# define reg_arg3(x) (x).gprs[4] /* r4 */ -# define reg_arg4(x) (x).gprs[5] /* r6 */ -#elif defined(__s390__) -# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_S390 -# define user_pt_regs s390_regs -# define reg_syscall(x) (x).gprs[1] /* r1 */ -# define reg_retval(x) (x).gprs[2] /* r2 */ -# define reg_sp(x) (x).gprs[15] /* r15 */ -# define reg_arg1(x) (x).gprs[2] /* r2 */ -# define reg_arg2(x) (x).gprs[3] /* r3 */ -# define reg_arg3(x) (x).gprs[4] /* r4 */ -# define reg_arg4(x) (x).gprs[5] /* r6 */ -#else -# error "Do not know how to find your architecture's registers" -#endif - -/* - * Compat definitions for running 32-bit binaries on 64-bit platforms. - * We must define the register struct too since there is no way to - * get it directly from the system headers. - */ -#if defined(__x86_64__) -struct i386_user_regs_struct { - unsigned int ebx; - unsigned int ecx; - unsigned int edx; - unsigned int esi; - unsigned int edi; - unsigned int ebp; - unsigned int eax; - unsigned int xds; - unsigned int xes; - unsigned int xfs; - unsigned int xgs; - unsigned int orig_eax; - unsigned int eip; - unsigned int xcs; - unsigned int eflags; - unsigned int esp; - unsigned int xss; -}; -# define SECCOMP_AUDIT_ARCH_COMPAT AUDIT_ARCH_I386 -# define COMPAT_execve 11 -# define COMPAT_execveat 358 -# define compat_user_pt_regs i386_user_regs_struct -# define compat_reg_syscall(x) (x).orig_eax -# define compat_reg_retval(x) (x).eax -# define compat_reg_sp(x) (x).esp -# define compat_reg_arg1(x) (x).ebx -# define compat_reg_arg2(x) (x).ecx -# define compat_reg_arg3(x) (x).edx -# define compat_reg_arg4(x) (x).esi -#elif defined(__arm__) -struct arm_pt_regs { - unsigned int uregs[18]; -}; -# define SECCOMP_AUDIT_ARCH_COMPAT AUDIT_ARCH_ARM -# define COMPAT_execve 11 -# define COMPAT_execveat 387 -# define compat_user_pt_regs arm_pt_regs -# define compat_reg_syscall(x) (x).uregs[7] /* r7 */ -# define compat_reg_retval(x) (x).uregs[0] /* r0 */ -# define compat_reg_sp(x) (x).uregs[13] /* r13 */ -# define compat_reg_arg1(x) (x).uregs[0] /* r0 */ -# define compat_reg_arg2(x) (x).uregs[1] /* r1 */ -# define compat_reg_arg3(x) (x).uregs[2] /* r2 */ -# define compat_reg_arg4(x) (x).uregs[3] /* r3 */ -#endif - -struct sudo_ptrace_regs { - union { - struct user_pt_regs native; -#ifdef SECCOMP_AUDIT_ARCH_COMPAT - struct compat_user_pt_regs compat; -#endif - } u; - unsigned int wordsize; - long addrmask; - bool compat; -}; +# include "exec_intercept.h" +# include "exec_ptrace.h" /* Register getters and setters. */ -#ifdef SECCOMP_AUDIT_ARCH_COMPAT +# ifdef SECCOMP_AUDIT_ARCH_COMPAT static inline long get_stack_pointer(struct sudo_ptrace_regs *regs) { @@ -367,7 +154,7 @@ set_sc_arg4(struct sudo_ptrace_regs *regs, long addr) } } -#else /* SECCOMP_AUDIT_ARCH_COMPAT */ +# else /* SECCOMP_AUDIT_ARCH_COMPAT */ static inline long get_stack_pointer(struct sudo_ptrace_regs *regs) @@ -434,8 +221,15 @@ set_sc_arg4(struct sudo_ptrace_regs *regs, long addr) { reg_arg4(regs->u.native) = addr; } -#endif /* SECCOMP_AUDIT_ARCH_COMPAT */ +# endif /* SECCOMP_AUDIT_ARCH_COMPAT */ +/* + * Get the registers for the given process and store in regs, which + * must be large enough. If the compat flag is set, pid is expected + * to refer to a 32-bit process and the md parameters will be filled + * in accordingly. + * Returns true on success, else false. + */ static bool ptrace_getregs(int pid, struct sudo_ptrace_regs *regs, bool compat) { @@ -461,6 +255,10 @@ ptrace_getregs(int pid, struct sudo_ptrace_regs *regs, bool compat) debug_return_bool(true); } +/* + * Set the registers, specified by regs, for the given process. + * Returns true on success, else false. + */ static bool ptrace_setregs(int pid, struct sudo_ptrace_regs *regs) { @@ -633,6 +431,7 @@ ptrace_write_string(pid_t pid, struct sudo_ptrace_regs *regs, long addr, /* * Use /proc/PID/cwd to determine the current working directory. + * Returns true on success, else false. */ static bool getcwd_by_pid(pid_t pid, char *buf, size_t bufsize) @@ -828,7 +627,7 @@ set_exec_filter(void) struct sock_filter exec_filter[] = { /* Load architecture value (AUDIT_ARCH_*) into the accumulator. */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, arch)), -#ifdef SECCOMP_AUDIT_ARCH_COMPAT +# ifdef SECCOMP_AUDIT_ARCH_COMPAT /* Match on the compat architecture or jump to the native arch check. */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SECCOMP_AUDIT_ARCH_COMPAT, 0, 4), /* Load syscall number into the accumulator. */ @@ -838,20 +637,20 @@ set_exec_filter(void) BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, COMPAT_execveat, 0, 8), /* Trace execve(2)/execveat(2) syscalls (w/ compat flag) */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRACE | 0x1), -#endif /* SECCOMP_AUDIT_ARCH_COMPAT */ +# endif /* SECCOMP_AUDIT_ARCH_COMPAT */ /* Jump to the end unless the architecture matches. */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SECCOMP_AUDIT_ARCH, 0, 6), /* Load syscall number into the accumulator. */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)), /* Jump to trace for execve(2)/execveat(2), else allow. */ -#ifdef X32_execve +# ifdef X32_execve BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, X32_execve, 3, 0), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, X32_execveat, 2, 0), -#else +# else /* No x32 support, check native system call numbers. */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_execve, 3, 0), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_execveat, 2, 3), -#endif /* X32_execve */ +# endif /* X32_execve */ /* If no x32 support, these two instructions are never reached. */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_execve, 1, 0), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_execveat, 0, 1), @@ -975,7 +774,7 @@ ptrace_intercept_execve(pid_t pid, struct intercept_closure *closure) debug_return_bool(false); } -#ifdef SECCOMP_AUDIT_ARCH_COMPAT +# ifdef SECCOMP_AUDIT_ARCH_COMPAT if (regs.compat) { syscallno = get_syscallno(®s); switch (syscallno) { @@ -992,19 +791,19 @@ ptrace_intercept_execve(pid_t pid, struct intercept_closure *closure) debug_return_bool(false); } } else -#endif /* SECCOMP_AUDIT_ARCH_COMPAT */ +# endif /* SECCOMP_AUDIT_ARCH_COMPAT */ { syscallno = get_syscallno(®s); switch (syscallno) { -#ifdef X32_execve +# ifdef X32_execve case X32_execve: -#endif +# endif case __NR_execve: /* Handled below. */ break; -#ifdef X32_execveat +# ifdef X32_execveat case X32_execveat: -#endif +# endif case __NR_execveat: /* We don't currently check execveat(2). */ debug_return_bool(true); @@ -1214,13 +1013,6 @@ exec_ptrace_handled(pid_t pid, int status, void *intercept) debug_return_bool(signo == 0); } #else -/* STUB */ -void -exec_ptrace_enable(void) -{ - return; -} - /* STUB */ bool have_seccomp_action(const char *action) diff --git a/src/exec_ptrace.h b/src/exec_ptrace.h new file mode 100644 index 000000000..9ffda5222 --- /dev/null +++ b/src/exec_ptrace.h @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2022 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef SUDO_EXEC_PTRACE_H +#define SUDO_EXEC_PTRACE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Older systems may not support execveat(2). */ +#ifndef __NR_execveat +# define __NR_execveat -1 +#endif + +/* In case userland doesn't define __X32_SYSCALL_BIT. */ +#if defined(__x86_64__) && !defined(__X32_SYSCALL_BIT) +# define __X32_SYSCALL_BIT 0x40000000 +#endif + +/* Align address to a word boundary of the given length. */ +#define WORDALIGN(_a, _l) (((_a) + ((_l) - 1)) & ~((_l) - 1)) + +/* + * See syscall(2) for a list of registers used in system calls. + * For example code, see tools/testing/selftests/seccomp/seccomp_bpf.c + * + * The structs and registers vary among the different platforms. + * We define user_regs_struct as the struct to use for gettings + * and setting the general registers and define accessor + * macros to get/set the individual struct members. + * + * The value of SECCOMP_AUDIT_ARCH is used when matching the architecture + * in the seccomp(2) filter. + */ +#if defined(__x86_64__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_X86_64 +# define X32_execve __X32_SYSCALL_BIT + 520 +# define X32_execveat __X32_SYSCALL_BIT + 545 +# define user_pt_regs user_regs_struct +# define reg_syscall(x) (x).orig_rax +# define reg_retval(x) (x).rax +# define reg_sp(x) (x).rsp +# define reg_arg1(x) (x).rdi +# define reg_arg2(x) (x).rsi +# define reg_arg3(x) (x).rdx +# define reg_arg4(x) (x).r10 +#elif defined(__aarch64__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_AARCH64 +# define reg_syscall(x) (x).regs[8] /* w8 */ +# define reg_retval(x) (x).regs[0] /* x0 */ +# define reg_sp(x) (x).sp /* sp */ +# define reg_arg1(x) (x).regs[0] /* x0 */ +# define reg_arg2(x) (x).regs[1] /* x1 */ +# define reg_arg3(x) (x).regs[2] /* x2 */ +# define reg_arg4(x) (x).regs[3] /* x3 */ +#elif defined(__arm__) +/* Note: assumes arm EABI, not OABI */ +/* Untested */ +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARM +# define user_pt_regs pt_regs +# define reg_syscall(x) (x).ARM_r7 +# define reg_retval(x) (x).ARM_r0 +# define reg_sp(x) (x).ARM_sp +# define reg_arg1(x) (x).ARM_r0 +# define reg_arg2(x) (x).ARM_r1 +# define reg_arg3(x) (x).ARM_r2 +# define reg_arg4(x) (x).ARM_r3 +#elif defined (__hppa__) +/* Untested (should also support hppa64) */ +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_PARISC +# define user_pt_regs user_regs_struct +# define reg_syscall(x) (x).gr[20] /* r20 */ +# define reg_retval(x) (x).gr[28] /* r28 */ +# define reg_sp(x) (x).gr[30] /* r30 */ +# define reg_arg1(x) (x).gr[26] /* r26 */ +# define reg_arg2(x) (x).gr[25] /* r25 */ +# define reg_arg3(x) (x).gr[24] /* r24 */ +# define reg_arg4(x) (x).gr[23] /* r23 */ +#elif defined(__i386__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_I386 +# define user_pt_regs user_regs_struct +# define reg_syscall(x) (x).orig_eax +# define reg_retval(x) (x).eax +# define reg_sp(x) (x).esp +# define reg_arg1(x) (x).ebx +# define reg_arg2(x) (x).ecx +# define reg_arg3(x) (x).edx +# define reg_arg4(x) (x).esi +#elif defined(__powerpc64__) +/* Untested */ +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_PPC64LE +# else +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_PPC64 +# endif +# define user_pt_regs pt_regs +# define reg_syscall(x) (x).gpr[0] /* r0 */ +# define reg_retval(x) (x).gpr[3] /* r3 */ +# define reg_sp(x) (x).gpr[1] /* r1 */ +# define reg_arg1(x) (x).gpr[3] /* r3 */ +# define reg_arg2(x) (x).gpr[4] /* r4 */ +# define reg_arg3(x) (x).gpr[5] /* r5 */ +# define reg_arg4(x) (x).gpr[6] /* r6 */ +#elif defined(__powerpc__) +/* Untested */ +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_PPC +# define user_pt_regs pt_regs +# define reg_syscall(x) (x).gpr[0] /* r0 */ +# define reg_retval(x) (x).gpr[3] /* r3 */ +# define reg_sp(x) (x).gpr[1] /* r1 */ +# define reg_arg1(x) (x).gpr[3] /* r3 */ +# define reg_arg2(x) (x).gpr[4] /* r4 */ +# define reg_arg3(x) (x).gpr[5] /* r5 */ +# define reg_arg4(x) (x).gpr[6] /* r6 */ +#elif defined(__riscv) && __riscv_xlen == 64 +/* Untested */ +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_RISCV64 +# define user_pt_regs user_regs_struct +# define reg_syscall(x) (x).a7 +# define reg_retval(x) (x).a0 +# define reg_sp(x) (x).sp +# define reg_arg1(x) (x).a0 +# define reg_arg2(x) (x).a1 +# define reg_arg3(x) (x).a2 +# define reg_arg4(x) (x).a3 +#elif defined(__s390x__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_S390X +# define user_pt_regs s390_regs +# define reg_syscall(x) (x).gprs[1] /* r1 */ +# define reg_retval(x) (x).gprs[2] /* r2 */ +# define reg_sp(x) (x).gprs[15] /* r15 */ +# define reg_arg1(x) (x).gprs[2] /* r2 */ +# define reg_arg2(x) (x).gprs[3] /* r3 */ +# define reg_arg3(x) (x).gprs[4] /* r4 */ +# define reg_arg4(x) (x).gprs[5] /* r6 */ +#elif defined(__s390__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_S390 +# define user_pt_regs s390_regs +# define reg_syscall(x) (x).gprs[1] /* r1 */ +# define reg_retval(x) (x).gprs[2] /* r2 */ +# define reg_sp(x) (x).gprs[15] /* r15 */ +# define reg_arg1(x) (x).gprs[2] /* r2 */ +# define reg_arg2(x) (x).gprs[3] /* r3 */ +# define reg_arg3(x) (x).gprs[4] /* r4 */ +# define reg_arg4(x) (x).gprs[5] /* r6 */ +#else +# error "Do not know how to find your architecture's registers" +#endif + +/* + * Compat definitions for running 32-bit binaries on 64-bit platforms. + * We must define the register struct too since there is no way to + * get it directly from the system headers. + * + * The value of SECCOMP_AUDIT_ARCH_COMPAT is used when matching the + * architecture in the seccomp(2) filter. We can tell when the compat + * arch matched by inspecting the message returned by PTRACE_GETEVENTMSG. + */ +#if defined(__x86_64__) +struct i386_user_regs_struct { + unsigned int ebx; + unsigned int ecx; + unsigned int edx; + unsigned int esi; + unsigned int edi; + unsigned int ebp; + unsigned int eax; + unsigned int xds; + unsigned int xes; + unsigned int xfs; + unsigned int xgs; + unsigned int orig_eax; + unsigned int eip; + unsigned int xcs; + unsigned int eflags; + unsigned int esp; + unsigned int xss; +}; +# define SECCOMP_AUDIT_ARCH_COMPAT AUDIT_ARCH_I386 +# define COMPAT_execve 11 +# define COMPAT_execveat 358 +# define compat_user_pt_regs i386_user_regs_struct +# define compat_reg_syscall(x) (x).orig_eax +# define compat_reg_retval(x) (x).eax +# define compat_reg_sp(x) (x).esp +# define compat_reg_arg1(x) (x).ebx +# define compat_reg_arg2(x) (x).ecx +# define compat_reg_arg3(x) (x).edx +# define compat_reg_arg4(x) (x).esi +#elif defined(__arm__) +struct arm_pt_regs { + unsigned int uregs[18]; +}; +# define SECCOMP_AUDIT_ARCH_COMPAT AUDIT_ARCH_ARM +# define COMPAT_execve 11 +# define COMPAT_execveat 387 +# define compat_user_pt_regs arm_pt_regs +# define compat_reg_syscall(x) (x).uregs[7] /* r7 */ +# define compat_reg_retval(x) (x).uregs[0] /* r0 */ +# define compat_reg_sp(x) (x).uregs[13] /* r13 */ +# define compat_reg_arg1(x) (x).uregs[0] /* r0 */ +# define compat_reg_arg2(x) (x).uregs[1] /* r1 */ +# define compat_reg_arg3(x) (x).uregs[2] /* r2 */ +# define compat_reg_arg4(x) (x).uregs[3] /* r3 */ +#endif + +struct sudo_ptrace_regs { + union { + struct user_pt_regs native; +#ifdef SECCOMP_AUDIT_ARCH_COMPAT + struct compat_user_pt_regs compat; +#endif + } u; + unsigned int wordsize; + long addrmask; + bool compat; +}; + +#endif /* SUDO_EXEC_PTRACE_H */