Created
August 10, 2016 19:44
-
-
Save khuey/3c43ac247c72cef8c956ca73281c9be7 to your computer and use it in GitHub Desktop.
This file contains 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
/* gcc -lpthread -g -o test test.c */ | |
#include <assert.h> | |
#include <errno.h> | |
#include <linux/filter.h> | |
#include <linux/seccomp.h> | |
#include <pthread.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/prctl.h> | |
#include <sys/ptrace.h> | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
#include <unistd.h> | |
static struct timespec ts_short = {0, 10 * 1000000}; | |
static struct timespec ts_long = {0, 100 * 1000000}; | |
static void *do_thread(__attribute__((unused)) void *p) { | |
nanosleep(&ts_short, NULL); | |
exit(0); | |
return NULL; | |
} | |
/* Trivial filter that just generates a ptrace trap for every syscall */ | |
static struct sock_filter filter = | |
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE | SECCOMP_RET_DATA); | |
static struct sock_fprog prog = {1, &filter}; | |
static void do_tracee(void) { | |
pthread_t thread; | |
/* Wait for ptracer to attach and continue us */ | |
kill(getpid(), SIGSTOP); | |
/* Spawn thread to wait for a short time and then exit_group */ | |
pthread_create(&thread, NULL, do_thread, NULL); | |
/* Install seccomp filter */ | |
assert(0 == prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); | |
assert(0 == prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (long)&prog, 0, 0)); | |
/* Generate a seccomp event */ | |
pause(); | |
} | |
int main(void) { | |
pid_t child; | |
int status; | |
int got_ptrace_exit_for_child = 0; | |
child = fork(); | |
if (!child) { | |
do_tracee(); | |
/* unreached */ | |
return 0; | |
} | |
/* Start tracing child. Trace thread-group-leader only. */ | |
assert(0 == ptrace(PTRACE_SEIZE, child, NULL, | |
(void *)(PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXIT | | |
PTRACE_O_TRACESECCOMP))); | |
assert(child == waitpid(child, &status, 0)); | |
assert(status == ((SIGSTOP << 8) | 0x7f)); | |
assert(0 == ptrace(PTRACE_CONT, child, NULL, NULL)); | |
while (1) { | |
printf("Waiting for %d ...\n", child); | |
assert(child == waitpid(child, &status, 0)); | |
if (WIFEXITED(status)) { | |
printf("%d exiting with status %d\n", child, WEXITSTATUS(status)); | |
printf("FAILED: did not see PTRACE_EVENT_EXIT before task %d exited\n", | |
child); | |
return 1; | |
} | |
if ((status >> 8) == (SIGTRAP | (PTRACE_EVENT_EXIT << 8))) { | |
printf("%d got PTRACE_EVENT_EXIT\n", child); | |
printf("SUCCESS: saw PTRACE_EVENT_EXIT before task %d exited\n", child); | |
return 0; | |
} | |
if ((status >> 8) == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) { | |
/* Ensure traced task is stopped in the seccomp trap while the untraced | |
task does an exit_group. */ | |
nanosleep(&ts_long, NULL); | |
continue; | |
} | |
printf("Issuing PTRACE_CONT for %d\n", child); | |
if (ptrace(PTRACE_CONT, child, NULL, NULL) < 0) { | |
printf("FAILED: %s trying to PTRACE_CONT task %d (no PTRACE_EVENT_EXIT " | |
"seen)\n", | |
strerror(errno), child); | |
return 1; | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment