Skip to content

Instantly share code, notes, and snippets.

@azlkiniue
Last active January 20, 2026 00:16
Show Gist options
  • Select an option

  • Save azlkiniue/63e847f2f0ec3589af888c2876e7f004 to your computer and use it in GitHub Desktop.

Select an option

Save azlkiniue/63e847f2f0ec3589af888c2876e7f004 to your computer and use it in GitHub Desktop.
ebpf.party solutions
#include "ep_platform.h"
#include "sched.h"
SEC("tp/sched/sched_process_exec")
int handle_exec(struct trace_event_raw_sched_process_exec *ctx) {
// 1. Try running the example as-is to see the output
// 2. Declare a buffer for the process name
// 3. Copy the process name into the buffer with a helper
// 4. Call DEBUG_STR on your buffer to see the output
// DEBUG_STR("Example", "Hi");
char buffer[16];
bpf_get_current_comm(&buffer, sizeof(buffer));
DEBUG_STR("Command", buffer);
if (bpf_strncmp(buffer, sizeof(buffer), "ls") == 0) return 0;
if (bpf_strncmp(buffer, sizeof(buffer), "sudo") == 0) return 0;
SUBMIT_STR(buffer);
return 0;
}
#include "ep_platform.h"
#include "sched.h"
SEC("tp/sched/sched_process_exec")
int handle_exec(struct trace_event_raw_sched_process_exec *ctx) {
// 1. Get and print the PID
// 2. Calculate the offset
// 3. Create the `fname` buffer
// 4. Populate `fname` with a helper
// DEBUG_STR("Hi", "Welcome back");
int pid = ctx->pid;
DEBUG_NUM("PID", pid);
int off = ctx->__data_loc_filename & 0xFFFF;
int len = ctx->__data_loc_filename >> 16;
char fname[32];
bpf_probe_read_kernel_str(fname, sizeof(fname), (void *)ctx + off);
DEBUG_STR_LEN("fname", fname, len);
if (bpf_strncmp(fname, sizeof(fname), "/bin/ls") == 0) return 0;
if (bpf_strncmp(fname, sizeof(fname), "/bin/sudo") == 0) return 0;
SUBMIT_STR_LEN(fname, len);
return 0;
}
#include "ep_platform.h"
#include "syscalls.h"
SEC("tp/syscalls/sys_enter_execve")
int trace_execve(struct trace_event_raw_sys_enter *ctx)
{
char filename[32];
// ctx->args[0] is the first syscall argument (filename pointer)
// const char* ptr = ...;
// copy it to the buffer
// bpf_probe_read_user_str(dst, size, src);
const char* ptr = (const char*) ctx->args[0];
int len = bpf_probe_read_user_str(filename, sizeof(filename), ptr);
DEBUG_STR("filename", filename);
DEBUG_NUM("len", len);
if (bpf_strncmp(filename, sizeof(filename), "/bin/ls") == 0) return 0;
if (bpf_strncmp(filename, sizeof(filename), "/bin/sudo") == 0) return 0;
SUBMIT_STR_LEN(filename, len);
return 0;
}
#include "ep_platform.h"
#include "syscalls.h"
SEC("tp/syscalls/sys_enter_execve")
int trace_execve(struct trace_event_raw_sys_enter *ctx)
{
// Get the argv pointer
// While we haven't made it to the terminator (or 10 args):
// Get the pointer to the argument
// If it's NULL, stop
// Read the pointed value
// Get the argv pointer
char **argv = (char **)ctx->args[1];
// In a loop, read the next pointer from the array
int i;
for (i=0; i<=10; i++)
{
char *arg_ptr;
bpf_probe_read_user(&arg_ptr, sizeof(arg_ptr), &argv[i]);
// Remember to check for the NULL terminator!
if (!arg_ptr)
return 0;
// Read the string that pointer points to
char arg_buf[64];
bpf_probe_read_user_str(arg_buf, sizeof(arg_buf), arg_ptr);
DEBUG_STR("buf", arg_buf);
if (bpf_strncmp(arg_buf, sizeof(arg_buf), "--password") == 0)
{
char *arg_ptr_pass;
bpf_probe_read_user(&arg_ptr_pass, sizeof(arg_ptr_pass), &argv[i+1]);
char arg_buf_pass[64];
int len = bpf_probe_read_user_str(arg_buf_pass, sizeof(arg_buf_pass), arg_ptr_pass);
DEBUG_STR("password", arg_buf_pass);
SUBMIT_STR_LEN(arg_buf_pass, len);
return 0;
}
}
return 0;
}
#include "ep_platform.h"
#include "sched.h"
#include "syscalls.h"
// Map to store process names, keyed by PID
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024);
__type(key, u64); // What you use to look up
__type(value, char[16]); // What you store
} process_names SEC(".maps");
// When a process starts: store its name
SEC("tracepoint/sched/sched_process_exec")
int on_process_start(struct trace_event_raw_sched_process_exec *ctx) {
u64 pid = bpf_get_current_pid_tgid();
char comm[16];
bpf_get_current_comm(comm, sizeof(comm));
bpf_map_update_elem(&process_names, &pid, comm, BPF_ANY);
return 0;
}
// When a process exits: check if we had stored it in the map
SEC("tracepoint/syscalls/sys_enter_exit")
int on_process_exit(struct trace_event_raw_sys_enter *ctx) {
u64 pid = bpf_get_current_pid_tgid();
// Look up the name we stored
char *comm = bpf_map_lookup_elem(&process_names, &pid);
if (!comm) return 0;
// Debug: see all processes and their exit codes
int exit_code = ctx->args[0]; // exit's first argument
DEBUG_NUM("Exit code", exit_code);
DEBUG_STR_LEN("Process", comm, 16);
// TODO: If process name is "exit_with_code", submit the exit code
if (bpf_strncmp(comm, sizeof(comm), "exit_with_code") == 0)
{
DEBUG_NUM("Submitted exit code", exit_code);
SUBMIT_NUM(exit_code);
}
// Clean up
bpf_map_delete_elem(&process_names, &pid);
return 0;
}
#include "ep_platform.h"
#include "syscalls.h"
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024);
__type(key, u64); // PID
__type(value, u64); // Buffer address
} read_buffers SEC(".maps");
SEC("tracepoint/syscalls/sys_enter_read")
int trace_read_entry(struct trace_event_raw_sys_enter *ctx)
{
u64 pid = bpf_get_current_pid_tgid();
u64 buf_addr = ctx->args[1];
bpf_map_update_elem(&read_buffers, &pid, &buf_addr, BPF_ANY);
return 0;
}
SEC("tracepoint/syscalls/sys_exit_read")
int trace_read_exit(struct trace_event_raw_sys_exit *ctx)
{
// Fill this in
size_t count = ctx->ret;
if (count <= 0) return 0;
DEBUG_NUM("count", count);
u64 pid = bpf_get_current_pid_tgid();
u64 *buf_ptr = bpf_map_lookup_elem(&read_buffers, &pid);
if (!buf_ptr) return 0;
char local_buf[46];
if (count > 46) count = 46;
bpf_probe_read_user(local_buf, count, (void *)*buf_ptr);
DEBUG_STR("buf", local_buf);
SUBMIT_STR_LEN(local_buf, count);
return 0;
}
#include "ep_platform.h"
#include "syscalls.h"
// Compound key for tracking (pid, fd) pairs
struct pid_fd_key {
u64 pid;
u32 fd;
};
// Current open in progress (PID → marker)
// Lifetime: open entry → exit only
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024);
__type(key, u64);
__type(value, u8);
} open_curr_fd_interesting SEC(".maps");
// Tracked interesting FDs ((pid, fd) → marker)
// Lifetime: open exit → until we're done tracking
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024);
__type(key, struct pid_fd_key);
__type(value, u8);
} open_interesting_fds SEC(".maps");
// Current read buffer (PID → buffer pointer)
// Lifetime: read entry → exit only
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024);
__type(key, u64);
__type(value, u64);
} read_curr_fd_buf SEC(".maps");
SEC("tracepoint/syscalls/sys_enter_open")
int trace_open_entry(struct trace_event_raw_sys_enter *ctx)
{
u64 pid = bpf_get_current_pid_tgid();
u8 mark = 1;
// Get pathname pointer from ctx->args[0]
// Read pathname string into local buffer with `bpf_probe_read_user_str`
// Check if pathname == "/tmp/password" with bpf_strncmp
// If yes, mark PID in open_curr_fd_interesting with `bpf_map_update_elem`
char pathname[20];
const char* ptr = (const char*) ctx->args[0];
bpf_probe_read_user_str(pathname, sizeof(pathname), ptr);
if (bpf_strncmp(pathname, sizeof(pathname), "/tmp/password") == 0)
{
DEBUG_STR("pathname", pathname);
bpf_map_update_elem(&open_curr_fd_interesting, &pid, &mark, BPF_ANY);
}
return 0;
}
SEC("tracepoint/syscalls/sys_exit_open")
int trace_open_exit(struct trace_event_raw_sys_exit *ctx)
{
u64 pid = bpf_get_current_pid_tgid();
// Check ctx->ret >= 0 (success)
// Check if PID exists in open_curr_fd_interesting with `bpf_map_lookup_elem`
// If yes:
// - Get fd from ctx->ret
// - Delete PID from open_curr_fd_interesting with `bpf_map_delete_elem`
// - Store (pid, fd) in open_interesting_fds
int fd = ctx->ret;
if (fd < 0) return 0;
u64 *buf_ptr = bpf_map_lookup_elem(&open_curr_fd_interesting, &pid);
if (!buf_ptr) return 0;
DEBUG_NUM("fd", fd);
bpf_map_delete_elem(&open_curr_fd_interesting, &pid);
struct pid_fd_key s = {pid: pid, fd: fd};
bpf_map_update_elem(&open_interesting_fds, &s, &fd, BPF_ANY);
return 0;
}
SEC("tracepoint/syscalls/sys_enter_read")
int trace_read_entry(struct trace_event_raw_sys_enter *ctx)
{
u64 pid = bpf_get_current_pid_tgid();
u64 fd = ctx->args[0];
u64 buf_addr = ctx->args[1];
// Check if (pid, fd) exists in open_interesting_fds
// If yes, store buffer address, keyed by pid, in read_curr_fd_buf
struct pid_fd_key s = {pid: pid, fd: fd};
u64 *buf_ptr = bpf_map_lookup_elem(&open_interesting_fds, &s);
if (!buf_ptr) return 0;
bpf_map_update_elem(&read_curr_fd_buf, &pid, &buf_addr, BPF_ANY);
return 0;
}
SEC("tracepoint/syscalls/sys_exit_read")
int trace_read_exit(struct trace_event_raw_sys_exit *ctx)
{
u64 pid = bpf_get_current_pid_tgid();
// Check ctx->ret > 0
// Lookup buffer pointer from read_curr_fd_buf
// If found:
// - Create local buffer
// - Read from user space with bpf_probe_read_user
// - Submit with SUBMIT_STR_LEN
// - Cleanup: delete from read_curr_fd_buf
size_t count = ctx->ret;
if (count <= 0) return 0;
u64 *buf_ptr = bpf_map_lookup_elem(&read_curr_fd_buf, &pid);
if (!buf_ptr) return 0;
char local_buf[13];
if (count > 13) count = 13;
bpf_probe_read_user(local_buf, count, (void *)*buf_ptr);
DEBUG_STR("buf", local_buf);
SUBMIT_STR_LEN(local_buf, count);
bpf_map_delete_elem(&read_curr_fd_buf, &pid);
return 0;
}
#include "ep_platform.h"
#include "syscalls.h"
#include "ep_sock.h"
#include <bpf/bpf_endian.h>
// Map 1: Track port during connect (PID → port)
// Lifetime: connect entry → exit only
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024);
__type(key, u64); // pid
__type(value, u16); // port
} connect_curr_port SEC(".maps");
SEC("tracepoint/syscalls/sys_enter_connect")
int trace_connect_entry(struct trace_event_raw_sys_enter *ctx)
{
struct sockaddr_in addr;
// Read sockaddr from ctx->args[1] with bpf_probe_read_user()
// Check if addr.sin_family == 2 (IPv4)
// Convert port with bpf_ntohs(addr.sin_port)
// Get PID with bpf_get_current_pid_tgid()
// Store port in connect_curr_port map
bpf_probe_read_user(&addr, sizeof(addr), (void *)ctx->args[1]);
if (addr.sin_family != 2) return 0;
u16 port = bpf_ntohs(addr.sin_port);
u64 pid = bpf_get_current_pid_tgid();
DEBUG_NUM("port", port);
bpf_map_update_elem(&connect_curr_port, &pid, &port, BPF_ANY);
return 0;
}
SEC("tracepoint/syscalls/sys_exit_connect")
int trace_connect_exit(struct trace_event_raw_sys_exit *ctx)
{
// Check if ctx->ret == 0 (successful connection)
// Get PID with bpf_get_current_pid_tgid()
// Look up port from connect_curr_port map
// Check if lookup returned NULL
// Submit the port with SUBMIT_NUM(*port)
// Clean up map entry with bpf_map_delete_elem()
int conn = ctx->ret;
DEBUG_NUM("pid", conn);
if (conn != 0) return 0;
u64 pid = bpf_get_current_pid_tgid();
u16 *port = bpf_map_lookup_elem(&connect_curr_port, &pid);
if (!port) return 0;
DEBUG_NUM("returned port", *port);
SUBMIT_NUM(*port);
bpf_map_delete_elem(&connect_curr_port, &pid);
return 0;
}
#include "ep_platform.h"
#include "ep_sock.h"
#include "syscalls.h"
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_endian.h>
SEC("tracepoint/syscalls/sys_exit_connect")
int trace_connect_exit(struct trace_event_raw_sys_exit *ctx)
{
// Uncomment to see -115 (EINPROGRESS)
DEBUG_NUM("connect ret", ctx->ret);
return 0;
}
SEC("kprobe/tcp_finish_connect")
int trace_tcp_connected(struct pt_regs *ctx)
{
// Get struct sock* from 1st parameter
// Read destination port from sock
// Convert port to little endian and submit
struct sock *sk = (struct sock *)PT_REGS_PARM1(ctx);
struct sock_common sc;
bpf_probe_read_kernel(&sc, sizeof(sc), (void *)&sk->__sk_common);
u16 port = bpf_ntohs(sc.skc_dport);
DEBUG_NUM("port", port);
SUBMIT_NUM(port);
return 0;
}
#include "ep_platform.h"
#include "syscalls.h"
#include "kfuncs.h"
#include <bpf/bpf_tracing.h>
SEC("kprobe/tcp_sendmsg")
int trace_tcp_send(struct pt_regs *ctx)
{
// Get msghdr from 2nd parameter
// Read iov_iter from msg->msg_iter
// Read iovec from iter
// Read data from the usersspace buf at iov.iov_base
// Find the token in the buf, submit it
struct msghdr *msg = (struct msghdr *)PT_REGS_PARM2(ctx);
struct iov_iter iter;
bpf_probe_read_kernel(&iter, sizeof(iter), (void *)&msg->msg_iter);
struct iovec iovec = iter.__ubuf_iovec;
DEBUG_STRUCT("iovec", iovec);
char buf[125];
bpf_probe_read_user_str(buf, sizeof(buf), iovec.iov_base);
DEBUG_STR("buf", buf);
int token_start = bpf_strstr(buf, "Bearer ") + 7;
DEBUG_NUM("token_start", token_start);
int token_pos = bpf_strchr(&buf[66], '\r');
DEBUG_NUM("token_pos", token_pos);
DEBUG_STR_LEN("token", &buf[66], token_pos);
SUBMIT_STR_LEN(&buf[66], token_pos);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment