Skip to content

Commit

Permalink
Use seccomp filter instead of stepping syscalls
Browse files Browse the repository at this point in the history
  • Loading branch information
i-ky committed Feb 8, 2023
1 parent bfbcbf4 commit 9fb7ead
Showing 1 changed file with 96 additions and 26 deletions.
122 changes: 96 additions & 26 deletions src/basset.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
#include <stdio.h>
#include <unistd.h>

#include <sys/prctl.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <sys/wait.h>

#include <linux/filter.h>
#include <linux/ptrace.h>
#include <linux/seccomp.h>

#undef PTRACE_CONT
#undef PTRACE_GETEVENTMSG
#undef PTRACE_GET_SYSCALL_INFO
#undef PTRACE_SETOPTIONS
#undef PTRACE_SYSCALL
#undef PTRACE_TRACEME

#include <cassert>
#include <csignal>
#include <iostream>

Expand Down Expand Up @@ -39,12 +45,12 @@ int main(int argc, char *argv[]) {

if (ptrace(PTRACE_SETOPTIONS, pid, nullptr,
PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK |
PTRACE_O_TRACEEXEC | PTRACE_O_TRACESYSGOOD) == -1) {
PTRACE_O_TRACEEXEC | PTRACE_O_TRACESECCOMP) == -1) {
perror("cannot ptrace(PTRACE_SETOPTIONS)");
return -1;
}

if (ptrace(PTRACE_SYSCALL, pid, nullptr, nullptr) == -1) {
if (ptrace(PTRACE_CONT, pid, nullptr, nullptr) == -1) {
perror("cannot ptrace(PTRACE_CONT)");
return -1;
}
Expand All @@ -60,33 +66,79 @@ int main(int argc, char *argv[]) {
} else if (WIFSTOPPED(wstatus)) {
cerr << pid << " stopped\n";

ptrace_syscall_info data;

if (auto res =
ptrace(PTRACE_GET_SYSCALL_INFO, pid, sizeof(data), &data)) {
if (res == -1) {
perror("cannot ptrace(PTRACE_GET_SYSCALL_INFO)");
} else if (res > sizeof(data)) {
cerr << "some data truncated\n";
} else {
switch (data.op) {
case PTRACE_SYSCALL_INFO_ENTRY:
cerr << "entering syscall " << data.entry.nr << '\n';
break;
case PTRACE_SYSCALL_INFO_EXIT:
cerr << "syscall returned " << data.exit.rval << '\n';
break;
case PTRACE_SYSCALL_INFO_SECCOMP:
case PTRACE_SYSCALL_INFO_NONE:
default:
cerr << "unexpected syscall operation: "
<< static_cast<int>(data.op) << '\n';
if (WSTOPSIG(wstatus) == SIGTRAP) {
switch (wstatus >> 16) {
case PTRACE_EVENT_CLONE:
case PTRACE_EVENT_EXEC:
case PTRACE_EVENT_FORK:
case PTRACE_EVENT_VFORK: {
unsigned long data;

if (ptrace(PTRACE_GETEVENTMSG, pid, nullptr, &data) == -1) {
perror("cannot ptrace(PTRACE_GETEVENTMSG)");
return -1;
}

cerr << "event msg: " << data << '\n';
break;
}
case PTRACE_EVENT_SECCOMP: {
unsigned long ret_data;

if (ptrace(PTRACE_GETEVENTMSG, pid, nullptr, &ret_data) == -1) {
perror("cannot ptrace(PTRACE_GETEVENTMSG)");
return -1;
}

cerr << "SECCOMP_RET_DATA: " << ret_data << '\n';

ptrace_syscall_info data;
auto res =
ptrace(PTRACE_GET_SYSCALL_INFO, pid, sizeof(data), &data);

if (res == -1) {
perror("cannot ptrace(PTRACE_GET_SYSCALL_INFO)");
return -1;
}

if (res > sizeof(data)) {
cerr << "some data truncated\n";
} else {
assert(res > 0);

switch (data.op) {
case PTRACE_SYSCALL_INFO_SECCOMP: {
cerr << "seccomp " << data.seccomp.nr << '\n';

for (auto arg : data.seccomp.args) {
cerr << arg << ',';
}

cerr << '\n';
assert(ret_data == data.seccomp.ret_data);
break;
}
case PTRACE_SYSCALL_INFO_NONE:
case PTRACE_SYSCALL_INFO_ENTRY:
case PTRACE_SYSCALL_INFO_EXIT:
default:
cerr << "unexpected syscall operation: "
<< static_cast<int>(data.op) << '\n';
return -1;
}
}
break;
}
default:
cerr << "unknown stop event, signal: " << (wstatus >> 16) << '\n';
return -1;
}
} else {
cerr << "got signal: " << WSTOPSIG(wstatus) << '\n';
}

if (ptrace(PTRACE_SYSCALL, pid, nullptr, nullptr) == -1) {
perror("cannot ptrace(PTRACE_SYSCALL)");
if (ptrace(PTRACE_CONT, pid, nullptr, nullptr) == -1) {
perror("cannot ptrace(PTRACE_CONT)");
return -1;
}
} else if (WIFCONTINUED(wstatus)) {
Expand All @@ -105,6 +157,24 @@ int main(int argc, char *argv[]) {
return -1;
}

sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(seccomp_data, nr)),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_chdir, 0, 1),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
};
sock_fprog prog = {sizeof(filter) / sizeof(*filter), filter};

if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) {
perror("cannot prctl(PR_SET_NO_NEW_PRIVS)");
return -1;
}

if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0) != 0) {
perror("cannot prctl(PR_SET_SECCOMP)");
return -1;
}

// allow parent to ptrace(PTRACE_SETOPTIONS)
if (raise(SIGSTOP) != 0) {
perror("cannot raise(SIGSTOP)");
Expand Down

0 comments on commit 9fb7ead

Please sign in to comment.