【eBPF开发入门】案例(二)之监控系统调用

文章介绍了如何使用BPF(BerkeleyPacketFilter)和BCC库在Linux下创建Python脚本,实现实时监控和计数sys_clone系统调用,以及两个示例程序syscall_counter.py和syscall_trace.py,分别用于计数和详细追踪系统调用信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0x01编辑代码

  1. 创建一个新文件syscall_counter.py,然后输入以下Python脚本。这个脚本使用BCC创建了一个eBPF程序,该程序会挂接(hook)到sys_clone系统调用,每次调用都会增加计数器。
from bcc import BPF

# 定义eBPF程序
prog = """
#include <linux/sched.h>

BPF_HASH(syscall_count, u32, u64);

int count_sys_clone(struct pt_regs *ctx) {
    u32 pid = bpf_get_current_pid_tgid() >> 32;  // 获取进程ID
    u64 zero = 0, *val;
    
    // 增加syscall_count哈希表中对应PID的计数
    val = syscall_count.lookup_or_try_init(&pid, &zero);
    if (val) {
      (*val)++;
    }
    
    return 0;
}
"""

# 加载eBPF程序
b = BPF(text=prog)
b.attach_kprobe(event=b.get_syscall_fnname("clone"), fn_name="count_sys_clone")

# 输出标题
print("%-6s %-12s" % ("PID", "CLONE-COUNT"))

try:
    # 循环检索并输出系统调用的计数
    while True:
        syscall_count = b.get_table("syscall_count")
        for k, v in syscall_count.items():
            print("%-6d %-12d" % (k.value, v.value))
        b.trace_print()
        syscall_count.clear()

except KeyboardInterrupt:
    pass

  1. 保存文件后,使用具有必要权限的用户(通常是root)来运行此脚本
sudo python syscall_counter.py

0x实时跟踪系统调用

  • 实时监控系统调用。
  • 分析系统调用的使用模式,以识别性能热点或不寻常的系统行为。

syscall_trace.py

from bcc import BPF

# 定义eBPF程序
program = """
#include <uapi/linux/ptrace.h>

// 定义输出数据的结构体
struct data_t {
    u64 ts;
    u32 pid;
    char comm[TASK_COMM_LEN];
    char syscall[__SYSCALL_NAME_LEN];
    int ret;
};

BPF_PERF_OUTPUT(syscalls);

// 记录系统调用的入口
int trace_syscall_entry(struct pt_regs *ctx) {
    struct data_t data = {};
    data.ts = bpf_ktime_get_ns();
    data.pid = bpf_get_current_pid_tgid() >> 32;
    bpf_get_current_comm(&data.comm, sizeof(data.comm));

    // 获取系统调用名称
    int syscall_nr = PT_REGS_PARM1(ctx);
    bpf_probe_read_kernel_str(&data.syscall, sizeof(data.syscall), (void *)syscall_nr);

    syscalls.perf_submit(ctx, &data, sizeof(data));
    return 0;
}

// 记录系统调用的退出
int trace_syscall_exit(struct pt_regs *ctx) {
    struct data_t data = {};
    data.ts = bpf_ktime_get_ns();
    data.pid = bpf_get_current_pid_tgid() >> 32;
    data.ret = PT_REGS_RC(ctx);
    bpf_get_current_comm(&data.comm, sizeof(data.comm));

    // 获取系统调用名称
    int syscall_nr = PT_REGS_PARM1(ctx);
    bpf_probe_read_kernel_str(&data.syscall, sizeof(data.syscall), (void *)syscall_nr);

    syscalls.perf_submit(ctx, &data, sizeof(data));
    return 0;
}
"""

b = BPF(text=program)
b.attach_tracepoint(tp="raw_syscalls:sys_enter", fn_name="trace_syscall_entry")
b.attach_tracepoint(tp="raw_syscalls:sys_exit", fn_name="trace_syscall_exit")

print("Tracing syscalls... Hit Ctrl-C to end.")

# 处理事件的回调函数
def print_event(cpu, data, size):
    event = b["syscalls"].event(data)
    print(f"[{event.ts}] PID: {event.pid}, Comm: {event.comm}, Syscall: {event.syscall}, Return: {event.ret}")

b["syscalls"].open_perf_buffer(print_event)

while True:
    try:
        b.perf_buffer_poll()
    except KeyboardInterrupt:
        break
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值