From 32432ef9bbb44ea74d4dae858786db75c082623f Mon Sep 17 00:00:00 2001 From: akaher Date: Tue, 16 Apr 2019 13:50:08 +0000 Subject: [PATCH 06/11] This patch is to 'Add ARM64 support to peekfd'. ARM64 copy user_pt_regs to user space instead of pt_regs. So in this patch, mapping the require user_pt_regs except orig_x0, as orig_x0 not available in user_pt_regs for SYSCALL exit. For each SYSCALL, peekfd catches user_pt_regs for SYSCALL entry/exit. Value of orig_x0 is available in user_pt_regs->x0 of SYSCALL entry. So to get orig_x0, stores user_pt_regs of SYSCALL entry, and then compare 'fd and addr of buffer' of SYSCALL exit with SYSCALL entry to retrive orig_x0 at the time of SYSCALL exit. Signed-off-by: Ajay Kaher --- Makefile.am | 6 +++ configure.ac | 3 ++ src/peekfd.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 118 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 8859818..441ae94 100644 --- a/Makefile.am +++ b/Makefile.am @@ -40,6 +40,12 @@ if WANT_PEEKFD_ARM bin_PROGRAMS += src/peekfd AM_CPPFLAGS += -DARM endif + +if WANT_PEEKFD_ARM64 + bin_PROGRAMS += src/peekfd + AM_CPPFLAGS += -DARM64 +endif + if WANT_PEEKFD_MIPS bin_PROGRAMS += src/peekfd AM_CPPFLAGS += -DMIPS diff --git a/configure.ac b/configure.ac index 176a2fc..407cd97 100644 --- a/configure.ac +++ b/configure.ac @@ -131,6 +131,7 @@ AC_CHECK_MEMBERS([struct user_regs_struct.orig_eax, AC_CHECK_MEMBERS([struct pt_regs.orig_gpr3, struct pt_regs.gpr], [],[], [#include ]) AC_CHECK_MEMBERS([struct pt_regs.uregs],[],[], [#include ]) +AC_CHECK_MEMBERS([struct user_pt_regs.regs],[],[], [#include ]) AC_CHECK_MEMBERS([struct pt_regs.regs, struct pt_regs.cp0_status],[],[], [#include ]) AC_CHECK_MEMBERS([struct pt_regs.orig_d0, @@ -163,6 +164,8 @@ AM_CONDITIONAL(WANT_PEEKFD_PPC, test $ac_cv_member_struct_pt_regs_gpr = yes ) AM_CONDITIONAL(WANT_PEEKFD_ARM, test $ac_cv_member_struct_pt_regs_uregs = yes) +AM_CONDITIONAL(WANT_PEEKFD_ARM64, + test $ac_cv_member_struct_user_pt_regs_regs = yes) AM_CONDITIONAL(WANT_PEEKFD_MIPS, test $build_cpu = mipsel && test $ac_cv_member_struct_pt_regs_regs = yes && diff --git a/src/peekfd.c b/src/peekfd.c index 5aa990a..f41391a 100644 --- a/src/peekfd.c +++ b/src/peekfd.c @@ -35,9 +35,17 @@ #include #include #include +#include +#include +#include #include "i18n.h" +#ifdef ARM64 +#include +#include +#endif + #ifdef I386 #define REG_ORIG_ACCUM orig_eax #define REG_ACCUM eax @@ -72,6 +80,16 @@ #define REG_PARAM1 ARM_ORIG_r0 #define REG_PARAM2 ARM_r1 #define REG_PARAM3 ARM_r2 + +#elif defined(ARM64) + #define REG_ORIG_ACCUM regs[8] + #define REG_ACCUM regs[0] + #define REG_PARAM1 regs[0] + #define REG_PARAM2 regs[1] + #define REG_PARAM3 regs[2] + + + #elif defined(MIPS) #ifndef MIPSEL #error only little endian supported @@ -94,6 +112,59 @@ int num_attached_pids = 0; pid_t attached_pids[MAX_ATTACHED_PIDS]; int *fds = NULL; +#ifdef ARM64 +struct user_pt_regs_node { + struct user_pt_regs regs; + struct user_pt_regs_node *user_pt_regs_next; +}; + +void user_pt_regs_insert(struct user_pt_regs_node** user_pt_regs_head, struct user_pt_regs *regs) +{ + struct user_pt_regs_node* new_node = + (struct user_pt_regs_node*) malloc(sizeof(struct user_pt_regs_node)); + + memcpy(&new_node->regs, regs, sizeof(struct user_pt_regs)); + new_node->user_pt_regs_next = (*user_pt_regs_head); + (*user_pt_regs_head) = new_node; +} + +struct user_pt_regs * user_pt_regs_search(struct user_pt_regs_node** user_pt_regs_head, struct user_pt_regs *regs) +{ + struct user_pt_regs_node* current = *user_pt_regs_head; + while (current != NULL) + { + if ((current->regs.REG_ORIG_ACCUM == regs->REG_ORIG_ACCUM) && (current->regs.REG_PARAM2 == regs->REG_PARAM2)) + return ¤t->regs; + current = current->user_pt_regs_next; + } + return NULL; +} + + +int user_pt_regs_delete(struct user_pt_regs_node** user_pt_regs_head, struct user_pt_regs *regs) +{ + struct user_pt_regs_node* temp = *user_pt_regs_head, *prev; + + if (temp != NULL && (&temp->regs == regs)) + { + *user_pt_regs_head = temp->user_pt_regs_next; + free(temp); + return 0; + } + + while (temp != NULL && (&temp->regs != regs)) + { + prev = temp; + temp = temp->user_pt_regs_next; + } + + if (temp == NULL) return -1; + prev->user_pt_regs_next = temp->user_pt_regs_next; + free(temp); + return 0; +} +#endif + void detach(int signum) { int i; for (i = 0; i < num_attached_pids; i++) @@ -260,6 +331,10 @@ int main(int argc, char **argv) unsigned char *lastbuf = NULL; unsigned long last_buf_size = -1; +#ifdef ARM64 + struct user_pt_regs_node* user_pt_regs_head = NULL; +#endif + for(;;) { int status; pid_t pid = wait(&status); @@ -274,6 +349,18 @@ int main(int argc, char **argv) #elif defined(ARM) struct pt_regs regs; ptrace(PTRACE_GETREGS, pid, 0, ®s); + +#elif defined(ARM64) + struct user_pt_regs regs, *old_regs; + struct iovec io; + io.iov_base = ®s; + io.iov_len = sizeof(regs); + + if (ptrace(PTRACE_GETREGSET, pid, (void*) NT_PRSTATUS, (void*) &io) == -1) { + printf("ARM64: PTRACE_GETREGSET: %s\n", strerror(errno)); + return errno; + } + #elif defined(MIPS) struct pt_regs regs; long pc = ptrace(PTRACE_PEEKUSER, pid, 64, 0); @@ -287,12 +374,26 @@ int main(int argc, char **argv) ptrace(PTRACE_GETREGS, pid, 0, ®s); #endif /*unsigned int b = ptrace(PTRACE_PEEKTEXT, pid, regs.eip, 0);*/ - if ((follow_forks && regs.REG_ORIG_ACCUM == SYS_fork) - || (follow_clones && regs.REG_ORIG_ACCUM == SYS_clone)) { + +#if defined(ARM64) + if (follow_forks && regs.REG_ORIG_ACCUM == SYS_clone) { +#else + if ((follow_forks && regs.REG_ORIG_ACCUM == SYS_fork) + || (follow_clones && regs.REG_ORIG_ACCUM == SYS_clone)) { +#endif if (regs.REG_ACCUM > 0) attach(regs.REG_ACCUM); } if ((regs.REG_ORIG_ACCUM == SYS_read || regs.REG_ORIG_ACCUM == SYS_write) && (regs.REG_PARAM3 == regs.REG_ACCUM)) { +#ifdef ARM64 + /* ARM64 doesn't expose orig_x0 to user space, + so retrive orig_x0 from older user pt regs */ + old_regs = user_pt_regs_search(&user_pt_regs_head, ®s); + if (old_regs != NULL) { + regs.REG_PARAM1 = old_regs->REG_PARAM1; + user_pt_regs_delete(&user_pt_regs_head, old_regs); + } +#endif for (i = 0; i < numfds; i++) if (fds[i] == (int)regs.REG_PARAM1) break; @@ -348,7 +449,12 @@ int main(int argc, char **argv) fflush(stdout); } } - +#ifdef ARM64 + else if (regs.REG_ORIG_ACCUM == SYS_read || regs.REG_ORIG_ACCUM == SYS_write) + { + user_pt_regs_insert(&user_pt_regs_head,®s); + } +#endif ptrace(PTRACE_SYSCALL, pid, 0, 0); } } -- 2.20.1