Message ID | 20190910115527.5235-14-kpsingh@chromium.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Kernel Runtime Security Instrumentation | expand |
On 9/10/19 12:55 PM, KP Singh wrote: > From: KP Singh <kpsingh@google.com> > > * The program takes the name of an environment variable as an > argument. > * An eBPF program is loaded and attached to the > process_execution hook. > * The name of the environment variable passed is updated in a > eBPF per-cpu map. > * The eBPF program uses the krsi_get_env_var helper to get the > the value of this variable and logs the result to the perf > events buffer. > * The user-space program listens to the perf events and prints > the values. > > Example execution: > > ./krsi LD_PRELOAD > > [p_pid=123] LD_PRELOAD is not set > [p_pid=456] LD_PRELOAD=/lib/bad.so > [p_pid=789] WARNING! LD_PRELOAD is set 2 times > [p_pid=789] LD_PRELOAD=/lib/decoy.so > [p_pid=789] LD_PRELOAD=/lib/bad.so > > In a separate session the following [1, 2, 3] exec system calls > are made where: > > [1, 2, 3] char *argv[] = {"/bin/ls", 0}; > > [1] char *envp = {0}; > [2] char *envp = {"LD_PRELOAD=/lib/bad.so", 0}; > [3] char *envp = {"LD_PRELOAD=/lib/decoy.so, "LD_PRELOAD=/lib/bad.so", 0}; > > This example demonstrates that user-space is free to choose the format > in which the data is logged and can use very specific helpers like > krsi_get_env_var to populate only the data that is required. > > Signed-off-by: KP Singh <kpsingh@google.com> > --- > MAINTAINERS | 3 + > samples/bpf/.gitignore | 1 + > samples/bpf/Makefile | 3 + > samples/bpf/krsi_helpers.h | 31 ++++++ > samples/bpf/krsi_kern.c | 52 ++++++++++ > samples/bpf/krsi_user.c | 202 +++++++++++++++++++++++++++++++++++++ The KRSI does not depend on kernel headers. I would recommend to put this into tools/testing/selftests/bpf as a selftest. Selftest is the place to test regressions with bpf changes. The krsi_kern.c can be put into tools/testing/selftests/bpf/progs and krsi_user.c can be put into tools/testing/selftests/bpf/prog_tests. > 6 files changed, 292 insertions(+) > create mode 100644 samples/bpf/krsi_helpers.h > create mode 100644 samples/bpf/krsi_kern.c > create mode 100644 samples/bpf/krsi_user.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index 8e0364391d8b..ec378abb4c23 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -9005,6 +9005,9 @@ F: kernel/kprobes.c > KRSI SECURITY MODULE > M: KP Singh <kpsingh@chromium.org> > S: Supported > +F: samples/bpf/krsi_helpers.h > +F: samples/bpf/krsi_kern.c > +F: samples/bpf/krsi_user.c > F: security/krsi/ > > KS0108 LCD CONTROLLER DRIVER > diff --git a/samples/bpf/.gitignore b/samples/bpf/.gitignore > index 74d31fd3c99c..6bbf5a04877f 100644 > --- a/samples/bpf/.gitignore > +++ b/samples/bpf/.gitignore > @@ -2,6 +2,7 @@ cpustat > fds_example > hbm > ibumad > +krsi > lathist > lwt_len_hist > map_perf_test > diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile > index 1d9be26b4edd..33d3bef17549 100644 > --- a/samples/bpf/Makefile > +++ b/samples/bpf/Makefile > @@ -8,6 +8,7 @@ hostprogs-y := test_lru_dist > hostprogs-y += sock_example > hostprogs-y += fds_example > hostprogs-y += sockex1 > +hostprogs-y += krsi > hostprogs-y += sockex2 > hostprogs-y += sockex3 > hostprogs-y += tracex1 > @@ -62,6 +63,7 @@ TRACE_HELPERS := ../../tools/testing/selftests/bpf/trace_helpers.o > > fds_example-objs := fds_example.o > sockex1-objs := sockex1_user.o > +krsi-objs := krsi_user.o $(TRACE_HELPERS) > sockex2-objs := sockex2_user.o > sockex3-objs := bpf_load.o sockex3_user.o > tracex1-objs := bpf_load.o tracex1_user.o > @@ -113,6 +115,7 @@ hbm-objs := bpf_load.o hbm.o $(CGROUP_HELPERS) > # Tell kbuild to always build the programs > always := $(hostprogs-y) > always += sockex1_kern.o > +always += krsi_kern.o > always += sockex2_kern.o > always += sockex3_kern.o > always += tracex1_kern.o > diff --git a/samples/bpf/krsi_helpers.h b/samples/bpf/krsi_helpers.h > new file mode 100644 > index 000000000000..3007bfd6212e > --- /dev/null > +++ b/samples/bpf/krsi_helpers.h > @@ -0,0 +1,31 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > + > +#ifndef _KRSI_HELPERS_H > +#define _KRSI_HELPERS_H > + > +#define __bpf_percpu_val_align __aligned(8) > + > +#define ENV_VAR_NAME_MAX_LEN 48 > +#define ENV_VAR_VAL_MAX_LEN 4096 > + > +#define MAX_CPUS 128 > + > +#define __LOWER(x) (x & 0xffffffff) > +#define __UPPER(x) (x >> 32) > + > +struct krsi_env_value { > + // The name of the environment variable. > + char name[ENV_VAR_NAME_MAX_LEN]; > + // The value of the environment variable (if set). > + char value[ENV_VAR_VAL_MAX_LEN]; > + // Indicates if an overflow occurred while reading the value of the > + // of the environment variable. This means that an -E2BIG was received > + // from the krsi_get_env_var helper. > + bool overflow; > + // The number of times the environment variable was set. > + __u32 times; > + // The PID of the parent process. > + __u32 p_pid; > +} __bpf_percpu_val_align; > + > +#endif // _KRSI_HELPERS_H > diff --git a/samples/bpf/krsi_kern.c b/samples/bpf/krsi_kern.c > new file mode 100644 > index 000000000000..087a6f0cc81d > --- /dev/null > +++ b/samples/bpf/krsi_kern.c > @@ -0,0 +1,52 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +#include <linux/ptrace.h> > +#include <uapi/linux/bpf.h> > +#include <uapi/linux/ip.h> > +#include "bpf_helpers.h" > +#include "krsi_helpers.h" > + > +#define MAX_CPUS 128 > + > +struct bpf_map_def SEC("maps") env_map = { > + .type = BPF_MAP_TYPE_PERCPU_ARRAY, > + .key_size = sizeof(u32), > + .value_size = sizeof(struct krsi_env_value), > + .max_entries = 1, > +}; > + > +struct bpf_map_def SEC("maps") perf_map = { > + .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, > + .key_size = sizeof(int), > + .value_size = sizeof(u32), > + .max_entries = MAX_CPUS, > +}; > + > +SEC("krsi") > +int env_dumper(void *ctx) > +{ > + u64 times_ret; > + s32 ret; > + u32 map_id = 0; > + char *map_value; > + struct krsi_env_value *env; > + > + env = bpf_map_lookup_elem(&env_map, &map_id); > + if (!env) > + return -ENOMEM; > + times_ret = krsi_get_env_var(ctx, env->name, ENV_VAR_NAME_MAX_LEN, > + env->value, ENV_VAR_VAL_MAX_LEN); > + ret = __LOWER(times_ret); > + if (ret == -E2BIG) > + env->overflow = true; > + else if (ret < 0) > + return ret; > + > + env->times = __UPPER(times_ret); > + env->p_pid = bpf_get_current_pid_tgid(); > + bpf_perf_event_output(ctx, &perf_map, BPF_F_CURRENT_CPU, env, > + sizeof(struct krsi_env_value)); > + > + return 0; > +} > +char _license[] SEC("license") = "GPL"; > diff --git a/samples/bpf/krsi_user.c b/samples/bpf/krsi_user.c > new file mode 100644 > index 000000000000..1fad29bf017a > --- /dev/null > +++ b/samples/bpf/krsi_user.c > @@ -0,0 +1,202 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <errno.h> > +#include <err.h> > +#include <assert.h> > +#include <linux/limits.h> > +#include <linux/bpf.h> > +#include <bpf/bpf.h> > +#include "bpf/libbpf.h" > +#include <unistd.h> > +#include <sys/types.h> > +#include <sys/stat.h> > +#include <sys/sysinfo.h> > +#include <sys/ioctl.h> > +#include <fcntl.h> > +#include <sys/resource.h> > + > +#include "perf-sys.h" > +#include "trace_helpers.h" > +#include "krsi_helpers.h" > + > +#define LSM_HOOK_PATH "/sys/kernel/security/krsi/process_execution" > + > +static int pmu_fds[MAX_CPUS]; > +static struct perf_event_mmap_page *headers[MAX_CPUS]; > + > +static int print_env(void *d, int size) > +{ > + struct krsi_env_value *env = d; > + int times = env->times; > + char *next = env->value; > + size_t total = 0; > + > + if (env->times > 1) > + printf("[p_pid=%u] WARNING! %s is set %u times\n", > + env->p_pid, env->name, env->times); > + > + /* > + * krsi_get_env_var ensures that even overflows > + * are null terminated. Incase of an overflow, > + * this logic tries to print as much information > + * that was gathered. > + */ > + while (times && total < ENV_VAR_NAME_MAX_LEN) { > + next += total; > + if (env->overflow) > + printf("[p_pid=%u] OVERFLOW! %s=%s\n", > + env->p_pid, env->name, next); > + else > + printf("[p_pid=%u] %s=%s\n", > + env->p_pid, env->name, next); > + times--; > + total += strlen(next) + 1; > + } > + > + if (!env->times) > + printf("p_pid=%u] %s is not set\n", > + env->p_pid, env->name); > + > + return LIBBPF_PERF_EVENT_CONT; > +} > + > +static int open_perf_events(int map_fd, int num) > +{ > + int i; > + struct perf_event_attr attr = { > + .sample_type = PERF_SAMPLE_RAW, > + .type = PERF_TYPE_SOFTWARE, > + .config = PERF_COUNT_SW_BPF_OUTPUT, > + .wakeup_events = 1, /* get an fd notification for every event */ > + }; > + > + for (i = 0; i < num; i++) { > + int key = i; > + int ret; > + > + ret = sys_perf_event_open(&attr, -1 /*pid*/, i/*cpu*/, > + -1/*group_fd*/, 0); > + if (ret < 0) > + return ret; > + pmu_fds[i] = ret; > + ret = bpf_map_update_elem(map_fd, &key, &pmu_fds[i], BPF_ANY); > + if (ret < 0) > + return ret; > + ioctl(pmu_fds[i], PERF_EVENT_IOC_ENABLE, 0); > + } > + return 0; > +} > + > +static int update_env_map(struct bpf_object *prog_obj, const char *env_var_name, > + int numcpus) > +{ > + struct bpf_map *map; > + struct krsi_env_value *env; > + int map_fd; > + int key = 0, ret = 0, i; > + > + map = bpf_object__find_map_by_name(prog_obj, "env_map"); > + if (!map) > + return -EINVAL; > + > + map_fd = bpf_map__fd(map); > + if (map_fd < 0) > + return map_fd; > + > + env = malloc(numcpus * sizeof(struct krsi_env_value)); > + if (!env) { > + ret = -ENOMEM; > + goto out; > + } > + > + for (i = 0; i < numcpus; i++) > + strcpy(env[i].name, env_var_name); > + > + ret = bpf_map_update_elem(map_fd, &key, env, BPF_ANY); > + if (ret < 0) > + goto out; > + > +out: > + free(env); > + return ret; > +} > + > +int main(int argc, char **argv) > +{ > + struct bpf_object *prog_obj; > + const char *env_var_name; > + struct bpf_prog_load_attr attr; > + int prog_fd, target_fd, map_fd; > + int ret, i, numcpus; > + struct bpf_map *map; > + char filename[PATH_MAX]; > + struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; > + > + > + if (argc != 2) > + errx(EXIT_FAILURE, "Usage %s env_var_name\n", argv[0]); > + > + env_var_name = argv[1]; > + if (strlen(env_var_name) > ENV_VAR_NAME_MAX_LEN - 1) > + errx(EXIT_FAILURE, > + "<env_var_name> cannot be more than %d in length", > + ENV_VAR_NAME_MAX_LEN - 1); > + > + > + setrlimit(RLIMIT_MEMLOCK, &r); > + snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); > + > + memset(&attr, 0, sizeof(struct bpf_prog_load_attr)); > + attr.prog_type = BPF_PROG_TYPE_KRSI; > + attr.expected_attach_type = BPF_KRSI; > + attr.file = filename; > + > + /* Attach the BPF program to the given hook */ > + target_fd = open(LSM_HOOK_PATH, O_RDWR); > + if (target_fd < 0) > + err(EXIT_FAILURE, "Failed to open target file"); > + > + if (bpf_prog_load_xattr(&attr, &prog_obj, &prog_fd)) > + err(EXIT_FAILURE, "Failed to load eBPF program"); > + > + numcpus = get_nprocs(); > + if (numcpus > MAX_CPUS) > + numcpus = MAX_CPUS; > + > + ret = update_env_map(prog_obj, env_var_name, numcpus); > + if (ret < 0) > + err(EXIT_FAILURE, "Failed to update env map"); > + > + map = bpf_object__find_map_by_name(prog_obj, "perf_map"); > + if (!map) > + err(EXIT_FAILURE, > + "Finding the perf event map in obj file failed"); > + > + map_fd = bpf_map__fd(map); > + if (map_fd < 0) > + err(EXIT_FAILURE, "Failed to get fd for perf events map"); > + > + ret = bpf_prog_attach(prog_fd, target_fd, BPF_KRSI, > + BPF_F_ALLOW_OVERRIDE); > + if (ret < 0) > + err(EXIT_FAILURE, "Failed to attach prog to LSM hook"); > + > + ret = open_perf_events(map_fd, numcpus); > + if (ret < 0) > + err(EXIT_FAILURE, "Failed to open perf events handler"); > + > + for (i = 0; i < numcpus; i++) { > + ret = perf_event_mmap_header(pmu_fds[i], &headers[i]); > + if (ret < 0) > + err(EXIT_FAILURE, "perf_event_mmap_header"); > + } > + > + ret = perf_event_poller_multi(pmu_fds, headers, numcpus, print_env); > + if (ret < 0) > + err(EXIT_FAILURE, "Failed to poll perf events"); > + > + return EXIT_SUCCESS; > +} >
diff --git a/MAINTAINERS b/MAINTAINERS index 8e0364391d8b..ec378abb4c23 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9005,6 +9005,9 @@ F: kernel/kprobes.c KRSI SECURITY MODULE M: KP Singh <kpsingh@chromium.org> S: Supported +F: samples/bpf/krsi_helpers.h +F: samples/bpf/krsi_kern.c +F: samples/bpf/krsi_user.c F: security/krsi/ KS0108 LCD CONTROLLER DRIVER diff --git a/samples/bpf/.gitignore b/samples/bpf/.gitignore index 74d31fd3c99c..6bbf5a04877f 100644 --- a/samples/bpf/.gitignore +++ b/samples/bpf/.gitignore @@ -2,6 +2,7 @@ cpustat fds_example hbm ibumad +krsi lathist lwt_len_hist map_perf_test diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 1d9be26b4edd..33d3bef17549 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -8,6 +8,7 @@ hostprogs-y := test_lru_dist hostprogs-y += sock_example hostprogs-y += fds_example hostprogs-y += sockex1 +hostprogs-y += krsi hostprogs-y += sockex2 hostprogs-y += sockex3 hostprogs-y += tracex1 @@ -62,6 +63,7 @@ TRACE_HELPERS := ../../tools/testing/selftests/bpf/trace_helpers.o fds_example-objs := fds_example.o sockex1-objs := sockex1_user.o +krsi-objs := krsi_user.o $(TRACE_HELPERS) sockex2-objs := sockex2_user.o sockex3-objs := bpf_load.o sockex3_user.o tracex1-objs := bpf_load.o tracex1_user.o @@ -113,6 +115,7 @@ hbm-objs := bpf_load.o hbm.o $(CGROUP_HELPERS) # Tell kbuild to always build the programs always := $(hostprogs-y) always += sockex1_kern.o +always += krsi_kern.o always += sockex2_kern.o always += sockex3_kern.o always += tracex1_kern.o diff --git a/samples/bpf/krsi_helpers.h b/samples/bpf/krsi_helpers.h new file mode 100644 index 000000000000..3007bfd6212e --- /dev/null +++ b/samples/bpf/krsi_helpers.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _KRSI_HELPERS_H +#define _KRSI_HELPERS_H + +#define __bpf_percpu_val_align __aligned(8) + +#define ENV_VAR_NAME_MAX_LEN 48 +#define ENV_VAR_VAL_MAX_LEN 4096 + +#define MAX_CPUS 128 + +#define __LOWER(x) (x & 0xffffffff) +#define __UPPER(x) (x >> 32) + +struct krsi_env_value { + // The name of the environment variable. + char name[ENV_VAR_NAME_MAX_LEN]; + // The value of the environment variable (if set). + char value[ENV_VAR_VAL_MAX_LEN]; + // Indicates if an overflow occurred while reading the value of the + // of the environment variable. This means that an -E2BIG was received + // from the krsi_get_env_var helper. + bool overflow; + // The number of times the environment variable was set. + __u32 times; + // The PID of the parent process. + __u32 p_pid; +} __bpf_percpu_val_align; + +#endif // _KRSI_HELPERS_H diff --git a/samples/bpf/krsi_kern.c b/samples/bpf/krsi_kern.c new file mode 100644 index 000000000000..087a6f0cc81d --- /dev/null +++ b/samples/bpf/krsi_kern.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/ptrace.h> +#include <uapi/linux/bpf.h> +#include <uapi/linux/ip.h> +#include "bpf_helpers.h" +#include "krsi_helpers.h" + +#define MAX_CPUS 128 + +struct bpf_map_def SEC("maps") env_map = { + .type = BPF_MAP_TYPE_PERCPU_ARRAY, + .key_size = sizeof(u32), + .value_size = sizeof(struct krsi_env_value), + .max_entries = 1, +}; + +struct bpf_map_def SEC("maps") perf_map = { + .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(u32), + .max_entries = MAX_CPUS, +}; + +SEC("krsi") +int env_dumper(void *ctx) +{ + u64 times_ret; + s32 ret; + u32 map_id = 0; + char *map_value; + struct krsi_env_value *env; + + env = bpf_map_lookup_elem(&env_map, &map_id); + if (!env) + return -ENOMEM; + times_ret = krsi_get_env_var(ctx, env->name, ENV_VAR_NAME_MAX_LEN, + env->value, ENV_VAR_VAL_MAX_LEN); + ret = __LOWER(times_ret); + if (ret == -E2BIG) + env->overflow = true; + else if (ret < 0) + return ret; + + env->times = __UPPER(times_ret); + env->p_pid = bpf_get_current_pid_tgid(); + bpf_perf_event_output(ctx, &perf_map, BPF_F_CURRENT_CPU, env, + sizeof(struct krsi_env_value)); + + return 0; +} +char _license[] SEC("license") = "GPL"; diff --git a/samples/bpf/krsi_user.c b/samples/bpf/krsi_user.c new file mode 100644 index 000000000000..1fad29bf017a --- /dev/null +++ b/samples/bpf/krsi_user.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <err.h> +#include <assert.h> +#include <linux/limits.h> +#include <linux/bpf.h> +#include <bpf/bpf.h> +#include "bpf/libbpf.h" +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/sysinfo.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <sys/resource.h> + +#include "perf-sys.h" +#include "trace_helpers.h" +#include "krsi_helpers.h" + +#define LSM_HOOK_PATH "/sys/kernel/security/krsi/process_execution" + +static int pmu_fds[MAX_CPUS]; +static struct perf_event_mmap_page *headers[MAX_CPUS]; + +static int print_env(void *d, int size) +{ + struct krsi_env_value *env = d; + int times = env->times; + char *next = env->value; + size_t total = 0; + + if (env->times > 1) + printf("[p_pid=%u] WARNING! %s is set %u times\n", + env->p_pid, env->name, env->times); + + /* + * krsi_get_env_var ensures that even overflows + * are null terminated. Incase of an overflow, + * this logic tries to print as much information + * that was gathered. + */ + while (times && total < ENV_VAR_NAME_MAX_LEN) { + next += total; + if (env->overflow) + printf("[p_pid=%u] OVERFLOW! %s=%s\n", + env->p_pid, env->name, next); + else + printf("[p_pid=%u] %s=%s\n", + env->p_pid, env->name, next); + times--; + total += strlen(next) + 1; + } + + if (!env->times) + printf("p_pid=%u] %s is not set\n", + env->p_pid, env->name); + + return LIBBPF_PERF_EVENT_CONT; +} + +static int open_perf_events(int map_fd, int num) +{ + int i; + struct perf_event_attr attr = { + .sample_type = PERF_SAMPLE_RAW, + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_BPF_OUTPUT, + .wakeup_events = 1, /* get an fd notification for every event */ + }; + + for (i = 0; i < num; i++) { + int key = i; + int ret; + + ret = sys_perf_event_open(&attr, -1 /*pid*/, i/*cpu*/, + -1/*group_fd*/, 0); + if (ret < 0) + return ret; + pmu_fds[i] = ret; + ret = bpf_map_update_elem(map_fd, &key, &pmu_fds[i], BPF_ANY); + if (ret < 0) + return ret; + ioctl(pmu_fds[i], PERF_EVENT_IOC_ENABLE, 0); + } + return 0; +} + +static int update_env_map(struct bpf_object *prog_obj, const char *env_var_name, + int numcpus) +{ + struct bpf_map *map; + struct krsi_env_value *env; + int map_fd; + int key = 0, ret = 0, i; + + map = bpf_object__find_map_by_name(prog_obj, "env_map"); + if (!map) + return -EINVAL; + + map_fd = bpf_map__fd(map); + if (map_fd < 0) + return map_fd; + + env = malloc(numcpus * sizeof(struct krsi_env_value)); + if (!env) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < numcpus; i++) + strcpy(env[i].name, env_var_name); + + ret = bpf_map_update_elem(map_fd, &key, env, BPF_ANY); + if (ret < 0) + goto out; + +out: + free(env); + return ret; +} + +int main(int argc, char **argv) +{ + struct bpf_object *prog_obj; + const char *env_var_name; + struct bpf_prog_load_attr attr; + int prog_fd, target_fd, map_fd; + int ret, i, numcpus; + struct bpf_map *map; + char filename[PATH_MAX]; + struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; + + + if (argc != 2) + errx(EXIT_FAILURE, "Usage %s env_var_name\n", argv[0]); + + env_var_name = argv[1]; + if (strlen(env_var_name) > ENV_VAR_NAME_MAX_LEN - 1) + errx(EXIT_FAILURE, + "<env_var_name> cannot be more than %d in length", + ENV_VAR_NAME_MAX_LEN - 1); + + + setrlimit(RLIMIT_MEMLOCK, &r); + snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); + + memset(&attr, 0, sizeof(struct bpf_prog_load_attr)); + attr.prog_type = BPF_PROG_TYPE_KRSI; + attr.expected_attach_type = BPF_KRSI; + attr.file = filename; + + /* Attach the BPF program to the given hook */ + target_fd = open(LSM_HOOK_PATH, O_RDWR); + if (target_fd < 0) + err(EXIT_FAILURE, "Failed to open target file"); + + if (bpf_prog_load_xattr(&attr, &prog_obj, &prog_fd)) + err(EXIT_FAILURE, "Failed to load eBPF program"); + + numcpus = get_nprocs(); + if (numcpus > MAX_CPUS) + numcpus = MAX_CPUS; + + ret = update_env_map(prog_obj, env_var_name, numcpus); + if (ret < 0) + err(EXIT_FAILURE, "Failed to update env map"); + + map = bpf_object__find_map_by_name(prog_obj, "perf_map"); + if (!map) + err(EXIT_FAILURE, + "Finding the perf event map in obj file failed"); + + map_fd = bpf_map__fd(map); + if (map_fd < 0) + err(EXIT_FAILURE, "Failed to get fd for perf events map"); + + ret = bpf_prog_attach(prog_fd, target_fd, BPF_KRSI, + BPF_F_ALLOW_OVERRIDE); + if (ret < 0) + err(EXIT_FAILURE, "Failed to attach prog to LSM hook"); + + ret = open_perf_events(map_fd, numcpus); + if (ret < 0) + err(EXIT_FAILURE, "Failed to open perf events handler"); + + for (i = 0; i < numcpus; i++) { + ret = perf_event_mmap_header(pmu_fds[i], &headers[i]); + if (ret < 0) + err(EXIT_FAILURE, "perf_event_mmap_header"); + } + + ret = perf_event_poller_multi(pmu_fds, headers, numcpus, print_env); + if (ret < 0) + err(EXIT_FAILURE, "Failed to poll perf events"); + + return EXIT_SUCCESS; +}