## eBPF 入门实践教程:编写 eBPF 程序 sigsnoop 工具监控全局 signal 事件 ### 背景 ### 实现原理 `sigsnoop` 在利用了linux的tracepoint挂载点,其在syscall进入和退出的各个关键挂载点均挂载了执行函数。 ```c SEC("tracepoint/syscalls/sys_enter_kill") int kill_entry(struct trace_event_raw_sys_enter *ctx) { pid_t tpid = (pid_t)ctx->args[0]; int sig = (int)ctx->args[1]; return probe_entry(tpid, sig); } SEC("tracepoint/syscalls/sys_exit_kill") int kill_exit(struct trace_event_raw_sys_exit *ctx) { return probe_exit(ctx, ctx->ret); } SEC("tracepoint/syscalls/sys_enter_tkill") int tkill_entry(struct trace_event_raw_sys_enter *ctx) { pid_t tpid = (pid_t)ctx->args[0]; int sig = (int)ctx->args[1]; return probe_entry(tpid, sig); } SEC("tracepoint/syscalls/sys_exit_tkill") int tkill_exit(struct trace_event_raw_sys_exit *ctx) { return probe_exit(ctx, ctx->ret); } SEC("tracepoint/syscalls/sys_enter_tgkill") int tgkill_entry(struct trace_event_raw_sys_enter *ctx) { pid_t tpid = (pid_t)ctx->args[1]; int sig = (int)ctx->args[2]; return probe_entry(tpid, sig); } SEC("tracepoint/syscalls/sys_exit_tgkill") int tgkill_exit(struct trace_event_raw_sys_exit *ctx) { return probe_exit(ctx, ctx->ret); } SEC("tracepoint/signal/signal_generate") int sig_trace(struct trace_event_raw_signal_generate *ctx) { struct event event = {}; pid_t tpid = ctx->pid; int ret = ctx->errno; int sig = ctx->sig; __u64 pid_tgid; __u32 pid; if (failed_only && ret == 0) return 0; if (target_signal && sig != target_signal) return 0; pid_tgid = bpf_get_current_pid_tgid(); pid = pid_tgid >> 32; if (filtered_pid && pid != filtered_pid) return 0; event.pid = pid; event.tpid = tpid; event.sig = sig; event.ret = ret; bpf_get_current_comm(event.comm, sizeof(event.comm)); bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); return 0; } ``` ### Eunomia中使用方式 ![result](../imgs/sigsnoop.png) ![result](../imgs/sigsnoop-prometheus.png) ### 总结