#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
#include <linux/net.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include "base/check_op.h"
#include "base/strings/safe_sprintf.h"
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/linux/bpf_dsl/policy.h"
#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
#include "sandbox/linux/tests/unit_tests.h"
namespace sandbox {
namespace {
Allow;
Arg;
If;
ResultExpr;
class DisallowSocketPolicy : public bpf_dsl::Policy { … };
BPF_DEATH_TEST_C(
SigsysHandlers,
SocketPrintsCorrectMessage,
DEATH_SEGV_MESSAGE(sandbox::GetSocketErrorMessageContentForTests()),
DisallowSocketPolicy) { … }
class DisallowSockoptPolicy : public bpf_dsl::Policy { … };
BPF_DEATH_TEST_C(
SigsysHandlers,
SetsockoptPrintsCorrectMessage,
DEATH_SEGV_MESSAGE(sandbox::GetSockoptErrorMessageContentForTests()),
DisallowSockoptPolicy) { … }
BPF_DEATH_TEST_C(
SigsysHandlers,
GetSockoptPrintsCorrectMessage,
DEATH_SEGV_MESSAGE(sandbox::GetSockoptErrorMessageContentForTests()),
DisallowSockoptPolicy) { … }
const char kSigsysMessage[] = …;
SANDBOX_DEATH_TEST(SigsysHandlers,
SigsysErrorDetails,
DEATH_SEGV_MESSAGE(kSigsysMessage)) { … }
#if defined(__NR_socketcall)
const int kDirectSocketSyscallRetVal = 37;
const size_t kNumArgsToCopy = 6;
uint64_t g_syscall_args[kNumArgsToCopy];
int g_syscall_no;
SANDBOX_EXPORT intptr_t
SIGSYSDirectSocketSyscallHandler(const struct arch_seccomp_data& args, void*) {
memcpy(g_syscall_args, args.args, kNumArgsToCopy * sizeof(uint64_t));
g_syscall_no = args.nr;
return kDirectSocketSyscallRetVal;
}
class RewriteSocketcallPolicy : public bpf_dsl::Policy {
public:
RewriteSocketcallPolicy() {
if (!CanRewriteSocketcall()) {
UnitTests::IgnoreThisTest();
return;
}
}
~RewriteSocketcallPolicy() override = default;
ResultExpr EvaluateSyscall(int sysno) const override {
switch (sysno) {
case __NR_socketcall:
return RewriteSocketcallSIGSYS();
case __NR_socket:
case __NR_bind:
case __NR_connect:
case __NR_listen:
case __NR_getsockname:
case __NR_getpeername:
case __NR_socketpair:
case __NR_sendto:
case __NR_recvfrom:
case __NR_shutdown:
case __NR_setsockopt:
case __NR_getsockopt:
case __NR_sendmsg:
case __NR_recvmsg:
case __NR_accept4:
case __NR_recvmmsg:
case __NR_sendmmsg:
return bpf_dsl::Trap(&SIGSYSDirectSocketSyscallHandler, nullptr);
default:
return Allow();
}
}
};
template <size_t N>
void CheckArgsMatch(long current_socketcall,
int sysno,
unsigned long (&expected_args)[N]) {
BPF_ASSERT_EQ(sysno, g_syscall_no);
for (size_t i = 0; i < N; i++) {
unsigned long rewritten_socketcall_arg =
*reinterpret_cast<unsigned long*>(&g_syscall_args[i]);
CHECK_EQ(rewritten_socketcall_arg, expected_args[i])
<< "Socketcall " << current_socketcall << " differs at argument " << i;
}
}
BPF_TEST_C(SigsysHandlers,
DirectSocketSyscallArgsMatch,
RewriteSocketcallPolicy) {
unsigned long socketcall_args[6] = {1, 2, 3, 4, 5, 6};
for (long i = 1; i <= 20; i++) {
switch (i) {
case SYS_SOCKET: {
unsigned long expected_args[3] = {1, 2, 3};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_socket, expected_args);
break;
}
case SYS_BIND: {
unsigned long expected_args[3] = {1, 2, 3};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_bind, expected_args);
break;
}
case SYS_CONNECT: {
unsigned long expected_args[3] = {1, 2, 3};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_connect, expected_args);
break;
}
case SYS_LISTEN: {
unsigned long expected_args[2] = {1, 2};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_listen, expected_args);
break;
}
case SYS_ACCEPT: {
unsigned long expected_args[4] = {1, 2, 3, 0};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_accept4, expected_args);
break;
}
case SYS_GETSOCKNAME: {
unsigned long expected_args[3] = {1, 2, 3};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_getsockname, expected_args);
break;
}
case SYS_GETPEERNAME: {
unsigned long expected_args[3] = {1, 2, 3};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_getpeername, expected_args);
break;
}
case SYS_SOCKETPAIR: {
unsigned long expected_args[4] = {1, 2, 3, 4};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_socketpair, expected_args);
break;
}
case SYS_SEND: {
unsigned long expected_args[6] = {1, 2, 3, 4, 0, 0};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_sendto, expected_args);
break;
}
case SYS_RECV: {
unsigned long expected_args[6] = {1, 2, 3, 4, 0, 0};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_recvfrom, expected_args);
break;
}
case SYS_SENDTO: {
unsigned long expected_args[6] = {1, 2, 3, 4, 5, 6};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_sendto, expected_args);
break;
}
case SYS_RECVFROM: {
unsigned long expected_args[6] = {1, 2, 3, 4, 5, 6};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_recvfrom, expected_args);
break;
}
case SYS_SHUTDOWN: {
unsigned long expected_args[2] = {1, 2};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_shutdown, expected_args);
break;
}
case SYS_SETSOCKOPT: {
unsigned long expected_args[5] = {1, 2, 3, 4, 5};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_setsockopt, expected_args);
break;
}
case SYS_GETSOCKOPT: {
unsigned long expected_args[5] = {1, 2, 3, 4, 5};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_getsockopt, expected_args);
break;
}
case SYS_SENDMSG: {
unsigned long expected_args[3] = {1, 2, 3};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_sendmsg, expected_args);
break;
}
case SYS_RECVMSG: {
unsigned long expected_args[3] = {1, 2, 3};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_recvmsg, expected_args);
break;
}
case SYS_ACCEPT4: {
unsigned long expected_args[4] = {1, 2, 3, 4};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_accept4, expected_args);
break;
}
case SYS_RECVMMSG: {
unsigned long expected_args[5] = {1, 2, 3, 4, 5};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_recvmmsg, expected_args);
break;
}
case SYS_SENDMMSG: {
unsigned long expected_args[4] = {1, 2, 3, 4};
BPF_ASSERT_EQ(syscall(__NR_socketcall, i, socketcall_args),
kDirectSocketSyscallRetVal);
CheckArgsMatch(i, __NR_sendmmsg, expected_args);
break;
}
}
}
}
#endif
}
}