Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix event.c for seccomp and ptrace #115

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 88 additions & 41 deletions src/tracee/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* 02110-1301 USA.
*/

#include <stdio.h>
#include <sched.h> /* CLONE_*, */
#include <sys/types.h> /* pid_t, */
#include <sys/ptrace.h> /* ptrace(1), PTRACE_*, */
Expand Down Expand Up @@ -47,6 +48,7 @@
#include "attribute.h"
#include "compat.h"


/**
* Start @tracee->exe with the given @argv[]. This function
* returns -errno if an error occurred, otherwise 0.
Expand Down Expand Up @@ -204,6 +206,27 @@ static void print_talloc_hierarchy(int signum, siginfo_t *siginfo UNUSED, void *

static int last_exit_status = -1;

/**
* Check if kernel >= 4.8
*/
bool is_kernel_4_8(void) {
struct utsname utsname;
int status;
static bool version_48 = false;
static int major = 0;
static int minor = 0;
if (! major) {
status = uname(&utsname);
if (status < 0)
return false;
sscanf(utsname.release, "%d.%d", &major, &minor);
if (major >= 4)
if (minor >= 8)
version_48 = true;
}
return version_48;
}

/**
* Check if this instance of PRoot can *technically* handle @tracee.
*/
Expand Down Expand Up @@ -362,6 +385,7 @@ int event_loop()
int handle_tracee_event(Tracee *tracee, int tracee_status)
{
static bool seccomp_detected = false;
static bool seccomp_enabled = false;
pid_t pid = tracee->pid;
long status;
int signal;
Expand Down Expand Up @@ -432,6 +456,7 @@ int handle_tracee_event(Tracee *tracee, int tracee_status)
status = ptrace(PTRACE_SETOPTIONS, tracee->pid, NULL,
default_ptrace_options | PTRACE_O_TRACESECCOMP);
if (status < 0) {
seccomp_enabled = false;
/* ... otherwise use default options only. */
status = ptrace(PTRACE_SETOPTIONS, tracee->pid, NULL,
default_ptrace_options);
Expand All @@ -440,7 +465,70 @@ int handle_tracee_event(Tracee *tracee, int tracee_status)
exit(EXIT_FAILURE);
}
}
else {
if (getenv("PROOT_NO_SECCOMP") == NULL)
seccomp_enabled = true;
}
}
/* Fall through. */
case SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8:
case SIGTRAP | PTRACE_EVENT_SECCOMP << 8:

if (is_kernel_4_8()) {
if (seccomp_enabled) {
if (!seccomp_detected) {
VERBOSE(tracee, 1, "ptrace acceleration (seccomp mode 2) enabled");
tracee->seccomp = ENABLED;
seccomp_detected = true;
}

unsigned long flags = 0;
status = ptrace(PTRACE_GETEVENTMSG, tracee->pid, NULL, &flags);
if (status < 0)
break;
}
}
else if (signal == (SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8) ||
signal == (SIGTRAP | PTRACE_EVENT_SECCOMP << 8)) {
unsigned long flags = 0;

signal = 0;

if (!seccomp_detected) {
VERBOSE(tracee, 1, "ptrace acceleration (seccomp mode 2) enabled");
tracee->seccomp = ENABLED;
seccomp_detected = true;
}

/* Use the common ptrace flow if seccomp was
* explicitely disabled for this tracee. */
if (tracee->seccomp != ENABLED)
break;

status = ptrace(PTRACE_GETEVENTMSG, tracee->pid, NULL, &flags);
if (status < 0)
break;

/* Use the common ptrace flow when
* sysexit has to be handled. */
if ((flags & FILTER_SYSEXIT) != 0) {
tracee->restart_how = PTRACE_SYSCALL;
break;
}

/* Otherwise, handle the sysenter
* stage right now. */
tracee->restart_how = PTRACE_CONT;
translate_syscall(tracee);

/* This syscall has disabled seccomp, so move
* the ptrace flow back to the common path to
* ensure its sysexit will be handled. */
if (tracee->seccomp == DISABLING)
tracee->restart_how = PTRACE_SYSCALL;
break;
}

/* Fall through. */
case SIGTRAP | 0x80:
signal = 0;
Expand Down Expand Up @@ -490,47 +578,6 @@ int handle_tracee_event(Tracee *tracee, int tracee_status)
}
break;

case SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8:
case SIGTRAP | PTRACE_EVENT_SECCOMP << 8: {
unsigned long flags = 0;

signal = 0;

if (!seccomp_detected) {
VERBOSE(tracee, 1, "ptrace acceleration (seccomp mode 2) enabled");
tracee->seccomp = ENABLED;
seccomp_detected = true;
}

/* Use the common ptrace flow if seccomp was
* explicitely disabled for this tracee. */
if (tracee->seccomp != ENABLED)
break;

status = ptrace(PTRACE_GETEVENTMSG, tracee->pid, NULL, &flags);
if (status < 0)
break;

/* Use the common ptrace flow when
* sysexit has to be handled. */
if ((flags & FILTER_SYSEXIT) != 0) {
tracee->restart_how = PTRACE_SYSCALL;
break;
}

/* Otherwise, handle the sysenter
* stage right now. */
tracee->restart_how = PTRACE_CONT;
translate_syscall(tracee);

/* This syscall has disabled seccomp, so move
* the ptrace flow back to the common path to
* ensure its sysexit will be handled. */
if (tracee->seccomp == DISABLING)
tracee->restart_how = PTRACE_SYSCALL;
break;
}

case SIGTRAP | PTRACE_EVENT_VFORK << 8:
signal = 0;
(void) new_child(tracee, CLONE_VFORK);
Expand Down