From 36e17d38ddc3211e5f03a2137a0f44daf6c9ca37 Mon Sep 17 00:00:00 2001 From: Luis Gerhorst <privat@luisgerhorst.de> Date: Fri, 2 Jul 2021 16:03:36 +0200 Subject: [PATCH] task_find: iterdents64, openat PoC --- libbpf | 2 +- src/Makefile | 2 +- src/task_find.bpf.c | 98 ++++++++++++++++++--------- src/task_find.c | 157 +++++++++++++++++++++++++++++++++++++++++++- src/task_find.h | 11 +++- 5 files changed, 234 insertions(+), 36 deletions(-) diff --git a/libbpf b/libbpf index e81b0f3..a258324 160000 --- a/libbpf +++ b/libbpf @@ -1 +1 @@ -Subproject commit e81b0f300b46c53a4a45763d77fa2c01cdbeca94 +Subproject commit a2583241a0cfe897a924acf7c666846f1ec3bda5 diff --git a/src/Makefile b/src/Makefile index 70f6e4b..f46ca8a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,7 +9,7 @@ INCLUDES := -I$(OUTPUT) -idirafter $(abspath ../libbpf/include) CFLAGS := -g -Wall ARCH := $(shell uname -m | sed 's/x86_64/x86/') -APPS = minimal bootstrap uprobe task task_bulk task_mmap task_sleep task_bulk_minimal task_ag task_find task_filter_magic +APPS = minimal bootstrap uprobe task_mmap task_bulk_minimal task_find task_filter_magic # task_ag task_sleep task task_bulk # Get Clang's default includes on this system. We'll explicitly add these dirs # to the includes list when compiling with `-target bpf` because otherwise some diff --git a/src/task_find.bpf.c b/src/task_find.bpf.c index 24b4817..190a303 100644 --- a/src/task_find.bpf.c +++ b/src/task_find.bpf.c @@ -8,55 +8,89 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; -#define PATHLEN UBUF_SIZE -char start_path[PATHLEN]; -uintptr_t ubuf_addr; +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, int); + __type(value, int); +} pdpf_map SEC(".maps"); + +uintptr_t root_path_user; SEC("task") -int handle_tp(void *ctx) +int entry(void *ctx) { int err = 0; - bpf_printk("ctx = %llx", ctx); - - char *ubuf; - ubuf = bpf_task_map(UBUF_SIZE, ubuf_addr); - if (ubuf == NULL) { - bpf_printk("Error: ubuf is NULL"); - return -1; + char root_path[256]; + err = bpf_probe_read_user(root_path, 256, root_path_user); + if (err) { + bpf_printk("Error: read_user = %d", err); + goto end; } - bpf_printk("ubuf = %llx:%llx, start_path = %s", ubuf, ubuf + UBUF_SIZE, start_path); - - strncpy(ubuf, start_path, PATHLEN); - bpf_printk("ubuf = %s", ubuf); + bpf_printk("root_path = %s", root_path); - int dfd = bpf_task_sys_open_3((uint64_t) ubuf_addr, O_RDONLY | O_DIRECTORY, 0777); + int dfd = bpf_task_sys_open_3(root_path_user, O_RDONLY | O_DIRECTORY, 0777); if (dfd < 0) { err = dfd; bpf_printk("Error: sys_open = %d", dfd); - goto unmap; + goto end; + } + + int *prog_fd = bpf_map_lookup_elem(&pdpf_map, &PDPF_KEY); + if (!prog_fd) { + bpf_printk("Error: !bpf_map_lookup_elem(&pdpf_map, &PDPF_KEY)"); + goto close; + } + + err = bpf_task_iterdents64(dfd, *prog_fd); + if (err) { + bpf_printk("iterdents64(%d, %d) = %d", dfd, *prog_fd, err); + goto close; + } + +close: + err = bpf_task_sys_close_1(dfd); + if (err) { + bpf_printk("close_err = %d", err); + goto end; } +end: + return err; +} - long nread = bpf_task_sys_getdents64_3(dfd, (uint64_t) ubuf_addr, UBUF_SIZE); - size_t recpos = 0; +SEC("iterdents64") +int process_dirent(struct bpf_dirent64 *d) { + int err = 0; -#pragma clang loop unroll(full) - for (size_t bpos = 0; bpos < UBUF_SIZE - sizeof(struct linux_dirent64); bpos++) { - if (bpos < nread && bpos == recpos) { - /* TODO: Fix verifier error. */ - struct linux_dirent64 *d = (struct linux_dirent64 *) (ubuf + bpos); + if (d->namelen <= 2) { + goto end; + } - bpf_printk("d->d_name = %s, reclen = %d.", d->d_name, (int) d->d_reclen); + int dfd = bpf_task_openat(d, O_RDONLY | O_DIRECTORY, 0777); + if (dfd < 0) { + goto end; + } + + bpf_printk("iterating %d/%s", d->dfd, d->name); + + int *prog_fd = bpf_map_lookup_elem(&pdpf_map, &PDPF_KEY); + if (!prog_fd) { + bpf_printk("Error: !bpf_map_lookup_elem(&pdpf_map, &PDPF_KEY)"); + goto close; + } - recpos += d->d_reclen; - } + err = bpf_task_iterdents64(dfd, *prog_fd); + if (err) { + bpf_printk("iterdents64(%d, %d) = %d", dfd, *prog_fd, err); + goto close; } - int close_err = bpf_task_sys_close_1(dfd); - if (close_err) { - bpf_printk("close_err = %d", close_err); +close: + err = bpf_task_sys_close_1(dfd); + if (err) { + bpf_printk("close_err = %d", err); } -unmap: - bpf_task_unmap(ubuf, UBUF_SIZE); +end: return err; } diff --git a/src/task_find.c b/src/task_find.c index 11e2d60..93e3654 100644 --- a/src/task_find.c +++ b/src/task_find.c @@ -2,7 +2,9 @@ /* Copyright (c) 2020 Facebook */ #include <stdio.h> #include <unistd.h> +#include <errno.h> #include <assert.h> +#include <pthread.h> /* man open(2) */ #include <sys/types.h> @@ -50,10 +52,152 @@ static void bump_memlock_rlimit(void) } } +static pthread_mutex_t print_mtx = PTHREAD_MUTEX_INITIALIZER; +enum log_level { + LOG_LEVEL_DEBUG = 10, + LOG_LEVEL_MSG = 20, + LOG_LEVEL_WARN = 30, + LOG_LEVEL_ERR = 40, + LOG_LEVEL_NONE = 100 +}; +static enum log_level log_threshold = LOG_LEVEL_ERR; + +static void set_log_level(enum log_level threshold) { + log_threshold = threshold; +} + +static void vplog(const unsigned int level, const char *fmt, va_list args) { + if (level < log_threshold) { + return; + } + + pthread_mutex_lock(&print_mtx); + FILE *stream = stderr; + + switch (level) { + case LOG_LEVEL_DEBUG: + fprintf(stream, "DEBUG: "); + break; + case LOG_LEVEL_MSG: + fprintf(stream, "MSG: "); + break; + case LOG_LEVEL_WARN: + fprintf(stream, "WARN: "); + break; + case LOG_LEVEL_ERR: + stream = stderr; + fprintf(stream, "ERR: "); + break; + } + + vfprintf(stream, fmt, args); + fprintf(stream, "\n"); + pthread_mutex_unlock(&print_mtx); +} + +static void log_debug(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vplog(LOG_LEVEL_DEBUG, fmt, args); + va_end(args); +} + +static void log_msg(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vplog(LOG_LEVEL_MSG, fmt, args); + va_end(args); +} + +static void log_warn(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vplog(LOG_LEVEL_WARN, fmt, args); + va_end(args); +} + +static void log_err(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vplog(LOG_LEVEL_ERR, fmt, args); + va_end(args); +} + +static void plog(const unsigned int level, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vplog(level, fmt, args); + va_end(args); +} + +#define NAME task_find +#define NAME_BPF task_find_bpf +#define BPF_OPEN task_find_bpf__open +#define BPF_LOAD task_find_bpf__load +#define BPF_DESTROY task_find_bpf__destroy + +/* https://stackoverflow.com/questions/5873722/c-macro-dynamic-include */ +#define __header(x) #x +#define _name_skel_h(x) __header(x.skel.h) +#define name_skel_h(x) _name_skel_h(x) +#define _name_h(x) __header(x.h) +#define name_h(x) _name_h(x) + +#include name_skel_h(NAME) +#include name_h(NAME) + static void print_usage(char **argv) { fprintf(stderr, "Usage: %s [-D --debug] [-v --variant bpf] PATH -name LITERAL\n", argv[0]); } +static int bpf_find_by_name(const char *path, const char *name, bool debug) { + struct NAME_BPF *skel; + int err = 0, ret = EXIT_SUCCESS; + + /* Set up libbpf errors and debug info callback */ + libbpf_set_print(libbpf_print_fn); + + /* Bump RLIMIT_MEMLOCK to allow BPF sub-system to do anything */ + bump_memlock_rlimit(); + + /* Open BPF application */ + skel = BPF_OPEN(); + if (!skel) { + fprintf(stderr, "Failed to open BPF skeleton\n"); + return EXIT_FAILURE; + } + + skel->bss->root_path_user = path; + + /* Load & verify BPF programs */ + err = BPF_LOAD(skel); + if (err) { + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); + ret = EXIT_FAILURE; + goto destroy; + } + + /* BPF_NOEXIST means: add new element if it doesn't exist */ + int value = bpf_program__fd(skel->progs.process_dirent); + err = bpf_map_update_elem(bpf_map__fd(skel->maps.pdpf_map), &PDPF_KEY, &value, BPF_ANY); + if (err == -1) { + perror("bpf_map_update_elem(bpf_map__fd(skel->maps.pdpf_map), &PDPF_KEY, &value, BPF_NOEXIST)"); + goto destroy; + } + + int prog_fd = bpf_program__fd(skel->progs.entry); + err = syscall(SYS_bpftask, prog_fd, NULL); + if (err) { + log_err("sys_bpftaks = %d", err); + ret = EXIT_FAILURE; + goto destroy; + } + +destroy: + BPF_DESTROY(skel); + return ret; +} + int main(int argc, char **argv) { bool debug = false; @@ -121,12 +265,23 @@ int main(int argc, char **argv) } if (debug) { + set_log_level(LOG_LEVEL_DEBUG); + for (size_t i = 0; i < argc; i++) { - fprintf(stderr, "%llu: %s, ", i, argv[i]); + fprintf(stderr, "%lu: %s, ", i, argv[i]); } fprintf(stderr, "\n"); fprintf(stderr, "%s: variant_bpf=%d, debug=%d, name='%s', path='%s'\n", argv[0], variant_bpf, debug, name, path); } + + if (variant_bpf) { + return bpf_find_by_name(path, name, debug); + } else { + fprintf(stderr, "Only bpf variant supported.\n"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; } diff --git a/src/task_find.h b/src/task_find.h index 3fe592a..dd9954f 100644 --- a/src/task_find.h +++ b/src/task_find.h @@ -1,6 +1,15 @@ #ifndef __TASK_H_ #define __TASK_H_ -#define UBUF_SIZE 512 +#define MAX_DEPTH 16 +#define UBUF_SIZE 1024 +#define PATHLEN 256 + +#define __packed __attribute__((__packed__)) + +struct __packed __attribute__((__aligned__(4096))) bpfmem { +}; + +static int PDPF_KEY = 0; #endif // __TASK_H_ -- GitLab