Skip to content

Instantly share code, notes, and snippets.

@haileys
Created October 31, 2013 04:13
Show Gist options
  • Select an option

  • Save haileys/7244284 to your computer and use it in GitHub Desktop.

Select an option

Save haileys/7244284 to your computer and use it in GitHub Desktop.
// 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