diff options
-rw-r--r-- | include/linux/bpfilter.h | 2 | ||||
-rw-r--r-- | net/bpfilter/bpfilter_kern.c | 37 | ||||
-rw-r--r-- | net/bpfilter/bpfilter_umh_blob.S | 2 | ||||
-rw-r--r-- | net/ipv4/bpfilter/sockopt.c | 11 |
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 | }; |
19 | extern struct bpfilter_umh_ops bpfilter_ops; | 21 | extern 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 */ |
17 | static DEFINE_MUTEX(bpfilter_lock); | 17 | static DEFINE_MUTEX(bpfilter_lock); |
18 | 18 | ||
19 | static void shutdown_umh(struct umh_info *info) | 19 | static 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 | ||
32 | static void __stop_umh(void) | 33 | static 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 | ||
40 | static void stop_umh(void) | 39 | static void stop_umh(void) |
@@ -85,7 +84,7 @@ out: | |||
85 | return ret; | 84 | return ret; |
86 | } | 85 | } |
87 | 86 | ||
88 | static int __init load_umh(void) | 87 | static 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 | ||
109 | static 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 | |||
111 | static void __exit fini_umh(void) | 124 | static 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 | } |
115 | module_init(load_umh); | 132 | module_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 |
4 | bpfilter_umh_start: | 4 | bpfilter_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 | ||
15 | static void bpfilter_umh_cleanup(struct umh_info *info) | 15 | static 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 | ||
54 | static int __init bpfilter_sockopt_init(void) | 62 | static 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 | ||