Android Kprobe使用
搜索了好久都没有找到关于Android中使用kprobe的例子,基本都是用tracepoint .于是自己摸索了下,记录下
手写例子
echo 'p:kprobes/myretprobe do_sys_openat2 dfd=$arg1:u32 filename=+0($arg2):string' > /sys/kernel/tracing/kprobe_events
echo 1 > /sys/kernel/tracing/events/kprobes/myretprobe/enable
echo 1 > /sys/kernel/tracing/tracing_on
cat /sys/kernel/tracing/trace_pipe
首先是prog程序
// bpf_kprobe_test.c
#include <linux/bpf.h>
#include <stdbool.h>
#include <stdint.h>
#include <bpf_helpers.h>
#include <string.h>
#include <linux/ptrace.h>
#include "bpf_kprobe_test.h"
DEFINE_BPF_MAP(do_faccessat_map, ARRAY, int, struct data, 128);
// 定义了函数kp_do_faccessat, 目前来看名字可以随便起没什么作用
DEFINE_BPF_PROG("kprobe/do_faccessat", AID_ROOT, AID_NET_ADMIN, kp_do_faccessat)
//(struct user_pt_regs *regs, int dirfd, const char *pathname, int mode) {
(struct user_pt_regs *regs) { // 这里aosp头文件叫做user_pt_regs, bcc中是pt_regs
int key = 100;
struct data data_t;
data_t.pid = bpf_get_current_pid_tgid() >> 32;
// aosp中本身不支持此函数,bcc支持,直接给aosp加上
// system/bpf/progs/include/bpf_helpers.h
bpf_get_current_comm(data_t.comm, sizeof(data_t.comm));
// 测试1
// 2-20 16:38:19.882 887 887 W LibBpfLoader: bpf_prog_load - BEGIN log_buf contents:
// 12-20 16:38:19.882 887 887 W LibBpfLoader: 0: (bf) r6 = r3
// 12-20 16:38:19.882 887 887 W LibBpfLoader: R3 !read_ok
// bpfload Permission denied, 可能是用户空间地址无法访问
//if (pathname)
// bpf_probe_read_str(&data_t.log, sizeof(data_t.log), (void *)pathname);
// 测试2 强行拷贝 bpfload 还是加载prog失败,不过这次没有R3 !read_ok
// memcpy(data_t.log, pathname, sizeof(data_t.log));
// 测试3 通过寄存器访问.测试OK 可以获取到pathname
// systemd-journal-338 do_faccessat /run/systemd/jo
// systemd-journal-338 do_faccessat /run/systemd/jo
// systemd-journal-338 do_faccessat /run/systemd/jo
// systemd-journal-338 do_faccessat /run/systemd/jo
bpf_probe_read_str(&data_t.log, sizeof(data_t.log), (void *)regs->regs[1]);
bpf_do_faccessat_map_update_elem(&key, &data_t, BPF_ANY);
return 0;
}
LICENSE("GPL");
头文件
// bpf_kprobe_test.h
#ifndef _BPF_KPROBE_TEST_H
#define _BPF_KPROBE_TEST_H
#include <linux/sched.h>
#ifndef TASK_COMM_LEN
#define TASK_COMM_LEN 16 // linux/sched.h
#endif
struct data {
pid_t pid;
char comm[TASK_COMM_LEN];
char log[16];
};
#endif // _BPF_KPROBE_TEST_H
测试程序
// bpf_kprobe_test_cli.cpp
#include <android-base/macros.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <bpf/BpfMap.h> // system/bpf/libbpf_android/include/bpf/BpfMap.h
#include <bpf/BpfUtils.h>
#include <libbpf_android.h>
#include "bpf_kprobe_test.h"
int main() {
constexpr const char tp_prog_path[] = "/sys/fs/bpf/prog_bpf_kprobe_test_kprobe_do_faccessat";
constexpr const char tp_map_path[] = "/sys/fs/bpf/map_bpf_kprobe_test_do_faccessat_map";
// Attach tracepoint and wait for 4 seconds
int mProgFd = bpf_obj_get(tp_prog_path);
// int mMapFd = bpf_obj_get(tp_map_path);
// 打开对应的id 文件
// /sys/kernel/tracing/events/task/task_rename/id
/**
* int bpf_attach_kprobe(int progfd, enum bpf_probe_attach_type attach_type,
* const char *ev_name, const char *fn_name, uint64_t fn_offset)
* 打开 /sys/kernel/tracing/kprobe_events
* 写入对应事件 'echo 'p:kprobes/do_faccessat_bcc_pid_ do_faccessat'
* 参考: https://www.kernel.org/doc/html/latest/trace/kprobetrace.html
*/
int pfd = bpf_attach_kprobe(mProgFd, BPF_PROBE_ENTRY,
"myprobe"/*probe name*/, "do_faccessat" /*函数符号*/, 0);
if (pfd < 0) {
printf("bpf_attach_kprobe error!\n");
exit(0);
}
sleep(1);
// 高版本使用fd构造BpfMap
android::bpf::BpfMap<int, struct data> myMap(tp_map_path);
pid_t pid = getpid();
printf("pid: %d\n", pid);
while(1) {
usleep(40000);
// android::base::Result<Value> 类型
data data_t = myMap.readValue(100).value();
printf("%s-%d do_faccessat %s\n", data_t.comm, data_t.pid, data_t.log);
}
exit(0);
}
Android.bp
bpf {
name: "bpf_kprobe_test.o",
srcs: ["bpf_kprobe_test.c"],
cflags: [
"-Wall",
"-Werror",
],
}
cc_binary {
name: "bpf_kprobe_test_cli",
cflags: [
"-Wall",
"-Werror",
"-Wthread-safety",
],
clang: true,
shared_libs: [
"libcutils",
"libbpf_android",
"libbase",
"liblog",
"libnetdutils",
"libbpf",
],
srcs: [
"bpf_kprobe_test_cli.cpp",
],
}
运行效果