summaryrefslogtreecommitdiffstats
path: root/kernel/usermode_driver.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2020-06-25 23:48:26 +0200
committerEric W. Biederman <ebiederm@xmission.com>2020-07-04 16:35:56 +0200
commit1c340ead18ee4b4a84357abdef6d4f39ee08328b (patch)
tree412b58dd03cf04a9fd8cc26caae482628a0fbd71 /kernel/usermode_driver.c
parentbpfilter: Move bpfilter_umh back into init data (diff)
downloadlinux-1c340ead18ee4b4a84357abdef6d4f39ee08328b.tar.xz
linux-1c340ead18ee4b4a84357abdef6d4f39ee08328b.zip
umd: Track user space drivers with struct pid
Use struct pid instead of user space pid values that are prone to wrap araound. In addition track the entire thread group instead of just the first thread that is started by exec. There are no multi-threaded user mode drivers today but there is nothing preclucing user drivers from being multi-threaded, so it is just a good idea to track the entire process. Take a reference count on the tgid's in question to make it possible to remove exit_umh in a future change. As a struct pid is available directly use kill_pid_info. The prior process signalling code was iffy in using a userspace pid known to be in the initial pid namespace and then looking up it's task in whatever the current pid namespace is. It worked only because kernel threads always run in the initial pid namespace. As the tgid is now refcounted verify the tgid is NULL at the start of fork_usermode_driver to avoid the possibility of silent pid leaks. v1: https://lkml.kernel.org/r/87mu4qdlv2.fsf_-_@x220.int.ebiederm.org v2: https://lkml.kernel.org/r/a70l4oy8.fsf_-_@x220.int.ebiederm.org Link: https://lkml.kernel.org/r/20200702164140.4468-12-ebiederm@xmission.com Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Acked-by: Alexei Starovoitov <ast@kernel.org> Tested-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'kernel/usermode_driver.c')
-rw-r--r--kernel/usermode_driver.c15
1 files changed, 10 insertions, 5 deletions
diff --git a/kernel/usermode_driver.c b/kernel/usermode_driver.c
index a86798759f83..f77f8d7ce9e3 100644
--- a/kernel/usermode_driver.c
+++ b/kernel/usermode_driver.c
@@ -133,7 +133,7 @@ static int umd_setup(struct subprocess_info *info, struct cred *new)
set_fs_pwd(current->fs, &umd_info->wd);
umd_info->pipe_to_umh = to_umh[1];
umd_info->pipe_from_umh = from_umh[0];
- umd_info->pid = task_pid_nr(current);
+ umd_info->tgid = get_pid(task_tgid(current));
current->flags |= PF_UMH;
return 0;
}
@@ -146,6 +146,8 @@ static void umd_cleanup(struct subprocess_info *info)
if (info->retval) {
fput(umd_info->pipe_to_umh);
fput(umd_info->pipe_from_umh);
+ put_pid(umd_info->tgid);
+ umd_info->tgid = NULL;
}
}
@@ -155,9 +157,9 @@ static void umd_cleanup(struct subprocess_info *info)
*
* Returns either negative error or zero which indicates success in
* executing a usermode driver. In such case 'struct umd_info *info'
- * is populated with two pipes and a pid of the process. The caller is
+ * is populated with two pipes and a tgid of the process. The caller is
* responsible for health check of the user process, killing it via
- * pid, and closing the pipes when user process is no longer needed.
+ * tgid, and closing the pipes when user process is no longer needed.
*/
int fork_usermode_driver(struct umd_info *info)
{
@@ -165,6 +167,9 @@ int fork_usermode_driver(struct umd_info *info)
char **argv = NULL;
int err;
+ if (WARN_ON_ONCE(info->tgid))
+ return -EBUSY;
+
err = -ENOMEM;
argv = argv_split(GFP_KERNEL, info->driver_name, NULL);
if (!argv)
@@ -192,11 +197,11 @@ EXPORT_SYMBOL_GPL(fork_usermode_driver);
void __exit_umh(struct task_struct *tsk)
{
struct umd_info *info;
- pid_t pid = tsk->pid;
+ struct pid *tgid = task_tgid(tsk);
mutex_lock(&umh_list_lock);
list_for_each_entry(info, &umh_list, list) {
- if (info->pid == pid) {
+ if (info->tgid == tgid) {
list_del(&info->list);
mutex_unlock(&umh_list_lock);
goto out;