Skip to content

Commit e2dc9bf

Browse files
committed
umd: Transform fork_usermode_blob into fork_usermode_driver
Instead of loading a binary blob into a temporary file with shmem_kernel_file_setup load a binary blob into a temporary tmpfs filesystem. This means that the blob can be stored in an init section and discared, and it means the binary blob will have a filename so can be executed normally. The only tricky thing about this code is that in the helper function blob_to_mnt __fput_sync is used. That is because a file can not be executed if it is still open for write, and the ordinary delayed close for kernel threads does not happen soon enough, which causes the following exec to fail. The function umd_load_blob is not called with any locks so this should be safe. Executing the blob normally winds up correcting several problems with the user mode driver code discovered by Tetsuo Handa[1]. By passing an ordinary filename into the exec, it is no longer necessary to figure out how to turn a O_RDWR file descriptor into a properly referende counted O_EXEC file descriptor that forbids all writes. For path based LSMs there are no new special cases. [1] https://lore.kernel.org/linux-fsdevel/[email protected]/ 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 1199c6c commit e2dc9bf

File tree

3 files changed

+113
-33
lines changed

3 files changed

+113
-33
lines changed

include/linux/usermode_driver.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define __LINUX_USERMODE_DRIVER_H__
33

44
#include <linux/umh.h>
5+
#include <linux/path.h>
56

67
#ifdef CONFIG_BPFILTER
78
void __exit_umh(struct task_struct *tsk);
@@ -23,8 +24,11 @@ struct umd_info {
2324
struct file *pipe_from_umh;
2425
struct list_head list;
2526
void (*cleanup)(struct umd_info *info);
27+
struct path wd;
2628
pid_t pid;
2729
};
28-
int fork_usermode_blob(void *data, size_t len, struct umd_info *info);
30+
int umd_load_blob(struct umd_info *info, const void *data, size_t len);
31+
int umd_unload_blob(struct umd_info *info);
32+
int fork_usermode_driver(struct umd_info *info);
2933

3034
#endif /* __LINUX_USERMODE_DRIVER_H__ */

kernel/usermode_driver.c

Lines changed: 97 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,98 @@
44
*/
55
#include <linux/shmem_fs.h>
66
#include <linux/pipe_fs_i.h>
7+
#include <linux/mount.h>
8+
#include <linux/fs_struct.h>
9+
#include <linux/task_work.h>
710
#include <linux/usermode_driver.h>
811

912
static LIST_HEAD(umh_list);
1013
static DEFINE_MUTEX(umh_list_lock);
1114

15+
static struct vfsmount *blob_to_mnt(const void *data, size_t len, const char *name)
16+
{
17+
struct file_system_type *type;
18+
struct vfsmount *mnt;
19+
struct file *file;
20+
ssize_t written;
21+
loff_t pos = 0;
22+
23+
type = get_fs_type("tmpfs");
24+
if (!type)
25+
return ERR_PTR(-ENODEV);
26+
27+
mnt = kern_mount(type);
28+
put_filesystem(type);
29+
if (IS_ERR(mnt))
30+
return mnt;
31+
32+
file = file_open_root(mnt->mnt_root, mnt, name, O_CREAT | O_WRONLY, 0700);
33+
if (IS_ERR(file)) {
34+
mntput(mnt);
35+
return ERR_CAST(file);
36+
}
37+
38+
written = kernel_write(file, data, len, &pos);
39+
if (written != len) {
40+
int err = written;
41+
if (err >= 0)
42+
err = -ENOMEM;
43+
filp_close(file, NULL);
44+
mntput(mnt);
45+
return ERR_PTR(err);
46+
}
47+
48+
fput(file);
49+
50+
/* Flush delayed fput so exec can open the file read-only */
51+
flush_delayed_fput();
52+
task_work_run();
53+
return mnt;
54+
}
55+
56+
/**
57+
* umd_load_blob - Remember a blob of bytes for fork_usermode_driver
58+
* @info: information about usermode driver
59+
* @data: a blob of bytes that can be executed as a file
60+
* @len: The lentgh of the blob
61+
*
62+
*/
63+
int umd_load_blob(struct umd_info *info, const void *data, size_t len)
64+
{
65+
struct vfsmount *mnt;
66+
67+
if (WARN_ON_ONCE(info->wd.dentry || info->wd.mnt))
68+
return -EBUSY;
69+
70+
mnt = blob_to_mnt(data, len, info->driver_name);
71+
if (IS_ERR(mnt))
72+
return PTR_ERR(mnt);
73+
74+
info->wd.mnt = mnt;
75+
info->wd.dentry = mnt->mnt_root;
76+
return 0;
77+
}
78+
EXPORT_SYMBOL_GPL(umd_load_blob);
79+
80+
/**
81+
* umd_unload_blob - Disassociate @info from a previously loaded blob
82+
* @info: information about usermode driver
83+
*
84+
*/
85+
int umd_unload_blob(struct umd_info *info)
86+
{
87+
if (WARN_ON_ONCE(!info->wd.mnt ||
88+
!info->wd.dentry ||
89+
info->wd.mnt->mnt_root != info->wd.dentry))
90+
return -EINVAL;
91+
92+
kern_unmount(info->wd.mnt);
93+
info->wd.mnt = NULL;
94+
info->wd.dentry = NULL;
95+
return 0;
96+
}
97+
EXPORT_SYMBOL_GPL(umd_unload_blob);
98+
1299
static int umd_setup(struct subprocess_info *info, struct cred *new)
13100
{
14101
struct umd_info *umd_info = info->data;
@@ -43,6 +130,7 @@ static int umd_setup(struct subprocess_info *info, struct cred *new)
43130
return err;
44131
}
45132

