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

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