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