Enable ptrace support for MIPS but only for log_subcmds.
It is not possible to change the syscall return value on MIPS so we cannot support full intercept mode. Another complication on MIPS is that if a system call is invoked via syscall(__NR_###), v0 holds __NR_O32_Linux and the real syscall is in the first arg (a0) and other args are shifted by one.
This commit is contained in:
@@ -109,9 +109,9 @@ static inline void
|
|||||||
set_sc_arg1(struct sudo_ptrace_regs *regs, unsigned long addr)
|
set_sc_arg1(struct sudo_ptrace_regs *regs, unsigned long addr)
|
||||||
{
|
{
|
||||||
if (regs->compat) {
|
if (regs->compat) {
|
||||||
compat_reg_arg1(regs->u.compat) = addr;
|
compat_reg_set_arg1(regs->u.compat, addr);
|
||||||
} else {
|
} else {
|
||||||
reg_arg1(regs->u.native) = addr;
|
reg_set_arg1(regs->u.native, addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,9 +129,9 @@ static inline void
|
|||||||
set_sc_arg2(struct sudo_ptrace_regs *regs, unsigned long addr)
|
set_sc_arg2(struct sudo_ptrace_regs *regs, unsigned long addr)
|
||||||
{
|
{
|
||||||
if (regs->compat) {
|
if (regs->compat) {
|
||||||
compat_reg_arg2(regs->u.compat) = addr;
|
compat_reg_set_arg2(regs->u.compat, addr);
|
||||||
} else {
|
} else {
|
||||||
reg_arg2(regs->u.native) = addr;
|
reg_set_arg2(regs->u.native, addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,9 +150,9 @@ static inline void
|
|||||||
set_sc_arg3(struct sudo_ptrace_regs *regs, unsigned long addr)
|
set_sc_arg3(struct sudo_ptrace_regs *regs, unsigned long addr)
|
||||||
{
|
{
|
||||||
if (regs->compat) {
|
if (regs->compat) {
|
||||||
compat_reg_arg3(regs->u.compat) = addr;
|
compat_reg_set_arg3(regs->u.compat, addr);
|
||||||
} else {
|
} else {
|
||||||
reg_arg3(regs->u.native) = addr;
|
reg_set_arg3(regs->u.native, addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,9 +170,9 @@ static inline void
|
|||||||
set_sc_arg4(struct sudo_ptrace_regs *regs, unsigned long addr)
|
set_sc_arg4(struct sudo_ptrace_regs *regs, unsigned long addr)
|
||||||
{
|
{
|
||||||
if (regs->compat) {
|
if (regs->compat) {
|
||||||
compat_reg_arg4(regs->u.compat) = addr;
|
compat_reg_set_arg4(regs->u.compat, addr);
|
||||||
} else {
|
} else {
|
||||||
reg_arg4(regs->u.native) = addr;
|
reg_set_arg4(regs->u.native, addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# endif /* notyet */
|
# endif /* notyet */
|
||||||
@@ -212,7 +212,7 @@ get_sc_arg1(struct sudo_ptrace_regs *regs)
|
|||||||
static inline void
|
static inline void
|
||||||
set_sc_arg1(struct sudo_ptrace_regs *regs, unsigned long addr)
|
set_sc_arg1(struct sudo_ptrace_regs *regs, unsigned long addr)
|
||||||
{
|
{
|
||||||
reg_arg1(regs->u.native) = addr;
|
reg_set_arg1(regs->u.native, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned long
|
static inline unsigned long
|
||||||
@@ -224,7 +224,7 @@ get_sc_arg2(struct sudo_ptrace_regs *regs)
|
|||||||
static inline void
|
static inline void
|
||||||
set_sc_arg2(struct sudo_ptrace_regs *regs, unsigned long addr)
|
set_sc_arg2(struct sudo_ptrace_regs *regs, unsigned long addr)
|
||||||
{
|
{
|
||||||
reg_arg2(regs->u.native) = addr;
|
reg_set_arg2(regs->u.native, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned long
|
static inline unsigned long
|
||||||
@@ -237,7 +237,7 @@ get_sc_arg3(struct sudo_ptrace_regs *regs)
|
|||||||
static inline void
|
static inline void
|
||||||
set_sc_arg3(struct sudo_ptrace_regs *regs, unsigned long addr)
|
set_sc_arg3(struct sudo_ptrace_regs *regs, unsigned long addr)
|
||||||
{
|
{
|
||||||
reg_arg3(regs->u.native) = addr;
|
reg_set_arg3(regs->u.native, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned long
|
static inline unsigned long
|
||||||
@@ -249,7 +249,7 @@ get_sc_arg4(struct sudo_ptrace_regs *regs)
|
|||||||
static inline void
|
static inline void
|
||||||
set_sc_arg4(struct sudo_ptrace_regs *regs, unsigned long addr)
|
set_sc_arg4(struct sudo_ptrace_regs *regs, unsigned long addr)
|
||||||
{
|
{
|
||||||
reg_arg4(regs->u.native) = addr;
|
reg_set_arg4(regs->u.native, addr);
|
||||||
}
|
}
|
||||||
# endif /* notyet */
|
# endif /* notyet */
|
||||||
# endif /* SECCOMP_AUDIT_ARCH_COMPAT */
|
# endif /* SECCOMP_AUDIT_ARCH_COMPAT */
|
||||||
@@ -1280,10 +1280,15 @@ exec_ptrace_stopped(pid_t pid, int status, void *intercept)
|
|||||||
bool
|
bool
|
||||||
exec_ptrace_intercept_supported(void)
|
exec_ptrace_intercept_supported(void)
|
||||||
{
|
{
|
||||||
|
# ifdef __mips__
|
||||||
|
/* MIPS doesn't support changing the syscall return value. */
|
||||||
|
return false;
|
||||||
|
# else
|
||||||
if (seccomp_trap_supported == -1)
|
if (seccomp_trap_supported == -1)
|
||||||
seccomp_trap_supporetd = have_seccomp_action("trap");
|
seccomp_trap_supported = have_seccomp_action("trap");
|
||||||
|
|
||||||
return seccomp_trap_supported == true;
|
return seccomp_trap_supported == true;
|
||||||
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@@ -37,6 +37,10 @@
|
|||||||
# define __X32_SYSCALL_BIT 0x40000000
|
# define __X32_SYSCALL_BIT 0x40000000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__mips__) && !defined(__NR_O32_Linux)
|
||||||
|
# define __NR_O32_Linux 4000
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Align address to a (compat) word boundary. */
|
/* Align address to a (compat) word boundary. */
|
||||||
#define WORDALIGN(_a, _r) \
|
#define WORDALIGN(_a, _r) \
|
||||||
(((_a) + ((long)(_r).wordsize - 1L)) & ~((long)(_r).wordsize - 1L))
|
(((_a) + ((long)(_r).wordsize - 1L)) & ~((long)(_r).wordsize - 1L))
|
||||||
@@ -141,20 +145,60 @@
|
|||||||
# else
|
# else
|
||||||
# error "Unsupported MIPS ABI"
|
# error "Unsupported MIPS ABI"
|
||||||
# endif
|
# endif
|
||||||
/* Untested/incomplete.
|
/*
|
||||||
* If called via syscall(__NR_###), v0 holds __NR_O32_Linux and the real
|
* If called via syscall(__NR_###), v0 holds __NR_O32_Linux and the real
|
||||||
* syscall the first arg (a0) and other args are shifted by one.
|
* syscall is in the first arg (a0). The actual args are shifted by one.
|
||||||
* We don't currently support this.
|
|
||||||
* MIPS does not support setting the syscall return value via ptrace.
|
* MIPS does not support setting the syscall return value via ptrace.
|
||||||
*/
|
*/
|
||||||
# define sudo_pt_regs struct pt_regs
|
# define sudo_pt_regs struct pt_regs
|
||||||
# define reg_syscall(x) (x).regs[2] /* v0 */
|
# define reg_syscall(_r) ({ \
|
||||||
|
__u64 _nr; \
|
||||||
|
if ((_r).regs[2] == __NR_O32_Linux) \
|
||||||
|
_nr = (_r).regs[4]; /* a0 */ \
|
||||||
|
else \
|
||||||
|
_nr = (_r).regs[2]; /* v0 */ \
|
||||||
|
_nr; \
|
||||||
|
})
|
||||||
# define reg_retval(x) (x).regs[2] /* v0 */
|
# define reg_retval(x) (x).regs[2] /* v0 */
|
||||||
# define reg_sp(x) (x).regs[29] /* sp */
|
# define reg_sp(x) (x).regs[29] /* sp */
|
||||||
# define reg_arg1(x) (x).regs[4] /* a0 */
|
# define reg_arg1(x) \
|
||||||
# define reg_arg2(x) (x).regs[5] /* a1 */
|
((x).regs[2] == __NR_O32_Linux ? (x).regs[5] : (x).regs[4])
|
||||||
# define reg_arg3(x) (x).regs[6] /* a2 */
|
# define reg_set_arg1(_r, _v) do { \
|
||||||
# define reg_arg4(x) (x).regs[7] /* a3 */
|
if ((_r).regs[2] == __NR_O32_Linux) \
|
||||||
|
(_r).regs[5] = _v; /* a1 */ \
|
||||||
|
else \
|
||||||
|
(_r).regs[4] = _v; /* a0 */ \
|
||||||
|
} while (0)
|
||||||
|
# define reg_arg2(x) \
|
||||||
|
((x).regs[2] == __NR_O32_Linux ? (x).regs[6] : (x).regs[5])
|
||||||
|
# define reg_set_arg2(_r, _v) do { \
|
||||||
|
if ((_r).regs[2] == __NR_O32_Linux) \
|
||||||
|
(_r).regs[6] = _v; /* a2 */ \
|
||||||
|
else \
|
||||||
|
(_r).regs[5] = _v; /* a1 */ \
|
||||||
|
} while (0)
|
||||||
|
# define reg_arg3(x) \
|
||||||
|
((x).regs[2] == __NR_O32_Linux ? (x).regs[7] : (x).regs[6])
|
||||||
|
# define reg_set_arg3(_r, _v) do { \
|
||||||
|
if ((_r).regs[2] == __NR_O32_Linux) \
|
||||||
|
(_r).regs[7] = _v; /* a3 */ \
|
||||||
|
else \
|
||||||
|
(_r).regs[6] = _v; /* a2 */ \
|
||||||
|
} while (0)
|
||||||
|
# define reg_arg4(x) \
|
||||||
|
((x).regs[2] == __NR_O32_Linux ? (x).regs[8] : (x).regs[7])
|
||||||
|
# define reg_set_arg4(_r, _v) do { \
|
||||||
|
if ((_r).regs[2] == __NR_O32_Linux) \
|
||||||
|
(_r).regs[8] = _v; /* a4 */ \
|
||||||
|
else \
|
||||||
|
(_r).regs[7] = _v; /* a3 */ \
|
||||||
|
} while (0)
|
||||||
|
# define reg_set_syscall(_r, _nr) do { \
|
||||||
|
if ((_r).regs[2] == __NR_O32_Linux) \
|
||||||
|
(_r).regs[4] = _nr; /* a0 */ \
|
||||||
|
else \
|
||||||
|
(_r).regs[2] = _nr; /* v0 */ \
|
||||||
|
} while (0)
|
||||||
#elif defined(__powerpc__)
|
#elif defined(__powerpc__)
|
||||||
# if defined(__powerpc64__)
|
# if defined(__powerpc64__)
|
||||||
# if BYTE_ORDER == LITTLE_ENDIAN
|
# if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
@@ -333,6 +377,48 @@ struct ppc_pt_regs {
|
|||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Set the syscall arguments the "normal" way by default. */
|
||||||
|
#ifndef reg_set_arg1
|
||||||
|
# define reg_set_arg1(_r, _v) do { \
|
||||||
|
reg_arg1(_r) = (_v); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
#ifndef compat_reg_set_arg1
|
||||||
|
# define compat_reg_set_arg1(_r, _v) do { \
|
||||||
|
compat_reg_arg1(_r) = (_v); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
#ifndef reg_set_arg2
|
||||||
|
# define reg_set_arg2(_r, _v) do { \
|
||||||
|
reg_arg2(_r) = (_v); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
#ifndef compat_reg_set_arg2
|
||||||
|
# define compat_reg_set_arg2(_r, _v) do { \
|
||||||
|
compat_reg_arg2(_r) = (_v); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
#ifndef reg_set_arg3
|
||||||
|
# define reg_set_arg3(_r, _v) do { \
|
||||||
|
reg_arg3(_r) = (_v); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
#ifndef compat_reg_set_arg3
|
||||||
|
# define compat_reg_set_arg3(_r, _v) do { \
|
||||||
|
compat_reg_arg3(_r) = (_v); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
#ifndef reg_set_arg4
|
||||||
|
# define reg_set_arg4(_r, _v) do { \
|
||||||
|
reg_arg4(_r) = (_v); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
#ifndef compat_reg_set_arg4
|
||||||
|
# define compat_reg_set_arg4(_r, _v) do { \
|
||||||
|
compat_reg_arg4(_r) = (_v); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
struct sudo_ptrace_regs {
|
struct sudo_ptrace_regs {
|
||||||
union {
|
union {
|
||||||
sudo_pt_regs native;
|
sudo_pt_regs native;
|
||||||
|
@@ -92,10 +92,11 @@ union sudo_token_un {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Use ptrace-based intercept (using seccomp) on Linux if possible.
|
* Use ptrace-based intercept (using seccomp) on Linux if possible.
|
||||||
|
* On MIPS we can't change the syscall return and only support log_subcmds.
|
||||||
*/
|
*/
|
||||||
#if defined(_PATH_SUDO_INTERCEPT) && defined(__linux__)
|
#if defined(_PATH_SUDO_INTERCEPT) && defined(__linux__)
|
||||||
# if defined(HAVE_DECL_SECCOMP_SET_MODE_FILTER) && HAVE_DECL_SECCOMP_SET_MODE_FILTER
|
# if defined(HAVE_DECL_SECCOMP_SET_MODE_FILTER) && HAVE_DECL_SECCOMP_SET_MODE_FILTER
|
||||||
# if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || defined(__arm__) || defined(__powerpc__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__s390__)
|
# if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || defined(__arm__) || defined(__mips__) || defined(__powerpc__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__s390__)
|
||||||
# ifndef HAVE_PTRACE_INTERCEPT
|
# ifndef HAVE_PTRACE_INTERCEPT
|
||||||
# define HAVE_PTRACE_INTERCEPT 1
|
# define HAVE_PTRACE_INTERCEPT 1
|
||||||
# endif /* HAVE_PTRACE_INTERCEPT */
|
# endif /* HAVE_PTRACE_INTERCEPT */
|
||||||
|
Reference in New Issue
Block a user