From ddcd7d1921ab2e6ad16e81fbcb97dbab0128aeed Mon Sep 17 00:00:00 2001 From: Luis Gerhorst <privat@luisgerhorst.de> Date: Tue, 23 Mar 2021 14:50:15 +0100 Subject: [PATCH] Send mmap to userspace --- libbpf | 2 +- src/Makefile | 2 +- src/libc.bpf.h | 7 +++ src/task.bpf.c | 13 +++-- src/task.c | 2 + src/task_mmap.bpf.c | 43 +++++++++++++++++ src/task_mmap.c | 114 ++++++++++++++++++++++++++++++++++++++++++++ src/task_mmap.h | 10 ++++ 8 files changed, 186 insertions(+), 7 deletions(-) create mode 100644 src/task_mmap.bpf.c create mode 100644 src/task_mmap.c create mode 100644 src/task_mmap.h diff --git a/libbpf b/libbpf index 7d47201..bd56208 160000 --- a/libbpf +++ b/libbpf @@ -1 +1 @@ -Subproject commit 7d472018596917df2824a8942edaec86d03fa277 +Subproject commit bd56208c08425849e496ba06170551a8ba8241ed diff --git a/src/Makefile b/src/Makefile index 14be821..1eb4cf4 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 +APPS = minimal bootstrap uprobe task task_bulk task_mmap # 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/libc.bpf.h b/src/libc.bpf.h index 90c6d10..1d907f4 100644 --- a/src/libc.bpf.h +++ b/src/libc.bpf.h @@ -7,6 +7,7 @@ #include <bits/mman-linux.h> #undef _SYS_MMAN_H #include <asm-generic/fcntl.h> +#include <asm-generic/mman.h> /* MAP_POPULATE */ #define NULL ((void *) 0) @@ -16,6 +17,7 @@ typedef __u64 uintptr_t; typedef uintptr_t size_t; typedef __u64 ino64_t; typedef __u64 off64_t; +typedef off64_t off_t; /* Copied from man getdents64(2). */ struct linux_dirent64 { @@ -36,4 +38,9 @@ static char *strncpy(char *dest, const char *src, size_t n) { return dest; } +static void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { + uint64_t arg_tail[3] = {flags, fd, offset}; + return bpf_task_sys_mmap_6((uint64_t) addr, length, prot, arg_tail, sizeof(arg_tail)); +} + #endif // __TASK_LIBC_BPF_H_ diff --git a/src/task.bpf.c b/src/task.bpf.c index 9ed39ed..91615b1 100644 --- a/src/task.bpf.c +++ b/src/task.bpf.c @@ -16,22 +16,25 @@ int handle_tp(long **ctx) { int err = 0; - bpf_printk("ctx = %p", ctx); + bpf_printk("ctx = %llx", ctx); char *ubuf; ubuf = bpf_task_mmap(UBUF_SIZE); if (ubuf == NULL) { return -1; } + bpf_printk("ubuf = %llx:%llx, start_path = %s", ubuf, ubuf + UBUF_SIZE, start_path); - /* bpf_printk seems to so some magic to ensure it never reads past the - * allocated area. */ - bpf_printk("ubuf = %s", ubuf); + /* BUG: page fault, page not present */ + bpf_printk("ubuf = '%c'", ubuf[0]); + + /* BUG: This triggers a segfault in the kernel (at least on the + * hardware). How does ringbuf prevent this? */ + /* bpf_printk("ubuf = %s", ubuf); */ strncpy(ubuf, start_path, PATHLEN); /* bpf_printk seems to so some magic to ensure it never reads past the * allocated area. */ - bpf_printk("ubuf = %s", ubuf); int dfd = bpf_task_sys_open_3((uint64_t) ubuf, O_RDONLY | O_DIRECTORY, 0777); if (dfd < 0) { diff --git a/src/task.c b/src/task.c index 01e53d0..e476ed9 100644 --- a/src/task.c +++ b/src/task.c @@ -65,6 +65,8 @@ int main(int argc, char **argv) long ret = syscall(SYS_bpftask, prog_fd, &output); printf("syscall(SYS_bfptask, %d, ...) = %d\n", prog_fd, (int) ret); + char *ubuf = (char *) ret; + ubuf[0] = 'c'; printf("Successfully started!\n"); cleanup: diff --git a/src/task_mmap.bpf.c b/src/task_mmap.bpf.c new file mode 100644 index 0000000..3b667ec --- /dev/null +++ b/src/task_mmap.bpf.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright (c) 2020 Facebook */ +#include <linux/bpf.h> +#include <bpf/bpf_helpers.h> + +#include "task_mmap.h" +#include "libc.bpf.h" + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; + +#define PATHLEN 256 +#define UBUF_SIZE 256 + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} rb SEC(".maps"); + +SEC("task") +int entry(long *ctx) +{ + int err = 0; + + /* TODO: Why is %p different from %llx? */ + bpf_printk("ctx = %llx", ctx); + + /* map_populate */ + char *ubuf; + ubuf = mmap(NULL, UBUF_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0); + if (ubuf == NULL) { + return -1; + } + bpf_printk("ubuf = %llx:%llx", ubuf, ubuf + UBUF_SIZE); + + struct event *e; + e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); + if (!e) + return -1; + e->ubuf = ubuf; + bpf_ringbuf_submit(e, 0); + + return 0; +} diff --git a/src/task_mmap.c b/src/task_mmap.c new file mode 100644 index 0000000..eb37c48 --- /dev/null +++ b/src/task_mmap.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +/* Copyright (c) 2020 Facebook */ +#include <argp.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> +#include <time.h> +#include <sys/resource.h> +#include <bpf/libbpf.h> +#include "task_mmap.skel.h" +#include "task_mmap.h" + +/* Must match __NR_bpftask in unistd.h of the target kernel. */ +#define SYS_bpftask 442 + +static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) +{ + return vfprintf(stderr, format, args); +} + +static void bump_memlock_rlimit(void) +{ + struct rlimit rlim_new = { + .rlim_cur = RLIM_INFINITY, + .rlim_max = RLIM_INFINITY, + }; + + if (setrlimit(RLIMIT_MEMLOCK, &rlim_new)) { + fprintf(stderr, "Failed to increase RLIMIT_MEMLOCK limit!\n"); + exit(1); + } +} + +static volatile bool done; + +static int handle_event(void *ctx, void *data, size_t data_sz) +{ + const struct event *e = data; + + printf("ubuf = %p\n", e->ubuf); + e->ubuf[0] = 'c'; + + done = true; + + return 0; +} + +int main(int argc, char **argv) +{ + struct task_mmap_bpf *skel; + int err; + + if (argc != 1) { + fprintf(stderr, "Usage: %s\n", argv[0]); + return 1; + } + + /* 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 = task_mmap_bpf__open(); + if (!skel) { + fprintf(stderr, "Failed to open BPF skeleton\n"); + return 1; + } + + /* Load & verify BPF programs */ + err = task_mmap_bpf__load(skel); + if (err) { + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); + goto cleanup; + } + + /* Set up ring buffer polling */ + struct ring_buffer *rb = NULL; + 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; + } + + int prog_fd = bpf_program__fd(skel->progs.entry); + + long output; + void *prog_ctx = &output; + + long ret = syscall(SYS_bpftask, prog_fd, prog_ctx); + printf("syscall(SYS_bfptask, %d, %p) = %d\n", prog_fd, prog_ctx, (int) ret); + + while (!done) { + err = ring_buffer__poll(rb, 100 /* timeout, ms */); + /* Ctrl-C will cause -EINTR */ + if (err == -EINTR) { + err = 0; + break; + } + if (err < 0) { + printf("Error polling perf buffer: %d\n", err); + break; + } + } + + + printf("Successfully started!\n"); + +cleanup: + task_mmap_bpf__destroy(skel); + return -err; +} diff --git a/src/task_mmap.h b/src/task_mmap.h new file mode 100644 index 0000000..656e381 --- /dev/null +++ b/src/task_mmap.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +/* Copyright (c) 2020 Facebook */ +#ifndef __TASK_MMAP_H +#define __TASK_MMAP_H + +struct event { + char *ubuf; +}; + +#endif /* __TASK_MMAP_H */ -- GitLab