xref: /openbmc/linux/net/bpfilter/bpfilter_kern.c (revision ba61bb17)
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 
13 #define UMH_start _binary_net_bpfilter_bpfilter_umh_start
14 #define UMH_end _binary_net_bpfilter_bpfilter_umh_end
15 
16 extern char UMH_start;
17 extern char UMH_end;
18 
19 static struct umh_info info;
20 /* since ip_getsockopt() can run in parallel, serialize access to umh */
21 static DEFINE_MUTEX(bpfilter_lock);
22 
23 static void shutdown_umh(struct umh_info *info)
24 {
25 	struct task_struct *tsk;
26 
27 	if (!info->pid)
28 		return;
29 	tsk = pid_task(find_vpid(info->pid), PIDTYPE_PID);
30 	if (tsk)
31 		force_sig(SIGKILL, tsk);
32 	fput(info->pipe_to_umh);
33 	fput(info->pipe_from_umh);
34 	info->pid = 0;
35 }
36 
37 static void __stop_umh(void)
38 {
39 	if (IS_ENABLED(CONFIG_INET)) {
40 		bpfilter_process_sockopt = NULL;
41 		shutdown_umh(&info);
42 	}
43 }
44 
45 static void stop_umh(void)
46 {
47 	mutex_lock(&bpfilter_lock);
48 	__stop_umh();
49 	mutex_unlock(&bpfilter_lock);
50 }
51 
52 static int __bpfilter_process_sockopt(struct sock *sk, int optname,
53 				      char __user *optval,
54 				      unsigned int optlen, bool is_set)
55 {
56 	struct mbox_request req;
57 	struct mbox_reply reply;
58 	loff_t pos;
59 	ssize_t n;
60 	int ret = -EFAULT;
61 
62 	req.is_set = is_set;
63 	req.pid = current->pid;
64 	req.cmd = optname;
65 	req.addr = (long)optval;
66 	req.len = optlen;
67 	mutex_lock(&bpfilter_lock);
68 	if (!info.pid)
69 		goto out;
70 	n = __kernel_write(info.pipe_to_umh, &req, sizeof(req), &pos);
71 	if (n != sizeof(req)) {
72 		pr_err("write fail %zd\n", n);
73 		__stop_umh();
74 		ret = -EFAULT;
75 		goto out;
76 	}
77 	pos = 0;
78 	n = kernel_read(info.pipe_from_umh, &reply, sizeof(reply), &pos);
79 	if (n != sizeof(reply)) {
80 		pr_err("read fail %zd\n", n);
81 		__stop_umh();
82 		ret = -EFAULT;
83 		goto out;
84 	}
85 	ret = reply.status;
86 out:
87 	mutex_unlock(&bpfilter_lock);
88 	return ret;
89 }
90 
91 static int __init load_umh(void)
92 {
93 	int err;
94 
95 	/* fork usermode process */
96 	err = fork_usermode_blob(&UMH_start, &UMH_end - &UMH_start, &info);
97 	if (err)
98 		return err;
99 	pr_info("Loaded bpfilter_umh pid %d\n", info.pid);
100 
101 	/* health check that usermode process started correctly */
102 	if (__bpfilter_process_sockopt(NULL, 0, 0, 0, 0) != 0) {
103 		stop_umh();
104 		return -EFAULT;
105 	}
106 	if (IS_ENABLED(CONFIG_INET))
107 		bpfilter_process_sockopt = &__bpfilter_process_sockopt;
108 
109 	return 0;
110 }
111 
112 static void __exit fini_umh(void)
113 {
114 	stop_umh();
115 }
116 module_init(load_umh);
117 module_exit(fini_umh);
118 MODULE_LICENSE("GPL");
119