Last active
June 30, 2024 12:29
-
-
Save teknoraver/ed341c5506027c7cdda9e759fdd30c21 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*.o | |
sysctl_monitor | |
vmlinux.h | |
*.skel.h |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
LDLIBS += -lbpf | |
CFLAGS += -O2 -pipe -g -Wall | |
all:: sysctl_monitor | |
vmlinux.h: | |
bpftool btf dump file /sys/kernel/btf/vmlinux format c > $@ | |
sysctl_monitor_bpf.skel.h: sysctl_monitor.bpf.o | |
bpftool gen skeleton $< > $@ | |
sysctl_monitor.bpf.o: sysctl_monitor.bpf.c vmlinux.h | |
clang $(CFLAGS) -target bpf -c $< -o $@ | |
sysctl_monitor: sysctl_monitor.c sysctl_monitor_bpf.skel.h | |
clean:: | |
$(RM) *.o sysctl_monitor *.skel.h vmlinux.h |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "vmlinux.h" | |
#include <bpf/bpf_helpers.h> | |
#include "vals.h" | |
struct { | |
__uint(type, BPF_MAP_TYPE_RINGBUF); | |
__uint(max_entries, 256 * 1024); | |
} written_sysctls SEC(".maps"); | |
static bool my_streq(const char *s1, const char *s2, int l) | |
{ | |
for (int i = 0; i < l; i++) { | |
if (s1[i] != s2[i]) | |
return false; | |
if (!s1[i]) | |
return true; | |
} | |
return true; | |
} | |
struct str { | |
char *s; | |
int l; | |
}; | |
static long cut_last(int i, struct str *str) | |
{ | |
char *s; | |
i = str->l - i - 1; | |
s = str->s + i; | |
// Sanity checks for the preverifier | |
if (i < 0 || i >= str->l) | |
return 1; | |
if (*s == 0) | |
return 0; | |
if (*s == '\n' || *s == '\r' || *s == ' ' || *s == '\t') { | |
*s = 0; | |
return 0; | |
} | |
return 1; | |
} | |
// Cut off trailing whitespace and newlines | |
static void chop(char *s, int l) | |
{ | |
struct str str = { s, l }; | |
bpf_loop(l, cut_last, &str, 0); | |
} | |
SEC("cgroup/sysctl") | |
int sysctl_monitor(struct bpf_sysctl *ctx) | |
{ | |
struct vals vals = { }; | |
// Allow reads | |
if (!ctx->write) | |
return 1; | |
// Only monitor net/ | |
bpf_sysctl_get_name(ctx, vals.name, sizeof(vals.name), 0); | |
if (bpf_strncmp(vals.name, 4, "net/")) | |
return 1; | |
bpf_get_current_comm(vals.comm, sizeof(vals.comm)); | |
bpf_sysctl_get_current_value(ctx, vals.current, sizeof(vals.current)); | |
bpf_sysctl_get_new_value(ctx, vals.newvalue, sizeof(vals.newvalue)); | |
// Both the kernel and userspace applications add a newline at the end, | |
// remove it from both strings | |
chop(vals.current, sizeof(vals.current)); | |
chop(vals.newvalue, sizeof(vals.newvalue)); | |
// If new value is the same, ignore it | |
if (my_streq(vals.current, vals.newvalue, sizeof(vals.current))) | |
return 1; | |
bpf_ringbuf_output(&written_sysctls, &vals, sizeof(vals), 0); | |
return 0; | |
} | |
char _license[] SEC("license") = "GPL"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _GNU_SOURCE | |
#include <stdio.h> | |
#include <fcntl.h> | |
#include <signal.h> | |
#include <errno.h> | |
#include <bpf/bpf.h> | |
#include <bpf/libbpf.h> | |
#include "vals.h" | |
#include "sysctl_monitor_bpf.skel.h" | |
#define CGROUP_MOUNT_DFLT "/sys/fs/cgroup" | |
struct ring_buffer *rb; | |
static void int_exit(int sig) | |
{ | |
int cgfd = open(CGROUP_MOUNT_DFLT, O_PATH | O_DIRECTORY | O_CLOEXEC); | |
if (cgfd >= 0) { | |
bpf_prog_detach(cgfd, BPF_CGROUP_SYSCTL); | |
close(cgfd); | |
} | |
} | |
static int log_sysctl_writes(void *ctx, void *data, size_t data_sz) | |
{ | |
struct vals *vals = data; | |
printf("%s tried to update '%s' from '%s' to '%s'\n", vals->comm, vals->name, vals->current, vals->newvalue); | |
return 0; | |
} | |
static int attach_bpf(void) | |
{ | |
struct sysctl_monitor_bpf *skel; | |
int progfd, cgfd; | |
int err; | |
cgfd = open(CGROUP_MOUNT_DFLT, O_PATH | O_DIRECTORY | O_CLOEXEC); | |
if (cgfd < 0) { | |
printf("failed to open cgroup mount point\n"); | |
return 1; | |
} | |
skel = sysctl_monitor_bpf__open_and_load(); | |
if (!skel) { | |
printf("failed to open and load BPF object\n"); | |
return 1; | |
} | |
err = sysctl_monitor_bpf__attach(skel); | |
if (err) { | |
printf("failed to attach BPF program\n"); | |
return 1; | |
} | |
rb = ring_buffer__new(bpf_map__fd(skel->maps.written_sysctls), log_sysctl_writes, NULL, NULL); | |
if (!rb) { | |
printf("failed to create ring buffer\n"); | |
return 1; | |
} | |
progfd = bpf_program__fd(skel->progs.sysctl_monitor); | |
if (bpf_prog_attach(progfd, cgfd, BPF_CGROUP_SYSCTL, BPF_F_ALLOW_OVERRIDE) < 0) { | |
close(progfd); | |
return 1; | |
} | |
close(progfd); | |
return 0; | |
} | |
int main(int argc, char **argv) | |
{ | |
int ret, cgfd; | |
signal(SIGINT, int_exit); | |
signal(SIGTERM, int_exit); | |
signal(SIGQUIT, int_exit); | |
if (attach_bpf()) | |
return 1; | |
// In business | |
while (1) { | |
ret = ring_buffer__poll(rb, 1000); | |
if (ret < 0) { | |
if (errno == EINTR) | |
break; | |
printf("Error polling ring buffer\n"); | |
break; | |
} | |
} | |
cgfd = open(CGROUP_MOUNT_DFLT, O_PATH | O_DIRECTORY | O_CLOEXEC); | |
if (cgfd >= 0) { | |
bpf_prog_detach(cgfd, BPF_CGROUP_SYSCTL); | |
close(cgfd); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
struct vals { | |
char comm[32]; | |
char name[64]; | |
char current[32]; | |
char newvalue[32]; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment