diff --git a/execsnoop-bcc/readme.md b/execsnoop-bcc/readme.md new file mode 100644 index 0000000..09c4cb7 --- /dev/null +++ b/execsnoop-bcc/readme.md @@ -0,0 +1,3 @@ +- depend [bcc](https://github.com/iovisor/bcc) + +- huge memory usage, at least 50M \ No newline at end of file diff --git a/execsnoop-kernel/execsnoop b/execsnoop-kernel/execsnoop new file mode 100755 index 0000000..3a6eb36 Binary files /dev/null and b/execsnoop-kernel/execsnoop differ diff --git a/execsnoop-kernel/execsnoop_kern.c b/execsnoop-kernel/execsnoop_kern.c new file mode 100644 index 0000000..b03fa07 --- /dev/null +++ b/execsnoop-kernel/execsnoop_kern.c @@ -0,0 +1,93 @@ +#include "linux/sched.h" +#include +#include +#include +#include +#include + +#define TASK_COMM_LEN 16 +struct event { + char comm[TASK_COMM_LEN]; + pid_t pid; + pid_t tgid; + pid_t ppid; + uid_t uid; +}; + +/* /sys/kernel/debug/tracing/events/syscalls/sys_enter_execve/format */ +struct syscalls_enter_execve_args { + __u64 unused; + int syscall_nr; + const char filename_ptr; + const char *const * argv; + const char *const * envp; +}; + +/* /sys/kernel/debug/tracing/events/syscalls/sys_exit_execve/format */ +struct syscalls_exit_execve_args { + __u64 unused; + int syscall_nr; + long ret; +}; + +struct bpf_map_def SEC("maps") records = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(pid_t), + .value_size = sizeof(struct event), + .max_entries = 1024, +}; +struct bpf_map_def SEC("maps") perf_events = { + .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, + .key_size = sizeof(u32), + .value_size = sizeof(u32), + .max_entries = 128, +}; + +SEC("tracepoint/syscalls/sys_enter_execve") +int syscall_enter_execve(struct syscalls_enter_execve_args *ctx){ + pid_t pid, tgid; uid_t uid; + struct event *event; + struct task_struct *task, *task_p; + + u64 id = bpf_get_current_pid_tgid(); + pid = (pid_t)id; + tgid = id >> 32; + uid = (__u32)bpf_get_current_uid_gid(); + + struct event empty_event={}; + if (bpf_map_update_elem(&records, &pid, &empty_event, BPF_NOEXIST)!=0) return 0; + event = bpf_map_lookup_elem(&records, &pid); + if (!event) return 0; + + event->pid = pid; + event->tgid = tgid; + event->uid = uid; + + /* ppid is not reliable here, normal in arch, but become 0 in ubuntu 20.04 */ + task = (struct task_struct*)bpf_get_current_task(); + bpf_probe_read(&task_p, sizeof(struct task_struct*),&task->real_parent); + bpf_probe_read(&event->ppid,sizeof(pid_t),&task_p->tgid); + + return 0; +} + +SEC("tracepoint/syscalls/sys_exit_execve") +int syscall_exit_execve(struct syscalls_exit_execve_args *ctx){ + pid_t pid; + struct event *event; + + pid = (pid_t)bpf_get_current_pid_tgid(); + event = bpf_map_lookup_elem(&records,&pid); + if (!event) return 0; + if (ctx->ret < 0) goto cleanup; + + /* get comm */ + bpf_get_current_comm(&event->comm,sizeof(event->comm)); + bpf_perf_event_output(ctx, &perf_events, BPF_F_CURRENT_CPU, event, sizeof(struct event)); +cleanup: + bpf_map_delete_elem(&records, &pid); + return 0; +} + +char _license[] SEC("license") = "GPL"; +u32 _version SEC("version") = LINUX_VERSION_CODE; diff --git a/execsnoop-kernel/execsnoop_kern.o b/execsnoop-kernel/execsnoop_kern.o new file mode 100644 index 0000000..d9d1828 Binary files /dev/null and b/execsnoop-kernel/execsnoop_kern.o differ diff --git a/execsnoop-kernel/execsnoop_user.c b/execsnoop-kernel/execsnoop_user.c new file mode 100644 index 0000000..2b6f7c6 --- /dev/null +++ b/execsnoop-kernel/execsnoop_user.c @@ -0,0 +1,40 @@ + +#include +#include +#include "bpf_load.h" + +#define TASK_COMM_LEN 16 +struct event { + char comm[TASK_COMM_LEN]; + pid_t pid; + pid_t tgid; + pid_t ppid; + uid_t uid; +}; +static void print_bpf_output(void *ctx, int cpu, void *data, __u32 size) { + struct event *e=data; + printf("comm: %s, pid: %d, tgid: %d, ppid: %d, uid: %d\n",e->comm,e->pid,e->tgid,e->ppid,e->uid); +} + +int main(int argc, char **argv) { + struct perf_buffer_opts pb_opts = {}; + struct perf_buffer *pb; + int ret; + + if (load_bpf_file("execsnoop_kern.o")!=0) { + printf("%s", bpf_log_buf); + return 1; + } + + pb_opts.sample_cb = print_bpf_output; + pb = perf_buffer__new(map_fd[1], 8, &pb_opts); + ret = libbpf_get_error(pb); + if (ret) { + printf("failed to setup perf_buffer: %d\n", ret); + return 1; + } + + while ((ret = perf_buffer__poll(pb, -1)) >= 0) {} + kill(0, SIGINT); + return ret; +} diff --git a/execsnoop-kernel/readme.md b/execsnoop-kernel/readme.md new file mode 100644 index 0000000..531c7d7 --- /dev/null +++ b/execsnoop-kernel/readme.md @@ -0,0 +1,101 @@ + +## Prons and cons + +- use stable execve tracepoint, so build once and should work everywhere +- need to build in kernel tree + +## Build in kernel tree + +- ready and config kernel tree + +```bash +# kernel config +gunzip -c /proc/config.gz > .config +make oldconfig && make prepare +# install headers to ./usr/include +make headers_install -j8 +# build bpf +make M=samples/bpf -j8 +``` + +- put or link `execsnoop_kern.c` and `execsnoop_user.c` to *samples/bpf/* +- edit *samples/bpf/makefile* + +```makefile +# in samples/bpf/makefile +tprogs-y += execsnoop +execsnoop-objs := bpf_load.o execsnoop_user.o $(TRACE_HELPERS) +always-y += execsnoop_kern.o +``` + +## Run + +```bash +cd samples/bpf +sudo bash -c "ulimit -l unlimited && ./execsnoop" +``` + +## Detail build command + +using `make V=1 M=samples/bpf | tee -a log.txt` to get and filter following command + +- build `execsnoop_kern.o` + +```bash +clang -nostdinc \ + -isystem /usr/lib/gcc/x86_64-pc-linux-gnu/10.1.0/include \ + -I./arch/x86/include \ + -I./arch/x86/include/generated \ + -I./include \ + -I./arch/x86/include/uapi \ + -I./arch/x86/include/generated/uapi \ + -I./include/uapi \ + -I./include/generated/uapi \ + -include ./include/linux/kconfig.h \ + -I./samples/bpf \ + -I./tools/testing/selftests/bpf/ \ + -I./tools/lib/ \ + -include asm_goto_workaround.h \ + -D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \ + -D__TARGET_ARCH_x86 -Wno-compare-distinct-pointer-types \ + -Wno-gnu-variable-sized-type-not-at-end \ + -Wno-address-of-packed-member -Wno-tautological-compare \ + -Wno-unknown-warning-option \ + -fno-stack-protector -g \ + -O2 -emit-llvm -c samples/bpf/execsnoop_kern.c \ + -o - | llc -march=bpf -filetype=obj -o samples/bpf/execsnoop_kern.o +``` + +- build `execsnoop_user.o` + +```bash + gcc -Wall -O2 -Wmissing-prototypes -Wstrict-prototypes \ + -I./usr/include \ + -I./tools/testing/selftests/bpf/ \ + -I./tools/lib/ \ + -I./tools/include \ + -I./tools/perf \ + -DHAVE_ATTR_TEST=0 \ + -c -o samples/bpf/execsnoop_user.o samples/bpf/execsnoop_user.c +``` + +- build `execsnoop` + +```bash + gcc -Wall -O2 -Wmissing-prototypes -Wstrict-prototypes \ + -I./usr/include \ + -I./tools/testing/selftests/bpf/ \ + -I./tools/lib/ \ + -I./tools/include \ + -I./tools/perf \ + -DHAVE_ATTR_TEST=0 \ + -o samples/bpf/execsnoop \ + samples/bpf/bpf_load.o samples/bpf/execsnoop_user.o \ + tools/testing/selftests/bpf/trace_helpers.o tools/lib/bpf/libbpf.a \ + -lelf -lz +``` + +## Some resources + +- [A thorough introduction to eBPF](https://lwn.net/Articles/740157/) +- [Write eBPF program in pure C](http://terenceli.github.io/%E6%8A%80%E6%9C%AF/2020/01/18/ebpf-in-c) diff --git a/execsnoop-libbpf/readme.md b/execsnoop-libbpf/readme.md index bbd3dce..e22f1f2 100644 --- a/execsnoop-libbpf/readme.md +++ b/execsnoop-libbpf/readme.md @@ -1,11 +1,21 @@ -## Depency -- libbpf - - /usr/lib/libbpf.a - - some head file -- bpf - - `/usr/bin/bpftool` to generate skeleton and dump btf +## Resource -## Refer +- [libbpf](https://github.com/libbpf/libbpf) +- [libbpf-tools](https://github.com/iovisor/bcc/tree/master/libbpf-tools) examples use libbpf +- [bpftool](https://www.archlinux.org/packages/community/x86_64/bpf/) to generate skeleton and dump btf -- https://facebookmicrosites.github.io/bpf/blog/2020/02/19/bpf-portability-and-co-re.html \ No newline at end of file +## Prons + +- BPF CO-RE (Compile Once – Run Everywhere) +- small memory usage + +## Cons + +- `vmlinux.h`does not contain `#define` etc. And often causes confilct with other headers to cause redifinition error +- comment in code for different types is gone +- need kernel built with `CONFIG_DEBUG_INFO_BTF=y`, while ubuntu 20.04 still not + +## Build + +- see *makefile* \ No newline at end of file