Commit e80eb1dc authored by Eric W. Biederman's avatar Eric W. Biederman

bpfilter: Take advantage of the facilities of struct pid

Instead of relying on the exit_umh cleanup callback use the fact a
struct pid can be tested to see if a process still exists, and that
struct pid has a wait queue that notifies when the process dies.

v1: https://lkml.kernel.org/r/87h7uydlu9.fsf_-_@x220.int.ebiederm.org
v2: https://lkml.kernel.org/r/874kqt4owu.fsf_-_@x220.int.ebiederm.org
Link: https://lkml.kernel.org/r/20200702164140.4468-14-ebiederm@xmission.comReviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
Tested-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parent 38fd525a
...@@ -10,6 +10,8 @@ int bpfilter_ip_set_sockopt(struct sock *sk, int optname, char __user *optval, ...@@ -10,6 +10,8 @@ int bpfilter_ip_set_sockopt(struct sock *sk, int optname, char __user *optval,
unsigned int optlen); unsigned int optlen);
int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval, int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval,
int __user *optlen); int __user *optlen);
void bpfilter_umh_cleanup(struct umd_info *info);
struct bpfilter_umh_ops { struct bpfilter_umh_ops {
struct umd_info info; struct umd_info info;
/* since ip_getsockopt() can run in parallel, serialize access to umh */ /* since ip_getsockopt() can run in parallel, serialize access to umh */
...@@ -18,7 +20,6 @@ struct bpfilter_umh_ops { ...@@ -18,7 +20,6 @@ struct bpfilter_umh_ops {
char __user *optval, char __user *optval,
unsigned int optlen, bool is_set); unsigned int optlen, bool is_set);
int (*start)(void); int (*start)(void);
bool stop;
}; };
extern struct bpfilter_umh_ops bpfilter_ops; extern struct bpfilter_umh_ops bpfilter_ops;
#endif #endif
...@@ -18,10 +18,11 @@ static void shutdown_umh(void) ...@@ -18,10 +18,11 @@ static void shutdown_umh(void)
struct umd_info *info = &bpfilter_ops.info; struct umd_info *info = &bpfilter_ops.info;
struct pid *tgid = info->tgid; struct pid *tgid = info->tgid;
if (bpfilter_ops.stop) if (tgid) {
return; kill_pid(tgid, SIGKILL, 1);
wait_event(tgid->wait_pidfd, thread_group_exited(tgid));
kill_pid(tgid, SIGKILL, 1); bpfilter_umh_cleanup(info);
}
} }
static void __stop_umh(void) static void __stop_umh(void)
...@@ -77,7 +78,6 @@ static int start_umh(void) ...@@ -77,7 +78,6 @@ static int start_umh(void)
err = fork_usermode_driver(&bpfilter_ops.info); err = fork_usermode_driver(&bpfilter_ops.info);
if (err) if (err)
return err; return err;
bpfilter_ops.stop = false;
pr_info("Loaded bpfilter_umh pid %d\n", pid_nr(bpfilter_ops.info.tgid)); pr_info("Loaded bpfilter_umh pid %d\n", pid_nr(bpfilter_ops.info.tgid));
/* health check that usermode process started correctly */ /* health check that usermode process started correctly */
...@@ -100,16 +100,11 @@ static int __init load_umh(void) ...@@ -100,16 +100,11 @@ static int __init load_umh(void)
return err; return err;
mutex_lock(&bpfilter_ops.lock); mutex_lock(&bpfilter_ops.lock);
if (!bpfilter_ops.stop) {
err = -EFAULT;
goto out;
}
err = start_umh(); err = start_umh();
if (!err && IS_ENABLED(CONFIG_INET)) { if (!err && IS_ENABLED(CONFIG_INET)) {
bpfilter_ops.sockopt = &__bpfilter_process_sockopt; bpfilter_ops.sockopt = &__bpfilter_process_sockopt;
bpfilter_ops.start = &start_umh; bpfilter_ops.start = &start_umh;
} }
out:
mutex_unlock(&bpfilter_ops.lock); mutex_unlock(&bpfilter_ops.lock);
if (err) if (err)
umd_unload_blob(&bpfilter_ops.info); umd_unload_blob(&bpfilter_ops.info);
......
...@@ -12,16 +12,14 @@ ...@@ -12,16 +12,14 @@
struct bpfilter_umh_ops bpfilter_ops; struct bpfilter_umh_ops bpfilter_ops;
EXPORT_SYMBOL_GPL(bpfilter_ops); EXPORT_SYMBOL_GPL(bpfilter_ops);
static void bpfilter_umh_cleanup(struct umd_info *info) void bpfilter_umh_cleanup(struct umd_info *info)
{ {
mutex_lock(&bpfilter_ops.lock);
bpfilter_ops.stop = true;
fput(info->pipe_to_umh); fput(info->pipe_to_umh);
fput(info->pipe_from_umh); fput(info->pipe_from_umh);
put_pid(info->tgid); put_pid(info->tgid);
info->tgid = NULL; info->tgid = NULL;
mutex_unlock(&bpfilter_ops.lock);
} }
EXPORT_SYMBOL_GPL(bpfilter_umh_cleanup);
static int bpfilter_mbox_request(struct sock *sk, int optname, static int bpfilter_mbox_request(struct sock *sk, int optname,
char __user *optval, char __user *optval,
...@@ -39,7 +37,11 @@ static int bpfilter_mbox_request(struct sock *sk, int optname, ...@@ -39,7 +37,11 @@ static int bpfilter_mbox_request(struct sock *sk, int optname,
goto out; goto out;
} }
} }
if (bpfilter_ops.stop) { if (bpfilter_ops.info.tgid &&
thread_group_exited(bpfilter_ops.info.tgid))
bpfilter_umh_cleanup(&bpfilter_ops.info);
if (!bpfilter_ops.info.tgid) {
err = bpfilter_ops.start(); err = bpfilter_ops.start();
if (err) if (err)
goto out; goto out;
...@@ -70,9 +72,8 @@ int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval, ...@@ -70,9 +72,8 @@ int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval,
static int __init bpfilter_sockopt_init(void) static int __init bpfilter_sockopt_init(void)
{ {
mutex_init(&bpfilter_ops.lock); mutex_init(&bpfilter_ops.lock);
bpfilter_ops.stop = true; bpfilter_ops.info.tgid = NULL;
bpfilter_ops.info.driver_name = "bpfilter_umh"; bpfilter_ops.info.driver_name = "bpfilter_umh";
bpfilter_ops.info.cleanup = &bpfilter_umh_cleanup;
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment