"Fossies" - the Fresh Open Source Software Archive

Member "reptyr-reptyr-0.8.0/platform/freebsd/freebsd_ptrace.c" (29 Sep 2020, 10106 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 "freebsd_ptrace.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.7.0_vs_0.8.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 #include <sys/ptrace.h>
   24 #include <sys/types.h>
   25 #include <sys/user.h>
   26 #include <sys/wait.h>
   27 #include <unistd.h>
   28 #include <stdlib.h>
   29 #include <stdio.h>
   30 #include <errno.h>
   31 #include <string.h>
   32 #include <sys/syscall.h>
   33 #include <sys/mman.h>
   34 #include <assert.h>
   35 #include <stddef.h>
   36 #include <signal.h>
   37 
   38 #include "../../ptrace.h"
   39 
   40 #include "../platform.h"
   41 
   42 #define min(x, y) ({                \
   43     typeof(x) _min1 = (x);          \
   44     typeof(y) _min2 = (y);          \
   45     _min1 < _min2 ? _min1 : _min2; })
   46 
   47 static int __ptrace_command(struct ptrace_child *child, int req,
   48                             void *, int);
   49 
   50 #define ptrace_command(cld, req, ...) _ptrace_command(cld, req, ## __VA_ARGS__, 0, 0)
   51 #define _ptrace_command(cld, req, addr, data, ...) __ptrace_command((cld), (req), (void*)(addr), (int)(data))
   52 
   53 
   54 struct ptrace_personality {
   55     size_t syscall_rv;
   56     size_t syscall_arg0;
   57     size_t syscall_arg1;
   58     size_t syscall_arg2;
   59     size_t syscall_arg3;
   60     size_t syscall_arg4;
   61     size_t syscall_arg5;
   62     size_t reg_ip;
   63 };
   64 
   65 
   66 static struct ptrace_personality *personality(struct ptrace_child *child);
   67 
   68 #if defined(__amd64__)
   69 #include "arch/amd64.h"
   70 #elif defined(__i386__)
   71 #include "arch/i386.h"
   72 #elif defined(__arm__)
   73 #include "arch/arm.h"
   74 #else
   75 #error Unsupported architecture.
   76 #endif
   77 
   78 #ifndef ARCH_HAVE_MULTIPLE_PERSONALITIES
   79 int arch_get_personality(struct ptrace_child *child) {
   80     return 0;
   81 }
   82 
   83 struct syscall_numbers arch_syscall_numbers[] = {
   84 #include "arch/default-syscalls.h"
   85 };
   86 #endif
   87 
   88 static struct ptrace_personality *personality(struct ptrace_child *child) {
   89     return &arch_personality[child->personality];
   90 }
   91 
   92 struct syscall_numbers *ptrace_syscall_numbers(struct ptrace_child *child) {
   93     return &arch_syscall_numbers[child->personality];
   94 }
   95 
   96 int ptrace_attach_child(struct ptrace_child *child, pid_t pid) {
   97     memset(child, 0, sizeof(*child));
   98     child->pid = pid;
   99 
  100     if (ptrace_command(child, PT_ATTACH, 0, 0) < 0)
  101         return -1;
  102 
  103     return ptrace_finish_attach(child, pid);
  104 }
  105 
  106 int ptrace_finish_attach(struct ptrace_child *child, pid_t pid) {
  107     memset(child, 0, sizeof(*child));
  108     child->pid = pid;
  109 
  110     if (ptrace_wait(child) < 0)
  111         goto detach;
  112 
  113     ptrace_command(child, PT_FOLLOW_FORK, 0, 1);
  114 
  115     if (arch_get_personality(child))
  116         goto detach;
  117 
  118     kill(pid, SIGCONT);
  119 
  120     return 0;
  121 
  122 detach:
  123     /* Don't clobber child->error */
  124     ptrace(PT_DETACH, child->pid, (caddr_t)1, 0);
  125     return -1;
  126 }
  127 
  128 int ptrace_detach_child(struct ptrace_child *child) {
  129     if (ptrace_command(child, PT_DETACH, (caddr_t)1, 0) < 0)
  130         return -1;
  131     child->state = ptrace_detached;
  132     return 0;
  133 }
  134 
  135 int ptrace_wait(struct ptrace_child *child) {
  136     struct ptrace_lwpinfo lwpinfo;
  137     if (waitpid(child->pid, &child->status, 0) < 0) {
  138         child->error = errno;
  139         return -1;
  140     }
  141     if (WIFEXITED(child->status) || WIFSIGNALED(child->status)) {
  142         child->state = ptrace_exited;
  143     } else if (WIFSTOPPED(child->status)) {
  144         ptrace_command(child, PT_LWPINFO, &lwpinfo, sizeof(lwpinfo));
  145         child->state = ptrace_stopped;
  146         if (lwpinfo.pl_flags & PL_FLAG_FORKED)
  147             child->forked_pid = lwpinfo.pl_child_pid;
  148         if (lwpinfo.pl_flags & PL_FLAG_SCE)
  149             child->state = ptrace_at_syscall;
  150         if (lwpinfo.pl_flags & PL_FLAG_SCX)
  151             child->state = ptrace_after_syscall;
  152     } else {
  153         child->error = EINVAL;
  154         return -1;
  155     }
  156     return 0;
  157 }
  158 
  159 int ptrace_advance_to_state(struct ptrace_child *child,
  160                             enum child_state desired) {
  161     int err;
  162     while (child->state != desired) {
  163         switch (desired) {
  164         case ptrace_after_syscall:
  165             if (WIFSTOPPED(child->status) && WSTOPSIG(child->status) == SIGSEGV) {
  166                 child->error = EAGAIN;
  167                 return -1;
  168             }
  169             err = ptrace_command(child, PT_TO_SCX, (caddr_t)1, 0);
  170             break;
  171         case ptrace_at_syscall:
  172             if (WIFSTOPPED(child->status) && WSTOPSIG(child->status) == SIGSEGV) {
  173                 child->error = EAGAIN;
  174                 return -1;
  175             }
  176             err = ptrace_command(child, PT_TO_SCE, (caddr_t)1, 0);
  177             break;
  178         case ptrace_running:
  179             return ptrace_command(child, PT_CONTINUE, (caddr_t)1, 0);
  180         case ptrace_stopped:
  181             err = kill(child->pid, SIGSTOP);
  182             if (err < 0)
  183                 child->error = errno;
  184             break;
  185         default:
  186             child->error = EINVAL;
  187             return -1;
  188         }
  189         if (err < 0)
  190             return err;
  191         if (ptrace_wait(child) < 0)
  192             return -1;
  193     }
  194     return 0;
  195 }
  196 
  197 
  198 int ptrace_save_regs(struct ptrace_child *child) {
  199     if (ptrace_advance_to_state(child, ptrace_at_syscall) < 0)
  200         return -1;
  201     if (ptrace_command(child, PT_GETREGS, &child->regs, 0) < 0)
  202         return -1;
  203     arch_save_syscall(child);
  204     arch_fixup_regs(child);
  205     if (arch_save_syscall(child) < 0)
  206         return -1;
  207     return 0;
  208 }
  209 
  210 int ptrace_restore_regs(struct ptrace_child *child) {
  211     int err;
  212     err = ptrace_command(child, PT_SETREGS, &child->regs, 0);
  213     if (err < 0)
  214         return err;
  215     return arch_restore_syscall(child);
  216 }
  217 
  218 unsigned long ptrace_remote_syscall(struct ptrace_child *child,
  219                                     unsigned long sysno,
  220                                     unsigned long p0, unsigned long p1,
  221                                     unsigned long p2, unsigned long p3,
  222                                     unsigned long p4, unsigned long p5) {
  223 #ifdef PT_GET_SC_RET
  224     struct ptrace_sc_ret psr;
  225 #endif
  226     unsigned long rv;
  227     if (ptrace_advance_to_state(child, ptrace_at_syscall) < 0)
  228         return -1;
  229 #define setreg(r, v) arch_set_register(child,personality(child)->r,v)
  230 
  231     //if (arch_set_syscall(child, sysno) < 0)
  232     //return -1;
  233 
  234     setreg(syscall_rv, sysno);
  235 
  236     setreg(syscall_arg0, p0);
  237     setreg(syscall_arg1, p1);
  238     setreg(syscall_arg2, p2);
  239     setreg(syscall_arg3, p3);
  240     setreg(syscall_arg4, p4);
  241     setreg(syscall_arg5, p5);
  242 
  243     if (ptrace_advance_to_state(child, ptrace_after_syscall) < 0)
  244         return -1;
  245 
  246 #ifndef PT_GET_SC_RET
  247     /*
  248      * In case of an error, this is technically incorrect.  FreeBSD, on most
  249      * architectures, stores the return value in this register as expected and
  250      * sets a separate bit to indicate if this an error or not -- contrary to
  251      * the Linux convention of negative values indicating an error, positive
  252      * values otherwise.  This should switch to PT_GET_SC_RET unconditionally
  253      * as it makes its way into all supported releases.
  254      */
  255     rv = arch_get_register(child, personality(child)->syscall_rv);
  256 
  257     if (child->error)
  258         return -1;
  259 #else
  260     if (ptrace_command(child, PT_GET_SC_RET, &psr, sizeof(psr)) < 0)
  261         return -1;
  262 
  263     if (psr.sr_error != 0)
  264         rv = -psr.sr_error;
  265     else
  266         rv = psr.sr_retval[0];
  267 #endif
  268     setreg(reg_ip, *(unsigned long*)((void*)&child->regs +
  269                                      personality(child)->reg_ip));
  270 
  271 #undef setreg
  272 
  273     return rv;
  274 }
  275 
  276 int ptrace_memcpy_to_child(struct ptrace_child *child, child_addr_t dst, const void *src, size_t n) {
  277     int scratch;
  278 
  279     while (n >= sizeof(int)) {
  280         if (ptrace_command(child, PT_WRITE_D, dst, *((int*)src)) < 0)
  281             return -1;
  282         dst += sizeof(int);
  283         src += sizeof(int);
  284         n -= sizeof(int);
  285     }
  286 
  287     if (n) {
  288         scratch = ptrace_command(child, PT_READ_D, dst);
  289         if (child->error)
  290             return -1;
  291         memcpy(&scratch, src, n);
  292         if (ptrace_command(child, PT_WRITE_D, dst, scratch) < 0)
  293             return -1;
  294     }
  295 
  296     return 0;
  297 }
  298 
  299 int ptrace_memcpy_from_child(struct ptrace_child *child, void *dst, child_addr_t src, size_t n) {
  300     int scratch;
  301 
  302     while (n) {
  303         scratch = ptrace_command(child, PT_READ_D, src);
  304         if (child->error) return -1;
  305         memcpy(dst, &scratch, min(n, sizeof(int)));
  306 
  307         dst += sizeof(int);
  308         src += sizeof(int);
  309         if (n >= sizeof(int))
  310             n -= sizeof(int);
  311         else
  312             n = 0;
  313     }
  314     return 0;
  315 }
  316 
  317 static int __ptrace_command(struct ptrace_child *child, int req,
  318                             void *addr, int data) {
  319     long rv;
  320     errno = 0;
  321     rv = ptrace(req, child->pid, addr, data);
  322     child->error = errno;
  323     return rv;
  324 }
  325 
  326 
  327 #ifdef BUILD_PTRACE_MAIN
  328 int main(int argc, char **argv) {
  329     struct ptrace_child child;
  330     pid_t pid;
  331 
  332     if (argc < 2) {
  333         printf("Usage: %s pid\n", argv[0]);
  334         return 1;
  335     }
  336     pid = atoi(argv[1]);
  337 
  338     assert(!ptrace_attach_child(&child, pid));
  339     assert(!ptrace_save_regs(&child));
  340 
  341     printf("mmap = %lx\n", ptrace_remote_syscall(&child, 477, 0,
  342             4096, PROT_READ | PROT_WRITE,
  343             MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
  344 
  345     //reset_user_struct(&child.regs);
  346     assert(!ptrace_restore_regs(&child));
  347     assert(!ptrace_detach_child(&child));
  348 
  349     return 0;
  350 }
  351 #endif