]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - net/bpfilter/bpfilter_kern.c
net: dsa: fix panic on shutdown if multi-chip tree failed to probe
[mirror_ubuntu-jammy-kernel.git] / net / bpfilter / bpfilter_kern.c
CommitLineData
d2ba09c1
AS
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
8e75887d
MY
13extern char bpfilter_umh_start;
14extern char bpfilter_umh_end;
d2ba09c1 15
61fbf593 16static void shutdown_umh(void)
d2ba09c1 17{
1c340ead
EB
18 struct umd_info *info = &bpfilter_ops.info;
19 struct pid *tgid = info->tgid;
d2ba09c1 20
e80eb1dc
EB
21 if (tgid) {
22 kill_pid(tgid, SIGKILL, 1);
23 wait_event(tgid->wait_pidfd, thread_group_exited(tgid));
24 bpfilter_umh_cleanup(info);
84258438 25 }
d2ba09c1
AS
26}
27
28static void __stop_umh(void)
29{
61fbf593
TY
30 if (IS_ENABLED(CONFIG_INET))
31 shutdown_umh();
d2ba09c1
AS
32}
33
c9ffebdd 34static int bpfilter_send_req(struct mbox_request *req)
d2ba09c1 35{
d2ba09c1 36 struct mbox_reply reply;
4f010246 37 loff_t pos = 0;
d2ba09c1 38 ssize_t n;
d2ba09c1 39
1c340ead 40 if (!bpfilter_ops.info.tgid)
c9ffebdd 41 return -EFAULT;
a4fa4589 42 pos = 0;
c9ffebdd 43 n = kernel_write(bpfilter_ops.info.pipe_to_umh, req, sizeof(*req),
5b4cb650 44 &pos);
c9ffebdd 45 if (n != sizeof(*req)) {
d2ba09c1 46 pr_err("write fail %zd\n", n);
c9ffebdd 47 goto stop;
d2ba09c1
AS
48 }
49 pos = 0;
5b4cb650
TY
50 n = kernel_read(bpfilter_ops.info.pipe_from_umh, &reply, sizeof(reply),
51 &pos);
d2ba09c1
AS
52 if (n != sizeof(reply)) {
53 pr_err("read fail %zd\n", n);
c9ffebdd 54 goto stop;
d2ba09c1 55 }
c9ffebdd
CH
56 return reply.status;
57stop:
58 __stop_umh();
59 return -EFAULT;
60}
61
62static int bpfilter_process_sockopt(struct sock *sk, int optname,
b03afaa8 63 sockptr_t optval, unsigned int optlen,
c9ffebdd
CH
64 bool is_set)
65{
66 struct mbox_request req = {
67 .is_set = is_set,
68 .pid = current->pid,
69 .cmd = optname,
b03afaa8 70 .addr = (uintptr_t)optval.user,
c9ffebdd
CH
71 .len = optlen,
72 };
b03afaa8 73 if (uaccess_kernel() || sockptr_is_kernel(optval)) {
d200cf62
CH
74 pr_err("kernel access not supported\n");
75 return -EFAULT;
76 }
c9ffebdd 77 return bpfilter_send_req(&req);
d2ba09c1
AS
78}
79
61fbf593 80static int start_umh(void)
d2ba09c1 81{
c9ffebdd 82 struct mbox_request req = { .pid = current->pid };
d2ba09c1
AS
83 int err;
84
85 /* fork usermode process */
e2dc9bf3 86 err = fork_usermode_driver(&bpfilter_ops.info);
d2ba09c1
AS
87 if (err)
88 return err;
1c340ead 89 pr_info("Loaded bpfilter_umh pid %d\n", pid_nr(bpfilter_ops.info.tgid));
d2ba09c1
AS
90
91 /* health check that usermode process started correctly */
c9ffebdd 92 if (bpfilter_send_req(&req) != 0) {
71a85084 93 shutdown_umh();
d2ba09c1
AS
94 return -EFAULT;
95 }
d71dbdaa 96
d2ba09c1
AS
97 return 0;
98}
99
61fbf593
TY
100static int __init load_umh(void)
101{
102 int err;
103
e2dc9bf3
EB
104 err = umd_load_blob(&bpfilter_ops.info,
105 &bpfilter_umh_start,
106 &bpfilter_umh_end - &bpfilter_umh_start);
107 if (err)
108 return err;
109
71a85084 110 mutex_lock(&bpfilter_ops.lock);
61fbf593
TY
111 err = start_umh();
112 if (!err && IS_ENABLED(CONFIG_INET)) {
c9ffebdd 113 bpfilter_ops.sockopt = &bpfilter_process_sockopt;
61fbf593
TY
114 bpfilter_ops.start = &start_umh;
115 }
71a85084 116 mutex_unlock(&bpfilter_ops.lock);
e2dc9bf3
EB
117 if (err)
118 umd_unload_blob(&bpfilter_ops.info);
61fbf593
TY
119 return err;
120}
121
d2ba09c1
AS
122static void __exit fini_umh(void)
123{
71a85084 124 mutex_lock(&bpfilter_ops.lock);
61fbf593 125 if (IS_ENABLED(CONFIG_INET)) {
71a85084 126 shutdown_umh();
61fbf593
TY
127 bpfilter_ops.start = NULL;
128 bpfilter_ops.sockopt = NULL;
129 }
71a85084 130 mutex_unlock(&bpfilter_ops.lock);
e2dc9bf3
EB
131
132 umd_unload_blob(&bpfilter_ops.info);
d2ba09c1
AS
133}
134module_init(load_umh);
135module_exit(fini_umh);
136MODULE_LICENSE("GPL");