pts/seccomp: MIPS register access
MIPS PTRACE_GETREGSET returns an array of register values. Define
ARCH_REGS to reflect this and use the offsets defined in asm/regs.h
to access it.
Incorporates some additional changes from lkml.org patch by Matt
Redfearn (https://lkml.org/lkml/2016/3/29/184):
- support the O32 syscall which passes the real syscall number in a0.
- 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.
Bug: 27484186
Change-Id: I066b01a271bc8f2eecab5e3adb5aa2117fcf5b86
diff --git a/pts/seccomp/seccomp_bpf.c b/pts/seccomp/seccomp_bpf.c
index f7c28f3..dfe30b3 100644
--- a/pts/seccomp/seccomp_bpf.c
+++ b/pts/seccomp/seccomp_bpf.c
@@ -1216,9 +1216,15 @@
# define SYSCALL_NUM gprs[2]
# define SYSCALL_RET gprs[2]
#elif defined(__mips__)
-# define ARCH_REGS struct pt_regs
-# define SYSCALL_NUM regs[2]
-# define SYSCALL_RET regs[2]
+#include <asm/reg.h>
+typedef struct {
+ unsigned long regs[EF_SIZE/sizeof(unsigned long)];
+} user_regs;
+# define ARCH_REGS user_regs
+# define SYSCALL_NUM regs[EF_R2]
+# define SYSCALL_RET regs[EF_R2]
+# define SYSCALL_SYSCALL_NUM regs[EF_R4]
+# define SYSCALL_NUM_RET_SHARE_REG
#else
# error "Do not know how to find your architecture's registers and syscalls"
#endif
@@ -1236,6 +1242,10 @@
return -1;
}
+#if defined(__mips__)
+ if (regs.SYSCALL_NUM == __NR_O32_Linux)
+ return regs.SYSCALL_SYSCALL_NUM;
+#endif
return regs.SYSCALL_NUM;
}
@@ -1257,6 +1267,13 @@
{
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__)
# ifndef PTRACE_SET_SYSCALL
@@ -1287,7 +1304,11 @@
/* If syscall is skipped, change return value. */
if (syscall == -1)
+#ifdef SYSCALL_NUM_RET_SHARE_REG
+ TH_LOG("Can't modify syscall return on this architecture");
+#else
regs.SYSCALL_RET = 1;
+#endif
iov.iov_base = ®s;
iov.iov_len = sizeof(regs);
@@ -1421,8 +1442,13 @@
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);
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. */
EXPECT_EQ(1, syscall(__NR_gettid));
+#endif
EXPECT_NE(self->mytid, syscall(__NR_gettid));
}