Changeset 2505 for neercs


Ignore:
Timestamp:
Jul 1, 2008, 1:26:30 AM (12 years ago)
Author:
Sam Hocevar
Message:
  • Start refactoring grab.c: instead of writing code to the stack, we wait for a system call to be made and simply rewind eip/rip. Should now work on amd64, too.
Location:
neercs/trunk/src
Files:
3 edited

Legend:

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

    r2504 r2505  
    2323#include <unistd.h>
    2424
    25 #include "config.h"
    26 
    2725#if defined USE_GRAB
    2826#   include <sys/ioctl.h>
     
    3937#include "neercs.h"
    4038
     39#define X(x) #x
     40#define STRINGIFY(x) X(x)
     41
    4142#if defined __x86_64__
    4243#   define RAX rax
     
    4647#   define RSP rsp
    4748#   define RIP rip
     49#   define RDI rdi
     50#   define RSI rsi
     51#   define SYSCALL 0x050fL /* 0F 05 = syscall */
     52#   define FMT "%016lx"
    4853#else
    4954#   define RAX eax
     
    5358#   define RSP esp
    5459#   define RIP eip
     60#   define RDI edi
     61#   define RSI esi
     62#   define SYSCALL 0x80cd /* CD 80 = int $0x80 */
     63#   define FMT "%08lx"
    5564#endif
    5665
    5766#if defined USE_GRAB
    58 static int memcpy_from_target(pid_t pid, void* dest, void* src, size_t n)
    59 {
     67/* For debugging purposes only. Prints register and stack information. */
     68static 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/* FIXME: this function and the following have alignment issues */
     115static int memcpy_from_target(pid_t pid, void* dest, long src, size_t n)
     116{
     117    long *d = (long*)dest;
    60118    unsigned int i;
    61     long *d, *s;
    62     d = (long*) dest;
    63     s = (long*) src;
    64     n /= sizeof(long);
    65     for(i = 0; i < n; i++)
    66     {
    67         d[i] = ptrace(PTRACE_PEEKTEXT, pid, s + i, 0);
     119
     120    for(i = 0; i < n / sizeof(long); i++)
     121    {
     122        d[i] = ptrace(PTRACE_PEEKTEXT, pid, src + i * sizeof(long), 0);
    68123        if(errno)
    69124        {
    70             perror("ptrace(PTRACE_PEEKTEXT)");
     125            perror("ptrace_peektext");
    71126            return -1;
    72127        }
     
    75130}
    76131
    77 static int memcpy_into_target(pid_t pid, void* dest, void* src, size_t n)
    78 {
     132static int memcpy_into_target(pid_t pid, long dest, void* src, size_t n)
     133{
     134    long *s = (long*) src;
    79135    unsigned int i;
    80     long *d, *s;
    81     d = (long*) dest;
    82     s = (long*) src;
     136
    83137    for(i = 0; i < n / sizeof(long); i++)
    84138    {
    85         if(ptrace(PTRACE_POKETEXT, pid, d + i, s[i]) == -1)
    86         {
    87             perror("ptrace(PTRACE_POKETEXT)");
     139        if(ptrace(PTRACE_POKETEXT, pid, dest + i * sizeof(long), s[i]) == -1)
     140        {
     141            perror("ptrace_poketext");
    88142            return -1;
    89143        }
     
    92146}
    93147
    94 static int do_syscall(pid_t pid, struct user_regs_struct *regs)
     148static long do_syscall(pid_t pid, long call, long arg1, long arg2, long arg3)
    95149{
    96150    /* Method for remote syscall:
    97      *  - store current register status into oregs
    98      *  - move stack pointer to the next empty element
    99      *  - store current read stack contents into oinst
    100      *  - put CD 80 (int 0x80) into the stack
    101      *  - set instruction pointer to the current stack address
    102      *  - single step: execute instruction (int 0x80)
    103      *  - get new register values
    104      *  - restore old register values from oregs
    105      *  - restore old stack contents from oinst */
    106     struct user_regs_struct oregs;
     151     *  - wait until the traced application exits from a syscall
     152     *  - save registers
     153     *  - rewind eip/rip to point on the syscall instruction
     154     *  - single step: execute syscall instruction
     155     *  - restore registers */
     156    struct user_regs_struct regs, oldregs;
    107157    long oinst;
    108158
    109     if(ptrace(PTRACE_GETREGS, pid, NULL, &oregs) < 0)
     159    for(;;)
     160    {
     161        if(ptrace(PTRACE_GETREGS, pid, NULL, &oldregs) < 0)
     162        {
     163            fprintf(stderr, "PTRACE_GETREGS failed\n");
     164            return -1;
     165        }
     166
     167        oinst = ptrace(PTRACE_PEEKTEXT, pid, oldregs.RIP - 2, 0) & 0xffff;
     168
     169        if(oinst == SYSCALL)
     170            break;
     171
     172        if(ptrace(PTRACE_SYSCALL, pid, NULL, 0) < 0)
     173        {
     174            perror("ptrace_syscall (1)");
     175            return -1;
     176        }
     177        waitpid(pid, NULL, 0);
     178
     179        if(ptrace(PTRACE_SYSCALL, pid, NULL, 0) < 0)
     180        {
     181            perror("ptrace_syscall (2)");
     182            return -1;
     183        }
     184        waitpid(pid, NULL, 0);
     185    }
     186
     187    regs = oldregs;
     188    regs.RIP = regs.RIP - 2;
     189    regs.RAX = call;
     190#if defined __x86_64__
     191    regs.RDI = arg1;
     192    regs.RSI = arg2;
     193    regs.RDX = arg3;
     194#else
     195    regs.RBX = arg1;
     196    regs.RCX = arg2;
     197    regs.RDX = arg3;
     198#endif
     199
     200    if(ptrace(PTRACE_SETREGS, pid, NULL, &regs) < 0)
     201    {
     202        fprintf(stderr, "PTRACE_SETREGS failed\n");
     203        return -1;
     204    }
     205
     206    if(ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0)
     207    {
     208        fprintf(stderr, "PTRACE_SINGLESTEP failed\n");
     209        return -1;
     210    }
     211    waitpid(pid, NULL, 0);
     212
     213    if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
     214    {
     215        fprintf(stderr, "PTRACE_GETREGS failed\n");
     216        return -1;
     217    }
     218
     219    if(ptrace(PTRACE_SETREGS, pid, NULL, &oldregs) < 0)
     220    {
     221        fprintf(stderr, "PTRACE_SETREGS failed\n");
     222        return -1;
     223    }
     224
     225    debug("syscall %ld returned %ld", call, regs.RAX);
     226
     227    if((long)regs.RAX < 0)
     228    {
     229        errno = -(long)regs.RAX;
     230        perror("syscall");
     231        return -1;
     232    }
     233
     234    return regs.RAX;
     235}
     236
     237static int do_close(pid_t pid, int fd)
     238{
     239    return do_syscall(pid, SYS_close, fd, 0, 0);
     240}
     241
     242static int do_dup2(pid_t pid, int oldfd, int newfd)
     243{
     244    return do_syscall(pid, SYS_dup2, oldfd, newfd, 0);
     245}
     246
     247static int do_open(pid_t pid, char *path, int mode)
     248{
     249    char path_data[4096], backup_data[4096];
     250    struct user_regs_struct regs;
     251    long target_data;
     252    size_t size = (strlen(path) + sizeof(long)) & ~(sizeof(long) - 1L);
     253    int ret;
     254
     255    if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
    110256    {
    111257        fprintf(stderr, "PTRACE_GETREGS failed\n");
     
    113259    }
    114260
    115     regs->RSP = oregs.RSP - sizeof(long);
    116 
    117     oinst = ptrace(PTRACE_PEEKTEXT, pid, regs->RSP, 0);
    118     if(errno)
    119     {
    120         fprintf(stderr, "PTRACE_PEEKTEXT failed\n");
    121         return errno;
    122     }
    123 
    124     if(ptrace(PTRACE_POKETEXT, pid, regs->RSP, (long)0x80cd) < 0) /* int 0x80 */
    125     {
    126         fprintf(stderr, "PTRACE_POKETEXT failed\n");
    127         return errno;
    128     }
    129 
    130     regs->RIP = regs->RSP;
    131 
    132     if(ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0)
    133     {
    134         fprintf(stderr, "PTRACE_SETREGS failed\n");
    135         return errno;
    136     }
    137 
    138     if(ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0)
    139     {
    140         fprintf(stderr, "PTRACE_SINGLESTEP failed\n");
    141         return errno;
    142     }
    143     waitpid(pid, NULL, 0);
    144 
    145     if(ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0)
    146     {
    147         fprintf(stderr, "PTRACE_GETREGS failed\n");
    148         return errno;
    149     }
    150 
    151     if(ptrace(PTRACE_SETREGS, pid, NULL, &oregs) < 0)
    152     {
    153         fprintf(stderr, "PTRACE_SETREGS failed\n");
    154         return errno;
    155     }
    156 
    157     if(ptrace(PTRACE_POKETEXT, pid, oregs.RSP - sizeof(long), oinst) < 0)
    158     {
    159         fprintf(stderr, "PTRACE_POKETEXT failed\n");
    160         return errno;
    161     }
    162 
    163     return 0;
    164 }
    165 
    166 static int do_close(pid_t pid, int fd)
    167 {
    168     struct user_regs_struct regs;
    169     if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
    170     {
    171         fprintf(stderr, "PTRACE_GETREGS failed\n");
    172         return errno;
    173     }
    174 
    175     regs.RAX = SYS_close;
    176     regs.RBX = fd;
    177 
    178     return do_syscall(pid, &regs);
    179 }
    180 
    181 static int do_dup2(pid_t pid, int oldfd, int newfd)
    182 {
    183     struct user_regs_struct regs;
    184     if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
    185     {
    186         fprintf(stderr, "PTRACE_GETREGS failed\n");
    187         return errno;
    188     }
    189 
    190     regs.RAX = SYS_dup2;
    191     regs.RBX = oldfd;
    192     regs.RCX = newfd;
    193 
    194     return do_syscall(pid, &regs);
    195 }
    196 
    197 static int do_open(pid_t pid, char *path, int mode, int *fd)
    198 {
    199     struct user_regs_struct regs;
    200     void *backup_page;
    201     void *target_page = (void*)(0x08048000);
    202     size_t size = (1 << 12); /* 4K */
    203     int ret;
    204 
    205     /* Backup the page that we will use */
    206     backup_page = malloc(size);
    207     if(memcpy_from_target(pid, backup_page, target_page, size) < 0)
    208         return -1;
    209 
    210     if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
    211     {
    212         fprintf(stderr, "PTRACE_GETREGS failed\n");
    213         return errno;
    214     }
     261    target_data = (regs.RSP - size) & ~(sizeof(long) - 1L);
     262
     263    /* Backup the data that we will use */
     264    if(memcpy_from_target(pid, backup_data, target_data, size) < 0)
     265        return -1;
    215266
    216267    /* +4 (or 8) because it's truncated on a multiple of 4 (or 8)
    217268     * and we need 1 */
    218     memcpy_into_target(pid, target_page, path, strlen(path) + sizeof(long));
    219 
    220     regs.RAX = SYS_open;
    221     regs.RBX = (long)target_page;
    222     regs.RCX = O_RDWR;
    223     regs.RDX = 0755;
    224 
    225     if((ret = do_syscall(pid, &regs)) != 0)
    226     {
    227         return ret;
    228     }
    229 
    230     /* Restore the pages */
    231     memcpy_into_target(pid, target_page, backup_page, size);
    232 
    233     *fd  = regs.RAX;
    234 
    235     return 0;
     269    sprintf(path_data, "%s", path);
     270    memcpy_into_target(pid, target_data, path_data, size);
     271
     272    ret = do_syscall(pid, SYS_open, target_data, O_RDWR, 0755);
     273
     274    /* Restore the datas */
     275    memcpy_into_target(pid, target_data, backup_data, size);
     276
     277    if(ret < 0)
     278    {
     279        errno = ret;
     280        return -1;
     281    }
     282
     283    return ret;
    236284}
    237285
    238286static int do_setsid(pid_t pid)
    239287{
    240     struct user_regs_struct regs;
    241     int ret;
    242 
    243     if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
    244     {
    245         fprintf(stderr, "PTRACE_GETREGS failed\n");
    246         return errno;
    247     }
     288    long ret;
    248289
    249290    debug("Running setsid on process %d (sid=%d)", pid, getsid(pid));
    250291
    251     regs.RAX = SYS_setpgid;
    252     regs.RBX = 0;
    253     regs.RCX = getsid(pid);
    254 
    255     if((ret = do_syscall(pid, &regs)) != 0)
     292    ret = do_syscall(pid, SYS_setpgid, 0, getsid(pid), 0);
     293    if(ret < 0)
    256294    {
    257295        fprintf(stderr, "syscall setpgid failed\n");
     
    259297    }
    260298
    261     if(regs.RAX != 0)
    262     {
    263         fprintf(stderr, "setpgid returned %ld\n", (long)regs.RAX);
    264         return -regs.RAX;
    265     }
    266 
    267     regs.RAX = SYS_setsid;
    268 
    269     if((ret = do_syscall(pid, &regs)) != 0)
     299    if(ret != 0)
     300    {
     301        fprintf(stderr, "setpgid returned %ld\n", ret);
     302        return -ret;
     303    }
     304
     305    ret = do_syscall(pid, SYS_setsid, 0, 0, 0);
     306    if(ret < 0)
    270307    {
    271308        fprintf(stderr, "syscall setsid failed\n");
     
    275312    debug("pid %d has now sid %d", pid, getsid(pid));
    276313
    277     if((long int)regs.RAX == -1L)
    278     {
    279         fprintf(stderr, "getsid failed\n");
    280         return -regs.RAX;
    281     }
    282 
    283314    return 0;
    284315}
    285316#endif
    286317
    287 int grab_process(pid_t pid, char *ptyname, int ptyfd)
     318int grab_process(long pid, char *ptyname, int ptyfd)
    288319{
    289320#if defined USE_GRAB
     
    295326    debug("pty is %s", ptyname);
    296327
    297     kill(pid, SIGSTOP);
    298328    if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0)
    299329    {
    300         fprintf(stderr, "Cannot access process %d\n", pid);
     330        fprintf(stderr, "Cannot access process %ld\n", pid);
    301331        return errno;
    302332    }
    303     kill(pid, SIGCONT);
    304333    waitpid(pid, NULL, 0);
    305334
    306335    for(i = 0; i <= 2; i++)
    307336    {
    308         snprintf(fdstr, sizeof(fdstr), "/proc/%d/fd/%d", pid, i);
    309         to_open[i]=0;
     337        snprintf(fdstr, sizeof(fdstr), "/proc/%ld/fd/%d", pid, i);
     338        to_open[i] = 0;
    310339        lstat(fdstr, &stat_buf);
    311340        if((stat_buf.st_mode & S_IRUSR) && (stat_buf.st_mode & S_IWUSR))
     
    319348            continue;
    320349
    321         if(!S_ISCHR(stat_buf.st_mode) || MAJOR(stat_buf.st_rdev) != UNIX98_PTY_SLAVE_MAJOR)
     350        if(!S_ISCHR(stat_buf.st_mode)
     351            || MAJOR(stat_buf.st_rdev) != UNIX98_PTY_SLAVE_MAJOR)
    322352            continue;
    323353
    324         debug("fd %d is a pty", i);
     354        debug("found pty %d", i);
     355
    325356        if((ret = do_close(pid, i)))
    326357        {
    327358            fprintf(stderr, "do_close %s\n", strerror(ret));
    328359        }
    329         to_open[i]=1;
     360        to_open[i] = 1;
    330361    }
    331362
     
    339370        if(!to_open[i])
    340371            continue;
    341         if((ret = do_open(pid, ptyname, mode, &fd)))
    342         {
    343             fprintf(stderr, "do_open %s\n", strerror(ret));
    344         }
    345         if((ret = do_dup2(pid, fd, i)))
    346         {
    347             fprintf(stderr, "do_dup2 %s\n", strerror(ret));
     372        fd = do_open(pid, ptyname, mode);
     373        if(fd < 0)
     374        {
     375            perror("do_open");
     376        }
     377        ret = do_dup2(pid, fd, i);
     378        if(ret < 0)
     379        {
     380            perror("do_dup2");
    348381        }
    349382    }
  • neercs/trunk/src/neercs.h

    r2500 r2505  
    1515
    1616#include <stdint.h>
     17
    1718#include <caca.h>
    1819
     
    132133
    133134int create_pty(char *cmd, unsigned int w, unsigned int h, int *cpid);
    134 int create_pty_grab(pid_t pid, unsigned int w, unsigned int h);
    135 int grab_process(pid_t pid, char *ptyname, int ptyfd);
     135int create_pty_grab(long pid, unsigned int w, unsigned int h);
     136int grab_process(long pid, char *ptyname, int ptyfd);
    136137
    137138long int import_term(struct screen_list *screen_list, struct screen *sc, void const *data, unsigned int size);
     
    206207int fill_config(struct screen_list *screen_list);
    207208
    208 #if 0
     209#if 1
    209210#   define debug(f, z...) fprintf(stderr, f "\n", z)
    210211#else
  • neercs/trunk/src/term.c

    r2479 r2505  
    582582}
    583583
    584 int create_pty_grab(pid_t pid, unsigned int w, unsigned int h)
     584int create_pty_grab(long pid, unsigned int w, unsigned int h)
    585585{
    586586    int fdm, fds;
Note: See TracChangeset for help on using the changeset viewer.