133+
set_fs_pwd(current->fs, &umd_info->wd);
46134
umd_info->pipe_to_umh = to_umh[1];
47135
umd_info->pipe_from_umh = from_umh[0];
48136
umd_info->pid = task_pid_nr(current);
@@ -62,39 +150,21 @@ static void umd_cleanup(struct subprocess_info *info)
62150
}
63151

64152
/**
65-
* fork_usermode_blob - fork a blob of bytes as a usermode process
66-
* @data: a blob of bytes that can be do_execv-ed as a file
67-
* @len: length of the blob
68-
* @info: information about usermode process (shouldn't be NULL)
153+
* fork_usermode_driver - fork a usermode driver
154+
* @info: information about usermode driver (shouldn't be NULL)
69155
*
70-
* Returns either negative error or zero which indicates success
71-
* in executing a blob of bytes as a usermode process. In such
72-
* case 'struct umd_info *info' is populated with two pipes
73-
* and a pid of the process. The caller is responsible for health
74-
* check of the user process, killing it via pid, and closing the
75-
* pipes when user process is no longer needed.
156+
* Returns either negative error or zero which indicates success in
157+
* 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
159+
* responsible for health check of the user process, killing it via
160+
* pid, and closing the pipes when user process is no longer needed.
76161
*/
77-
int fork_usermode_blob(void *data, size_t len, struct umd_info *info)
162+
int fork_usermode_driver(struct umd_info *info)
78163
{
79164
struct subprocess_info *sub_info;
80165
char **argv = NULL;
81-
struct file *file;
82-
ssize_t written;
83-
loff_t pos = 0;
84166
int err;
85167

86-
file = shmem_kernel_file_setup(info->driver_name, len, 0);
87-
if (IS_ERR(file))
88-
return PTR_ERR(file);
89-
90-
written = kernel_write(file, data, len, &pos);
91-
if (written != len) {
92-
err = written;
93-
if (err >= 0)
94-
err = -ENOMEM;
95-
goto out;
96-
}
97-
98168
err = -ENOMEM;
99169
argv = argv_split(GFP_KERNEL, info->driver_name, NULL);
100170
if (!argv)
@@ -106,7 +176,6 @@ int fork_usermode_blob(void *data, size_t len, struct umd_info *info)
106176
if (!sub_info)
107177
goto out;
108178

109-
sub_info->file = file;
110179
err = call_usermodehelper_exec(sub_info, UMH_WAIT_EXEC);
111180
if (!err) {
112181
mutex_lock(&umh_list_lock);
@@ -116,10 +185,9 @@ int fork_usermode_blob(void *data, size_t len, struct umd_info *info)
116185
out:
117186
if (argv)
118187
argv_free(argv);
119-
fput(file);
120188
return err;
121189
}
122-
EXPORT_SYMBOL_GPL(fork_usermode_blob);
190+
EXPORT_SYMBOL_GPL(fork_usermode_driver);
123191

124192
void __exit_umh(struct task_struct *tsk)
125193
{

net/bpfilter/bpfilter_kern.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,7 @@ static int start_umh(void)
7777
int err;
7878

7979
/* fork usermode process */
80-
err = fork_usermode_blob(&bpfilter_umh_start,
81-
&bpfilter_umh_end - &bpfilter_umh_start,
82-
&bpfilter_ops.info);
80+
err = fork_usermode_driver(&bpfilter_ops.info);
8381
if (err)
8482
return err;
8583
bpfilter_ops.stop = false;
@@ -98,6 +96,12 @@ static int __init load_umh(void)
9896
{
9997
int err;
10098

99+
err = umd_load_blob(&bpfilter_ops.info,
100+
&bpfilter_umh_start,
101+
&bpfilter_umh_end - &bpfilter_umh_start);
102+
if (err)
103+
return err;
104+
101105
mutex_lock(&bpfilter_ops.lock);
102106
if (!bpfilter_ops.stop) {
103107
err = -EFAULT;
@@ -110,6 +114,8 @@ static int __init load_umh(void)
110114
}
111115
out:
112116
mutex_unlock(&bpfilter_ops.lock);
117+
if (err)
118+
umd_unload_blob(&bpfilter_ops.info);
113119
return err;
114120
}
115121

@@ -122,6 +128,8 @@ static void __exit fini_umh(void)
122128
bpfilter_ops.sockopt = NULL;
123129
}
124130
mutex_unlock(&bpfilter_ops.lock);
131+
132+
umd_unload_blob(&bpfilter_ops.info);
125133
}
126134
module_init(load_umh);
127135
module_exit(fini_umh);

0 commit comments

Comments
 (0)