0001
0002 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0003 #include <linux/init.h>
0004 #include <linux/module.h>
0005 #include <linux/umh.h>
0006 #include <linux/bpfilter.h>
0007 #include <linux/sched.h>
0008 #include <linux/sched/signal.h>
0009 #include <linux/fs.h>
0010 #include <linux/file.h>
0011 #include "msgfmt.h"
0012
0013 extern char bpfilter_umh_start;
0014 extern char bpfilter_umh_end;
0015
0016 static void shutdown_umh(void)
0017 {
0018 struct umd_info *info = &bpfilter_ops.info;
0019 struct pid *tgid = info->tgid;
0020
0021 if (tgid) {
0022 kill_pid(tgid, SIGKILL, 1);
0023 wait_event(tgid->wait_pidfd, thread_group_exited(tgid));
0024 bpfilter_umh_cleanup(info);
0025 }
0026 }
0027
0028 static void __stop_umh(void)
0029 {
0030 if (IS_ENABLED(CONFIG_INET))
0031 shutdown_umh();
0032 }
0033
0034 static int bpfilter_send_req(struct mbox_request *req)
0035 {
0036 struct mbox_reply reply;
0037 loff_t pos = 0;
0038 ssize_t n;
0039
0040 if (!bpfilter_ops.info.tgid)
0041 return -EFAULT;
0042 pos = 0;
0043 n = kernel_write(bpfilter_ops.info.pipe_to_umh, req, sizeof(*req),
0044 &pos);
0045 if (n != sizeof(*req)) {
0046 pr_err("write fail %zd\n", n);
0047 goto stop;
0048 }
0049 pos = 0;
0050 n = kernel_read(bpfilter_ops.info.pipe_from_umh, &reply, sizeof(reply),
0051 &pos);
0052 if (n != sizeof(reply)) {
0053 pr_err("read fail %zd\n", n);
0054 goto stop;
0055 }
0056 return reply.status;
0057 stop:
0058 __stop_umh();
0059 return -EFAULT;
0060 }
0061
0062 static int bpfilter_process_sockopt(struct sock *sk, int optname,
0063 sockptr_t optval, unsigned int optlen,
0064 bool is_set)
0065 {
0066 struct mbox_request req = {
0067 .is_set = is_set,
0068 .pid = current->pid,
0069 .cmd = optname,
0070 .addr = (uintptr_t)optval.user,
0071 .len = optlen,
0072 };
0073 if (sockptr_is_kernel(optval)) {
0074 pr_err("kernel access not supported\n");
0075 return -EFAULT;
0076 }
0077 return bpfilter_send_req(&req);
0078 }
0079
0080 static int start_umh(void)
0081 {
0082 struct mbox_request req = { .pid = current->pid };
0083 int err;
0084
0085
0086 err = fork_usermode_driver(&bpfilter_ops.info);
0087 if (err)
0088 return err;
0089 pr_info("Loaded bpfilter_umh pid %d\n", pid_nr(bpfilter_ops.info.tgid));
0090
0091
0092 if (bpfilter_send_req(&req) != 0) {
0093 shutdown_umh();
0094 return -EFAULT;
0095 }
0096
0097 return 0;
0098 }
0099
0100 static int __init load_umh(void)
0101 {
0102 int err;
0103
0104 err = umd_load_blob(&bpfilter_ops.info,
0105 &bpfilter_umh_start,
0106 &bpfilter_umh_end - &bpfilter_umh_start);
0107 if (err)
0108 return err;
0109
0110 mutex_lock(&bpfilter_ops.lock);
0111 err = start_umh();
0112 if (!err && IS_ENABLED(CONFIG_INET)) {
0113 bpfilter_ops.sockopt = &bpfilter_process_sockopt;
0114 bpfilter_ops.start = &start_umh;
0115 }
0116 mutex_unlock(&bpfilter_ops.lock);
0117 if (err)
0118 umd_unload_blob(&bpfilter_ops.info);
0119 return err;
0120 }
0121
0122 static void __exit fini_umh(void)
0123 {
0124 mutex_lock(&bpfilter_ops.lock);
0125 if (IS_ENABLED(CONFIG_INET)) {
0126 shutdown_umh();
0127 bpfilter_ops.start = NULL;
0128 bpfilter_ops.sockopt = NULL;
0129 }
0130 mutex_unlock(&bpfilter_ops.lock);
0131
0132 umd_unload_blob(&bpfilter_ops.info);
0133 }
0134 module_init(load_umh);
0135 module_exit(fini_umh);
0136 MODULE_LICENSE("GPL");