Files
sudo/src/exec_ptrace.h
Todd C. Miller f82aa334cc Use the entire word in ptrace_get_vec_len() and ptrace_read_vec().
For compat binaries, use the upper 32-bits as the next word instead
of calling ptrace(2) to get it.  This reduces the number of ptrace(2)
calls when reading argv and envp for compat binaries.
2022-05-09 10:09:30 -06:00

239 lines
8.0 KiB
C

/*
* Copyright (c) 2022 Todd C. Miller <Todd.Miller@sudo.ws>
*
* 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 <elf.h>
#include <sys/prctl.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <asm/unistd.h>
#include <linux/audit.h>
#include <linux/ptrace.h>
#include <linux/seccomp.h>
#include <linux/filter.h>
/* 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 (native) word boundary. */
#define WORDALIGN(_a) (((_a) + (sizeof(long) - 1L)) & ~(sizeof(long) - 1L))
/*
* 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;
bool compat;
};
#endif /* SUDO_EXEC_PTRACE_H */