BACKPORT: umh: Separate the user mode driver and the user mode helper support

This makes it clear which code is part of the core user mode
helper support and which code is needed to implement user mode
drivers.

This makes the kernel smaller for everyone who does not use a usermode
driver.

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]>
Change-Id: If31178fea04e49c2f11cbd5ece59a3bc18d50aa2
Signed-off-by: "Eric W. Biederman" <[email protected]>
This commit is contained in:
Eric W. Biederman 2020-06-26 12:23:00 -05:00 • committed by basamaryan
commit 8c4e16cec8
No known key found for this signature in database
GPG key ID: 210D5384FB2A5885
8 changed files with 179 additions and 158 deletions

View file

@ -27,8 +27,6 @@
#include <linux/ptrace.h>
#include <linux/async.h>
#include <linux/uaccess.h>
#include <linux/shmem_fs.h>
#include <linux/pipe_fs_i.h>
#include <trace/events/module.h>
@ -39,8 +37,6 @@ static kernel_cap_t usermodehelper_bset = CAP_FULL_SET;
static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET;
static DEFINE_SPINLOCK(umh_sysctl_lock);
static DECLARE_RWSEM(umhelper_sem);
static LIST_HEAD(umh_list);
static DEFINE_MUTEX(umh_list_lock);
static void call_usermodehelper_freeinfo(struct subprocess_info *info)
{
@ -411,121 +407,6 @@ struct subprocess_info *call_usermodehelper_setup(const char *path, char **argv,
}
EXPORT_SYMBOL(call_usermodehelper_setup);
static int umd_setup(struct subprocess_info *info, struct cred *new)
{
struct umh_info *umh_info = info->data;
struct file *from_umh[2];
struct file *to_umh[2];
int err;
/* create pipe to send data to umh */
err = create_pipe_files(to_umh, 0);
if (err)
return err;
err = replace_fd(0, to_umh[0], 0);
fput(to_umh[0]);
if (err < 0) {
fput(to_umh[1]);
return err;
}
/* create pipe to receive data from umh */
err = create_pipe_files(from_umh, 0);
if (err) {
fput(to_umh[1]);
replace_fd(0, NULL, 0);
return err;
}
err = replace_fd(1, from_umh[1], 0);
fput(from_umh[1]);
if (err < 0) {
fput(to_umh[1]);
replace_fd(0, NULL, 0);
fput(from_umh[0]);
return err;
}
umh_info->pipe_to_umh = to_umh[1];
umh_info->pipe_from_umh = from_umh[0];
umh_info->pid = task_pid_nr(current);
current->flags |= PF_UMH;
return 0;
}
static void umd_cleanup(struct subprocess_info *info)
{
struct umh_info *umh_info = info->data;
/* cleanup if umh_setup() was successful but exec failed */
if (info->retval) {
fput(umh_info->pipe_to_umh);
fput(umh_info->pipe_from_umh);
}
}
/**
* fork_usermode_blob - fork a blob of bytes as a usermode process
* @data: a blob of bytes that can be do_execv-ed as a file
* @len: length of the blob
* @info: information about usermode process (shouldn't be NULL)
*
* If info->cmdline is set it will be used as command line for the
* user process, else "usermodehelper" is used.
*
* Returns either negative error or zero which indicates success
* in executing a blob of bytes as a usermode process. In such
* case 'struct umh_info *info' is populated with two pipes
* and a pid 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.
*/
int fork_usermode_blob(void *data, size_t len, struct umh_info *info)
{
const char *cmdline = (info->cmdline) ? info->cmdline : "usermodehelper";
struct subprocess_info *sub_info;
char **argv = NULL;
struct file *file;
ssize_t written;
loff_t pos = 0;
int err;
file = shmem_kernel_file_setup("", len, 0);
if (IS_ERR(file))
return PTR_ERR(file);
written = kernel_write(file, data, len, &pos);
if (written != len) {
err = written;
if (err >= 0)
err = -ENOMEM;
goto out;
}
err = -ENOMEM;
argv = argv_split(GFP_KERNEL, cmdline, NULL);
if (!argv)
goto out;
sub_info = call_usermodehelper_setup("none", argv, NULL, GFP_KERNEL,
umd_setup, umd_cleanup, info);
if (!sub_info)
goto out;
sub_info->file = file;
err = call_usermodehelper_exec(sub_info, UMH_WAIT_EXEC);
if (!err) {
mutex_lock(&umh_list_lock);
list_add(&info->list, &umh_list);
mutex_unlock(&umh_list_lock);
}
out:
if (argv)
argv_free(argv);
fput(file);
return err;
}
EXPORT_SYMBOL_GPL(fork_usermode_blob);
/**
* call_usermodehelper_exec - start a usermode application
* @sub_info: information about the subprocessa
@ -687,26 +568,6 @@ static int proc_cap_handler(struct ctl_table *table, int write,
return 0;
}
void __exit_umh(struct task_struct *tsk)
{
struct umh_info *info;
pid_t pid = tsk->pid;
mutex_lock(&umh_list_lock);
list_for_each_entry(info, &umh_list, list) {
if (info->pid == pid) {
list_del(&info->list);
mutex_unlock(&umh_list_lock);
goto out;
}
}
mutex_unlock(&umh_list_lock);
return;
out:
if (info->cleanup)
info->cleanup(info);
}
struct ctl_table usermodehelper_table[] = {
{
.procname = "bset",