Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 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> |
| 5 | #include <linux/umh.h> |
| 6 | #include <linux/bpfilter.h> |
| 7 | #include <linux/sched.h> |
| 8 | #include <linux/sched/signal.h> |
| 9 | #include <linux/fs.h> |
| 10 | #include <linux/file.h> |
| 11 | #include "msgfmt.h" |
| 12 | |
Masahiro Yamada | 8e75887 | 2018-06-26 20:13:48 -0700 | [diff] [blame] | 13 | extern char bpfilter_umh_start; |
| 14 | extern char bpfilter_umh_end; |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 15 | |
Taehee Yoo | 61fbf59 | 2019-01-09 02:24:53 +0900 | [diff] [blame] | 16 | static void shutdown_umh(void) |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 17 | { |
| 18 | struct task_struct *tsk; |
| 19 | |
Taehee Yoo | 61fbf59 | 2019-01-09 02:24:53 +0900 | [diff] [blame] | 20 | if (bpfilter_ops.stop) |
Alexei Starovoitov | 66e58e0ef | 2018-06-07 15:31:14 -0700 | [diff] [blame] | 21 | return; |
Taehee Yoo | 61fbf59 | 2019-01-09 02:24:53 +0900 | [diff] [blame] | 22 | |
| 23 | tsk = get_pid_task(find_vpid(bpfilter_ops.info.pid), PIDTYPE_PID); |
Taehee Yoo | 8425843 | 2018-10-17 00:35:10 +0900 | [diff] [blame] | 24 | if (tsk) { |
Eric W. Biederman | 1dfd171 | 2019-05-15 12:23:03 -0500 | [diff] [blame] | 25 | send_sig(SIGKILL, tsk, 1); |
Taehee Yoo | 8425843 | 2018-10-17 00:35:10 +0900 | [diff] [blame] | 26 | put_task_struct(tsk); |
| 27 | } |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 28 | } |
| 29 | |
| 30 | static void __stop_umh(void) |
| 31 | { |
Taehee Yoo | 61fbf59 | 2019-01-09 02:24:53 +0900 | [diff] [blame] | 32 | if (IS_ENABLED(CONFIG_INET)) |
| 33 | shutdown_umh(); |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 34 | } |
| 35 | |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 36 | static int __bpfilter_process_sockopt(struct sock *sk, int optname, |
| 37 | char __user *optval, |
| 38 | unsigned int optlen, bool is_set) |
| 39 | { |
| 40 | struct mbox_request req; |
| 41 | struct mbox_reply reply; |
| 42 | loff_t pos; |
| 43 | ssize_t n; |
Alexei Starovoitov | 66e58e0ef | 2018-06-07 15:31:14 -0700 | [diff] [blame] | 44 | int ret = -EFAULT; |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 45 | |
| 46 | req.is_set = is_set; |
| 47 | req.pid = current->pid; |
| 48 | req.cmd = optname; |
Shanthosh RK | 33aa8da | 2018-10-05 20:57:48 +0530 | [diff] [blame] | 49 | req.addr = (long __force __user)optval; |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 50 | req.len = optlen; |
Taehee Yoo | 5b4cb65 | 2019-01-09 02:24:34 +0900 | [diff] [blame] | 51 | if (!bpfilter_ops.info.pid) |
Alexei Starovoitov | 66e58e0ef | 2018-06-07 15:31:14 -0700 | [diff] [blame] | 52 | goto out; |
Taehee Yoo | 5b4cb65 | 2019-01-09 02:24:34 +0900 | [diff] [blame] | 53 | n = __kernel_write(bpfilter_ops.info.pipe_to_umh, &req, sizeof(req), |
| 54 | &pos); |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 55 | if (n != sizeof(req)) { |
| 56 | pr_err("write fail %zd\n", n); |
| 57 | __stop_umh(); |
| 58 | ret = -EFAULT; |
| 59 | goto out; |
| 60 | } |
| 61 | pos = 0; |
Taehee Yoo | 5b4cb65 | 2019-01-09 02:24:34 +0900 | [diff] [blame] | 62 | n = kernel_read(bpfilter_ops.info.pipe_from_umh, &reply, sizeof(reply), |
| 63 | &pos); |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 64 | if (n != sizeof(reply)) { |
| 65 | pr_err("read fail %zd\n", n); |
| 66 | __stop_umh(); |
| 67 | ret = -EFAULT; |
| 68 | goto out; |
| 69 | } |
| 70 | ret = reply.status; |
| 71 | out: |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 72 | return ret; |
| 73 | } |
| 74 | |
Taehee Yoo | 61fbf59 | 2019-01-09 02:24:53 +0900 | [diff] [blame] | 75 | static int start_umh(void) |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 76 | { |
| 77 | int err; |
| 78 | |
| 79 | /* fork usermode process */ |
Masahiro Yamada | 8e75887 | 2018-06-26 20:13:48 -0700 | [diff] [blame] | 80 | err = fork_usermode_blob(&bpfilter_umh_start, |
| 81 | &bpfilter_umh_end - &bpfilter_umh_start, |
Taehee Yoo | 5b4cb65 | 2019-01-09 02:24:34 +0900 | [diff] [blame] | 82 | &bpfilter_ops.info); |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 83 | if (err) |
| 84 | return err; |
Taehee Yoo | 61fbf59 | 2019-01-09 02:24:53 +0900 | [diff] [blame] | 85 | bpfilter_ops.stop = false; |
Taehee Yoo | 5b4cb65 | 2019-01-09 02:24:34 +0900 | [diff] [blame] | 86 | pr_info("Loaded bpfilter_umh pid %d\n", bpfilter_ops.info.pid); |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 87 | |
| 88 | /* health check that usermode process started correctly */ |
Shanthosh RK | 33aa8da | 2018-10-05 20:57:48 +0530 | [diff] [blame] | 89 | if (__bpfilter_process_sockopt(NULL, 0, NULL, 0, 0) != 0) { |
Taehee Yoo | 71a8508 | 2019-01-09 02:25:10 +0900 | [diff] [blame] | 90 | shutdown_umh(); |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 91 | return -EFAULT; |
| 92 | } |
Arnd Bergmann | d71dbda | 2018-05-29 11:55:06 +0200 | [diff] [blame] | 93 | |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 94 | return 0; |
| 95 | } |
| 96 | |
Taehee Yoo | 61fbf59 | 2019-01-09 02:24:53 +0900 | [diff] [blame] | 97 | static int __init load_umh(void) |
| 98 | { |
| 99 | int err; |
| 100 | |
Taehee Yoo | 71a8508 | 2019-01-09 02:25:10 +0900 | [diff] [blame] | 101 | mutex_lock(&bpfilter_ops.lock); |
| 102 | if (!bpfilter_ops.stop) { |
| 103 | err = -EFAULT; |
| 104 | goto out; |
| 105 | } |
Taehee Yoo | 61fbf59 | 2019-01-09 02:24:53 +0900 | [diff] [blame] | 106 | err = start_umh(); |
| 107 | if (!err && IS_ENABLED(CONFIG_INET)) { |
| 108 | bpfilter_ops.sockopt = &__bpfilter_process_sockopt; |
| 109 | bpfilter_ops.start = &start_umh; |
| 110 | } |
Taehee Yoo | 71a8508 | 2019-01-09 02:25:10 +0900 | [diff] [blame] | 111 | out: |
| 112 | mutex_unlock(&bpfilter_ops.lock); |
Taehee Yoo | 61fbf59 | 2019-01-09 02:24:53 +0900 | [diff] [blame] | 113 | return err; |
| 114 | } |
| 115 | |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 116 | static void __exit fini_umh(void) |
| 117 | { |
Taehee Yoo | 71a8508 | 2019-01-09 02:25:10 +0900 | [diff] [blame] | 118 | mutex_lock(&bpfilter_ops.lock); |
Taehee Yoo | 61fbf59 | 2019-01-09 02:24:53 +0900 | [diff] [blame] | 119 | if (IS_ENABLED(CONFIG_INET)) { |
Taehee Yoo | 71a8508 | 2019-01-09 02:25:10 +0900 | [diff] [blame] | 120 | shutdown_umh(); |
Taehee Yoo | 61fbf59 | 2019-01-09 02:24:53 +0900 | [diff] [blame] | 121 | bpfilter_ops.start = NULL; |
| 122 | bpfilter_ops.sockopt = NULL; |
| 123 | } |
Taehee Yoo | 71a8508 | 2019-01-09 02:25:10 +0900 | [diff] [blame] | 124 | mutex_unlock(&bpfilter_ops.lock); |
Alexei Starovoitov | d2ba09c | 2018-05-21 19:22:30 -0700 | [diff] [blame] | 125 | } |
| 126 | module_init(load_umh); |
| 127 | module_exit(fini_umh); |
| 128 | MODULE_LICENSE("GPL"); |