🍳 bpftrace Recipes
Practical bpftrace scripts for common system administration and performance analysis tasks. These recipes solve real-world problems with eBPF-powered observability.
CPU Profiling by Process
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | #!/usr/bin/env bpftrace
// Profile CPU usage across all processes
profile:hz:997
{
@cpu_time[comm] = count();
}
// Print top consumers every 30 seconds
interval:s:30
{
printf("=== CPU Usage (last 30s) ===\n");
print(@cpu_time);
clear(@cpu_time);
}
// Cleanup on exit
END
{
clear(@cpu_time);
}
|
Memory Allocation Analysis
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 | #!/usr/bin/env bpftrace
// Track malloc calls and sizes
uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc
{
@malloc_sizes = hist(arg0);
@malloc_by_process[comm] = sum(arg0);
}
// Track memory leaks (allocations without frees)
uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc
{
@allocs[tid, arg0] = 1;
}
uretprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc
{
$ptr = retval;
@alloc_ptrs[$ptr] = arg0; // Store size with pointer
}
uprobe:/lib/x86_64-linux-gnu/libc.so.6:free
{
delete(@alloc_ptrs[arg0]); // Remove when freed
}
// Report leaks periodically
interval:s:60
{
printf("=== Potential Memory Leaks ===\n");
print(@alloc_ptrs);
}
|
I/O Latency Monitoring
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 | #!/usr/bin/env bpftrace
// Track file I/O latency
tracepoint:syscalls:sys_enter_open
{
@start[tid] = nsecs;
}
tracepoint:syscalls:sys_exit_open
/@start[tid]/
{
@open_latency = hist(nsecs - @start[tid]);
delete(@start[tid]);
}
tracepoint:syscalls:sys_enter_read
{
@read_start[tid] = nsecs;
}
tracepoint:syscalls:sys_exit_read
/@read_start[tid] && args->ret > 0/
{
@read_latency = hist(nsecs - @read_start[tid]);
@read_sizes = hist(args->ret);
delete(@read_start[tid]);
}
// Report every 5 minutes
interval:s:300
{
printf("=== I/O Latency Report ===\n");
printf("Open latency distribution:\n");
print(@open_latency);
printf("Read latency distribution:\n");
print(@read_latency);
printf("Read size distribution:\n");
print(@read_sizes);
clear(@open_latency);
clear(@read_latency);
clear(@read_sizes);
}
|
🌐 Network Monitoring Recipes
TCP Connection Tracking
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 | #!/usr/bin/env bpftrace
// Monitor TCP connection attempts
kprobe:tcp_v4_connect
{
$addr = (struct sockaddr_in *)arg1;
@connections[comm, ntop(AF_INET, $addr->sin_addr.s_addr), $addr->sin_port] = count();
}
// Track established connections
kprobe:tcp_set_state
/arg1 == 1/ // TCP_ESTABLISHED
{
@established[comm] = count();
}
// Track closed connections
kprobe:tcp_set_state
/arg1 == 7/ // TCP_CLOSE
{
@closed[comm] = count();
}
// Report every minute
interval:s:60
{
printf("=== TCP Connection Report ===\n");
printf("New connections:\n");
print(@connections);
printf("Established connections:\n");
print(@established);
printf("Closed connections:\n");
print(@closed);
clear(@connections);
clear(@established);
clear(@closed);
}
|
Network Throughput Analysis
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | #!/usr/bin/env bpftrace
// Monitor network send/receive throughput
kprobe:tcp_sendmsg
{
@bytes_sent[comm] = sum(arg2); // arg2 is size
}
kprobe:tcp_recvmsg
{
@bytes_received[comm] = sum(arg2); // arg2 is size
}
// Calculate throughput every 10 seconds
interval:s:10
{
printf("=== Network Throughput (last 10s) ===\n");
printf("Bytes sent by process:\n");
print(@bytes_sent);
printf("Bytes received by process:\n");
print(@bytes_received);
// Calculate MB/s
$sent_mb = sum(@bytes_sent) / 1024 / 1024 / 10;
$recv_mb = sum(@bytes_received) / 1024 / 1024 / 10;
printf("Throughput: %.2f MB/s sent, %.2f MB/s received\n", $sent_mb, $recv_mb);
clear(@bytes_sent);
clear(@bytes_received);
}
|
DNS Query Monitoring
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | #!/usr/bin/env bpftrace
// Monitor DNS queries (UDP port 53)
tracepoint:syscalls:sys_enter_sendto
/arg2 == 13568/ // htons(53) for little-endian
{
printf("DNS Query: %s (PID: %d)\n", comm, pid);
@dns_queries[comm] = count();
}
// Monitor DNS responses
tracepoint:syscalls:sys_enter_recvfrom
/arg2 == 13568/
{
@dns_responses[comm] = count();
}
// Report DNS activity
interval:s:30
{
printf("=== DNS Activity (last 30s) ===\n");
printf("Queries: %d\n", sum(@dns_queries));
printf("Responses: %d\n", sum(@dns_responses));
print(@dns_queries);
clear(@dns_queries);
clear(@dns_responses);
}
|
🔒 Security and Audit Recipes
File Access Monitoring
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 | #!/usr/bin/env bpftrace
// Monitor access to sensitive files
tracepoint:syscalls:sys_enter_openat
{
$filename = str(args->filename);
// Monitor /etc/passwd access
if (strncmp($filename, "/etc/passwd", 11) == 0) {
printf("ALERT: %s (PID: %d) accessed /etc/passwd\n", comm, pid);
@passwd_access[comm, uid] = count();
}
// Monitor SSH directory access
if (strstr($filename, ".ssh/") != 0) {
printf("SSH ACCESS: %s (PID: %d) accessed %s\n", comm, pid, $filename);
@ssh_access[comm, $filename] = count();
}
// Monitor executable creation
if (args->flags & 0x40) { // O_CREAT
@file_creations[comm, $filename] = count();
}
}
// Report security events
interval:s:60
{
if (sum(@passwd_access) > 0) {
printf("=== Security Alert: /etc/passwd Access ===\n");
print(@passwd_access);
}
if (sum(@ssh_access) > 0) {
printf("=== SSH Access Detected ===\n");
print(@ssh_access);
}
if (sum(@file_creations) > 0) {
printf("=== File Creations ===\n");
print(@file_creations);
}
clear(@passwd_access);
clear(@ssh_access);
clear(@file_creations);
}
|
Privilege Escalation Detection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 | #!/usr/bin/env bpftrace
// Monitor setuid/setgid calls
kprobe:sys_setuid
{
printf("SETUID: %s (PID: %d) setting UID to %d\n", comm, pid, arg0);
@uid_changes[comm, uid, arg0] = count();
}
kprobe:sys_setgid
{
printf("SETGID: %s (PID: %d) setting GID to %d\n", comm, pid, arg0);
@gid_changes[comm, gid, arg0] = count();
}
// Monitor capability changes
kprobe:cap_capable
{
printf("CAPABILITY CHECK: %s (PID: %d) requesting CAP %d\n", comm, pid, arg2);
@capability_requests[comm, arg2] = count();
}
// Alert on suspicious activity
interval:s:30
{
if (sum(@uid_changes) > 0 || sum(@gid_changes) > 0) {
printf("=== Privilege Changes Detected ===\n");
print(@uid_changes);
print(@gid_changes);
}
if (sum(@capability_requests) > 0) {
printf("=== Capability Requests ===\n");
print(@capability_requests);
}
clear(@uid_changes);
clear(@gid_changes);
clear(@capability_requests);
}
|
Process Execution Monitoring
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 | #!/usr/bin/env bpftrace
// Monitor all process executions
tracepoint:syscalls:sys_enter_execve
{
$cmdline = str(args->argv[0]);
// Log all executions
printf("EXEC: %s (PID: %d, PPID: %d) -> %s\n", comm, pid, ((struct task_struct*)curtask)->real_parent->pid, $cmdline);
// Monitor suspicious commands
if (strstr($cmdline, "nc ") != 0 || strstr($cmdline, "ncat ") != 0 || strstr($cmdline, "socat ") != 0) {
printf("SUSPICIOUS: Network tool executed: %s\n", $cmdline);
@suspicious_execs[comm, $cmdline] = count();
}
// Monitor shell spawning
if (strstr($cmdline, "sh") != 0 || strstr($cmdline, "bash") != 0 || strstr($cmdline, "zsh") != 0) {
@shell_spawns[comm] = count();
}
}
// Report execution statistics
interval:s:60
{
printf("=== Process Execution Summary ===\n");
if (sum(@suspicious_execs) > 0) {
printf("Suspicious executions detected:\n");
print(@suspicious_execs);
}
if (sum(@shell_spawns) > 0) {
printf("Shell spawns: %d\n", sum(@shell_spawns));
}
clear(@suspicious_execs);
clear(@shell_spawns);
}
|
🛠️ System Health Recipes
Resource Exhaustion Detection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 | #!/usr/bin/env bpftrace
// Monitor file descriptor usage
tracepoint:syscalls:sys_enter_open
{
@fds_per_process[pid, comm] = count();
}
tracepoint:syscalls:sys_exit_close
{
if (@fds_per_process[pid, comm] > 0) {
@fds_per_process[pid, comm]--;
}
}
// Alert on high FD usage
interval:s:10
{
foreach ([pid, comm] : @fds_per_process) {
if (@fds_per_process[pid, comm] > 1000) {
printf("WARNING: Process %s (PID: %d) has %d open file descriptors\n",
comm, pid, @fds_per_process[pid, comm]);
}
}
}
|
System Call Rate Monitoring
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | #!/usr/bin/env bpftrace
// Count system calls by type
tracepoint:syscalls:sys_enter_*
{
@syscall_rates[probe] = count();
@total_syscalls = count();
}
// Calculate rates and alert on anomalies
interval:s:5
{
$rate = @total_syscalls / 5; // Calls per second
if ($rate > 10000) {
printf("HIGH SYSCALL RATE: %d calls/sec\n", $rate);
print(@syscall_rates);
}
clear(@syscall_rates);
@total_syscalls = 0;
}
|
🧾 Summary
✅ Production-ready monitoring solutions
✅ Low-overhead system observation
✅ Customizable alerts and metrics
✅ Security-focused audit capabilities
✅ Performance-oriented analysis tools
🧾 See Also