"Fossies" - the Fresh Open Source Software Archive

Member "reptyr-reptyr-0.9.0/platform/linux/linux_ptrace.c" (12 Jun 2022, 10192 Bytes) of package /linux/privat/reptyr-reptyr-0.9.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "linux_ptrace.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.8.0_vs_0.9.0.

    1 /*
    2  * Copyright (C) 2011 by Nelson Elhage
    3  *
    4  * Permission is hereby granted, free of charge, to any person obtaining a copy
    5  * of this software and associated documentation files (the "Software"), to deal
    6  * in the Software without restriction, including without limitation the rights
    7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    8  * copies of the Software, and to permit persons to whom the Software is
    9  * furnished to do so, subject to the following conditions:
   10  *
   11  * The above copyright notice and this permission notice shall be included in
   12  * all copies or substantial portions of the Software.
   13  *
   14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   20  * THE SOFTWARE.
   21  */
   22 
   23 #ifdef __linux__
   24 
   25 #include <elf.h>
   26 #include "../../ptrace.h"
   27 #include "../platform.h"
   28 
   29 /*
   30  * RHEL 5's kernel supports these flags, but their libc doesn't ship a ptrace.h
   31  * that defines them. Define them here, and if our kernel doesn't support them,
   32  * we'll find out when PTRACE_SETOPTIONS fails.
   33  */
   34 #ifndef PTRACE_O_TRACESYSGOOD
   35 #define PTRACE_O_TRACESYSGOOD 0x00000001
   36 #endif
   37 
   38 #ifndef PTRACE_O_TRACEFORK
   39 #define PTRACE_O_TRACEFORK 0x00000002
   40 #endif
   41 
   42 #ifndef PTRACE_EVENT_FORK
   43 #define PTRACE_EVENT_FORK 1
   44 #endif
   45 
   46 #define min(x, y) ({                \
   47     typeof(x) _min1 = (x);          \
   48     typeof(y) _min2 = (y);          \
   49     _min1 < _min2 ? _min1 : _min2; })
   50 
   51 #ifdef PTRACE_TRACEME
   52 static long __ptrace_command(struct ptrace_child *child, int req,
   53                              void *, void*);
   54 #else
   55 static long __ptrace_command(struct ptrace_child *child, enum __ptrace_request req,
   56                              void *, void*);
   57 #endif
   58 
   59 #define ptrace_command(cld, req, ...) _ptrace_command(cld, req, ## __VA_ARGS__, NULL, NULL)
   60 #define _ptrace_command(cld, req, addr, data, ...) __ptrace_command((cld), (req), (void*)(addr), (void*)(data))
   61 
   62 #define ptr(regs, off) ((unsigned long*)((void*)(regs)+(off)))
   63 
   64 struct ptrace_personality {
   65     size_t syscall_rv;
   66     size_t syscall_arg0;
   67     size_t syscall_arg1;
   68     size_t syscall_arg2;
   69     size_t syscall_arg3;
   70     size_t syscall_arg4;
   71     size_t syscall_arg5;
   72     size_t reg_ip;
   73 };
   74 
   75 static struct ptrace_personality *personality(struct ptrace_child *child);
   76 
   77 #if defined(__amd64__)
   78 #include "arch/amd64.h"
   79 #elif defined(__i386__)
   80 #include "arch/i386.h"
   81 #elif defined(__arm__)
   82 #include "arch/arm.h"
   83 #elif defined(__aarch64__)
   84 #include "arch/aarch64.h"
   85 #elif defined(__powerpc__)
   86 #include "arch/powerpc.h"
   87 #elif defined(__riscv) && __riscv_xlen == 64
   88 #include "arch/riscv64.h"
   89 #else
   90 #error Unsupported architecture.
   91 #endif
   92 
   93 #ifndef ARCH_HAVE_MULTIPLE_PERSONALITIES
   94 int arch_get_personality(struct ptrace_child *child) {
   95     return 0;
   96 }
   97 
   98 struct syscall_numbers arch_syscall_numbers[] = {
   99 #include "arch/default-syscalls.h"
  100 };
  101 #endif
  102 
  103 static struct ptrace_personality *personality(struct ptrace_child *child) {
  104     return &arch_personality[child->personality];
  105 }
  106 
  107 struct syscall_numbers *ptrace_syscall_numbers(struct ptrace_child *child) {
  108     return &arch_syscall_numbers[child->personality];
  109 }
  110 
  111 int ptrace_attach_child(struct ptrace_child *child, pid_t pid) {
  112     memset(child, 0, sizeof * child);
  113     child->pid = pid;
  114     if (ptrace_command(child, PTRACE_ATTACH) < 0)
  115         return -1;
  116 
  117     return ptrace_finish_attach(child, pid);
  118 }
  119 
  120 int ptrace_finish_attach(struct ptrace_child *child, pid_t pid) {
  121     memset(child, 0, sizeof * child);
  122     child->pid = pid;
  123 
  124     kill(pid, SIGCONT);
  125     if (ptrace_wait(child) < 0)
  126         goto detach;
  127 
  128     if (arch_get_personality(child))
  129         goto detach;
  130 
  131     if (ptrace_command(child, PTRACE_SETOPTIONS, 0,
  132                        PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK) < 0)
  133         goto detach;
  134 
  135     return 0;
  136 
  137 detach:
  138     /* Don't clobber child->error */
  139     ptrace(PTRACE_DETACH, child->pid, 0, 0);
  140     return -1;
  141 }
  142 
  143 int ptrace_detach_child(struct ptrace_child *child) {
  144     if (ptrace_command(child, PTRACE_DETACH, 0, 0) < 0)
  145         return -1;
  146     child->state = ptrace_detached;
  147     return 0;
  148 }
  149 
  150 int ptrace_wait(struct ptrace_child *child) {
  151     if (waitpid(child->pid, &child->status, 0) < 0) {
  152         child->error = errno;
  153         return -1;
  154     }
  155     if (WIFEXITED(child->status) || WIFSIGNALED(child->status)) {
  156         child->state = ptrace_exited;
  157     } else if (WIFSTOPPED(child->status)) {
  158         int sig = WSTOPSIG(child->status);
  159         if (sig & 0x80) {
  160             child->state = (child->state == ptrace_at_syscall) ?
  161                            ptrace_after_syscall : ptrace_at_syscall;
  162         } else {
  163             int event = child->status >> 16;
  164             if (sig == SIGTRAP && event == PTRACE_EVENT_FORK)
  165                 ptrace_command(child, PTRACE_GETEVENTMSG, 0, &child->forked_pid);
  166             if (child->state != ptrace_at_syscall)
  167                 child->state = ptrace_stopped;
  168         }
  169     } else {
  170         child->error = EINVAL;
  171         return -1;
  172     }
  173     return 0;
  174 }
  175 
  176 int ptrace_advance_to_state(struct ptrace_child *child,
  177                             enum child_state desired) {
  178     int err;
  179     while (child->state != desired) {
  180         switch (desired) {
  181         case ptrace_after_syscall:
  182         case ptrace_at_syscall:
  183             if (WIFSTOPPED(child->status) && WSTOPSIG(child->status) == SIGSEGV) {
  184                 child->error = EAGAIN;
  185                 return -1;
  186             }
  187             err = ptrace_command(child, PTRACE_SYSCALL, 0, 0);
  188             break;
  189         case ptrace_running:
  190             return ptrace_command(child, PTRACE_CONT, 0, 0);
  191         case ptrace_stopped:
  192             err = kill(child->pid, SIGSTOP);
  193             if (err < 0)
  194                 child->error = errno;
  195             break;
  196         default:
  197             child->error = EINVAL;
  198             return -1;
  199         }
  200         if (err < 0)
  201             return err;
  202         if (ptrace_wait(child) < 0)
  203             return -1;
  204     }
  205     return 0;
  206 }
  207 
  208 
  209 int ptrace_save_regs(struct ptrace_child *child) {
  210     if (ptrace_advance_to_state(child, ptrace_at_syscall) < 0)
  211         return -1;
  212 
  213     struct iovec reg_iovec = {
  214         .iov_base = &child->regs,
  215         .iov_len = sizeof(child->regs)
  216     };
  217     if (ptrace_command(child, PTRACE_GETREGSET, NT_PRSTATUS, &reg_iovec) < 0)
  218         return -1;
  219     arch_fixup_regs(child);
  220     if (arch_save_syscall(child) < 0)
  221         return -1;
  222     return 0;
  223 }
  224 
  225 int ptrace_restore_regs(struct ptrace_child *child) {
  226     int err;
  227     struct iovec reg_iovec = {
  228         .iov_base = &child->regs,
  229         .iov_len = sizeof(child->regs)
  230     };
  231     err = ptrace_command(child, PTRACE_SETREGSET, NT_PRSTATUS, &reg_iovec);
  232     if (err < 0)
  233         return err;
  234     return arch_restore_syscall(child);
  235 }
  236 
  237 unsigned long ptrace_remote_syscall(struct ptrace_child *child,
  238                                     unsigned long sysno,
  239                                     unsigned long p0, unsigned long p1,
  240                                     unsigned long p2, unsigned long p3,
  241                                     unsigned long p4, unsigned long p5) {
  242     unsigned long rv;
  243     if (ptrace_advance_to_state(child, ptrace_at_syscall) < 0)
  244         return -1;
  245 
  246     if (arch_set_syscall(child, sysno) < 0)
  247         return -1;
  248 
  249     typeof(child->regs) regs;
  250 
  251     struct iovec reg_iovec = {
  252         .iov_base = &regs,
  253         .iov_len = sizeof(regs)
  254     };
  255 
  256 #define setreg(r, v) (*ptr(&regs, (personality(child)->r))) = (v)
  257 
  258     if (ptrace_command(child, PTRACE_GETREGSET, NT_PRSTATUS, &reg_iovec) < 0)
  259         return -1;
  260 
  261     setreg(syscall_arg0, p0);
  262     setreg(syscall_arg1, p1);
  263     setreg(syscall_arg2, p2);
  264     setreg(syscall_arg3, p3);
  265     setreg(syscall_arg4, p4);
  266     setreg(syscall_arg5, p5);
  267 
  268     if (ptrace_command(child, PTRACE_SETREGSET, NT_PRSTATUS, &reg_iovec) < 0)
  269         return -1;
  270 
  271     if (ptrace_advance_to_state(child, ptrace_after_syscall) < 0)
  272         return -1;
  273 
  274     if (ptrace_command(child, PTRACE_GETREGSET, NT_PRSTATUS, &reg_iovec) < 0)
  275         return -1;
  276 
  277     rv = *ptr(&regs, (personality(child)->syscall_rv));
  278 
  279     setreg(reg_ip, *(unsigned long*)((void*)&child->regs + personality(child)->reg_ip));
  280 
  281     if (ptrace_command(child, PTRACE_SETREGSET, NT_PRSTATUS, &reg_iovec) < 0)
  282         return -1;
  283 
  284 #undef setreg
  285 
  286     return rv;
  287 }
  288 
  289 int ptrace_memcpy_to_child(struct ptrace_child *child, child_addr_t dst, const void *src, size_t n) {
  290     unsigned long scratch;
  291 
  292     while (n >= sizeof(unsigned long)) {
  293         if (ptrace_command(child, PTRACE_POKEDATA, dst, *((unsigned long*)src)) < 0)
  294             return -1;
  295         dst += sizeof(unsigned long);
  296         src += sizeof(unsigned long);
  297         n -= sizeof(unsigned long);
  298     }
  299 
  300     if (n) {
  301         scratch = ptrace_command(child, PTRACE_PEEKDATA, dst);
  302         if (child->error)
  303             return -1;
  304         memcpy(&scratch, src, n);
  305         if (ptrace_command(child, PTRACE_POKEDATA, dst, scratch) < 0)
  306             return -1;
  307     }
  308 
  309     return 0;
  310 }
  311 
  312 int ptrace_memcpy_from_child(struct ptrace_child *child, void *dst, child_addr_t src, size_t n) {
  313     unsigned long scratch;
  314 
  315     while (n) {
  316         scratch = ptrace_command(child, PTRACE_PEEKDATA, src);
  317         if (child->error) return -1;
  318         memcpy(dst, &scratch, min(n, sizeof(unsigned long)));
  319 
  320         dst += sizeof(unsigned long);
  321         src += sizeof(unsigned long);
  322         if (n >= sizeof(unsigned long))
  323             n -= sizeof(unsigned long);
  324         else
  325             n = 0;
  326     }
  327     return 0;
  328 }
  329 
  330 #ifdef PTRACE_TRACEME
  331 static long __ptrace_command(struct ptrace_child *child, int req,
  332                              void *addr, void *data) {
  333 #else
  334 static long __ptrace_command(struct ptrace_child *child, enum __ptrace_request req,
  335                              void *addr, void *data) {
  336 #endif
  337     long rv;
  338     errno = 0;
  339     rv = ptrace(req, child->pid, addr, data);
  340     child->error = errno;
  341     return rv;
  342 }
  343 
  344 #endif