Loading...
// SPDX-License-Identifier: GPL-2.0 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/init.h> #include <linux/module.h> #include <linux/pid.h> #include <linux/fs.h> #include <linux/sched/signal.h> #include "bpf_preload.h" extern char bpf_preload_umd_start; extern char bpf_preload_umd_end; static int preload(struct bpf_preload_info *obj); static int finish(void); static struct bpf_preload_ops umd_ops = { .info.driver_name = "bpf_preload", .preload = preload, .finish = finish, .owner = THIS_MODULE, }; static int preload(struct bpf_preload_info *obj) { int magic = BPF_PRELOAD_START; loff_t pos = 0; int i, err; ssize_t n; err = fork_usermode_driver(&umd_ops.info); if (err) return err; /* send the start magic to let UMD proceed with loading BPF progs */ n = kernel_write(umd_ops.info.pipe_to_umh, &magic, sizeof(magic), &pos); if (n != sizeof(magic)) return -EPIPE; /* receive bpf_link IDs and names from UMD */ pos = 0; for (i = 0; i < BPF_PRELOAD_LINKS; i++) { n = kernel_read(umd_ops.info.pipe_from_umh, &obj[i], sizeof(*obj), &pos); if (n != sizeof(*obj)) return -EPIPE; } return 0; } static int finish(void) { int magic = BPF_PRELOAD_END; struct pid *tgid; loff_t pos = 0; ssize_t n; /* send the last magic to UMD. It will do a normal exit. */ n = kernel_write(umd_ops.info.pipe_to_umh, &magic, sizeof(magic), &pos); if (n != sizeof(magic)) return -EPIPE; tgid = umd_ops.info.tgid; if (tgid) { wait_event(tgid->wait_pidfd, thread_group_exited(tgid)); umd_cleanup_helper(&umd_ops.info); } return 0; } static int __init load_umd(void) { int err; err = umd_load_blob(&umd_ops.info, &bpf_preload_umd_start, &bpf_preload_umd_end - &bpf_preload_umd_start); if (err) return err; bpf_preload_ops = &umd_ops; return err; } static void __exit fini_umd(void) { struct pid *tgid; bpf_preload_ops = NULL; /* kill UMD in case it's still there due to earlier error */ tgid = umd_ops.info.tgid; if (tgid) { kill_pid(tgid, SIGKILL, 1); wait_event(tgid->wait_pidfd, thread_group_exited(tgid)); umd_cleanup_helper(&umd_ops.info); } umd_unload_blob(&umd_ops.info); } late_initcall(load_umd); module_exit(fini_umd); MODULE_LICENSE("GPL"); |