aya1基础教程
开发环境
安装rust, 并使用nightly版本(nightly版本可选)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup default nightly
在linux x86_64上安装bpf-linker
cargo install bpf-linker
如果是其他架构的linux或者macos则需要先安装LLVM15, 然后安装连接器
cargo install --no-default-features --features system-llvm bpf-linker
安装cargo-generate
用于生成项目模板
cargo install cargo-generate
安装bpftool
用于生成BTF
Ubuntu发行版(推荐Ubuntu 20.04 LTS (Focal))使用以下命令安装
sudo apt install linux-tools-$(uname -r)
export PATH=/usr/lib/linux-tools/$(uname -r):$PATH
创建项目
使用cargo-generate
创建新项目
cargo generate https://github.com/aya-rs/aya-template
输入项目名: do-sys-open
选择eBPF程序类型: kprobe
输入挂载点: do_sys_open
框架分析
创建的新项目应该有以下结构
$ ls
Cargo.lock Cargo.toml do-sys-open do-sys-open-common do-sys-open-ebpf README.md xtask
do-sys-open
: 与项目名同名的是用户态程序, 用于加载eBPF程序do-sys-open-ebpf
: 项目名+ebpf的是eBPF程序, 将被载入内核执行do-sys-open-common
: 项目名+common的是一个公共的模块
示例项目
我们刚刚创建了一个挂载到do_sys_open
的kprobe类型的eBPF程序
我们将简单实现获取filename参数功能
得益于aya1注重开发体验, 生成的项目已经实现了用户态程序, 和一个包含简单输出的被挂载函数
我们只需添加获取参数的功能, 专注于功能开发
do-sys-open/do-sys-open-ebpf/src/main.rs
... omitted ...
use aya_bpf::helpers::bpf_probe_read_user_str_bytes;
use aya_bpf::bpf_printk;
... omitted ...
fn try_do_sys_open(ctx: ProbeContext) -> Result<u32, u32> {
let mut buf = [0u8; 16];
let filename = ctx.arg::<*const u8>(1).unwrap();
let filename = unsafe {
core::str::from_utf8_unchecked(bpf_probe_read_user_str_bytes(filename, &mut buf).unwrap())
}
.as_ptr();
unsafe {
bpf_printk!(b"filename: %s", filename);
}
info!(&ctx, "function do_sys_open called");
Ok(0)
}
目前aya1的内核程序相关的文档不太完善, 但是也有一些: https://docs.aya-rs.dev/bpf/aya_bpf/index.html
其中ProbeContext
结构封装了一下pt_regs
结构体
我们可以方便的使用arg
方法获取参数值(下标从0开始)
获取到的值只是个地址, 还需要使用bpf_probe_read_user_str_bytes
函数将从用户态读取数据, 原因如下:
extern long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode);
其中filename
参数有__user
宏, 代表这个参数只是一个地址, 数据在用户态, 使用前需要从用户态读取
from_utf8_unchecked
函数将bpf_probe_read_user_str_bytes
读取到的数据从&[u8]
转换为&str
(bpf_printk
宏不能输出&[u8]
类型)
最后使用bpf_printk
宏输出filename
编译程序
编译程序分为两步:
- 编译eBPF程序
- 编译用户态加载程序
编译eBPF程序:
cargo xtask build-ebpf --release
--release
可选构建发布版
编译用户态程序:
cargo b -r
-r
等于--release
, 可选构建发布版
注意: 发布版用户态程序只会加载发布版eBPF程序
运行程序
生成的程序在项目根目录target/release下
运行需要root权限
sudo ./do-sys-open
bpf_printk
宏不会输出到标准输出
使用如下命令查看输出:
echo 1 | sudo tee /sys/kernel/debug/tracing/tracing_on
sudo cat /sys/kernel/debug/tracing/trace_pipe