Skip to content

Commit

Permalink
Add support for Linux >= 4.8
Browse files Browse the repository at this point in the history
* Detect seccomp event order and handle both old and new one
* If new seccomp order is in use, syscalls with FILTER_SYSEXIT
  are handled immediately as we cannot reach syscall entry event
  as it already happened (but wasn't delivered as it wasn't requested)
* When we set PR_void syscall in non-seccomp handler, ignore next
  SIGSYS, beacuse Android seccomp policy disallows -1 syscall

#13
  • Loading branch information
michalbednarski committed Apr 26, 2018
1 parent c24fa3a commit 47138da
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 4 deletions.
46 changes: 43 additions & 3 deletions src/tracee/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,9 +368,16 @@ int event_loop()
int handle_tracee_event(Tracee *tracee, int tracee_status)
{
static bool seccomp_detected = false;
static bool seccomp_after_ptrace_enter = false;
static bool seccomp_after_ptrace_enter_checked = false;
long status;
int signal;

if (!seccomp_after_ptrace_enter_checked) {
seccomp_after_ptrace_enter = getenv("PROOT_ASSUME_NEW_SECCOMP") != NULL;
seccomp_after_ptrace_enter_checked = true;
}

/* Don't overwrite restart_how if it is explicitly set
* elsewhere, i.e in the ptrace emulation when single
* stepping. */
Expand Down Expand Up @@ -479,8 +486,20 @@ int handle_tracee_event(Tracee *tracee, int tracee_status)
case DISABLED:
if (!tracee->seccomp_already_handled_enter)
{
bool was_sysenter = IS_IN_SYSENTER(tracee);

translate_syscall(tracee);

/* In case we've changed on enter sysnum to PR_void,
* seccomp check is happening after our change
* and seccomp policy raises SIGSYS on -1 syscall,
* set tracee flag to ignore next SIGSYS. */
if (was_sysenter) {
tracee->skip_next_seccomp_signal = (
seccomp_after_ptrace_enter &&
get_sysnum(tracee, CURRENT) == PR_void);
}

/* Redeliver signal suppressed during
* syscall chain once it's finished. */
if (tracee->chain.suppressed_signal && tracee->chain.syscalls == NULL) {
Expand Down Expand Up @@ -520,14 +539,25 @@ int handle_tracee_event(Tracee *tracee, int tracee_status)

signal = 0;

assert(IS_IN_SYSENTER(tracee));

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

tracee->skip_next_seccomp_signal = false;

/* If kernel triggered seccomp event after we handled
* syscall enter, skip this event and continue as it didn't happen */
if (seccomp_after_ptrace_enter && !IS_IN_SYSENTER(tracee))
{
tracee->restart_how = tracee->last_restart_how;
break;
}

assert(IS_IN_SYSENTER(tracee));

/* Use the common ptrace flow if seccomp was
* explicitely disabled for this tracee. */
if (tracee->seccomp != ENABLED)
Expand All @@ -540,6 +570,10 @@ int handle_tracee_event(Tracee *tracee, int tracee_status)
/* Use the common ptrace flow when
* sysexit has to be handled. */
if ((flags & FILTER_SYSEXIT) != 0) {
if (seccomp_after_ptrace_enter) {
tracee->restart_how = PTRACE_SYSCALL;
translate_syscall(tracee);
}
tracee->restart_how = PTRACE_SYSCALL;
break;
}
Expand Down Expand Up @@ -575,6 +609,7 @@ int handle_tracee_event(Tracee *tracee, int tracee_status)
case SIGTRAP | PTRACE_EVENT_EXEC << 8:
case SIGTRAP | PTRACE_EVENT_EXIT << 8:
signal = 0;
tracee->restart_how = tracee->last_restart_how;
break;

case SIGSTOP:
Expand All @@ -597,7 +632,11 @@ int handle_tracee_event(Tracee *tracee, int tracee_status)
siginfo_t siginfo = {};
ptrace(PTRACE_GETSIGINFO, tracee->pid, NULL, &siginfo);
if (siginfo.si_code == SYS_SECCOMP) {
signal = handle_seccomp_event(tracee);
if (tracee->skip_next_seccomp_signal) {
signal = 0;
} else {
signal = handle_seccomp_event(tracee);
}
} else {
VERBOSE(tracee, 1, "non-seccomp SIGSYS");
}
Expand Down Expand Up @@ -643,6 +682,7 @@ bool restart_tracee(Tracee *tracee, int signal)
if (status < 0)
return false; /* The process likely died in a syscall. */

tracee->last_restart_how = tracee->restart_how;
tracee->restart_how = 0;
tracee->running = true;

Expand Down
6 changes: 5 additions & 1 deletion src/tracee/tracee.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ typedef struct tracee {
#else
enum __ptrace_request
#endif
restart_how;
restart_how, last_restart_how;

/* Value of the tracee's general purpose registers. */
struct user_regs_struct _regs[NB_REG_VERSION];
Expand All @@ -166,6 +166,10 @@ typedef struct tracee {
SIGSTOP_PENDING, /* Block SIGSTOP until the parent is unknown. */
} sigstop;

/* True if next SIGSYS caused by seccomp should be silently dropped
* without affecting state of any registers. */
bool skip_next_seccomp_signal;

/* Context used to collect all the temporary dynamic memory
* allocations. */
TALLOC_CTX *ctx;
Expand Down

0 comments on commit 47138da

Please sign in to comment.