eBPF Hook sys_enter_connect/bind跟踪点无法阻断特定进程Socket连接求助
问题根源与解决方法
你用tracepoint的sys_enter_connect/sys_enter_bind无法阻断连接的核心原因是:tracepoint是内核提供的观测性钩子,仅用于采集数据,其BPF程序的返回值不会影响原系统调用的执行流程。返回-1在这里没有任何阻断作用,系统调用会继续正常执行。
要实现系统调用阻断,需要使用能够修改系统调用返回值的钩子类型,比如fentry(推荐)或kprobe。以下是具体实现方案:
1. 使用fentry钩子拦截系统调用
fentry是内核4.17+提供的函数入口钩子,稳定性优于kprobe,直接hook系统调用的内核实现函数(如__sys_connect、__sys_bind),通过修改寄存器里的返回值来阻断调用。
示例代码
#include <linux/bpf.h> #include <bpf/bpf_helpers.h> #include <bpf/bpf_tracing.h> #include <linux/socket.h> #include <linux/types.h> // 拦截__sys_connect SEC("fentry/__sys_connect") int BPF_PROG(hook_sys_connect, int fd, struct sockaddr __user *uservaddr, int addrlen) { u64 pid_tgid = bpf_get_current_pid_tgid(); u32 pid = pid_tgid >> 32; // 获取进程PID char comm[16]; // 获取当前进程名(最多15字符+结束符) bpf_get_current_comm(&comm, sizeof(comm)); // 替换为你要拦截的PID或进程名 if (pid == 1234 || __builtin_memcmp(comm, "target_proc", 11) == 0) { // 设置系统调用返回错误码(EPERM表示权限不足) *PT_REGS_RC(ctx) = -EPERM; return 0; } return 0; } // 拦截__sys_bind SEC("fentry/__sys_bind") int BPF_PROG(hook_sys_bind, int fd, struct sockaddr __user *addr, int addrlen) { u64 pid_tgid = bpf_get_current_pid_tgid(); u32 pid = pid_tgid >> 32; char comm[16]; bpf_get_current_comm(&comm, sizeof(comm)); if (pid == 1234 || __builtin_memcmp(comm, "target_proc", 11) == 0) { *PT_REGS_RC(ctx) = -EPERM; return 0; } return 0; } char _license[] SEC("license") = "GPL";
2. 低内核版本兼容方案(使用kprobe)
如果内核版本低于4.17,可改用kprobe钩子,原理类似,只是hook的是系统调用的入口点:
示例代码
#include <linux/bpf.h> #include <bpf/bpf_helpers.h> #include <bpf/bpf_tracing.h> #include <linux/socket.h> // 拦截sys_connect的kprobe SEC("kprobe/sys_connect") int BPF_KPROBE(hook_sys_connect, int fd, struct sockaddr __user *uservaddr, int addrlen) { u64 pid_tgid = bpf_get_current_pid_tgid(); u32 pid = pid_tgid >> 32; char comm[16]; bpf_get_current_comm(&comm, sizeof(comm)); if (pid == 1234 || __builtin_memcmp(comm, "target_proc", 11) == 0) { // 修改返回值,阻断调用 bpf_set_retval(ctx, -EPERM); return 0; } return 0; } // 拦截sys_bind的kprobe SEC("kprobe/sys_bind") int BPF_KPROBE(hook_sys_bind, int fd, struct sockaddr __user *addr, int addrlen) { u64 pid_tgid = bpf_get_current_pid_tgid(); u32 pid = pid_tgid >> 32; char comm[16]; bpf_get_current_comm(&comm, sizeof(comm)); if (pid == 1234 || __builtin_memcmp(comm, "target_proc", 11) == 0) { bpf_set_retval(ctx, -EPERM); return 0; } return 0; } char _license[] SEC("license") = "GPL";
3. 关键注意事项
- 内核版本适配:fentry需要Linux 4.17+,kprobe兼容性更好但稳定性稍差;不同架构的系统调用名称可能有差异(如arm64下是
sys_connect而非__sys_connect),需根据目标架构调整。 - 权限要求:加载BPF程序需要
CAP_BPF、CAP_PERFMON等权限,建议用root用户或赋予对应权限的用户执行。 - 进程匹配准确性:
bpf_get_current_comm获取的进程名是16字节长度,注意目标进程名的长度不要超过15字符,否则会被截断。 - 验证阻断效果:可通过
strace目标进程,确认系统调用是否返回-EPERM错误。
内容的提问来源于stack exchange,提问作者nvd
相关产品推荐
相关产品推荐

