Move register definitions to exec_ptrace.h
This commit is contained in:
1
MANIFEST
1
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
|
||||
|
@@ -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 $@
|
||||
|
@@ -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 */
|
||||
|
@@ -37,226 +37,13 @@
|
||||
|
||||
#include "sudo.h"
|
||||
#include "sudo_exec.h"
|
||||
#include "exec_intercept.h"
|
||||
|
||||
#ifdef HAVE_PTRACE_INTERCEPT
|
||||
# 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 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)
|
||||
|
239
src/exec_ptrace.h
Normal file
239
src/exec_ptrace.h
Normal file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* 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 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 */
|
Reference in New Issue
Block a user