1 // SPDX-License-Identifier: GPL-2.0
2 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3 #include <linux/init.h>
4 #include <linux/module.h>
6 #include <linux/bpfilter.h>
7 #include <linux/sched.h>
8 #include <linux/sched/signal.h>
10 #include <linux/file.h>
13 extern char bpfilter_umh_start;
14 extern char bpfilter_umh_end;
16 /* since ip_getsockopt() can run in parallel, serialize access to umh */
17 static DEFINE_MUTEX(bpfilter_lock);
19 static void shutdown_umh(void)
21 struct task_struct *tsk;
23 if (bpfilter_ops.stop)
26 tsk = get_pid_task(find_vpid(bpfilter_ops.info.pid), PIDTYPE_PID);
28 force_sig(SIGKILL, tsk);
33 static void __stop_umh(void)
35 if (IS_ENABLED(CONFIG_INET))
39 static void stop_umh(void)
41 mutex_lock(&bpfilter_lock);
43 mutex_unlock(&bpfilter_lock);
46 static int __bpfilter_process_sockopt(struct sock *sk, int optname,
48 unsigned int optlen, bool is_set)
50 struct mbox_request req;
51 struct mbox_reply reply;
57 req.pid = current->pid;
59 req.addr = (long __force __user)optval;
61 mutex_lock(&bpfilter_lock);
62 if (!bpfilter_ops.info.pid)
64 n = __kernel_write(bpfilter_ops.info.pipe_to_umh, &req, sizeof(req),
66 if (n != sizeof(req)) {
67 pr_err("write fail %zd\n", n);
73 n = kernel_read(bpfilter_ops.info.pipe_from_umh, &reply, sizeof(reply),
75 if (n != sizeof(reply)) {
76 pr_err("read fail %zd\n", n);
83 mutex_unlock(&bpfilter_lock);
87 static int start_umh(void)
91 /* fork usermode process */
92 err = fork_usermode_blob(&bpfilter_umh_start,
93 &bpfilter_umh_end - &bpfilter_umh_start,
97 bpfilter_ops.stop = false;
98 pr_info("Loaded bpfilter_umh pid %d\n", bpfilter_ops.info.pid);
100 /* health check that usermode process started correctly */
101 if (__bpfilter_process_sockopt(NULL, 0, NULL, 0, 0) != 0) {
109 static int __init load_umh(void)
113 if (!bpfilter_ops.stop)
116 if (!err && IS_ENABLED(CONFIG_INET)) {
117 bpfilter_ops.sockopt = &__bpfilter_process_sockopt;
118 bpfilter_ops.start = &start_umh;
124 static void __exit fini_umh(void)
126 if (IS_ENABLED(CONFIG_INET)) {
127 bpfilter_ops.start = NULL;
128 bpfilter_ops.sockopt = NULL;
132 module_init(load_umh);
133 module_exit(fini_umh);
134 MODULE_LICENSE("GPL");