libbpf-bootstrap开发指南:内核态探针- kprobe

目录

代码分析

BPF程序部分

功能说明

BPF_CORE_READ

用户程序部分

功能说明

执行效果


代码分析

BPF程序部分
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright (c) 2021 Sartura */
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>

char LICENSE[] SEC("license") = "Dual BSD/GPL";

SEC("kprobe/do_unlinkat")
int BPF_KPROBE(do_unlinkat, int dfd, struct filename *name)
{
	pid_t pid;
	const char *filename;

	pid = bpf_get_current_pid_tgid() >> 32;
	filename = BPF_CORE_READ(name, name);
	bpf_printk("KPROBE ENTRY pid = %d, filename = %s\n", pid, filename);
	return 0;
}

SEC("kretprobe/do_unlinkat")
int BPF_KRETPROBE(do_unlinkat_exit, long ret)
{
	pid_t pid;

	pid = bpf_get_current_pid_tgid() >> 32;
	bpf_printk("KPROBE EXIT: pid = %d, ret = %ld\n", pid, ret);
	return 0;
}
功能说明

用来监控在 Linux 中的文件删除操作的,具体来说是 unlinkat 系统调用

do_unlinkat 和 do_unlinkat_exit 不是系统调用,而是与 unlinkat 系统调用相关的内核函数和 BPF 程序中的探针。

  1. do_unlinkat 是一个内核函数,它实现了 unlinkat 系统调用的功能。unlinkat 系统调用用于删除一个文件或者目录,其原型如下
int unlinkat(int dirfd, const char *pathname, int flags);

其中 dirfd 是一个文件描述符,它引用了一个目录;pathname 是要删除的文件或者目录的路径;flags 可以是 0,也可以是 AT_REMOVEDIR,如果是 AT_REMOVEDIR,那么 pathname 就会被当作目录处理。

do_unlinkat 接收的参数与此类似,但是 pathname 参数被替换为了一个 struct filename * 类型的参数,这是因为在内核中,文件名经常以 struct filename 结构体的形式进行传递。

  • do_unlinkat_exit 是 BPF 程序中定义的一个探针,它是一个 kretprobe。kretprobe 是内核返回探针,它会在某个内核函数执行完毕后触发。在这个 BPF 程序中,do_unlinkat_exit 会在 do_unlinkat 函数执行完毕后触发。

do_unlinkat_exit 探针的功能是获取 do_unlinkat 的返回值,并打印一条包含了执行这个函数的进程的 PID 和返回值的消息。这对于追踪 unlinkat 系统调用的行为非常有用,因为你可以看到每次这个系统调用执行时的 PID 和返回值。

BPF_CORE_READ

BPF_CORE_READ(src, field) 是一个 eBPF 提供的宏,用于从内核空间读取数据。这个宏的工作方式类似于 C 语言的 . 运算符,但是它可以安全地用于读取内核数据,而不会导致 eBPF 程序因为尝试访问无效的内核内存地址而被终止。

BPF_CORE_READ(name, name) 这行代码的意图是从 struct filename *name 结构体中读取 name 字段的值,然后将这个值赋给 filename 变量。在这里,struct filename *name 是内核函数 do_unlinkat 的一个参数,struct filename 结构体的 name 字段通常用于存储文件名。

用户程序部分
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
/* Copyright (c) 2021 Sartura
 * Based on minimal.c by Facebook */

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <sys/resource.h>
#include <bpf/libbpf.h>
#include "kprobe.skel.h"

static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
{
	return vfprintf(stderr, format, args);
}

static volatile sig_atomic_t stop;

static void sig_int(int signo)
{
	stop = 1;
}

int main(int argc, char **argv)
{
	struct kprobe_bpf *skel;
	int err;

	/* Set up libbpf errors and debug info callback */
	libbpf_set_print(libbpf_print_fn);

	/* Open load and verify BPF application */
	skel = kprobe_bpf__open_and_load();
	if (!skel) {
		fprintf(stderr, "Failed to open BPF skeleton\n");
		return 1;
	}

	/* Attach tracepoint handler */
	err = kprobe_bpf__attach(skel);
	if (err) {
		fprintf(stderr, "Failed to attach BPF skeleton\n");
		goto cleanup;
	}

	if (signal(SIGINT, sig_int) == SIG_ERR) {
		fprintf(stderr, "can't set signal handler: %s\n", strerror(errno));
		goto cleanup;
	}

	printf("Successfully started! Please run `sudo cat /sys/kernel/debug/tracing/trace_pipe` "
	       "to see output of the BPF programs.\n");

	while (!stop) {
		fprintf(stderr, ".");
		sleep(1);
	}

cleanup:
	kprobe_bpf__destroy(skel);
	return -err;
}
功能说明

加载一个 BPF 程序,将其附加到内核,然后等待用户的中断信号。

执行效果

  URL Classifier-6018    [004] d..31 77753.806532: bpf_trace_printk: KPROBE ENTRY pid = 5723, filename = /home/zy/snap/firefox/common/.cache/mozilla/firefox/faxkuo36.default/safebrowsing-updating/social-tracking-protection-twitter-digest256.sbstore

  URL Classifier-6018    [004] d..31 77753.806536: bpf_trace_printk: KPROBE EXIT: pid = 5723, ret = 0

 ThreadPoolForeg-50602   [006] d..31 77754.683597: bpf_trace_printk: KPROBE ENTRY pid = 6861, filename = /home/zy/.config/clash_win/Cache/Cache_Data/7c2d1cffc51cc88b_0

 ThreadPoolForeg-50602   [006] d..31 77754.683616: bpf_trace_printk: KPROBE EXIT: pid = 6861, ret = 0

 ThreadPoolForeg-50602   [006] d..31 77754.683625: bpf_trace_printk: KPROBE ENTRY pid = 6861, filename = /home/zy/.config/clash_win/Cache/Cache_Data/a70ac0571625a32a_0

 ThreadPoolForeg-50602   [006] d..31 77754.683637: bpf_trace_printk: KPROBE EXIT: pid = 6861, ret = 0

 ThreadPoolForeg-50618   [016] d..31 77754.683904: bpf_trace_printk: KPROBE ENTRY pid = 6861, filename = /home/zy/.config/clash_win/Cache/Cache_Data/352fee22ce52ccf1_0

 ThreadPoolForeg-50618   [016] d..31 77754.683934: bpf_trace_printk: KPROBE EXIT: pid = 6861, ret = 0

 Chrome_IOThread-6809    [012] d..31 77754.684552: bpf_trace_printk: KPROBE ENTRY pid = 6798, filename = /dev/shm/.org.chromium.Chromium.rrvRWo

 Chrome_IOThread-6809    [012] d..31 77754.684555: bpf_trace_printk: KPROBE EXIT: pid = 6798, ret = 0

 Chrome_IOThread-6809    [014] d..31 77754.685207: bpf_trace_printk: KPROBE ENTRY pid = 6798, filename = /dev/shm/.org.chromium.Chromium.n57azy

 Chrome_IOThread-6809    [014] d..31 77754.685209: bpf_trace_printk: KPROBE EXIT: pid = 6798, ret = 0

 Chrome_IOThread-6809    [014] d..31 77754.685665: bpf_trace_printk: KPROBE ENTRY pid = 6798, filename = /dev/shm/.org.chromium.Chromium.lHj06A

 Chrome_IOThread-6809    [014] d..31 77754.685666: bpf_trace_printk: KPROBE EXIT: pid = 6798, ret = 0

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ym影子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值