通過strace抓取之前這個loader的系統調用:
bpf(BPF_OBJ_GET, {pathname="/sys/fs/bpf/prog_bpftest_tracepoint_raw_syscalls_sys_enter", bpf_fd=0, file_flags=0}, 120) = 3openat(AT_FDCWD, "/sys/kernel/tracing/events/raw_syscalls/sys_enter/id", O_RDONLY|O_CLOEXEC) = 4read(4, "21\n", 4096) = 3close(4) = 0perf_event_open({type=PERF_TYPE_TRACEPOINT, size=0, config=21, ...}, -1, 0, -1, PERF_FLAG_FD_CLOEXEC) = 4ioctl(4, PERF_EVENT_IOC_SET_BPF, 3) = 0ioctl(4, PERF_EVENT_IOC_ENABLE, 0) = 0nanosleep({tv_sec=1, tv_nsec=0}, 0x7ff104b788) = 0bpf(BPF_OBJ_GET, {pathname="/sys/fs/bpf/map_bpftest_execve_map", bpf_fd=0, file_flags=0}, 120) = 5nanosleep({tv_sec=0, tv_nsec=40000000}, NULL) = 0bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=5, key=0x7ff104b5f4, value=0x7ff104b5e8}, 120) = 0
通過上面的系統調用,我們就能理清楚,loader程序到底做了哪些工作。
接着我找到了Linux內核中的一個bpf_load.c,參考了一下在普通的Linux系統中,loader是怎麼處理的,所以我對該程序進行了修改,增加了以下代碼:
struct androidBPF { char *prog_path; char *map_path; char *tp_category; char *tp_name;};static int load_prog(char *prog_path){ int pfd; pfd = bpf_obj_get(prog_path); if (pfd < 0) { printf("bpf_prog_load() err=%d\n%s", errno, prog_path); return -1; } return pfd;}int attach_tracepoint(char *tp_category, char *tp_name){ char buf[256]; int efd, err, id; struct perf_event_attr attr = {}; attr.type = PERF_TYPE_TRACEPOINT; attr.sample_type = PERF_SAMPLE_RAW; attr.sample_period = 1; attr.wakeup_events = 1; strcpy(buf, DEBUGFS); strcat(buf, "events/"); strcat(buf, tp_category); strcat(buf, "/"); strcat(buf, tp_name); strcat(buf, "/id"); efd = open(buf, O_RDONLY, 0); if (efd < 0) { printf("failed to open %s\n", buf); return -1; } err = read(efd, buf, sizeof(buf)); if (err < 0 || err >= sizeof(buf)) { printf("read from failed '%s'\n", strerror(errno)); return -1; } close(efd); buf[err] = 0; id = atoi(buf); attr.config = id; efd = perf_event_open(&attr, -1/*pid*/, 0/*cpu*/, -1/*group_fd*/, 0); if (efd < 0) { printf("event %d fd %d err %s\n", id, efd, strerror(errno)); return -1; } return efd;}static int load_map(char *map_path){ int mfd; mfd = bpf_obj_get(map_path); if (mfd < 0) { printf("bpf_map_load() err=%d\n%s", errno, map_path); return -1; } return mfd;}int get_map_by_int_key(int *key, void *value){ int mfd, ret; mfd = map_fd[prog_cnt-1]; ret = bpf_lookup_elem(mfd, key, value); return ret;}int load_bpf_from_fs(struct androidBPF *abpf){ int fd, efd, mfd; fd = load_prog(abpf->prog_path); if (fd <= 0) { printf("[debug] load prog error.\n"); return fd; } prog_fd[prog_cnt] = fd; efd = attach_tracepoint(abpf->tp_category, abpf->tp_name); if (efd <= 0) { printf("[debug] attach_tracepoint error.\n"); return efd; } event_fd[prog_cnt] = efd; ioctl(efd, PERF_EVENT_IOC_ENABLE, 0); ioctl(efd, PERF_EVENT_IOC_SET_BPF, fd); printf("[debug] load bpf prog success.\n"); mfd = load_map(abpf->map_path); if (mfd <= 0) { printf("[debug] load_map error.\n"); return mfd; } map_fd[prog_cnt++] = mfd; return 0;}void read_trace_pipe(int times){ int trace_fd; trace_fd = open(DEBUGFS "trace_pipe", O_RDONLY, 0); if (trace_fd < 0) return; // times = 0, loop 0xffffffff do { static char buf[4096]; ssize_t sz; sz = read(trace_fd, buf, sizeof(buf) - 1); if (sz > 0) { buf[sz] = 0; puts(buf); } } while (--times);}
接着,我就能使用C代碼來寫loader了:
#include "bpf_load.h"#include <stdio.h>#include <string.h>int main(int argc, char **argv) { struct androidBPF abpf = {0, }; if (argc < 3) return 0; abpf.prog_path = argv[1]; abpf.map_path = argv[2]; abpf.tp_category = "raw_syscalls"; abpf.tp_name = "sys_enter"; if (load_bpf_from_fs(&abpf) != 0) { // 用於加載 ELF 格式的 BPF 程序 printf("The kernel didn't load the BPF program\n"); return -1; } int key, ret; key = 1; struct event_execv value; for (int i = 0; i < 10; i ++) { memset(&value, 0, sizeof(value)); ret = get_map_by_int_key(&key, &value); printf("[debug] ret = %d, pid = %d, gid = %d, comm = %s\n", ret, value.pid, value.gid, value.cmd); } // for (int i=0; i < 88; i++) // { // printf("debug value[%d] = 0x%x\n", i, *((char *)&value+i)); // } read_trace_pipe(1); return 0;}
在本地的arm64機器上就能編譯了:
$ ls -alFtotal 916drwxr-xr-x 1 hehe hehe 320 Oct 31 11:54 ./drwxr-xr-x 1 hehe hehe 416 Oct 30 22:34 ../-rw-rw-r-- 1 hehe hehe 4025 Oct 30 22:37 bpf_helpers.h-rw-rw-r-- 1 hehe hehe 10940 Oct 31 11:35 bpf_load.c-rw-rw-r-- 1 hehe hehe 1112 Oct 31 11:35 bpf_load.h-rw-rw-r-- 1 hehe hehe 3432 Oct 30 22:49 libbpf.c-rw-rw-r-- 1 hehe hehe 5294 Oct 30 22:50 libbpf.h-rw-r--r-- 1 hehe hehe 117176 Oct 30 22:54 libelf.so-rwxrwxr-x 1 hehe hehe 773016 Oct 31 11:54 loader*-rw-rw-r-- 1 hehe hehe 868 Oct 31 11:54 loader.c$ clang loader.c bpf_load.c libbpf.c -lelf -lz -o loader -static 參考
https://elixir.bootlin.com/linux/v4.14.2/source/samples/bpf/bpf_load.c
作者名片
END


