aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/bpfilter.h2
-rw-r--r--net/bpfilter/bpfilter_kern.c37
-rw-r--r--net/bpfilter/bpfilter_umh_blob.S2
-rw-r--r--net/ipv4/bpfilter/sockopt.c11
4 files changed, 40 insertions, 12 deletions
diff --git a/include/linux/bpfilter.h b/include/linux/bpfilter.h
index 70ffeed280e9..8ebcbdd70bdc 100644
--- a/include/linux/bpfilter.h
+++ b/include/linux/bpfilter.h
@@ -15,6 +15,8 @@ struct bpfilter_umh_ops {
15 int (*sockopt)(struct sock *sk, int optname, 15 int (*sockopt)(struct sock *sk, int optname,
16 char __user *optval, 16 char __user *optval,
17 unsigned int optlen, bool is_set); 17 unsigned int optlen, bool is_set);
18 int (*start)(void);
19 bool stop;
18}; 20};
19extern struct bpfilter_umh_ops bpfilter_ops; 21extern struct bpfilter_umh_ops bpfilter_ops;
20#endif 22#endif
diff --git a/net/bpfilter/bpfilter_kern.c b/net/bpfilter/bpfilter_kern.c
index a68940b74c01..c0fcde910a7a 100644
--- a/net/bpfilter/bpfilter_kern.c
+++ b/net/bpfilter/bpfilter_kern.c
@@ -16,13 +16,14 @@ extern char bpfilter_umh_end;
16/* since ip_getsockopt() can run in parallel, serialize access to umh */ 16/* since ip_getsockopt() can run in parallel, serialize access to umh */
17static DEFINE_MUTEX(bpfilter_lock); 17static DEFINE_MUTEX(bpfilter_lock);
18 18
19static void shutdown_umh(struct umh_info *info) 19static void shutdown_umh(void)
20{ 20{
21 struct task_struct *tsk; 21 struct task_struct *tsk;
22 22
23 if (!info->pid) 23 if (bpfilter_ops.stop)
24 return; 24 return;
25 tsk = get_pid_task(find_vpid(info->pid), PIDTYPE_PID); 25
26 tsk = get_pid_task(find_vpid(bpfilter_ops.info.pid), PIDTYPE_PID);
26 if (tsk) { 27 if (tsk) {
27 force_sig(SIGKILL, tsk); 28 force_sig(SIGKILL, tsk);
28 put_task_struct(tsk); 29 put_task_struct(tsk);
@@ -31,10 +32,8 @@ static void shutdown_umh(struct umh_info *info)
31 32
32static void __stop_umh(void) 33static void __stop_umh(void)
33{ 34{
34 if (IS_ENABLED(CONFIG_INET)) { 35 if (IS_ENABLED(CONFIG_INET))
35 bpfilter_ops.sockopt = NULL; 36 shutdown_umh();
36 shutdown_umh(&bpfilter_ops.info);
37 }
38} 37}
39 38
40static void stop_umh(void) 39static void stop_umh(void)
@@ -85,7 +84,7 @@ out:
85 return ret; 84 return ret;
86} 85}
87 86
88static int __init load_umh(void) 87static int start_umh(void)
89{ 88{
90 int err; 89 int err;
91 90
@@ -95,6 +94,7 @@ static int __init load_umh(void)
95 &bpfilter_ops.info); 94 &bpfilter_ops.info);
96 if (err) 95 if (err)
97 return err; 96 return err;
97 bpfilter_ops.stop = false;
98 pr_info("Loaded bpfilter_umh pid %d\n", bpfilter_ops.info.pid); 98 pr_info("Loaded bpfilter_umh pid %d\n", bpfilter_ops.info.pid);
99 99
100 /* health check that usermode process started correctly */ 100 /* health check that usermode process started correctly */
@@ -102,14 +102,31 @@ static int __init load_umh(void)
102 stop_umh(); 102 stop_umh();
103 return -EFAULT; 103 return -EFAULT;
104 } 104 }
105 if (IS_ENABLED(CONFIG_INET))
106 bpfilter_ops.sockopt = &__bpfilter_process_sockopt;
107 105
108 return 0; 106 return 0;
109} 107}
110 108
109static int __init load_umh(void)
110{
111 int err;
112
113 if (!bpfilter_ops.stop)
114 return -EFAULT;
115 err = start_umh();
116 if (!err && IS_ENABLED(CONFIG_INET)) {
117 bpfilter_ops.sockopt = &__bpfilter_process_sockopt;
118 bpfilter_ops.start = &start_umh;
119 }
120
121 return err;
122}
123
111static void __exit fini_umh(void) 124static void __exit fini_umh(void)
112{ 125{
126 if (IS_ENABLED(CONFIG_INET)) {
127 bpfilter_ops.start = NULL;
128 bpfilter_ops.sockopt = NULL;
129 }
113 stop_umh(); 130 stop_umh();
114} 131}
115module_init(load_umh); 132module_init(load_umh);
diff --git a/net/bpfilter/bpfilter_umh_blob.S b/net/bpfilter/bpfilter_umh_blob.S
index 40311d10d2f2..7f1c521dcc2f 100644
--- a/net/bpfilter/bpfilter_umh_blob.S
+++ b/net/bpfilter/bpfilter_umh_blob.S
@@ -1,5 +1,5 @@
1/* SPDX-License-Identifier: GPL-2.0 */ 1/* SPDX-License-Identifier: GPL-2.0 */
2 .section .init.rodata, "a" 2 .section .bpfilter_umh, "a"
3 .global bpfilter_umh_start 3 .global bpfilter_umh_start
4bpfilter_umh_start: 4bpfilter_umh_start:
5 .incbin "net/bpfilter/bpfilter_umh" 5 .incbin "net/bpfilter/bpfilter_umh"
diff --git a/net/ipv4/bpfilter/sockopt.c b/net/ipv4/bpfilter/sockopt.c
index c326cfbc0f62..de84ede4e765 100644
--- a/net/ipv4/bpfilter/sockopt.c
+++ b/net/ipv4/bpfilter/sockopt.c
@@ -14,6 +14,7 @@ EXPORT_SYMBOL_GPL(bpfilter_ops);
14 14
15static void bpfilter_umh_cleanup(struct umh_info *info) 15static void bpfilter_umh_cleanup(struct umh_info *info)
16{ 16{
17 bpfilter_ops.stop = true;
17 fput(info->pipe_to_umh); 18 fput(info->pipe_to_umh);
18 fput(info->pipe_from_umh); 19 fput(info->pipe_from_umh);
19 info->pid = 0; 20 info->pid = 0;
@@ -23,14 +24,21 @@ static int bpfilter_mbox_request(struct sock *sk, int optname,
23 char __user *optval, 24 char __user *optval,
24 unsigned int optlen, bool is_set) 25 unsigned int optlen, bool is_set)
25{ 26{
27 int err;
28
26 if (!bpfilter_ops.sockopt) { 29 if (!bpfilter_ops.sockopt) {
27 int err = request_module("bpfilter"); 30 err = request_module("bpfilter");
28 31
29 if (err) 32 if (err)
30 return err; 33 return err;
31 if (!bpfilter_ops.sockopt) 34 if (!bpfilter_ops.sockopt)
32 return -ECHILD; 35 return -ECHILD;
33 } 36 }
37 if (bpfilter_ops.stop) {
38 err = bpfilter_ops.start();
39 if (err)
40 return err;
41 }
34 return bpfilter_ops.sockopt(sk, optname, optval, optlen, is_set); 42 return bpfilter_ops.sockopt(sk, optname, optval, optlen, is_set);
35} 43}
36 44
@@ -53,6 +61,7 @@ int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval,
53 61
54static int __init bpfilter_sockopt_init(void) 62static int __init bpfilter_sockopt_init(void)
55{ 63{
64 bpfilter_ops.stop = true;
56 bpfilter_ops.info.cmdline = "bpfilter_umh"; 65 bpfilter_ops.info.cmdline = "bpfilter_umh";
57 bpfilter_ops.info.cleanup = &bpfilter_umh_cleanup; 66 bpfilter_ops.info.cleanup = &bpfilter_umh_cleanup;
58 67