Created
October 31, 2013 04:13
-
-
Save haileys/7244284 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // this is currently broken | |
| #define _GNU_SOURCE | |
| #include <asm/unistd.h> | |
| #include <errno.h> | |
| #include <signal.h> | |
| #include <stdbool.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <sys/ptrace.h> | |
| #include <sys/reg.h> | |
| #include <sys/types.h> | |
| #include <sys/user.h> | |
| #include <sys/wait.h> | |
| #include <unistd.h> | |
| static pid_t | |
| child; | |
| static void | |
| usage() | |
| { | |
| fprintf(stderr, "Usage: intsan <program> [<arguments>...]\n"); | |
| exit(1); | |
| } | |
| static long | |
| ptrace_child_(const char* request_name, enum __ptrace_request request, void* addr, void* data) | |
| { | |
| long ret = -EINTR; | |
| while(ret == -EINTR) { | |
| ret = ptrace(request, child, addr, data); | |
| } | |
| if(ret < 0) { | |
| fprintf(stderr, "ptrace(%s): %s\n", request_name, strerror(errno)); | |
| exit(EXIT_FAILURE); | |
| } | |
| return ret; | |
| } | |
| #define ptrace_child(req, addr, data) (ptrace_child_(#req, (req), (void*)(addr), (void*)(data))) | |
| static bool | |
| interruptible_syscall(int syscall_nr) | |
| { | |
| return true; | |
| return syscall_nr == __NR_read || syscall_nr == __NR_write; // TODO | |
| } | |
| static int | |
| wait_syscall() | |
| { | |
| ptrace_child(PTRACE_SYSCALL, NULL, NULL); | |
| int status; | |
| wait(&status); | |
| if(WIFEXITED(status)) { | |
| exit(WEXITSTATUS(status)); | |
| } | |
| return status; | |
| } | |
| static long | |
| get_syscall_nr() | |
| { | |
| // we can't use ptrace_child here because it inspects the return value | |
| #ifdef ORIG_EAX | |
| return ptrace(PTRACE_PEEKUSER, child, 4 * ORIG_EAX, NULL); | |
| #elif ORIG_RAX | |
| return ptrace(PTRACE_PEEKUSER, child, 8 * ORIG_RAX, NULL); | |
| #endif | |
| } | |
| static void | |
| set_syscall_nr(long nr) | |
| { | |
| #ifdef ORIG_EAX | |
| ptrace_child(PTRACE_POKEUSER, 4 * ORIG_EAX, nr); | |
| #elif ORIG_RAX | |
| ptrace_child(PTRACE_POKEUSER, 8 * ORIG_RAX, nr); | |
| #endif | |
| } | |
| static void | |
| set_retval(long retval) | |
| { | |
| #ifdef ORIG_EAX | |
| ptrace_child(PTRACE_POKEUSER, 4 * EAX, retval); | |
| #elif ORIG_RAX | |
| ptrace_child(PTRACE_POKEUSER, 8 * RAX, retval); | |
| #endif | |
| } | |
| int | |
| main(int argc, char** argv) | |
| { | |
| if(argc <= 1) { | |
| usage(); | |
| } | |
| child = fork(); | |
| if(child == 0) { | |
| ptrace(PTRACE_TRACEME, 0, NULL, NULL); | |
| execvp(argv[1], argv + 1); | |
| } | |
| ptrace_child(PTRACE_ATTACH, NULL, NULL); | |
| waitpid(child, NULL, 0); | |
| bool exec_seen = false; | |
| long last_syscall_seen = 0; | |
| while(!exec_seen) { | |
| wait_syscall(); | |
| if(get_syscall_nr() == __NR_execve) { | |
| exec_seen = true; | |
| } | |
| wait_syscall(); | |
| } | |
| while(1) { | |
| wait_syscall(); | |
| bool return_eintr = false; | |
| long nr = get_syscall_nr(); | |
| if(interruptible_syscall(nr)) { | |
| if(nr != last_syscall_seen) { | |
| //set_syscall_nr(~0l); // invalid syscall | |
| return_eintr = true; | |
| } else { | |
| //printf("saw this syscall before, ignoring\n"); | |
| } | |
| } | |
| last_syscall_seen = nr; | |
| wait_syscall(); | |
| if(return_eintr) { | |
| set_retval(-EINTR); | |
| } | |
| } | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment