Changeset 2509 for neercs


Ignore:
Timestamp:
Jul 1, 2008, 1:26:52 AM (12 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.
Location:
neercs/trunk/src
Files:
1 added
2 edited
1 copied

Legend:

Unmodified
Added
Removed
  • neercs/trunk/src/Makefile.am

    r2495 r2509  
    44neercs_SOURCES = neercs.h mygetopt.c recurrent.c main.c screens.c term.c \
    55                 grab.c effects.c wm.c screensaver.c attach.c configuration.c \
    6                                                                 input.c lock.c
     6                 mytrace.c mytrace.h input.c lock.c
    77neercs_CFLAGS = @CACA_CFLAGS@
    88neercs_LDADD = @CACA_LIBS@ @UTIL_LIBS@ @PAM_LIBS@
  • 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
  • neercs/trunk/src/mytrace.c

    r2508 r2509  
    22 *  neercs        console-based window manager
    33 *  Copyright (c) 2008 Pascal Terjan
     4 *            (c) 2008 Sam Hocevar <sam@zoy.org>
    45 *                All Rights Reserved
    56 *
     
    1718#include <errno.h>
    1819#include <fcntl.h>
    19 #include <signal.h>
    2020#include <stdio.h>
    2121#include <stdlib.h>
    2222#include <string.h>
    23 #include <unistd.h>
    2423
    2524#if defined USE_GRAB
     
    3029#   include <sys/user.h>
    3130#   include <sys/wait.h>
    32 
    33 #   include <linux/kdev_t.h>
    34 #   include <linux/major.h>
    3531#endif
    3632
    3733#include "neercs.h"
     34#include "mytrace.h"
     35
     36#if defined USE_GRAB
     37static int memcpy_from_target(struct mytrace *t,
     38                              char* dest, long src, size_t n);
     39static int memcpy_into_target(struct mytrace *t,
     40                              long dest, char *src, size_t n);
     41static long remote_syscall(pid_t pid, long call,
     42                           long arg1, long arg2, long arg3);
     43#if 0
     44static void print_registers(pid_t pid);
     45#endif
     46#endif
    3847
    3948#define X(x) #x
     
    6473#endif
    6574
    66 #if defined USE_GRAB
     75struct mytrace
     76{
     77    pid_t pid;
     78};
     79
     80struct mytrace* mytrace_attach(long int pid)
     81{
     82#if defined USE_GRAB
     83    struct mytrace *t;
     84
     85    if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0)
     86    {
     87        perror("ptrace_attach");
     88        return NULL;
     89    }
     90    waitpid(pid, NULL, 0);
     91
     92    t = malloc(sizeof(struct mytrace));
     93    t->pid = pid;
     94
     95    return t;
     96#else
     97    errno = ENOSYS;
     98    return NULL;
     99#endif
     100}
     101
     102int mytrace_detach(struct mytrace *t)
     103{
     104#if defined USE_GRAB
     105    ptrace(PTRACE_DETACH, t->pid, 0, 0);
     106    free(t);
     107
     108    return 0;
     109#else
     110    errno = ENOSYS;
     111    return -1;
     112#endif
     113}
     114
     115int mytrace_open(struct mytrace *t, char *path, int mode)
     116{
     117#if defined USE_GRAB
     118    char backup_data[4096];
     119    struct user_regs_struct regs;
     120    size_t size = strlen(path) + 1;
     121    int ret;
     122
     123    if(ptrace(PTRACE_GETREGS, t->pid, NULL, &regs) < 0)
     124    {
     125        fprintf(stderr, "PTRACE_GETREGS failed\n");
     126        return errno;
     127    }
     128
     129    /* Backup the data that we will use */
     130    if(memcpy_from_target(t, backup_data, regs.RSP, size) < 0)
     131        return -1;
     132
     133    /* +4 (or 8) because it's truncated on a multiple of 4 (or 8)
     134     * and we need 1 */
     135    sprintf(path, "%s", path);
     136    memcpy_into_target(t, regs.RSP, path, size);
     137
     138    ret = remote_syscall(t->pid, SYS_open, regs.RSP, O_RDWR, 0755);
     139
     140    /* Restore the datas */
     141    memcpy_into_target(t, regs.RSP, backup_data, size);
     142
     143    if(ret < 0)
     144    {
     145        errno = ret;
     146        return -1;
     147    }
     148
     149    return ret;
     150#else
     151    errno = ENOSYS;
     152    return -1;
     153#endif
     154}
     155
     156int mytrace_close(struct mytrace *t, int fd)
     157{
     158#if defined USE_GRAB
     159    return remote_syscall(t->pid, SYS_close, fd, 0, 0);
     160#else
     161    errno = ENOSYS;
     162    return -1;
     163#endif
     164}
     165
     166int mytrace_dup2(struct mytrace *t, int oldfd, int newfd)
     167{
     168#if defined USE_GRAB
     169    return remote_syscall(t->pid, SYS_dup2, oldfd, newfd, 0);
     170#else
     171    errno = ENOSYS;
     172    return -1;
     173#endif
     174}
     175
     176int mytrace_setpgid(struct mytrace *t, long pid, long pgid)
     177{
     178#if defined USE_GRAB
     179    return remote_syscall(t->pid, SYS_setpgid, pid, pgid, 0);
     180#else
     181    errno = ENOSYS;
     182    return -1;
     183#endif
     184}
     185
     186int mytrace_setsid(struct mytrace *t)
     187{
     188#if defined USE_GRAB
     189    return remote_syscall(t->pid, SYS_setsid, 0, 0, 0);
     190#else
     191    errno = ENOSYS;
     192    return -1;
     193#endif
     194}
     195
     196/*
     197 * XXX: the following functions are local
     198 */
     199
     200static int memcpy_from_target(struct mytrace *t,
     201                              char* dest, long src, size_t n)
     202{
     203    while(n)
     204    {
     205        long data;
     206        int align = sizeof(long) - 1;
     207        size_t todo = sizeof(long) - (src & align);
     208
     209        if(n < todo)
     210            todo = n;
     211
     212        data = ptrace(PTRACE_PEEKTEXT, t->pid, src - (src & align), 0);
     213        if(errno)
     214        {
     215            perror("ptrace_peektext");
     216            return -1;
     217        }
     218        memcpy(dest, (char *)&data + (src & align), todo);
     219
     220        dest += todo;
     221        src += todo;
     222        n -= todo;
     223    }
     224
     225    return 0;
     226}
     227
     228static int memcpy_into_target(struct mytrace *t,
     229                              long dest, char *src, size_t n)
     230{
     231    while(n)
     232    {
     233        long data;
     234        int align = sizeof(long) - 1;
     235        size_t todo = sizeof(long) - (dest & align);
     236
     237        if(n < todo)
     238            todo = n;
     239        if(todo != sizeof(long))
     240        {
     241            data = ptrace(PTRACE_PEEKTEXT, t->pid, dest - (dest & align), 0);
     242            if(errno)
     243            {
     244                perror("ptrace_peektext");
     245                return -1;
     246            }
     247        }
     248
     249        memcpy((char *)&data + (dest & align), src, todo);
     250        ptrace(PTRACE_POKETEXT, t->pid, dest - (dest & align), data);
     251        if(errno)
     252        {
     253            perror("ptrace_poketext");
     254            return -1;
     255        }
     256
     257        src += todo;
     258        dest += todo;
     259        n -= todo;
     260    }
     261
     262    return 0;
     263}
     264
     265static long remote_syscall(pid_t pid, long call,
     266                            long arg1, long arg2, long arg3)
     267{
     268    /* Method for remote syscall:
     269     *  - wait until the traced application exits from a syscall
     270     *  - save registers
     271     *  - rewind eip/rip to point on the syscall instruction
     272     *  - single step: execute syscall instruction
     273     *  - restore registers */
     274    struct user_regs_struct regs, oldregs;
     275    long oinst;
     276
     277    for(;;)
     278    {
     279        if(ptrace(PTRACE_GETREGS, pid, NULL, &oldregs) < 0)
     280        {
     281            fprintf(stderr, "PTRACE_GETREGS failed\n");
     282            return -1;
     283        }
     284
     285        oinst = ptrace(PTRACE_PEEKTEXT, pid, oldregs.RIP - 2, 0) & 0xffff;
     286
     287        if(oinst == SYSCALL)
     288            break;
     289
     290        if(ptrace(PTRACE_SYSCALL, pid, NULL, 0) < 0)
     291        {
     292            perror("ptrace_syscall (1)");
     293            return -1;
     294        }
     295        waitpid(pid, NULL, 0);
     296
     297        if(ptrace(PTRACE_SYSCALL, pid, NULL, 0) < 0)
     298        {
     299            perror("ptrace_syscall (2)");
     300            return -1;
     301        }
     302        waitpid(pid, NULL, 0);
     303    }
     304
     305    regs = oldregs;
     306    regs.RIP = regs.RIP - 2;
     307    regs.RAX = call;
     308#if defined __x86_64__
     309    regs.RDI = arg1;
     310    regs.RSI = arg2;
     311    regs.RDX = arg3;
     312#else
     313    regs.RBX = arg1;
     314    regs.RCX = arg2;
     315    regs.RDX = arg3;
     316#endif
     317
     318    if(ptrace(PTRACE_SETREGS, pid, NULL, &regs) < 0)
     319    {
     320        fprintf(stderr, "PTRACE_SETREGS failed\n");
     321        return -1;
     322    }
     323
     324    if(ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0)
     325    {
     326        fprintf(stderr, "PTRACE_SINGLESTEP failed\n");
     327        return -1;
     328    }
     329    waitpid(pid, NULL, 0);
     330
     331    if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
     332    {
     333        fprintf(stderr, "PTRACE_GETREGS failed\n");
     334        return -1;
     335    }
     336
     337    if(ptrace(PTRACE_SETREGS, pid, NULL, &oldregs) < 0)
     338    {
     339        fprintf(stderr, "PTRACE_SETREGS failed\n");
     340        return -1;
     341    }
     342
     343    debug("syscall %ld returned %ld", call, regs.RAX);
     344
     345    if((long)regs.RAX < 0)
     346    {
     347        errno = -(long)regs.RAX;
     348        perror("syscall");
     349        return -1;
     350    }
     351
     352    return regs.RAX;
     353}
     354
    67355/* For debugging purposes only. Prints register and stack information. */
     356#if 0
    68357static void print_registers(pid_t pid)
    69358{
     
    111400    fprintf(stderr, "...\n");
    112401}
    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
    343 
    344 int grab_process(long pid, char *ptyname, int ptyfd)
    345 {
    346 #if defined USE_GRAB
    347     int i, fd = 0, mode, ret;
    348     char fdstr[1024];
    349     char to_open[3];
    350     struct stat stat_buf;
    351 
    352     debug("pty is %s", ptyname);
    353 
    354     if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0)
    355     {
    356         fprintf(stderr, "Cannot access process %ld\n", pid);
    357         return errno;
    358     }
    359     waitpid(pid, NULL, 0);
    360 
    361     for(i = 0; i <= 2; i++)
    362     {
    363         snprintf(fdstr, sizeof(fdstr), "/proc/%ld/fd/%d", pid, i);
    364         to_open[i] = 0;
    365         lstat(fdstr, &stat_buf);
    366         if((stat_buf.st_mode & S_IRUSR) && (stat_buf.st_mode & S_IWUSR))
    367             mode = O_RDWR;
    368         else if(stat_buf.st_mode & S_IWUSR)
    369             mode = O_WRONLY;
    370         else
    371             mode = O_RDONLY;
    372 
    373         if(stat(fdstr, &stat_buf) < 0)
    374             continue;
    375 
    376         if(!S_ISCHR(stat_buf.st_mode)
    377             || MAJOR(stat_buf.st_rdev) != UNIX98_PTY_SLAVE_MAJOR)
    378             continue;
    379 
    380         debug("found pty %d", i);
    381 
    382         if((ret = do_close(pid, i)))
    383         {
    384             fprintf(stderr, "do_close %s\n", strerror(ret));
    385         }
    386         to_open[i] = 1;
    387     }
    388 
    389     if((ret = do_setsid(pid)))
    390     {
    391         fprintf(stderr, "do_setsid %s\n", strerror(ret));
    392     }
    393 
    394     for(i = 0; i <= 2; i++)
    395     {
    396         if(!to_open[i])
    397             continue;
    398         fd = do_open(pid, ptyname, mode);
    399         if(fd < 0)
    400         {
    401             perror("do_open");
    402         }
    403         ret = do_dup2(pid, fd, i);
    404         if(ret < 0)
    405         {
    406             perror("do_dup2");
    407         }
    408     }
    409 
    410     kill(pid, SIGWINCH);
    411     ptrace(PTRACE_DETACH, pid, 0, 0);
    412 
    413     return 0;
    414 #else
    415     return -1;
    416 #endif
    417 }
    418 
     402#endif
     403
Note: See TracChangeset for help on using the changeset viewer.