source: neercs/trunk/src/grab.c @ 2428

Last change on this file since 2428 was 2428, checked in by Pascal Terjan, 13 years ago
  • Remove code that was for the standalone test
  • Property svn:eol-style set to native
File size: 7.2 KB
Line 
1#include <errno.h>
2#include <fcntl.h>
3#include <signal.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <termios.h>
8#include <unistd.h>
9
10#include <linux/user.h>
11
12#include <sys/ioctl.h>
13#include <sys/ptrace.h>
14#include <sys/stat.h>
15#include <sys/syscall.h>
16#include <sys/wait.h>
17
18#include "neercs.h"
19
20static int memcpy_from_target(pid_t pid, void* dest, void* src, size_t n)
21{
22    unsigned int i;
23    long *d, *s;
24    d = (long*) dest;
25    s = (long*) src;
26    n /= sizeof(long);
27    for (i = 0; i < n; i++) {
28        d[i] = ptrace(PTRACE_PEEKTEXT, pid, s+i, 0);
29        if (errno) {
30            perror("ptrace(PTRACE_PEEKTEXT)");
31            return -1;
32        }
33    }
34    return 0;
35}
36
37static int memcpy_into_target(pid_t pid, void* dest, void* src, size_t n)
38{
39    unsigned int i;
40    long *d, *s;
41    d = (long*) dest;
42    s = (long*) src;
43    for (i = 0; i < n / sizeof(long); i++) {
44        if (ptrace(PTRACE_POKETEXT, pid, d+i, s[i]) == -1) {
45            perror("ptrace(PTRACE_POKETEXT)");
46            return -1;
47        }
48    }
49    return 0;
50}
51
52static int do_syscall(pid_t pid, struct user_regs_struct *regs)
53{
54
55    struct user_regs_struct oregs;
56    long oinst;
57
58    if(ptrace(PTRACE_GETREGS, pid, NULL, &oregs) < 0)
59    {
60        return errno;
61    }
62
63    regs->esp -= 4;
64
65    oinst = ptrace(PTRACE_PEEKTEXT, pid, regs->esp, 0);
66    if (errno) {
67        fprintf(stderr, "PTRACE_PEEKTEXT failed\n");
68        return errno;
69    }
70
71    if (ptrace(PTRACE_POKETEXT, pid, regs->esp, 0x80cd) < 0) { /* int 0x80 */
72        fprintf(stderr, "PTRACE_POKETEXT failed\n");
73        return errno;
74    }
75
76    regs->eip = regs->esp;
77    if(ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0)
78    {
79        return errno;
80    }
81
82    if(ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0)
83    {
84        return errno;
85    }
86    waitpid(pid, NULL, 0);
87
88    if(ptrace(PTRACE_SETREGS, pid, NULL, &oregs) < 0)
89    {
90        return errno;
91    }
92
93    if(ptrace(PTRACE_POKETEXT, pid, oregs.esp-4 , oinst) < 0)
94    {
95        return errno;
96    }
97
98    return 0;
99}
100
101static int do_close(pid_t pid, int fd)
102{
103    struct user_regs_struct regs;
104    if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
105    {
106        fprintf(stderr, "PTRACE_GETREGS failed\n");
107        return errno;
108    }
109
110    regs.eax = SYS_close;
111    regs.ebx = fd;
112
113    return do_syscall(pid, &regs);
114}
115
116static int do_dup2(pid_t pid, int oldfd, int newfd)
117{
118    struct user_regs_struct regs;
119    if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
120    {
121        fprintf(stderr, "PTRACE_GETREGS failed\n");
122        return errno;
123    }
124
125    regs.eax = SYS_dup2;
126    regs.ebx = oldfd;
127    regs.ecx = newfd;
128   
129    return do_syscall(pid, &regs);
130}
131
132static int do_open(pid_t pid, char *path, int mode, int *fd)
133{
134    struct user_regs_struct regs;
135    void *backup_page;
136    void *target_page = (void*)(0x08048000);
137    size_t size = (1<<12); /* 4K */
138    int ret;
139
140    /* Backup the page that we will use */
141    backup_page = malloc(size);
142    if (memcpy_from_target(pid, backup_page, target_page, size) < 0)
143        return -1;
144
145    if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
146    {
147        fprintf(stderr, "PTRACE_GETREGS failed\n");
148        return errno;
149    }
150
151    /* +4 because it's trcuncated on a multiple of 4 and we need 1 */
152    memcpy_into_target(pid, target_page, path, strlen(path)+4);
153
154    regs.eax = SYS_open;
155    regs.ebx = (long)target_page;
156    regs.ecx = O_RDWR;
157    regs.edx = 0755;
158   
159    if((ret = do_syscall(pid, &regs)) < 0)
160    {
161        return ret;
162    }
163
164    /* Restore the pages */
165    memcpy_into_target(pid, target_page, backup_page, size);
166
167    *fd  = regs.eax;
168
169    return 0;
170}
171
172static int do_get_termios(pid_t pid, int fd, struct termios *t) {
173    struct user_regs_struct regs;
174    void *backup_page;
175    void *target_page = (void*)(0x08048000);
176    size_t size = (1<<12)*2; /* 8K */
177    int ret;
178
179    /* Backup the pages that we will use */
180    backup_page = malloc(size);
181    if (memcpy_from_target(pid, backup_page, target_page, size) < 0)
182        return -1;
183
184    if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
185    {
186        fprintf(stderr, "PTRACE_GETREGS failed\n");
187        return errno;
188    }
189
190    regs.eax = SYS_ioctl;
191    regs.ebx = fd;
192    regs.ecx = TCGETS;
193    regs.edx = ((long)target_page);
194
195    if((ret = do_syscall(pid, &regs)) < 0)
196    {
197        return ret;
198    }
199
200    if (regs.eax < 0) {
201        fprintf(stderr, "ioctl failed\n");
202        return (-regs.eax);
203    }
204
205    memcpy_from_target(pid, t, (void*)(target_page), sizeof(struct termios));
206
207    /* Restore the pages */
208    memcpy_into_target(pid, target_page, backup_page, size);
209
210    return 0;
211}
212
213static int do_setpgrp(pid_t pid, int fd) {
214    struct user_regs_struct regs;
215    void *backup_page;
216    void *target_page = (void*)(0x08048000);
217    size_t size = (1<<12)*2; /* 8K */
218    int ret, pgrp;
219
220    /* Backup the pages that we will use */
221    backup_page = malloc(size);
222    if (memcpy_from_target(pid, backup_page, target_page, size) < 0)
223        return -1;
224
225    if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
226    {
227        fprintf(stderr, "PTRACE_GETREGS failed\n");
228        return errno;
229    }
230
231    pgrp = getpgrp();
232
233    memcpy_into_target(pid, target_page, &getpgrp, 4);
234
235    regs.eax = SYS_ioctl;
236    regs.ebx = fd;
237    regs.ecx = TIOCSPGRP;
238    regs.edx = (long)(target_page);
239    do_syscall(pid, &regs);
240
241
242    if((ret = do_syscall(pid, &regs)) < 0)
243    {
244        return ret;
245    }
246
247    if (regs.eax < 0) {
248        fprintf(stderr, "ioctl failed\n");
249        return (-regs.eax);
250    }
251
252    /* Restore the pages */
253    memcpy_into_target(pid, target_page, backup_page, size);
254
255    return 0;
256}
257
258int grab_process(pid_t pid, int ptyfd)
259{
260    struct termios t;
261    int i, fd = 0, mode, ret;
262    char tty[1024];
263    char fdstr[1024];
264    struct stat stat_buf;
265
266    snprintf(fdstr, sizeof(fdstr), "/proc/%d/fd/%d", getpid(), ptyfd);
267    if ((i = readlink(fdstr, tty, sizeof(tty)-1)) == -1) {
268        fprintf(stderr, "readlink failed\n");
269        return -1;
270    }
271    tty[i] = 0;
272    debug("Our pty is %s", tty);
273
274    if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0)
275    {
276        fprintf(stderr, "Cannot access process %d\n", pid);
277        return errno;
278    }
279    waitpid(pid, NULL, 0);
280
281    for(i=0; i<=2; i++)
282    {
283        snprintf(fdstr, sizeof(fdstr), "/proc/%d/fd/%d", pid, i);
284        lstat(fdstr, &stat_buf);
285        if ((stat_buf.st_mode & S_IRUSR) && (stat_buf.st_mode & S_IWUSR))
286            mode = O_RDWR;
287        else if (stat_buf.st_mode & S_IWUSR)
288            mode = O_WRONLY;
289        else
290            mode = O_RDONLY;
291
292        if (stat(fdstr, &stat_buf) < 0)
293            continue;
294        if (!S_ISCHR(stat_buf.st_mode)) //FIXME How to know for sure this is the pty and not /dev/null ?
295            continue;
296
297        debug("fd %d is a pty", i);
298        if((ret = do_get_termios(pid, i, &t)))
299        {
300            fprintf(stderr, "do_get_termios %s\n", strerror(ret));
301        }
302        if((ret = do_close(pid, i)))
303        {
304            fprintf(stderr, "do_close %s\n", strerror(ret));
305        }
306        if((ret = do_open(pid, tty, mode, &fd)))
307        {
308            fprintf(stderr, "do_open %s\n", strerror(ret));
309        }
310        if((ret = do_dup2(pid, fd, i)))
311        {
312            fprintf(stderr, "do_dup2 %s\n", strerror(ret));
313        }
314        if((ret = do_setpgrp(pid, i)))
315        {
316            fprintf(stderr, "do_setpgrp %s\n", strerror(ret));
317        }
318    }
319   
320    kill(pid, SIGWINCH);
321
322    ptrace(PTRACE_DETACH, pid, 0, 0);
323
324    return 0;
325}
Note: See TracBrowser for help on using the repository browser.