Changeset 2509
- Timestamp:
- Jul 1, 2008, 1:26:52 AM (15 years ago)
- Location:
- neercs/trunk/src
- Files:
-
- 1 added
- 2 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
neercs/trunk/src/Makefile.am
r2495 r2509 4 4 neercs_SOURCES = neercs.h mygetopt.c recurrent.c main.c screens.c term.c \ 5 5 grab.c effects.c wm.c screensaver.c attach.c configuration.c \ 6 6 mytrace.c mytrace.h input.c lock.c 7 7 neercs_CFLAGS = @CACA_CFLAGS@ 8 8 neercs_LDADD = @CACA_LIBS@ @UTIL_LIBS@ @PAM_LIBS@ -
neercs/trunk/src/grab.c
r2508 r2509 23 23 #include <unistd.h> 24 24 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 33 26 # include <linux/kdev_t.h> 34 27 # include <linux/major.h> … … 36 29 37 30 #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, ®s) < 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, ®s) < 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, ®s) < 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, ®s) < 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" 343 32 344 33 int grab_process(long pid, char *ptyname, int ptyfd) 345 34 { 346 #if defined USE_GRAB 35 #if defined HAVE_LINUX_KDEV_T_H 36 char fdstr[1024]; 37 struct mytrace *t; 347 38 int i, fd = 0, mode, ret; 348 char fdstr[1024];349 39 char to_open[3]; 350 40 struct stat stat_buf; … … 352 42 debug("pty is %s", ptyname); 353 43 354 if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) 44 t = mytrace_attach(pid); 45 if(!t) 355 46 { 356 47 fprintf(stderr, "Cannot access process %ld\n", pid); 357 return errno;48 return -1; 358 49 } 359 waitpid(pid, NULL, 0);360 50 51 /* Look for file descriptors that are PTYs */ 361 52 for(i = 0; i <= 2; i++) 362 53 { … … 380 71 debug("found pty %d", i); 381 72 382 if((ret = do_close(pid, i))) 73 ret = mytrace_close(t, i); 74 if(ret < 0) 383 75 { 384 fprintf(stderr, "do_close %s\n", strerror(ret));76 perror("mytrace_close"); 385 77 } 386 78 to_open[i] = 1; 387 79 } 388 80 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) 390 86 { 391 fprintf(stderr, "do_setsid %s\n", strerror(ret)); 87 fprintf(stderr, "syscall setpgid failed\n"); 88 mytrace_detach(t); 89 return -1; 392 90 } 393 91 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 */ 394 110 for(i = 0; i <= 2; i++) 395 111 { 396 112 if(!to_open[i]) 397 113 continue; 398 fd = do_open(pid, ptyname, mode);114 fd = mytrace_open(t, ptyname, mode); 399 115 if(fd < 0) 400 116 { 401 perror(" do_open");117 perror("mytrace_open"); 402 118 } 403 ret = do_dup2(pid, fd, i);119 ret = mytrace_dup2(t, fd, i); 404 120 if(ret < 0) 405 121 { 406 perror(" do_dup2");122 perror("mytrace_dup2"); 407 123 } 408 124 } 409 125 410 126 kill(pid, SIGWINCH); 411 ptrace(PTRACE_DETACH, pid, 0, 0); 127 128 mytrace_detach(t); 412 129 413 130 return 0; 414 131 #else 132 errno = ENOSYS; 415 133 return -1; 416 134 #endif -
neercs/trunk/src/mytrace.c
r2508 r2509 2 2 * neercs console-based window manager 3 3 * Copyright (c) 2008 Pascal Terjan 4 * (c) 2008 Sam Hocevar <sam@zoy.org> 4 5 * All Rights Reserved 5 6 * … … 17 18 #include <errno.h> 18 19 #include <fcntl.h> 19 #include <signal.h>20 20 #include <stdio.h> 21 21 #include <stdlib.h> 22 22 #include <string.h> 23 #include <unistd.h>24 23 25 24 #if defined USE_GRAB … … 30 29 # include <sys/user.h> 31 30 # include <sys/wait.h> 32 33 # include <linux/kdev_t.h>34 # include <linux/major.h>35 31 #endif 36 32 37 33 #include "neercs.h" 34 #include "mytrace.h" 35 36 #if defined USE_GRAB 37 static int memcpy_from_target(struct mytrace *t, 38 char* dest, long src, size_t n); 39 static int memcpy_into_target(struct mytrace *t, 40 long dest, char *src, size_t n); 41 static long remote_syscall(pid_t pid, long call, 42 long arg1, long arg2, long arg3); 43 #if 0 44 static void print_registers(pid_t pid); 45 #endif 46 #endif 38 47 39 48 #define X(x) #x … … 64 73 #endif 65 74 66 #if defined USE_GRAB 75 struct mytrace 76 { 77 pid_t pid; 78 }; 79 80 struct 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 102 int 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 115 int 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, ®s) < 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 156 int 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 166 int 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 176 int 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 186 int 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 200 static 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 228 static 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 265 static 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, ®s) < 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, ®s) < 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 67 355 /* For debugging purposes only. Prints register and stack information. */ 356 #if 0 68 357 static void print_registers(pid_t pid) 69 358 { … … 111 400 fprintf(stderr, "...\n"); 112 401 } 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, ®s) < 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, ®s) < 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, ®s) < 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.