"Fossies" - the Fresh Open Source Software Archive

Member "reptyr-reptyr-0.8.0/platform/linux/linux_ptrace.c" (29 Sep 2020, 10115 Bytes) of package /linux/privat/reptyr-reptyr-0.8.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.

    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 #else
   88 #error Unsupported architecture.
   89 #endif
   90 
   91 #ifndef ARCH_HAVE_MULTIPLE_PERSONALITIES
   92 int arch_get_personality(struct ptrace_child *child) {
   93     return 0;
   94 }
   95 
   96 struct syscall_numbers arch_syscall_numbers[] = {
   97 #include "arch/default-syscalls.h"
   98 };
   99 #endif
  100 
  101 static struct ptrace_personality *personality(struct ptrace_child *child) {
  102     return &arch_personality[child->personality];
  103 }
  104 
  105 struct syscall_numbers *ptrace_syscall_numbers(struct ptrace_child *child) {
  106     return &arch_syscall_numbers[child->personality];
  107 }
  108 
  109 int ptrace_attach_child(struct ptrace_child *child, pid_t pid) {
  110     memset(child, 0, sizeof * child);
  111     child->pid = pid;
  112     if (ptrace_command(child, PTRACE_ATTACH) < 0)
  113         return -1;
  114 
  115     return ptrace_finish_attach(child, pid);
  116 }
  117 
  118 int ptrace_finish_attach(struct ptrace_child *child, pid_t pid) {
  119     memset(child, 0, sizeof * child);
  120     child->pid = pid;
  121 
  122     kill(pid, SIGCONT);
  123     if (ptrace_wait(child) < 0)
  124         goto detach;
  125 
  126     if (arch_get_personality(child))
  127         goto detach;
  128 
  129     if (ptrace_command(child, PTRACE_SETOPTIONS, 0,
  130                        PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK) < 0)
  131         goto detach;
  132 
  133     return 0;
  134 
  135 detach:
  136     /* Don't clobber child->error */
  137     ptrace(PTRACE_DETACH, child->pid, 0, 0);
  138     return -1;
  139 }
  140 
  141 int ptrace_detach_child(struct ptrace_child *child) {
  142     if (ptrace_command(child, PTRACE_DETACH, 0, 0) < 0)
  143         return -1;
  144     child->state = ptrace_detached;
  145     return 0;
  146 }
  147 
  148 int ptrace_wait(struct ptrace_child *child) {
  149     if (waitpid(child->pid, &child->status, 0) < 0) {
  150         child->error = errno;
  151         return -1;
  152     }
  153     if (WIFEXITED(child->status) || WIFSIGNALED(child->status)) {
  154         child->state = ptrace_exited;
  155     } else if (WIFSTOPPED(child->status)) {
  156         int sig = WSTOPSIG(child->status);
  157         if (sig & 0x80) {
  158             child->state = (child->state == ptrace_at_syscall) ?
  159                            ptrace_after_syscall : ptrace_at_syscall;
  160         } else {
  161             if (sig == SIGTRAP && (((child->status >> 8) & PTRACE_EVENT_FORK) == PTRACE_EVENT_FORK))
  162                 ptrace_command(child, PTRACE_GETEVENTMSG, 0, &child->forked_pid);
  163             if (child->state != ptrace_at_syscall)
  164                 child->state = ptrace_stopped;
  165         }
  166     } else {
  167         child->error = EINVAL;
  168         return -1;
  169     }
  170     return 0;
  171 }
  172 
  173 int ptrace_advance_to_state(struct ptrace_child *child,
  174                             enum child_state desired) {
  175     int err;
  176     while (child->state != desired) {
  177         switch (desired) {
  178         case ptrace_after_syscall:
  179         case ptrace_at_syscall:
  180             if (WIFSTOPPED(child->status) && WSTOPSIG(child->status) == SIGSEGV) {
  181                 child->error = EAGAIN;
  182                 return -1;
  183             }
  184             err = ptrace_command(child, PTRACE_SYSCALL, 0, 0);
  185             break;
  186         case ptrace_running:
  187             return ptrace_command(child, PTRACE_CONT, 0, 0);
  188         case ptrace_stopped:
  189             err = kill(child->pid, SIGSTOP);
  190             if (err < 0)
  191                 child->error = errno;
  192             break;
  193         default:
  194             child->error = EINVAL;
  195             return -1;
  196         }
  197         if (err < 0)
  198             return err;
  199         if (ptrace_wait(child) < 0)
  200             return -1;
  201     }
  202     return 0;
  203 }
  204 
  205 
  206 int ptrace_save_regs(struct ptrace_child *child) {
  207     if (ptrace_advance_to_state(child, ptrace_at_syscall) < 0)
  208         return -1;
  209 
  210     struct iovec reg_iovec = {
  211         .iov_base = &child->regs,
  212         .iov_len = sizeof(child->regs)
  213     };
  214     if (ptrace_command(child, PTRACE_GETREGSET, NT_PRSTATUS, &reg_iovec) < 0)
  215         return -1;
  216     arch_fixup_regs(child);
  217     if (arch_save_syscall(child) < 0)
  218         return -1;
  219     return 0;
  220 }
  221 
  222 int ptrace_restore_regs(struct ptrace_child *child) {
  223     int err;
  224     struct iovec reg_iovec = {
  225         .iov_base = &child->regs,
  226         .iov_len = sizeof(child->regs)
  227     };
  228     err = ptrace_command(child, PTRACE_SETREGSET, NT_PRSTATUS, &reg_iovec);
  229     if (err < 0)
  230         return err;
  231     return arch_restore_syscall(child);
  232 }
  233 
  234 unsigned long ptrace_remote_syscall(struct ptrace_child *child,
  235                                     unsigned long sysno,
  236                                     unsigned long p0, unsigned long p1,
  237                                     unsigned long p2, unsigned long p3,
  238                                     unsigned long p4, unsigned long p5) {
  239     unsigned long rv;
  240     if (ptrace_advance_to_state(child, ptrace_at_syscall) < 0)
  241         return -1;
  242 
  243     if (arch_set_syscall(child, sysno) < 0)
  244         return -1;
  245 
  246     typeof(child->regs) regs;
  247 
  248     struct iovec reg_iovec = {
  249         .iov_base = &regs,
  250         .iov_len = sizeof(regs)
  251     };
  252 
  253 #define setreg(r, v) (*ptr(&regs, (personality(child)->r))) = (v)
  254 
  255     if (ptrace_command(child, PTRACE_GETREGSET, NT_PRSTATUS, &reg_iovec) < 0)
  256         return -1;
  257 
  258     setreg(syscall_arg0, p0);
  259     setreg(syscall_arg1, p1);
  260     setreg(syscall_arg2, p2);
  261     setreg(syscall_arg3, p3);
  262     setreg(syscall_arg4, p4);
  263     setreg(syscall_arg5, p5);
  264 
  265     if (ptrace_command(child, PTRACE_SETREGSET, NT_PRSTATUS, &reg_iovec) < 0)
  266         return -1;
  267 
  268     if (ptrace_advance_to_state(child, ptrace_after_syscall) < 0)
  269         return -1;
  270 
  271     if (ptrace_command(child, PTRACE_GETREGSET, NT_PRSTATUS, &reg_iovec) < 0)
  272         return -1;
  273 
  274     rv = *ptr(&regs, (personality(child)->syscall_rv));
  275 
  276     setreg(reg_ip, *(unsigned long*)((void*)&child->regs + personality(child)->reg_ip));
  277 
  278     if (ptrace_command(child, PTRACE_SETREGSET, NT_PRSTATUS, &reg_iovec) < 0)
  279         return -1;
  280 
  281 #undef setreg
  282 
  283     return rv;
  284 }
  285 
  286 int ptrace_memcpy_to_child(struct ptrace_child *child, child_addr_t dst, const void *src, size_t n) {
  287     unsigned long scratch;
  288 
  289     while (n >= sizeof(unsigned long)) {
  290         if (ptrace_command(child, PTRACE_POKEDATA, dst, *((unsigned long*)src)) < 0)
  291             return -1;
  292         dst += sizeof(unsigned long);
  293         src += sizeof(unsigned long);
  294         n -= sizeof(unsigned long);
  295     }
  296 
  297     if (n) {
  298         scratch = ptrace_command(child, PTRACE_PEEKDATA, dst);
  299         if (child->error)
  300             return -1;
  301         memcpy(&scratch, src, n);
  302         if (ptrace_command(child, PTRACE_POKEDATA, dst, scratch) < 0)
  303             return -1;
  304     }
  305 
  306     return 0;
  307 }
  308 
  309 int ptrace_memcpy_from_child(struct ptrace_child *child, void *dst, child_addr_t src, size_t n) {
  310     unsigned long scratch;
  311 
  312     while (n) {
  313         scratch = ptrace_command(child, PTRACE_PEEKDATA, src);
  314         if (child->error) return -1;
  315         memcpy(dst, &scratch, min(n, sizeof(unsigned long)));
  316 
  317         dst += sizeof(unsigned long);
  318         src += sizeof(unsigned long);
  319         if (n >= sizeof(unsigned long))
  320             n -= sizeof(unsigned long);
  321         else
  322             n = 0;
  323     }
  324     return 0;
  325 }
  326 
  327 #ifdef PTRACE_TRACEME
  328 static long __ptrace_command(struct ptrace_child *child, int req,
  329                              void *addr, void *data) {
  330 #else
  331 static long __ptrace_command(struct ptrace_child *child, enum __ptrace_request req,
  332                              void *addr, void *data) {
  333 #endif
  334     long rv;
  335     errno = 0;
  336     rv = ptrace(req, child->pid, addr, data);
  337     child->error = errno;
  338     return rv;
  339 }
  340 
  341 #endif