Summary Link to heading
I needed a method to monitor various system calls, and their associated arguments with a specific format. To do so I used ebpf. This is not a complete tutorial by any means on using ebpf, and rather just a simple example of how a system call can be monitored.
As a base I forked libbpf-bootstrap, and modified the ksyscall program accordingly.
Existing code Link to heading
The process of taking the example code in ksyscall, and abstracting it to work for all of these is fairly simple. First let’s look at one of the examples from ksyscall.bpf.c
SEC("ksyscall/tgkill")
int BPF_KSYSCALL(tgkill_entry, pid_t tgid, pid_t tid, int sig)
{
char comm[TASK_COMM_LEN];
__u32 caller_pid = bpf_get_current_pid_tgid() >> 32;
if (sig == 0) {
/*
If sig is 0, then no signal is sent, but existence and permission
checks are still performed; this can be used to check for the
existence of a process ID or process group ID that the caller is
permitted to signal.
*/
return 0;
}
bpf_get_current_comm(&comm, sizeof(comm));
bpf_printk(
"tgkill syscall called by PID %d (%s) for thread id %d with pid %d and signal %d.",
caller_pid, comm, tid, tgid, sig);
return 0;
}
SEC("ksyscall/tgkill")
tells us the BPF program to monitor for the tgkill syscall. The parameters are:
name
an arbitrary identifier- the rest of the parameters to this are as shown in
man tgkill
int tgkill(pid_t tgid, pid_t tid, int sig);
Once we have this information we move on to grabbing the callers PID via bpf_get_current_pid_tgid() >> 32
Then we grab the process name from bpf_get_current_comm(&comm, sizeof(comm))
storing it in comm
. We can now print the relevant information that we want to see via bpf_printk
New syscall Link to heading
Let’s add a new system call to monitor: setuid
:
First - man setuid
:
setuid(2) System Calls Manual setuid(2)
NAME
setuid - set user identity
LIBRARY
Standard C library (libc, -lc)
SYNOPSIS
#include <unistd.h>
int setuid(uid_t uid);
This should be simple, the call only has one parameter uid
SEC("ksyscall/setuid")
int BPF_KSYSCALL(setuid_entry, uid_t uid)
{
char comm[TASK_COMM_LEN];
__u32 caller_pid = bpf_get_current_pid_tgid() >> 32;
bpf_get_current_comm(&comm, sizeof(comm));
bpf_printk(
"setuid syscall called by PID %d (%s) with uid %d.",
caller_pid, comm, uid);
return 0;
}
Compile:
cd examples/c
make
Run:
sudo ./ksyscall
We can now observe the trace by reading from /sys/kernel/debug/tracing/trace_pipe
:
sudo cat /sys/kernel/debug/tracing/trace_pipe
xkbcomp-145848 [027] ...21 16218.164177: bpf_trace_printk: setuid syscall called by PID 145848 (Xorg) with uid 0.
unix_chkpwd-145891 [026] ...21 16221.035361: bpf_trace_printk: setuid syscall called by PID 145891 (sudo) with uid 0.