selftests/seccomp: add MIPS self-test support
This adds self-test support on MIPS, based on RFC patch from Kees Cook. Modifications from the RFC: - support the O32 syscall which passes the real syscall number in a0. - Use PTRACE_{GET,SET}REGS - Because SYSCALL_NUM and SYSCALL_RET are the same register, it is not possible to test modifying the syscall return value when skipping, since both would need to set the same register. Therefore modify that test case to just detect the skipped test. Tested on MIPS32r2 / MIPS64r2 with O32, N32 and N64 userlands. Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com> Acked-by: Kees Cook <keescook@chromium.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Shuah Khan <shuahkh@osg.samsung.com> Cc: Will Drewry <wad@chromium.org> Cc: IMG-MIPSLinuxKerneldevelopers@imgtec.com Cc: linux-kernel@vger.kernel.org Cc: linux-kselftest@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12977/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
parent
8571e645d1
commit
0ce105bf97
|
@ -5,6 +5,7 @@
|
||||||
* Test code for seccomp bpf.
|
* Test code for seccomp bpf.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
#include <asm/siginfo.h>
|
#include <asm/siginfo.h>
|
||||||
#define __have_siginfo_t 1
|
#define __have_siginfo_t 1
|
||||||
#define __have_sigval_t 1
|
#define __have_sigval_t 1
|
||||||
|
@ -14,7 +15,6 @@
|
||||||
#include <linux/filter.h>
|
#include <linux/filter.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <sys/ptrace.h>
|
#include <sys/ptrace.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/user.h>
|
#include <sys/user.h>
|
||||||
#include <linux/prctl.h>
|
#include <linux/prctl.h>
|
||||||
#include <linux/ptrace.h>
|
#include <linux/ptrace.h>
|
||||||
|
@ -1242,6 +1242,12 @@ TEST_F(TRACE_poke, getpid_runs_normally)
|
||||||
# define ARCH_REGS s390_regs
|
# define ARCH_REGS s390_regs
|
||||||
# define SYSCALL_NUM gprs[2]
|
# define SYSCALL_NUM gprs[2]
|
||||||
# define SYSCALL_RET gprs[2]
|
# define SYSCALL_RET gprs[2]
|
||||||
|
#elif defined(__mips__)
|
||||||
|
# define ARCH_REGS struct pt_regs
|
||||||
|
# define SYSCALL_NUM regs[2]
|
||||||
|
# define SYSCALL_SYSCALL_NUM regs[4]
|
||||||
|
# define SYSCALL_RET regs[2]
|
||||||
|
# define SYSCALL_NUM_RET_SHARE_REG
|
||||||
#else
|
#else
|
||||||
# error "Do not know how to find your architecture's registers and syscalls"
|
# error "Do not know how to find your architecture's registers and syscalls"
|
||||||
#endif
|
#endif
|
||||||
|
@ -1249,7 +1255,7 @@ TEST_F(TRACE_poke, getpid_runs_normally)
|
||||||
/* Use PTRACE_GETREGS and PTRACE_SETREGS when available. This is useful for
|
/* Use PTRACE_GETREGS and PTRACE_SETREGS when available. This is useful for
|
||||||
* architectures without HAVE_ARCH_TRACEHOOK (e.g. User-mode Linux).
|
* architectures without HAVE_ARCH_TRACEHOOK (e.g. User-mode Linux).
|
||||||
*/
|
*/
|
||||||
#if defined(__x86_64__) || defined(__i386__)
|
#if defined(__x86_64__) || defined(__i386__) || defined(__mips__)
|
||||||
#define HAVE_GETREGS
|
#define HAVE_GETREGS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1273,6 +1279,10 @@ int get_syscall(struct __test_metadata *_metadata, pid_t tracee)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__mips__)
|
||||||
|
if (regs.SYSCALL_NUM == __NR_O32_Linux)
|
||||||
|
return regs.SYSCALL_SYSCALL_NUM;
|
||||||
|
#endif
|
||||||
return regs.SYSCALL_NUM;
|
return regs.SYSCALL_NUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1297,6 +1307,13 @@ void change_syscall(struct __test_metadata *_metadata,
|
||||||
{
|
{
|
||||||
regs.SYSCALL_NUM = syscall;
|
regs.SYSCALL_NUM = syscall;
|
||||||
}
|
}
|
||||||
|
#elif defined(__mips__)
|
||||||
|
{
|
||||||
|
if (regs.SYSCALL_NUM == __NR_O32_Linux)
|
||||||
|
regs.SYSCALL_SYSCALL_NUM = syscall;
|
||||||
|
else
|
||||||
|
regs.SYSCALL_NUM = syscall;
|
||||||
|
}
|
||||||
|
|
||||||
#elif defined(__arm__)
|
#elif defined(__arm__)
|
||||||
# ifndef PTRACE_SET_SYSCALL
|
# ifndef PTRACE_SET_SYSCALL
|
||||||
|
@ -1327,7 +1344,11 @@ void change_syscall(struct __test_metadata *_metadata,
|
||||||
|
|
||||||
/* If syscall is skipped, change return value. */
|
/* If syscall is skipped, change return value. */
|
||||||
if (syscall == -1)
|
if (syscall == -1)
|
||||||
|
#ifdef SYSCALL_NUM_RET_SHARE_REG
|
||||||
|
TH_LOG("Can't modify syscall return on this architecture");
|
||||||
|
#else
|
||||||
regs.SYSCALL_RET = 1;
|
regs.SYSCALL_RET = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_GETREGS
|
#ifdef HAVE_GETREGS
|
||||||
ret = ptrace(PTRACE_SETREGS, tracee, 0, ®s);
|
ret = ptrace(PTRACE_SETREGS, tracee, 0, ®s);
|
||||||
|
@ -1465,8 +1486,13 @@ TEST_F(TRACE_syscall, syscall_dropped)
|
||||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);
|
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);
|
||||||
ASSERT_EQ(0, ret);
|
ASSERT_EQ(0, ret);
|
||||||
|
|
||||||
|
#ifdef SYSCALL_NUM_RET_SHARE_REG
|
||||||
|
/* gettid has been skipped */
|
||||||
|
EXPECT_EQ(-1, syscall(__NR_gettid));
|
||||||
|
#else
|
||||||
/* gettid has been skipped and an altered return value stored. */
|
/* gettid has been skipped and an altered return value stored. */
|
||||||
EXPECT_EQ(1, syscall(__NR_gettid));
|
EXPECT_EQ(1, syscall(__NR_gettid));
|
||||||
|
#endif
|
||||||
EXPECT_NE(self->mytid, syscall(__NR_gettid));
|
EXPECT_NE(self->mytid, syscall(__NR_gettid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue