qa/integration/fixtures/offline_wrapper/offline.c (56 lines of code) (raw):
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <sys/syscall.h>
#include <stddef.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <sys/prctl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
struct sock_filter reject_connect_and_bind[] = {
// LD|W|ABS == Load Word at ABSolute offset
// Load the syscall number
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, (offsetof(struct seccomp_data, nr))),
// JMP|JEQ|K Do a jump after comparing EQuality of the loaded value and a
// constant. If equal, jump 2 positions forward, if not equal, do not jump(zero jump).
// Is it the `connect` syscall?
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_connect, 2, 0),
// Is it the `bind` syscall?
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_bind, 1, 0),
// RET|K Return a constant.
// Neither bind nor connect? Allow it.
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
// Fun fact. `connect` and `bind` take the same arguments, so we can process them the same way.
// int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
// int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
// Ideally, we'd load the 2nd arg (sockaddr struct) and look at the `sa_family` member to see
// what kind of socket address is to be used. However, BPF/seccomp doesn't allow you to
// dereference pointers... so let's try relying on the sockaddr_len argument.
// Load third argument to the syscall (addrlen)
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, offsetof(struct seccomp_data, args[2])),
// Try filtering based on the sockaddr len. This isn't great, but may be better than nothing.
// - Reject sockaddr_in and sockaddr_in6
// - Allow everything else (unix sockets, etc)
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, sizeof(struct sockaddr_in), 1, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, sizeof(struct sockaddr_in6), 0, 1),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO|(EACCES&SECCOMP_RET_DATA)),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};
struct sock_filter reject_inet_socket[] = {
// LD|W|ABS == Load Word at ABSolute offset
// Load the syscall number
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, (offsetof(struct seccomp_data, nr))),
// Is it the `socket` syscall?
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_socket, 1, 0),
// Not `socket` call? Allow it.
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
// Load first argument to the syscall (domain)
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, offsetof(struct seccomp_data, args[0])),
// Reject INET and INET6
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AF_INET, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AF_INET6, 0, 1),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO|(EACCES&SECCOMP_RET_DATA)),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};
int main(int argc, char **argv) {
struct sock_filter *filter = reject_inet_socket;
unsigned short count = sizeof(reject_inet_socket) / sizeof(filter[0]);
struct sock_fprog prog = {
.len = count,
.filter = filter,
};
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
perror("seccomp PR_SET_NO_NEW_PRIVS");
return 1;
}
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
perror("seccomp");
return 1;
}
if (argc == 1) {
printf("Usage: %s <program> [args]\n", argv[0]);
return 1;
}
argv++;
execvp(argv[0], argv);
return 0;
}