From 9fb7ead2d2290dbfb4e403da8ea56a3b6f610e06 Mon Sep 17 00:00:00 2001 From: i-ky Date: Wed, 8 Feb 2023 07:37:50 +0000 Subject: [PATCH] Use seccomp filter instead of stepping syscalls --- src/basset.cpp | 122 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 96 insertions(+), 26 deletions(-) diff --git a/src/basset.cpp b/src/basset.cpp index 9945fd5..f81f187 100644 --- a/src/basset.cpp +++ b/src/basset.cpp @@ -1,16 +1,22 @@ #include #include +#include #include +#include #include +#include #include +#include +#undef PTRACE_CONT +#undef PTRACE_GETEVENTMSG #undef PTRACE_GET_SYSCALL_INFO #undef PTRACE_SETOPTIONS -#undef PTRACE_SYSCALL #undef PTRACE_TRACEME +#include #include #include @@ -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; } @@ -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(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(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)) { @@ -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)");