Skip to content

Commit 1c340ea

Browse files
committed
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/[email protected] v2: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Reviewed-by: Greg Kroah-Hartman <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Tested-by: Alexei Starovoitov <[email protected]> Signed-off-by: "Eric W. Biederman" <[email protected]>
1 parent 0fe3c63 commit 1c340ea

File tree

5 files changed

+20
-16
lines changed

5 files changed

+20
-16
lines changed

include/linux/usermode_driver.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ struct umd_info {
2525
struct list_head list;
2626
void (*cleanup)(struct umd_info *info);
2727
struct path wd;
28-
pid_t pid;
28+
struct pid *tgid;
2929
};
3030
int umd_load_blob(struct umd_info *info, const void *data, size_t len);
3131
int umd_unload_blob(struct umd_info *info);

kernel/exit.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,8 @@ void __noreturn do_exit(long code)
805805
exit_task_namespaces(tsk);
806806
exit_task_work(tsk);
807807
exit_thread(tsk);
808-
exit_umh(tsk);
808+
if (group_dead)
809+
exit_umh(tsk);
809810

810811
/*
811812
* Flush inherited counters to the parent - before the parent

kernel/usermode_driver.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ static int umd_setup(struct subprocess_info *info, struct cred *new)
133133
set_fs_pwd(current->fs, &umd_info->wd);
134134
umd_info->pipe_to_umh = to_umh[1];
135135
umd_info->pipe_from_umh = from_umh[0];
136-
umd_info->pid = task_pid_nr(current);
136+
umd_info->tgid = get_pid(task_tgid(current));
137137
current->flags |= PF_UMH;
138138
return 0;
139139
}
@@ -146,6 +146,8 @@ static void umd_cleanup(struct subprocess_info *info)
146146
if (info->retval) {
147147
fput(umd_info->pipe_to_umh);
148148
fput(umd_info->pipe_from_umh);
149+
put_pid(umd_info->tgid);
150+
umd_info->tgid = NULL;
149151
}
150152
}
151153

@@ -155,16 +157,19 @@ static void umd_cleanup(struct subprocess_info *info)
155157
*
156158
* Returns either negative error or zero which indicates success in
157159
* executing a usermode driver. In such case 'struct umd_info *info'
158-
* is populated with two pipes and a pid of the process. The caller is
160+
* is populated with two pipes and a tgid of the process. The caller is
159161
* responsible for health check of the user process, killing it via
160-
* pid, and closing the pipes when user process is no longer needed.
162+
* tgid, and closing the pipes when user process is no longer needed.
161163
*/
162164
int fork_usermode_driver(struct umd_info *info)
163165
{
164166
struct subprocess_info *sub_info;
165167
char **argv = NULL;
166168
int err;
167169

170+
if (WARN_ON_ONCE(info->tgid))
171+
return -EBUSY;
172+
168173
err = -ENOMEM;
169174
argv = argv_split(GFP_KERNEL, info->driver_name, NULL);
170175
if (!argv)
@@ -192,11 +197,11 @@ EXPORT_SYMBOL_GPL(fork_usermode_driver);
192197
void __exit_umh(struct task_struct *tsk)
193198
{
194199
struct umd_info *info;
195-
pid_t pid = tsk->pid;
200+
struct pid *tgid = task_tgid(tsk);
196201

197202
mutex_lock(&umh_list_lock);
198203
list_for_each_entry(info, &umh_list, list) {
199-
if (info->pid == pid) {
204+
if (info->tgid == tgid) {
200205
list_del(&info->list);
201206
mutex_unlock(&umh_list_lock);
202207
goto out;

net/bpfilter/bpfilter_kern.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,13 @@ extern char bpfilter_umh_end;
1515

1616
static void shutdown_umh(void)
1717
{
18-
struct task_struct *tsk;
18+
struct umd_info *info = &bpfilter_ops.info;
19+
struct pid *tgid = info->tgid;
1920

2021
if (bpfilter_ops.stop)
2122
return;
2223

23-
tsk = get_pid_task(find_vpid(bpfilter_ops.info.pid), PIDTYPE_PID);
24-
if (tsk) {
25-
send_sig(SIGKILL, tsk, 1);
26-
put_task_struct(tsk);
27-
}
24+
kill_pid(tgid, SIGKILL, 1);
2825
}
2926

3027
static void __stop_umh(void)
@@ -48,7 +45,7 @@ static int __bpfilter_process_sockopt(struct sock *sk, int optname,
4845
req.cmd = optname;
4946
req.addr = (long __force __user)optval;
5047
req.len = optlen;
51-
if (!bpfilter_ops.info.pid)
48+
if (!bpfilter_ops.info.tgid)
5249
goto out;
5350
n = __kernel_write(bpfilter_ops.info.pipe_to_umh, &req, sizeof(req),
5451
&pos);
@@ -81,7 +78,7 @@ static int start_umh(void)
8178
if (err)
8279
return err;
8380
bpfilter_ops.stop = false;
84-
pr_info("Loaded bpfilter_umh pid %d\n", bpfilter_ops.info.pid);
81+
pr_info("Loaded bpfilter_umh pid %d\n", pid_nr(bpfilter_ops.info.tgid));
8582

8683
/* health check that usermode process started correctly */
8784
if (__bpfilter_process_sockopt(NULL, 0, NULL, 0, 0) != 0) {

net/ipv4/bpfilter/sockopt.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ static void bpfilter_umh_cleanup(struct umd_info *info)
1818
bpfilter_ops.stop = true;
1919
fput(info->pipe_to_umh);
2020
fput(info->pipe_from_umh);
21-
info->pid = 0;
21+
put_pid(info->tgid);
22+
info->tgid = NULL;
2223
mutex_unlock(&bpfilter_ops.lock);
2324
}
2425

0 commit comments

Comments
 (0)