diff --git a/observer_agent/CMakeLists.txt b/observer_agent/CMakeLists.txt index 60be81bbba1178574b10bd7ceff2300d82e9c160..9d752c3931f5b3d4ff935f871d0f32577af3511c 100644 --- a/observer_agent/CMakeLists.txt +++ b/observer_agent/CMakeLists.txt @@ -9,5 +9,10 @@ add_custom_target(grpc_demo ALL add_executable(secDetectord grpc_comm/client.cpp grpc_comm/server.cpp service/main.cpp service/ringbuffer.cpp) target_include_directories(secDetectord PUBLIC service grpc_comm) +target_link_directories(secDetectord PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/ebpf) + +target_link_libraries(secDetectord ${CMAKE_CURRENT_BINARY_DIR}/ebpf/.output/fentry.o) target_link_libraries(secDetectord ${GRPC_PATH}/comm_api.pb.o ${GRPC_PATH}/comm_api.grpc.pb.o) target_link_libraries(secDetectord protobuf grpc++ grpc absl_synchronization) +target_link_libraries(secDetectord z elf bpf) + diff --git a/observer_agent/ebpf/CMakeLists.txt b/observer_agent/ebpf/CMakeLists.txt index dab70e56514122b5fadabefcbcc044b98ae34e2c..4ac77130de66cbbb5821d840447506a0df925a0d 100644 --- a/observer_agent/ebpf/CMakeLists.txt +++ b/observer_agent/ebpf/CMakeLists.txt @@ -5,10 +5,10 @@ project(ebpf) add_custom_target(ebpf ALL COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/.output COMMAND bpftool btf dump file /sys/kernel/btf/vmlinux format c > ${CMAKE_CURRENT_BINARY_DIR}/.output/vmlinux.h - COMMAND clang -g -O2 -target bpf -D__TARGET_ARCH_x86 -c ${CMAKE_CURRENT_SOURCE_DIR}/fentry.bpf.c -o ${CMAKE_CURRENT_BINARY_DIR}/.output/fentry.bpf.o + COMMAND clang -g -O2 -target bpf -D__TARGET_ARCH_x86 -I${CMAKE_CURRENT_BINARY_DIR}/.output -c ${CMAKE_CURRENT_SOURCE_DIR}/fentry.bpf.c -o ${CMAKE_CURRENT_BINARY_DIR}/.output/fentry.bpf.o COMMAND bpftool gen skeleton ${CMAKE_CURRENT_BINARY_DIR}/.output/fentry.bpf.o > ${CMAKE_CURRENT_BINARY_DIR}/.output/fentry.skel.h - COMMAND cc -g -Wall -I${CMAKE_CURRENT_BINARY_DIR}/.output -I${CMAKE_CURRENT_SOURCE_DIR} -c ${CMAKE_CURRENT_SOURCE_DIR}/fentry.c -o ${CMAKE_CURRENT_BINARY_DIR}/.output/fentry.o - COMMAND cc -g -Wall ${CMAKE_CURRENT_BINARY_DIR}/.output/fentry.o /usr/lib64/libbpf.a -lelf -lz -o fentry + COMMAND cc -g -Wall -fPIC -I${CMAKE_CURRENT_BINARY_DIR}/.output -I${CMAKE_CURRENT_SOURCE_DIR} -c ${CMAKE_CURRENT_SOURCE_DIR}/fentry.c -o ${CMAKE_CURRENT_BINARY_DIR}/.output/fentry.o ) - +add_executable(test_fentry ${CMAKE_CURRENT_SOURCE_DIR}/test_fentry.c) +target_link_libraries(test_fentry ${CMAKE_CURRENT_BINARY_DIR}/.output/fentry.o z elf bpf) diff --git a/observer_agent/ebpf/fentry.bpf.c b/observer_agent/ebpf/fentry.bpf.c index d99988171025d64dcaaf409a3a9716d849229cc3..11742fd12819f8d96e7c3d5cdc6779bebbb1d313 100644 --- a/observer_agent/ebpf/fentry.bpf.c +++ b/observer_agent/ebpf/fentry.bpf.c @@ -1,40 +1,132 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* Copyright (c) 2021 Sartura */ #include "vmlinux.h" +#include "fentry.h" #include #include +#include char LICENSE[] SEC("license") = "Dual BSD/GPL"; -SEC("lsm/task_free") -int BPF_PROG(do_bprm_check, struct task_struct *task) +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 1024 * 1024); +} rb SEC(".maps"); + +static inline u32 get_task_sid(struct task_struct *task) { - char buf[16]; - __u32 pid = bpf_get_current_pid_tgid() >> 32; - bpf_get_current_comm(buf, sizeof(buf)); - bpf_printk("bprm_check: pid = %d, comm = %d", pid, buf); + struct pid *pid; + u32 sid = 0; - return 0; + pid = BPF_CORE_READ(task, signal, pids[PIDTYPE_SID]); + if (!pid) + return 0; + sid = BPF_CORE_READ(pid, numbers[0].nr); + return sid; +} + +static struct task_struct *find_init_task() +{ + int i = 0; + struct task_struct *task; + struct task_struct *init_task = NULL; + task = (struct task_struct *)bpf_get_current_task(); + + for (i = 0; i < 64; i++) { + task = BPF_CORE_READ(task, real_parent); + if (!task || init_task == task) { + break; + } + + init_task = task; + } + return task; } -SEC("fentry/do_unlinkat") -int BPF_PROG(do_unlinkat, int dfd, struct filename *name) +static struct pid_namespace *pid_ns(struct task_struct *task) { - pid_t pid; + struct pid *pid = NULL; + u32 level = 0; + pid = BPF_CORE_READ(task, thread_pid); + if (!pid) + return NULL; + + return BPF_CORE_READ(pid, numbers[0].ns); +} + +static void get_common_info(struct ebpf_event *e) +{ + struct task_struct *parent = NULL; + struct task_struct *task = NULL; + + + e->timestamp = bpf_ktime_get_ns(); + e->pid = bpf_get_current_pid_tgid(); + e->pgid = e->tgid = bpf_get_current_pid_tgid() >> 32; + e->uid = bpf_get_current_uid_gid(); + e->gid = bpf_get_current_uid_gid() >> 32; + bpf_get_current_comm(&e->comm, sizeof(e->comm)); + /* + * exe path is diffcult to get in ebpf, we can get it from userspace + */ + bpf_get_current_comm(&e->exe, sizeof(e->exe)); - pid = bpf_get_current_pid_tgid() >> 32; - bpf_printk("fentry: pid = %d, filename = %s\n", pid, name->name); + task = (struct task_struct *)bpf_get_current_task(); + parent = (struct task_struct *)BPF_CORE_READ(task, real_parent); + + e->ppid = BPF_CORE_READ(parent, pid); + e->sid = get_task_sid(task); + e->pns = BPF_CORE_READ(pid_ns(task), ns.inum); + e->root_pns = BPF_CORE_READ(pid_ns(find_init_task()), ns.inum); + BPF_CORE_READ_INTO(&e->pcomm, parent, real_parent, comm); + BPF_CORE_READ_INTO(&e->nodename, task, nsproxy, uts_ns, name.nodename); +} + +SEC("tp/sched/sched_process_exec") +int handle_exec(struct trace_event_raw_sched_process_exec *ctx) +{ + struct ebpf_event *e = NULL; + + e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); + if (!e) + return 0; + + get_common_info(e); + strcpy(e->event_name, "sched_process_exec"); + + bpf_ringbuf_submit(e, 0); return 0; } -SEC("fexit/do_unlinkat") -int BPF_PROG(do_unlinkat_exit, int dfd, struct filename *name, long ret) +SEC("tp/sched/sched_process_exit") +int handle_exit(struct trace_event_raw_sched_process_exit *ctx) { - pid_t pid; + struct ebpf_event *e = NULL; + u32 exit_code = 0; + + e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); + if (!e) + return 0; - pid = bpf_get_current_pid_tgid() >> 32; - bpf_printk("fexit: pid = %d, filename = %s, ret = %ld\n", pid, name->name, ret); + get_common_info(e); + strcpy(e->event_name, "sched_process_exit"); + exit_code = BPF_CORE_READ((struct task_struct *)bpf_get_current_task(), exit_code); + e->process_info.exit_code = (exit_code >> 8) & 0xff; + bpf_ringbuf_submit(e, 0); return 0; } +SEC("tp/sched/sched_process_fork") +int handle_fork(struct trace_event_raw_sched_process_fork *ctx) +{ + struct ebpf_event *e = NULL; + + e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); + if (!e) + return 0; + get_common_info(e); + strcpy(e->event_name, "sched_process_fork"); + bpf_ringbuf_submit(e, 0); + return 0; +} diff --git a/observer_agent/ebpf/fentry.c b/observer_agent/ebpf/fentry.c index 9daa67f4feae49ac19e2b55c3b9a6818b7765691..2f6120c587777f5fa2a8b7dd38b35d7d3b621bc2 100644 --- a/observer_agent/ebpf/fentry.c +++ b/observer_agent/ebpf/fentry.c @@ -8,8 +8,10 @@ #include #include #include +#include #include #include "fentry.skel.h" +#include "fentry.h" static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) { @@ -18,14 +20,26 @@ static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va static volatile sig_atomic_t stop; -void sig_int(int signo) +static int handle_event(void *ctx, void *data, size_t data_sz) +{ + const struct ebpf_event *e = data; + printf("timestamp:%llu event_name:%s exe:%s pid:%u tgid:%u uid:%u gid:%u comm:%s" + " sid:%u ppid:%u pgid:%u pcomm:%s nodename:%s pns:%u root_pns:%u", + e->timestamp, e->event_name, e->exe, e->pid, e->tgid, e->uid, e->gid, e->comm, + e->sid, e->ppid, e->pgid, e->pcomm, e->nodename, e->pns, e->root_pns); + printf(" exit_code: %u\n", e->process_info.exit_code); + return 0; +} + +void stop_ebpf_prog() { stop = 1; } -int main(int argc, char **argv) +int start_and_poll_ebpf_prog() { struct fentry_bpf *skel; + struct ring_buffer *rb = NULL; int err; /* Set up libbpf errors and debug info callback */ @@ -45,20 +59,27 @@ int main(int argc, char **argv) goto cleanup; } - if (signal(SIGINT, sig_int) == SIG_ERR) { - fprintf(stderr, "can't set signal handler: %s\n", strerror(errno)); + rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event, NULL, NULL); + if (!rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer\n"); 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); + err = ring_buffer__poll(rb, -1); + if (err == -EINTR) { + err = 0; + break; + } + if (err < 0) { + fprintf(stderr, "poll failed, r:%d\n", err); + break; + } } cleanup: + ring_buffer__free(rb); fentry_bpf__destroy(skel); return -err; } diff --git a/observer_agent/ebpf/fentry.h b/observer_agent/ebpf/fentry.h new file mode 100644 index 0000000000000000000000000000000000000000..0a7027c9b1d51ffbb485c2e5f86975723187db16 --- /dev/null +++ b/observer_agent/ebpf/fentry.h @@ -0,0 +1,42 @@ +#ifndef __SECDETECTOR_EBPF_H +#define __SECDETECTOR_EBPF_H +// #include "secDetector_type.h" + +#define TASK_COMM_SIZE 16 +#define EVENT_NAME_SIZE 32 +#define MAX_FILENAME_SIZE 256 +#define MAX_TEXT_SIZE 4096 + +struct process_info { + unsigned exit_code; +}; + +struct file_info { + char filename[MAX_TEXT_SIZE]; +}; + +struct ebpf_event { + int type; + char event_name[EVENT_NAME_SIZE]; + // common info + unsigned long long timestamp; + unsigned uid; + unsigned gid; + char exe[MAX_FILENAME_SIZE]; + unsigned pid; + char comm[TASK_COMM_SIZE]; + unsigned tgid; + unsigned pgid; + unsigned ppid; + char pcomm[TASK_COMM_SIZE]; + unsigned sid; + char nodename[MAX_FILENAME_SIZE]; + unsigned pns; + unsigned root_pns; + union { + struct process_info process_info; + struct file_info info; + }; +}; + +#endif /* __SECDETECTOR_EBPF_H */ diff --git a/observer_agent/ebpf/test_fentry.c b/observer_agent/ebpf/test_fentry.c new file mode 100644 index 0000000000000000000000000000000000000000..56fe5ccc957748a481d50f2e830f3d10b055a9cc --- /dev/null +++ b/observer_agent/ebpf/test_fentry.c @@ -0,0 +1,8 @@ +#include + +int start_and_poll_ebpf_prog(); + +int main() +{ + start_and_poll_ebpf_prog(); +}