Skip to content

Commit 031e399

Browse files
author
Naadir Jeewa
committed
Linux 4.19.285-2: Add fixes for bpfilter and usermode helpers
affecting iptables. Signed-off-by: Naadir Jeewa <[email protected]>
1 parent 2480c8a commit 031e399

12 files changed

+1056
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
From 5b4cb650e569db2e6a09d2fa0ef8eb789a0ac5d8 Mon Sep 17 00:00:00 2001
2+
From: Taehee Yoo <[email protected]>
3+
Date: Wed, 9 Jan 2019 02:24:34 +0900
4+
Subject: [PATCH] net: bpfilter: use cleanup callback to release umh_info
5+
6+
Now, UMH process is killed, do_exit() calls the umh_info->cleanup callback
7+
to release members of the umh_info.
8+
This patch makes bpfilter_umh's cleanup routine to use the
9+
umh_info->cleanup callback.
10+
11+
Signed-off-by: Taehee Yoo <[email protected]>
12+
Signed-off-by: David S. Miller <[email protected]>
13+
---
14+
include/linux/bpfilter.h | 11 ++++++++---
15+
net/bpfilter/bpfilter_kern.c | 23 ++++++++++-------------
16+
net/ipv4/bpfilter/sockopt.c | 33 ++++++++++++++++++++++++++-------
17+
3 files changed, 44 insertions(+), 23 deletions(-)
18+
19+
diff --git a/include/linux/bpfilter.h b/include/linux/bpfilter.h
20+
index f02cee0225d4..70ffeed280e9 100644
21+
--- a/include/linux/bpfilter.h
22+
+++ b/include/linux/bpfilter.h
23+
@@ -3,13 +3,18 @@
24+
#define _LINUX_BPFILTER_H
25+
26+
#include <uapi/linux/bpfilter.h>
27+
+#include <linux/umh.h>
28+
29+
struct sock;
30+
int bpfilter_ip_set_sockopt(struct sock *sk, int optname, char __user *optval,
31+
unsigned int optlen);
32+
int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval,
33+
int __user *optlen);
34+
-extern int (*bpfilter_process_sockopt)(struct sock *sk, int optname,
35+
- char __user *optval,
36+
- unsigned int optlen, bool is_set);
37+
+struct bpfilter_umh_ops {
38+
+ struct umh_info info;
39+
+ int (*sockopt)(struct sock *sk, int optname,
40+
+ char __user *optval,
41+
+ unsigned int optlen, bool is_set);
42+
+};
43+
+extern struct bpfilter_umh_ops bpfilter_ops;
44+
#endif
45+
diff --git a/net/bpfilter/bpfilter_kern.c b/net/bpfilter/bpfilter_kern.c
46+
index 7acfc83087d5..a68940b74c01 100644
47+
--- a/net/bpfilter/bpfilter_kern.c
48+
+++ b/net/bpfilter/bpfilter_kern.c
49+
@@ -13,7 +13,6 @@
50+
extern char bpfilter_umh_start;
51+
extern char bpfilter_umh_end;
52+
53+
-static struct umh_info info;
54+
/* since ip_getsockopt() can run in parallel, serialize access to umh */
55+
static DEFINE_MUTEX(bpfilter_lock);
56+
57+
@@ -28,16 +27,13 @@ static void shutdown_umh(struct umh_info *info)
58+
send_sig(SIGKILL, tsk, 1);
59+
put_task_struct(tsk);
60+
}
61+
- fput(info->pipe_to_umh);
62+
- fput(info->pipe_from_umh);
63+
- info->pid = 0;
64+
}
65+
66+
static void __stop_umh(void)
67+
{
68+
if (IS_ENABLED(CONFIG_INET)) {
69+
- bpfilter_process_sockopt = NULL;
70+
- shutdown_umh(&info);
71+
+ bpfilter_ops.sockopt = NULL;
72+
+ shutdown_umh(&bpfilter_ops.info);
73+
}
74+
}
75+
76+
@@ -64,9 +60,10 @@ static int __bpfilter_process_sockopt(struct sock *sk, int optname,
77+
req.addr = (long __force __user)optval;
78+
req.len = optlen;
79+
mutex_lock(&bpfilter_lock);
80+
- if (!info.pid)
81+
+ if (!bpfilter_ops.info.pid)
82+
goto out;
83+
- n = __kernel_write(info.pipe_to_umh, &req, sizeof(req), &pos);
84+
+ n = __kernel_write(bpfilter_ops.info.pipe_to_umh, &req, sizeof(req),
85+
+ &pos);
86+
if (n != sizeof(req)) {
87+
pr_err("write fail %zd\n", n);
88+
__stop_umh();
89+
@@ -74,7 +71,8 @@ static int __bpfilter_process_sockopt(struct sock *sk, int optname,
90+
goto out;
91+
}
92+
pos = 0;
93+
- n = kernel_read(info.pipe_from_umh, &reply, sizeof(reply), &pos);
94+
+ n = kernel_read(bpfilter_ops.info.pipe_from_umh, &reply, sizeof(reply),
95+
+ &pos);
96+
if (n != sizeof(reply)) {
97+
pr_err("read fail %zd\n", n);
98+
__stop_umh();
99+
@@ -94,10 +94,10 @@ static int __init load_umh(void)
100+
/* fork usermode process */
101+
err = fork_usermode_blob(&bpfilter_umh_start,
102+
&bpfilter_umh_end - &bpfilter_umh_start,
103+
- &info);
104+
+ &bpfilter_ops.info);
105+
if (err)
106+
return err;
107+
- pr_info("Loaded bpfilter_umh pid %d\n", info.pid);
108+
+ pr_info("Loaded bpfilter_umh pid %d\n", bpfilter_ops.info.pid);
109+
110+
/* health check that usermode process started correctly */
111+
if (__bpfilter_process_sockopt(NULL, 0, NULL, 0, 0) != 0) {
112+
@@ -106,7 +103,7 @@ static int __init load_umh(void)
113+
return -EFAULT;
114+
}
115+
if (IS_ENABLED(CONFIG_INET))
116+
- bpfilter_process_sockopt = &__bpfilter_process_sockopt;
117+
+ bpfilter_ops.sockopt = &__bpfilter_process_sockopt;
118+
119+
return 0;
120+
}
121+
diff --git a/net/ipv4/bpfilter/sockopt.c b/net/ipv4/bpfilter/sockopt.c
122+
index 5e04ed25bc0e..c326cfbc0f62 100644
123+
--- a/net/ipv4/bpfilter/sockopt.c
124+
+++ b/net/ipv4/bpfilter/sockopt.c
125+
@@ -1,28 +1,37 @@
126+
// SPDX-License-Identifier: GPL-2.0
127+
+#include <linux/init.h>
128+
+#include <linux/module.h>
129+
#include <linux/uaccess.h>
130+
#include <linux/bpfilter.h>
131+
#include <uapi/linux/bpf.h>
132+
#include <linux/wait.h>
133+
#include <linux/kmod.h>
134+
+#include <linux/fs.h>
135+
+#include <linux/file.h>
136+
137+
-int (*bpfilter_process_sockopt)(struct sock *sk, int optname,
138+
- char __user *optval,
139+
- unsigned int optlen, bool is_set);
140+
-EXPORT_SYMBOL_GPL(bpfilter_process_sockopt);
141+
+struct bpfilter_umh_ops bpfilter_ops;
142+
+EXPORT_SYMBOL_GPL(bpfilter_ops);
143+
+
144+
+static void bpfilter_umh_cleanup(struct umh_info *info)
145+
+{
146+
+ fput(info->pipe_to_umh);
147+
+ fput(info->pipe_from_umh);
148+
+ info->pid = 0;
149+
+}
150+
151+
static int bpfilter_mbox_request(struct sock *sk, int optname,
152+
char __user *optval,
153+
unsigned int optlen, bool is_set)
154+
{
155+
- if (!bpfilter_process_sockopt) {
156+
+ if (!bpfilter_ops.sockopt) {
157+
int err = request_module("bpfilter");
158+
159+
if (err)
160+
return err;
161+
- if (!bpfilter_process_sockopt)
162+
+ if (!bpfilter_ops.sockopt)
163+
return -ECHILD;
164+
}
165+
- return bpfilter_process_sockopt(sk, optname, optval, optlen, is_set);
166+
+ return bpfilter_ops.sockopt(sk, optname, optval, optlen, is_set);
167+
}
168+
169+
int bpfilter_ip_set_sockopt(struct sock *sk, int optname, char __user *optval,
170+
@@ -41,3 +50,13 @@ int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval,
171+
172+
return bpfilter_mbox_request(sk, optname, optval, len, false);
173+
}
174+
+
175+
+static int __init bpfilter_sockopt_init(void)
176+
+{
177+
+ bpfilter_ops.info.cmdline = "bpfilter_umh";
178+
+ bpfilter_ops.info.cleanup = &bpfilter_umh_cleanup;
179+
+
180+
+ return 0;
181+
+}
182+
+
183+
+module_init(bpfilter_sockopt_init);
184+
--
185+
2.41.0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
From 876dcf2f3aaa0f68d437b368b93a4c4b81521191 Mon Sep 17 00:00:00 2001
2+
From: Olivier Brunel <[email protected]>
3+
Date: Sat, 20 Oct 2018 19:39:56 +0200
4+
Subject: [PATCH] umh: Add command line to user mode helpers
5+
6+
User mode helpers were spawned without a command line, and because
7+
an empty command line is used by many tools to identify processes as
8+
kernel threads, this could cause some issues.
9+
10+
Notably during killing spree on shutdown, since such helper would then
11+
be skipped (i.e. not killed) which would result in the process remaining
12+
alive, and thus preventing unmouting of the rootfs (as experienced with
13+
the bpfilter umh).
14+
15+
Fixes: 449325b52b7a ("umh: introduce fork_usermode_blob() helper")
16+
Signed-off-by: Olivier Brunel <[email protected]>
17+
Signed-off-by: David S. Miller <[email protected]>
18+
---
19+
include/linux/umh.h | 1 +
20+
kernel/umh.c | 16 ++++++++++++++--
21+
2 files changed, 15 insertions(+), 2 deletions(-)
22+
23+
diff --git a/include/linux/umh.h b/include/linux/umh.h
24+
index 5c812acbb80a..235f51b62c71 100644
25+
--- a/include/linux/umh.h
26+
+++ b/include/linux/umh.h
27+
@@ -44,6 +44,7 @@ struct subprocess_info *call_usermodehelper_setup_file(struct file *file,
28+
int (*init)(struct subprocess_info *info, struct cred *new),
29+
void (*cleanup)(struct subprocess_info *), void *data);
30+
struct umh_info {
31+
+ const char *cmdline;
32+
struct file *pipe_to_umh;
33+
struct file *pipe_from_umh;
34+
pid_t pid;
35+
diff --git a/kernel/umh.c b/kernel/umh.c
36+
index c449858946af..0baa672e023c 100644
37+
--- a/kernel/umh.c
38+
+++ b/kernel/umh.c
39+
@@ -405,11 +405,19 @@ struct subprocess_info *call_usermodehelper_setup_file(struct file *file,
40+
void (*cleanup)(struct subprocess_info *info), void *data)
41+
{
42+
struct subprocess_info *sub_info;
43+
+ struct umh_info *info = data;
44+
+ const char *cmdline = (info->cmdline) ? info->cmdline : "usermodehelper";
45+
46+
sub_info = kzalloc(sizeof(struct subprocess_info), GFP_KERNEL);
47+
if (!sub_info)
48+
return NULL;
49+
50+
+ sub_info->argv = argv_split(GFP_KERNEL, cmdline, NULL);
51+
+ if (!sub_info->argv) {
52+
+ kfree(sub_info);
53+
+ return NULL;
54+
+ }
55+
+
56+
INIT_WORK(&sub_info->work, call_usermodehelper_exec_work);
57+
sub_info->path = "none";
58+
sub_info->file = file;
59+
@@ -458,10 +466,11 @@ static int umh_pipe_setup(struct subprocess_info *info, struct cred *new)
60+
return 0;
61+
}
62+
63+
-static void umh_save_pid(struct subprocess_info *info)
64+
+static void umh_clean_and_save_pid(struct subprocess_info *info)
65+
{
66+
struct umh_info *umh_info = info->data;
67+
68+
+ argv_free(info->argv);
69+
umh_info->pid = info->pid;
70+
}
71+
72+
@@ -471,6 +480,9 @@ static void umh_save_pid(struct subprocess_info *info)
73+
* @len: length of the blob
74+
* @info: information about usermode process (shouldn't be NULL)
75+
*
76+
+ * If info->cmdline is set it will be used as command line for the
77+
+ * user process, else "usermodehelper" is used.
78+
+ *
79+
* Returns either negative error or zero which indicates success
80+
* in executing a blob of bytes as a usermode process. In such
81+
* case 'struct umh_info *info' is populated with two pipes
82+
@@ -500,7 +512,7 @@ int fork_usermode_blob(void *data, size_t len, struct umh_info *info)
83+
84+
err = -ENOMEM;
85+
sub_info = call_usermodehelper_setup_file(file, umh_pipe_setup,
86+
- umh_save_pid, info);
87+
+ umh_clean_and_save_pid, info);
88+
if (!sub_info)
89+
goto out;
90+
91+
--
92+
2.41.0
93+

0 commit comments

Comments
 (0)