Skip to content

Instantly share code, notes, and snippets.

@fntlnz
Last active January 22, 2024 07:55
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save fntlnz/08ae20befb91befd9a53cd91cdc6d507 to your computer and use it in GitHub Desktop.
Save fntlnz/08ae20befb91befd9a53cd91cdc6d507 to your computer and use it in GitHub Desktop.
Seccomp bpf filter example

Seccomp BPF filter example

Use bpf programs as filters for seccomp, the one in the example will block all the write syscalls after it's loaded.

Usage

Compile it with just

gcc main.c

Make sure your kernel has the right configs

cat /proc/config.gz| zcat  | grep -i CONFIG_SECCOMP
CONFIG_SECCOMP=y
CONFIG_SECCOMP_FILTER=y

Output examples

The program will only print the first "hey there!" then will exit

./a.out
hey there!

You can see what happens by running the program with strace

execve("./a.out", ["./a.out"], 0x7ffd85555100 /* 64 vars */) = 0
brk(NULL)                               = 0x5589eceec000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffe3fd63610) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=231787, ...}) = 0
mmap(NULL, 231787, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f664b7b2000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0000C\2\0\0\0\0\0"..., 832) = 832
lseek(3, 792, SEEK_SET)                 = 792
read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\201\336\t\36\251c\324\233E\371SoK\5H\334"..., 68) = 68
fstat(3, {st_mode=S_IFREG|0755, st_size=2136840, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f664b7b0000
lseek(3, 792, SEEK_SET)                 = 792
read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\201\336\t\36\251c\324\233E\371SoK\5H\334"..., 68) = 68
lseek(3, 864, SEEK_SET)                 = 864
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
mmap(NULL, 1848896, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f664b5ec000
mprotect(0x7f664b60e000, 1671168, PROT_NONE) = 0
mmap(0x7f664b60e000, 1355776, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7f664b60e000
mmap(0x7f664b759000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16d000) = 0x7f664b759000
mmap(0x7f664b7a6000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b9000) = 0x7f664b7a6000
mmap(0x7f664b7ac000, 13888, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f664b7ac000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f664b7b1500) = 0
mprotect(0x7f664b7a6000, 16384, PROT_READ) = 0
mprotect(0x5589eba07000, 4096, PROT_READ) = 0
mprotect(0x7f664b814000, 4096, PROT_READ) = 0
munmap(0x7f664b7b2000, 231787)          = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
brk(NULL)                               = 0x5589eceec000
brk(0x5589ecf0d000)                     = 0x5589ecf0d000
write(1, "hey there!\n", 11hey there!
)            = 11
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)  = 0
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, {len=6, filter=0x7ffe3fd635b0}) = 0
write(1, "something's gonna happen!!\n", 27) = -1 EPERM (Operation not permitted)
write(1, "it will not definitely print thi"..., 39) = -1 EPERM (Operation not permitted)
exit_group(0)                           = ?
+++ exited with 0 +++

You will notice that it is giving the error code we set EPERM when trying to do a write

#include <errno.h>
#include <linux/audit.h>
#include <linux/bpf.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <linux/unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/prctl.h>
#include <unistd.h>
static int install_filter(int nr, int arch, int error) {
struct sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, arch))),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arch, 0, 3),
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, nr))),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (error & SECCOMP_RET_DATA)),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
};
struct sock_fprog prog = {
.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
.filter = filter,
};
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
perror("prctl(NO_NEW_PRIVS)");
return 1;
}
if (prctl(PR_SET_SECCOMP, 2, &prog)) {
perror("prctl(PR_SET_SECCOMP)");
return 1;
}
return 0;
}
int main() {
printf("hey there!\n");
install_filter(__NR_write, AUDIT_ARCH_X86_64, EPERM);
printf("something's gonna happen!!\n");
printf("it will not definitely print this here\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment