I am getting into eBPF programming and want to use raw tracepoints, but I do not really understand, how to use them and how to access the arguments correctly. I would appreciate any help and hints to documantation.
My questions:
- How do I get the arguments from the syscall by using a raw_tracepoint instead of a tracepoint?
- BTW: What is the
uint16_t common_type;
of a raw tracepoint?
System: Ubuntu 2004 with Kernel 5.4 generic, x86_64
Explanation/Example:
I started with the "normal tracepoint" sys_enter_kill
, where I can create the struct with arguments from sudo cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_kill/format
:
// sudo cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_kill/format
// name: sys_enter_kill
// ID: 184
// format:
// field:unsigned short common_type; offset:0; size:2; signed:0;
// field:unsigned char common_flags; offset:2; size:1; signed:0;
// field:unsigned char common_preempt_count; offset:3; size:1;signed:0;
// field:int common_pid; offset:4; size:4; signed:1;
// field:int __syscall_nr; offset:8; size:4; signed:1;
// field:pid_t pid; offset:16; size:8; signed:0;
// field:int sig; offset:24; size:8; signed:0;
struct syscalls_enter_kill_args
{
unsigned short common_type;
unsigned char common_flags;
unsigned char common_preempt_count;
int common_pid;
long syscall_nr;
long pid;
long sig;
};
SEC("tracepoint/xxx")
int main_entry(struct syscalls_enter_kill_args *ctx)
{
if(ctx->sig != 9)
return 0;
u64 pid_tgid = bpf_get_current_pid_tgid();
u32 pid = pid_tgid;
bpf_printk("Catched function call; PID = : %d.\n", pid);
return 0;
}
This simple bpf program just outputs some text, whenever a kill signal is invoked. It only logs SIGKILL, not SIGINT, SIGQUIT, ...
Now I want to do the same functionality with the raw tracepoint sys_enter
.
// sudo cat /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/format
// name: sys_enter
// ID: 22
// format:
// field:unsigned short common_type; offset:0; size:2; signed:0;
// field:unsigned char common_flags; offset:2; size:1; signed:0;
// field:unsigned char common_preempt_count; offset:3; size:1;signed:0;
// field:int common_pid; offset:4; size:4; signed:1;
// field:long id; offset:8; size:8; signed:1;
// field:unsigned long args[6]; offset:16; size:48; signed:0;
struct sys_enter_args
{
uint16_t common_type;
uint8_t common_flags;
uint8_t common_preempt_count;
int32_t common_pid;
int64_t id;
uint64_t args[6]; // Je 4 Bytes
};
SEC("raw_tracepoint/xxx")
int main_entry_raw(struct sys_enter_args *ctx)
{
if(ctx->id != SYS_kill) // 62
return 0;
u64 pid_tgid = bpf_get_current_pid_tgid();
u32 pid = pid_tgid;
bpf_printk("Catched function call; PID = : %d.\n", pid);
bpf_printk(" type: %u\n", ctx->common_type);
bpf_printk(" id: %u\n", ctx->id);
uint64_t* args = ctx->args;
uint64_t arg3 = 0;
bpf_probe_read(&arg3, sizeof(uint64_t), args + 3);
bpf_printk(" Arg3: %u \n", arg3);
}
I thought, I might get the signal (SIGKILL/SIGINT/SIGQUIT/...) via
field:int sig; offset:24; size:8; signed:0;
from args[]
:
Offset=24 => Byte 3; size 8 => Type u64 = unsigned long.
However, this results no useful values.
So how do I get the value of the signal, which I can access in the tracepoint, also in the raw_tracepoint?
Thanks for help!