From 7a82798f6b160ed1b00c24fa8754d55ca8992a4d Mon Sep 17 00:00:00 2001 From: Steve Beattie Date: Thu, 2 Jul 2015 23:28:44 -0700 Subject: [PATCH] regression tests: have ptrace use PTRACE_GETREGSET by default Merge from trunk revision 3169 Bug: https://bugs.launchpad.net/apparmor/+bug/1470985 The ptrace regression test fails to compile on the arm64 platform, because it uses PTRACE_GETREGS and not the newer PTRACE_GETREGSET interface for getting access to arch-specific register information[0]. However, fixing it is complicated by the fact that the struct name for for the general purpose registers is not named consistently across architectures. This patch attempts to address those issues, and compiles at least on i386, amd64, arm64, arm (armhf), ppc64, and ppc64el. The test is verified to continue to function correctly on i386 and amd64. [0] https://sourceware.org/ml/archer/2010-q3/msg00193.html Signed-off-by: Steve Beattie Acked-by: John Johansen --- tests/regression/apparmor/ptrace.c | 52 ++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/tests/regression/apparmor/ptrace.c b/tests/regression/apparmor/ptrace.c index a9dd78512..797ff2f2f 100644 --- a/tests/regression/apparmor/ptrace.c +++ b/tests/regression/apparmor/ptrace.c @@ -7,7 +7,9 @@ #include #include #include +#include #include +#include #define NUM_CHLD_SYSCALLS 10 @@ -34,10 +36,50 @@ int interp_status(int status) return rc; } +#ifdef PTRACE_GETREGSET +# if defined(__x86_64__) || defined(__i386__) +# define ARCH_REGS_STRUCT struct user_regs_struct +# elif defined(__aarch64__) +# define ARCH_REGS_STRUCT struct user_pt_regs +# elif defined(__arm__) || defined(__powerpc__) || defined(__powerpc64__) +# define ARCH_REGS_STRUCT struct pt_regs +# endif + +int read_ptrace_registers(pid_t pid) +{ + ARCH_REGS_STRUCT regs; + struct iovec iov; + + iov.iov_base = ®s; + iov.iov_len = sizeof(regs); + + memset(®s, 0, sizeof(regs)); + if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov) == -1) { + perror("FAIL: parent ptrace(PTRACE_GETREGS) failed - "); + return errno; + } + + return 0; +} +#else /* ! PTRACE_GETREGSET so use PTRACE_GETREGS instead */ +int read_ptrace_registers(pid_t pid) +{ + struct user regs; + + memset(®s, 0, sizeof(regs)); + if (ptrace(PTRACE_GETREGS, pid, NULL, ®s) == -1) { + perror("FAIL: parent ptrace(PTRACE_GETREGS) failed - "); + return errno; + } + + return 0; +} +#endif + + /* return 0 on success. Child failure -errorno, parent failure errno */ int do_parent(pid_t pid, int trace, int num_syscall) { - struct user regs; int status, i; unsigned int rc; @@ -88,11 +130,9 @@ int do_parent(pid_t pid, int trace, int num_syscall) if (!WIFSTOPPED(status)) return interp_status(status); - memset(®s, 0, sizeof(regs)); - if (ptrace(PTRACE_GETREGS, pid, NULL, ®s) == -1) { - perror("FAIL: parent ptrace(PTRACE_GETREGS) failed - "); - return errno; - } + rc = read_ptrace_registers(pid); + if (rc != 0) + return rc; } if (ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1) {