Ignore:
Timestamp:
Jul 1, 2008, 1:26:52 AM (14 years ago)
Author:
Sam Hocevar
Message:
  • Split grab.c into the grabbing heuristic and the pure ptrace interface, because we might use it for other things in the future.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • neercs/trunk/src/grab.c

    r2508 r2509  
    2323#include <unistd.h>
    2424
    25 #if defined USE_GRAB
    26 #   include <sys/ioctl.h>
    27 #   include <sys/ptrace.h>
    28 #   include <sys/stat.h>
    29 #   include <sys/syscall.h>
    30 #   include <sys/user.h>
    31 #   include <sys/wait.h>
    32 
     25#if defined HAVE_LINUX_KDEV_T_H
    3326#   include <linux/kdev_t.h>
    3427#   include <linux/major.h>
     
    3629
    3730#include "neercs.h"
    38 
    39 #define X(x) #x
    40 #define STRINGIFY(x) X(x)
    41 
    42 #if defined __x86_64__
    43 #   define RAX rax
    44 #   define RBX rbx
    45 #   define RCX rcx
    46 #   define RDX rdx
    47 #   define RSP rsp
    48 #   define RIP rip
    49 #   define RDI rdi
    50 #   define RSI rsi
    51 #   define SYSCALL 0x050fL /* 0F 05 = syscall */
    52 #   define FMT "%016lx"
    53 #else
    54 #   define RAX eax
    55 #   define RBX ebx
    56 #   define RCX ecx
    57 #   define RDX edx
    58 #   define RSP esp
    59 #   define RIP eip
    60 #   define RDI edi
    61 #   define RSI esi
    62 #   define SYSCALL 0x80cd /* CD 80 = int $0x80 */
    63 #   define FMT "%08lx"
    64 #endif
    65 
    66 #if defined USE_GRAB
    67 /* For debugging purposes only. Prints register and stack information. */
    68 static void print_registers(pid_t pid)
    69 {
    70     union { long int l; unsigned char data[sizeof(long int)]; } inst;
    71     struct user_regs_struct regs;
    72     int i;
    73 
    74     if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
    75     {
    76         perror("ptrace_getregs");
    77         exit(errno);
    78     }
    79 
    80     fprintf(stderr, "  / %s: "FMT"   ", STRINGIFY(RAX), regs.RAX);
    81     fprintf(stderr, "%s: "FMT"\n", STRINGIFY(RBX), regs.RBX);
    82     fprintf(stderr, "  | %s: "FMT"   ", STRINGIFY(RCX), regs.RCX);
    83     fprintf(stderr, "%s: "FMT"\n", STRINGIFY(RDX), regs.RDX);
    84     fprintf(stderr, "  | %s: "FMT"   ", STRINGIFY(RDI), regs.RDI);
    85     fprintf(stderr, "%s: "FMT"\n", STRINGIFY(RSI), regs.RSI);
    86     fprintf(stderr, "  | %s: "FMT"   ", STRINGIFY(RSP), regs.RSP);
    87     fprintf(stderr, "%s: "FMT"\n", STRINGIFY(RIP), regs.RIP);
    88 
    89     inst.l = ptrace(PTRACE_PEEKTEXT, pid, regs.RIP - 4, 0);
    90     fprintf(stderr, "  | code: ... %02x %02x %02x %02x <---> ",
    91             inst.data[0], inst.data[1], inst.data[2], inst.data[3]);
    92     inst.l = ptrace(PTRACE_PEEKTEXT, pid, regs.RIP, 0);
    93     fprintf(stderr, "%02x %02x %02x %02x ...\n",
    94             inst.data[0], inst.data[1], inst.data[2], inst.data[3]);
    95 
    96     fprintf(stderr, "  \\ stack: ... ");
    97     for(i = -16; i < 24; i += sizeof(long))
    98     {
    99         inst.l = ptrace(PTRACE_PEEKDATA, pid, regs.RSP + i, 0);
    100 #if defined __x86_64__
    101         fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x %02x ",
    102                 inst.data[0], inst.data[1], inst.data[2], inst.data[3],
    103                 inst.data[4], inst.data[5], inst.data[6], inst.data[7]);
    104 #else
    105         fprintf(stderr, "%02x %02x %02x %02x ",
    106                 inst.data[0], inst.data[1], inst.data[2], inst.data[3]);
    107 #endif
    108         if(i == 0)
    109             fprintf(stderr, "[%s] ", STRINGIFY(RSP));
    110     }
    111     fprintf(stderr, "...\n");
    112 }
    113 
    114 static int memcpy_from_target(pid_t pid, char* dest, long src, size_t n)
    115 {
    116     while(n)
    117     {
    118         long data;
    119         int align = sizeof(long) - 1;
    120         size_t todo = sizeof(long) - (src & align);
    121 
    122         if(n < todo)
    123             todo = n;
    124 
    125         data = ptrace(PTRACE_PEEKTEXT, pid, src - (src & align), 0);
    126         if(errno)
    127         {
    128             perror("ptrace_peektext");
    129             return -1;
    130         }
    131         memcpy(dest, (char *)&data + (src & align), todo);
    132 
    133         dest += todo;
    134         src += todo;
    135         n -= todo;
    136     }
    137 
    138     return 0;
    139 }
    140 
    141 static int memcpy_into_target(pid_t pid, long dest, char* src, size_t n)
    142 {
    143     while(n)
    144     {
    145         long data;
    146         int align = sizeof(long) - 1;
    147         size_t todo = sizeof(long) - (dest & align);
    148 
    149         if(n < todo)
    150             todo = n;
    151         if(todo != sizeof(long))
    152         {
    153             data = ptrace(PTRACE_PEEKTEXT, pid, dest - (dest & align), 0);
    154             if(errno)
    155             {
    156                 perror("ptrace_peektext");
    157                 return -1;
    158             }
    159         }
    160 
    161         memcpy((char *)&data + (dest & align), src, todo);
    162         ptrace(PTRACE_POKETEXT, pid, dest - (dest & align), data);
    163         if(errno)
    164         {
    165             perror("ptrace_poketext");
    166             return -1;
    167         }
    168 
    169         src += todo;
    170         dest += todo;
    171         n -= todo;
    172     }
    173 
    174     return 0;
    175 }
    176 
    177 static long do_syscall(pid_t pid, long call, long arg1, long arg2, long arg3)
    178 {
    179     /* Method for remote syscall:
    180      *  - wait until the traced application exits from a syscall
    181      *  - save registers
    182      *  - rewind eip/rip to point on the syscall instruction
    183      *  - single step: execute syscall instruction
    184      *  - restore registers */
    185     struct user_regs_struct regs, oldregs;
    186     long oinst;
    187 
    188     for(;;)
    189     {
    190         if(ptrace(PTRACE_GETREGS, pid, NULL, &oldregs) < 0)
    191         {
    192             fprintf(stderr, "PTRACE_GETREGS failed\n");
    193             return -1;
    194         }
    195 
    196         oinst = ptrace(PTRACE_PEEKTEXT, pid, oldregs.RIP - 2, 0) & 0xffff;
    197 
    198         if(oinst == SYSCALL)
    199             break;
    200 
    201         if(ptrace(PTRACE_SYSCALL, pid, NULL, 0) < 0)
    202         {
    203             perror("ptrace_syscall (1)");
    204             return -1;
    205         }
    206         waitpid(pid, NULL, 0);
    207 
    208         if(ptrace(PTRACE_SYSCALL, pid, NULL, 0) < 0)
    209         {
    210             perror("ptrace_syscall (2)");
    211             return -1;
    212         }
    213         waitpid(pid, NULL, 0);
    214     }
    215 
    216     regs = oldregs;
    217     regs.RIP = regs.RIP - 2;
    218     regs.RAX = call;
    219 #if defined __x86_64__
    220     regs.RDI = arg1;
    221     regs.RSI = arg2;
    222     regs.RDX = arg3;
    223 #else
    224     regs.RBX = arg1;
    225     regs.RCX = arg2;
    226     regs.RDX = arg3;
    227 #endif
    228 
    229     if(ptrace(PTRACE_SETREGS, pid, NULL, &regs) < 0)
    230     {
    231         fprintf(stderr, "PTRACE_SETREGS failed\n");
    232         return -1;
    233     }
    234 
    235     if(ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0)
    236     {
    237         fprintf(stderr, "PTRACE_SINGLESTEP failed\n");
    238         return -1;
    239     }
    240     waitpid(pid, NULL, 0);
    241 
    242     if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
    243     {
    244         fprintf(stderr, "PTRACE_GETREGS failed\n");
    245         return -1;
    246     }
    247 
    248     if(ptrace(PTRACE_SETREGS, pid, NULL, &oldregs) < 0)
    249     {
    250         fprintf(stderr, "PTRACE_SETREGS failed\n");
    251         return -1;
    252     }
    253 
    254     debug("syscall %ld returned %ld", call, regs.RAX);
    255 
    256     if((long)regs.RAX < 0)
    257     {
    258         errno = -(long)regs.RAX;
    259         perror("syscall");
    260         return -1;
    261     }
    262 
    263     return regs.RAX;
    264 }
    265 
    266 static int do_close(pid_t pid, int fd)
    267 {
    268     return do_syscall(pid, SYS_close, fd, 0, 0);
    269 }
    270 
    271 static int do_dup2(pid_t pid, int oldfd, int newfd)
    272 {
    273     return do_syscall(pid, SYS_dup2, oldfd, newfd, 0);
    274 }
    275 
    276 static int do_open(pid_t pid, char *path, int mode)
    277 {
    278     char backup_data[4096];
    279     struct user_regs_struct regs;
    280     size_t size = strlen(path) + 1;
    281     int ret;
    282 
    283     if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
    284     {
    285         fprintf(stderr, "PTRACE_GETREGS failed\n");
    286         return errno;
    287     }
    288 
    289     /* Backup the data that we will use */
    290     if(memcpy_from_target(pid, backup_data, regs.RSP, size) < 0)
    291         return -1;
    292 
    293     /* +4 (or 8) because it's truncated on a multiple of 4 (or 8)
    294      * and we need 1 */
    295     sprintf(path, "%s", path);
    296     memcpy_into_target(pid, regs.RSP, path, size);
    297 
    298     ret = do_syscall(pid, SYS_open, regs.RSP, O_RDWR, 0755);
    299 
    300     /* Restore the datas */
    301     memcpy_into_target(pid, regs.RSP, backup_data, size);
    302 
    303     if(ret < 0)
    304     {
    305         errno = ret;
    306         return -1;
    307     }
    308 
    309     return ret;
    310 }
    311 
    312 static int do_setsid(pid_t pid)
    313 {
    314     long ret;
    315 
    316     debug("Running setsid on process %d (sid=%d)", pid, getsid(pid));
    317 
    318     ret = do_syscall(pid, SYS_setpgid, 0, getsid(pid), 0);
    319     if(ret < 0)
    320     {
    321         fprintf(stderr, "syscall setpgid failed\n");
    322         return ret;
    323     }
    324 
    325     if(ret != 0)
    326     {
    327         fprintf(stderr, "setpgid returned %ld\n", ret);
    328         return -ret;
    329     }
    330 
    331     ret = do_syscall(pid, SYS_setsid, 0, 0, 0);
    332     if(ret < 0)
    333     {
    334         fprintf(stderr, "syscall setsid failed\n");
    335         return ret;
    336     }
    337 
    338     debug("pid %d has now sid %d", pid, getsid(pid));
    339 
    340     return 0;
    341 }
    342 #endif
     31#include "mytrace.h"
    34332
    34433int grab_process(long pid, char *ptyname, int ptyfd)
    34534{
    346 #if defined USE_GRAB
     35#if defined HAVE_LINUX_KDEV_T_H
     36    char fdstr[1024];
     37    struct mytrace *t;
    34738    int i, fd = 0, mode, ret;
    348     char fdstr[1024];
    34939    char to_open[3];
    35040    struct stat stat_buf;
     
    35242    debug("pty is %s", ptyname);
    35343
    354     if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0)
     44    t = mytrace_attach(pid);
     45    if(!t)
    35546    {
    35647        fprintf(stderr, "Cannot access process %ld\n", pid);
    357         return errno;
     48        return -1;
    35849    }
    359     waitpid(pid, NULL, 0);
    36050
     51    /* Look for file descriptors that are PTYs */
    36152    for(i = 0; i <= 2; i++)
    36253    {
     
    38071        debug("found pty %d", i);
    38172
    382         if((ret = do_close(pid, i)))
     73        ret = mytrace_close(t, i);
     74        if(ret < 0)
    38375        {
    384             fprintf(stderr, "do_close %s\n", strerror(ret));
     76            perror("mytrace_close");
    38577        }
    38678        to_open[i] = 1;
    38779    }
    38880
    389     if((ret = do_setsid(pid)))
     81    /* Set the process's session ID */
     82    debug("Running setsid on process %ld (sid=%d)", pid, getsid(pid));
     83
     84    ret = mytrace_setpgid(t, 0, getsid(pid));
     85    if(ret < 0)
    39086    {
    391         fprintf(stderr, "do_setsid %s\n", strerror(ret));
     87        fprintf(stderr, "syscall setpgid failed\n");
     88        mytrace_detach(t);
     89        return -1;
    39290    }
    39391
     92    if(ret != 0)
     93    {
     94        fprintf(stderr, "setpgid returned %d\n", ret);
     95        mytrace_detach(t);
     96        return -1;
     97    }
     98
     99    ret = mytrace_setsid(t);
     100    if(ret < 0)
     101    {
     102        fprintf(stderr, "syscall setsid failed\n");
     103        mytrace_detach(t);
     104        return -1;
     105    }
     106
     107    debug("pid %ld has now sid %d", pid, getsid(pid));
     108
     109    /* Reopen PTY file descriptors */
    394110    for(i = 0; i <= 2; i++)
    395111    {
    396112        if(!to_open[i])
    397113            continue;
    398         fd = do_open(pid, ptyname, mode);
     114        fd = mytrace_open(t, ptyname, mode);
    399115        if(fd < 0)
    400116        {
    401             perror("do_open");
     117            perror("mytrace_open");
    402118        }
    403         ret = do_dup2(pid, fd, i);
     119        ret = mytrace_dup2(t, fd, i);
    404120        if(ret < 0)
    405121        {
    406             perror("do_dup2");
     122            perror("mytrace_dup2");
    407123        }
    408124    }
    409125
    410126    kill(pid, SIGWINCH);
    411     ptrace(PTRACE_DETACH, pid, 0, 0);
     127
     128    mytrace_detach(t);
    412129
    413130    return 0;
    414131#else
     132    errno = ENOSYS;
    415133    return -1;
    416134#endif
Note: See TracChangeset for help on using the changeset viewer.