-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path004-lock-bpfilter_umh-in-use.patch
161 lines (148 loc) · 4.31 KB
/
004-lock-bpfilter_umh-in-use.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
diff --git a/include/linux/bpfilter.h b/include/linux/bpfilter.h
index 8ebcbdd70..d815622cd 100644
--- a/include/linux/bpfilter.h
+++ b/include/linux/bpfilter.h
@@ -12,6 +12,8 @@ int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval,
int __user *optlen);
struct bpfilter_umh_ops {
struct umh_info info;
+ /* since ip_getsockopt() can run in parallel, serialize access to umh */
+ struct mutex lock;
int (*sockopt)(struct sock *sk, int optname,
char __user *optval,
unsigned int optlen, bool is_set);
diff --git a/net/bpfilter/bpfilter_kern.c b/net/bpfilter/bpfilter_kern.c
index c0fcde910..7ee4fea93 100644
--- a/net/bpfilter/bpfilter_kern.c
+++ b/net/bpfilter/bpfilter_kern.c
@@ -13,9 +13,6 @@
extern char bpfilter_umh_start;
extern char bpfilter_umh_end;
-/* since ip_getsockopt() can run in parallel, serialize access to umh */
-static DEFINE_MUTEX(bpfilter_lock);
-
static void shutdown_umh(void)
{
struct task_struct *tsk;
@@ -36,13 +33,6 @@ static void __stop_umh(void)
shutdown_umh();
}
-static void stop_umh(void)
-{
- mutex_lock(&bpfilter_lock);
- __stop_umh();
- mutex_unlock(&bpfilter_lock);
-}
-
static int __bpfilter_process_sockopt(struct sock *sk, int optname,
char __user *optval,
unsigned int optlen, bool is_set)
@@ -58,7 +48,6 @@ static int __bpfilter_process_sockopt(struct sock *sk, int optname,
req.cmd = optname;
req.addr = (long __force __user)optval;
req.len = optlen;
- mutex_lock(&bpfilter_lock);
if (!bpfilter_ops.info.pid)
goto out;
n = __kernel_write(bpfilter_ops.info.pipe_to_umh, &req, sizeof(req),
@@ -80,7 +69,6 @@ static int __bpfilter_process_sockopt(struct sock *sk, int optname,
}
ret = reply.status;
out:
- mutex_unlock(&bpfilter_lock);
return ret;
}
@@ -99,7 +87,7 @@ static int start_umh(void)
/* health check that usermode process started correctly */
if (__bpfilter_process_sockopt(NULL, 0, NULL, 0, 0) != 0) {
- stop_umh();
+ shutdown_umh();
return -EFAULT;
}
@@ -110,24 +98,30 @@ static int __init load_umh(void)
{
int err;
- if (!bpfilter_ops.stop)
- return -EFAULT;
+ mutex_lock(&bpfilter_ops.lock);
+ if (!bpfilter_ops.stop) {
+ err = -EFAULT;
+ goto out;
+ }
err = start_umh();
if (!err && IS_ENABLED(CONFIG_INET)) {
bpfilter_ops.sockopt = &__bpfilter_process_sockopt;
bpfilter_ops.start = &start_umh;
}
-
+out:
+ mutex_unlock(&bpfilter_ops.lock);
return err;
}
static void __exit fini_umh(void)
{
+ mutex_lock(&bpfilter_ops.lock);
if (IS_ENABLED(CONFIG_INET)) {
+ shutdown_umh();
bpfilter_ops.start = NULL;
bpfilter_ops.sockopt = NULL;
}
- stop_umh();
+ mutex_unlock(&bpfilter_ops.lock);
}
module_init(load_umh);
module_exit(fini_umh);
diff --git a/net/ipv4/bpfilter/sockopt.c b/net/ipv4/bpfilter/sockopt.c
index de84ede4e..1e976bb93 100644
--- a/net/ipv4/bpfilter/sockopt.c
+++ b/net/ipv4/bpfilter/sockopt.c
@@ -14,10 +14,12 @@ EXPORT_SYMBOL_GPL(bpfilter_ops);
static void bpfilter_umh_cleanup(struct umh_info *info)
{
+ mutex_lock(&bpfilter_ops.lock);
bpfilter_ops.stop = true;
fput(info->pipe_to_umh);
fput(info->pipe_from_umh);
info->pid = 0;
+ mutex_unlock(&bpfilter_ops.lock);
}
static int bpfilter_mbox_request(struct sock *sk, int optname,
@@ -25,21 +27,28 @@ static int bpfilter_mbox_request(struct sock *sk, int optname,
unsigned int optlen, bool is_set)
{
int err;
-
+ mutex_lock(&bpfilter_ops.lock);
if (!bpfilter_ops.sockopt) {
+ mutex_unlock(&bpfilter_ops.lock);
err = request_module("bpfilter");
+ mutex_lock(&bpfilter_ops.lock);
if (err)
- return err;
- if (!bpfilter_ops.sockopt)
- return -ECHILD;
+ goto out;
+ if (!bpfilter_ops.sockopt) {
+ err = -ECHILD;
+ goto out;
+ }
}
if (bpfilter_ops.stop) {
err = bpfilter_ops.start();
if (err)
- return err;
+ goto out;
}
- return bpfilter_ops.sockopt(sk, optname, optval, optlen, is_set);
+ err = bpfilter_ops.sockopt(sk, optname, optval, optlen, is_set);
+out:
+ mutex_unlock(&bpfilter_ops.lock);
+ return err;
}
int bpfilter_ip_set_sockopt(struct sock *sk, int optname, char __user *optval,
@@ -61,6 +70,7 @@ int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval,
static int __init bpfilter_sockopt_init(void)
{
+ mutex_init(&bpfilter_ops.lock);
bpfilter_ops.stop = true;
bpfilter_ops.info.cleanup = &bpfilter_umh_cleanup;