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

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