xref: /openbmc/linux/kernel/umh.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
223558693SLuis R. Rodriguez /*
323558693SLuis R. Rodriguez  * umh - the kernel usermode helper
423558693SLuis R. Rodriguez  */
523558693SLuis R. Rodriguez #include <linux/module.h>
623558693SLuis R. Rodriguez #include <linux/sched.h>
723558693SLuis R. Rodriguez #include <linux/sched/task.h>
823558693SLuis R. Rodriguez #include <linux/binfmts.h>
923558693SLuis R. Rodriguez #include <linux/syscalls.h>
1023558693SLuis R. Rodriguez #include <linux/unistd.h>
1123558693SLuis R. Rodriguez #include <linux/kmod.h>
1223558693SLuis R. Rodriguez #include <linux/slab.h>
1323558693SLuis R. Rodriguez #include <linux/completion.h>
1423558693SLuis R. Rodriguez #include <linux/cred.h>
1523558693SLuis R. Rodriguez #include <linux/file.h>
1623558693SLuis R. Rodriguez #include <linux/fdtable.h>
174013c149SLinus Torvalds #include <linux/fs_struct.h>
1823558693SLuis R. Rodriguez #include <linux/workqueue.h>
1923558693SLuis R. Rodriguez #include <linux/security.h>
2023558693SLuis R. Rodriguez #include <linux/mount.h>
2123558693SLuis R. Rodriguez #include <linux/kernel.h>
2223558693SLuis R. Rodriguez #include <linux/init.h>
2323558693SLuis R. Rodriguez #include <linux/resource.h>
2423558693SLuis R. Rodriguez #include <linux/notifier.h>
2523558693SLuis R. Rodriguez #include <linux/suspend.h>
2623558693SLuis R. Rodriguez #include <linux/rwsem.h>
2723558693SLuis R. Rodriguez #include <linux/ptrace.h>
2823558693SLuis R. Rodriguez #include <linux/async.h>
2923558693SLuis R. Rodriguez #include <linux/uaccess.h>
30e7cb072eSRasmus Villemoes #include <linux/initrd.h>
311fbcaa92SPeter Zijlstra #include <linux/freezer.h>
3223558693SLuis R. Rodriguez 
3323558693SLuis R. Rodriguez #include <trace/events/module.h>
3423558693SLuis R. Rodriguez 
3523558693SLuis R. Rodriguez static kernel_cap_t usermodehelper_bset = CAP_FULL_SET;
3623558693SLuis R. Rodriguez static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET;
3723558693SLuis R. Rodriguez static DEFINE_SPINLOCK(umh_sysctl_lock);
3823558693SLuis R. Rodriguez static DECLARE_RWSEM(umhelper_sem);
3923558693SLuis R. Rodriguez 
call_usermodehelper_freeinfo(struct subprocess_info * info)4023558693SLuis R. Rodriguez static void call_usermodehelper_freeinfo(struct subprocess_info *info)
4123558693SLuis R. Rodriguez {
4223558693SLuis R. Rodriguez 	if (info->cleanup)
4323558693SLuis R. Rodriguez 		(*info->cleanup)(info);
4423558693SLuis R. Rodriguez 	kfree(info);
4523558693SLuis R. Rodriguez }
4623558693SLuis R. Rodriguez 
umh_complete(struct subprocess_info * sub_info)4723558693SLuis R. Rodriguez static void umh_complete(struct subprocess_info *sub_info)
4823558693SLuis R. Rodriguez {
4923558693SLuis R. Rodriguez 	struct completion *comp = xchg(&sub_info->complete, NULL);
5023558693SLuis R. Rodriguez 	/*
5123558693SLuis R. Rodriguez 	 * See call_usermodehelper_exec(). If xchg() returns NULL
5223558693SLuis R. Rodriguez 	 * we own sub_info, the UMH_KILLABLE caller has gone away
5323558693SLuis R. Rodriguez 	 * or the caller used UMH_NO_WAIT.
5423558693SLuis R. Rodriguez 	 */
5523558693SLuis R. Rodriguez 	if (comp)
5623558693SLuis R. Rodriguez 		complete(comp);
5723558693SLuis R. Rodriguez 	else
5823558693SLuis R. Rodriguez 		call_usermodehelper_freeinfo(sub_info);
5923558693SLuis R. Rodriguez }
6023558693SLuis R. Rodriguez 
6123558693SLuis R. Rodriguez /*
6223558693SLuis R. Rodriguez  * This is the task which runs the usermode application
6323558693SLuis R. Rodriguez  */
call_usermodehelper_exec_async(void * data)6423558693SLuis R. Rodriguez static int call_usermodehelper_exec_async(void *data)
6523558693SLuis R. Rodriguez {
6623558693SLuis R. Rodriguez 	struct subprocess_info *sub_info = data;
6723558693SLuis R. Rodriguez 	struct cred *new;
6823558693SLuis R. Rodriguez 	int retval;
6923558693SLuis R. Rodriguez 
7023558693SLuis R. Rodriguez 	spin_lock_irq(&current->sighand->siglock);
7123558693SLuis R. Rodriguez 	flush_signal_handlers(current, 1);
7223558693SLuis R. Rodriguez 	spin_unlock_irq(&current->sighand->siglock);
7323558693SLuis R. Rodriguez 
7423558693SLuis R. Rodriguez 	/*
754013c149SLinus Torvalds 	 * Initial kernel threads share ther FS with init, in order to
764013c149SLinus Torvalds 	 * get the init root directory. But we've now created a new
774013c149SLinus Torvalds 	 * thread that is going to execve a user process and has its own
784013c149SLinus Torvalds 	 * 'struct fs_struct'. Reset umask to the default.
794013c149SLinus Torvalds 	 */
804013c149SLinus Torvalds 	current->fs->umask = 0022;
814013c149SLinus Torvalds 
824013c149SLinus Torvalds 	/*
8323558693SLuis R. Rodriguez 	 * Our parent (unbound workqueue) runs with elevated scheduling
8423558693SLuis R. Rodriguez 	 * priority. Avoid propagating that into the userspace child.
8523558693SLuis R. Rodriguez 	 */
8623558693SLuis R. Rodriguez 	set_user_nice(current, 0);
8723558693SLuis R. Rodriguez 
8823558693SLuis R. Rodriguez 	retval = -ENOMEM;
8923558693SLuis R. Rodriguez 	new = prepare_kernel_cred(current);
9023558693SLuis R. Rodriguez 	if (!new)
9123558693SLuis R. Rodriguez 		goto out;
9223558693SLuis R. Rodriguez 
9323558693SLuis R. Rodriguez 	spin_lock(&umh_sysctl_lock);
9423558693SLuis R. Rodriguez 	new->cap_bset = cap_intersect(usermodehelper_bset, new->cap_bset);
9523558693SLuis R. Rodriguez 	new->cap_inheritable = cap_intersect(usermodehelper_inheritable,
9623558693SLuis R. Rodriguez 					     new->cap_inheritable);
9723558693SLuis R. Rodriguez 	spin_unlock(&umh_sysctl_lock);
9823558693SLuis R. Rodriguez 
9923558693SLuis R. Rodriguez 	if (sub_info->init) {
10023558693SLuis R. Rodriguez 		retval = sub_info->init(sub_info, new);
10123558693SLuis R. Rodriguez 		if (retval) {
10223558693SLuis R. Rodriguez 			abort_creds(new);
10323558693SLuis R. Rodriguez 			goto out;
10423558693SLuis R. Rodriguez 		}
10523558693SLuis R. Rodriguez 	}
10623558693SLuis R. Rodriguez 
10723558693SLuis R. Rodriguez 	commit_creds(new);
10823558693SLuis R. Rodriguez 
109e7cb072eSRasmus Villemoes 	wait_for_initramfs();
110be619f7fSEric W. Biederman 	retval = kernel_execve(sub_info->path,
111be619f7fSEric W. Biederman 			       (const char *const *)sub_info->argv,
112be619f7fSEric W. Biederman 			       (const char *const *)sub_info->envp);
11323558693SLuis R. Rodriguez out:
11423558693SLuis R. Rodriguez 	sub_info->retval = retval;
11523558693SLuis R. Rodriguez 	/*
11623558693SLuis R. Rodriguez 	 * call_usermodehelper_exec_sync() will call umh_complete
11723558693SLuis R. Rodriguez 	 * if UHM_WAIT_PROC.
11823558693SLuis R. Rodriguez 	 */
11923558693SLuis R. Rodriguez 	if (!(sub_info->wait & UMH_WAIT_PROC))
12023558693SLuis R. Rodriguez 		umh_complete(sub_info);
12123558693SLuis R. Rodriguez 	if (!retval)
12223558693SLuis R. Rodriguez 		return 0;
12323558693SLuis R. Rodriguez 	do_exit(0);
12423558693SLuis R. Rodriguez }
12523558693SLuis R. Rodriguez 
12623558693SLuis R. Rodriguez /* Handles UMH_WAIT_PROC.  */
call_usermodehelper_exec_sync(struct subprocess_info * sub_info)12723558693SLuis R. Rodriguez static void call_usermodehelper_exec_sync(struct subprocess_info *sub_info)
12823558693SLuis R. Rodriguez {
12923558693SLuis R. Rodriguez 	pid_t pid;
13023558693SLuis R. Rodriguez 
1318043fc14SChristoph Hellwig 	/* If SIGCLD is ignored do_wait won't populate the status. */
13223558693SLuis R. Rodriguez 	kernel_sigaction(SIGCHLD, SIG_DFL);
133343f4c49SEric W. Biederman 	pid = user_mode_thread(call_usermodehelper_exec_async, sub_info, SIGCHLD);
1348043fc14SChristoph Hellwig 	if (pid < 0)
13523558693SLuis R. Rodriguez 		sub_info->retval = pid;
1368043fc14SChristoph Hellwig 	else
1378043fc14SChristoph Hellwig 		kernel_wait(pid, &sub_info->retval);
13823558693SLuis R. Rodriguez 
13923558693SLuis R. Rodriguez 	/* Restore default kernel sig handler */
14023558693SLuis R. Rodriguez 	kernel_sigaction(SIGCHLD, SIG_IGN);
14123558693SLuis R. Rodriguez 	umh_complete(sub_info);
14223558693SLuis R. Rodriguez }
14323558693SLuis R. Rodriguez 
14423558693SLuis R. Rodriguez /*
14523558693SLuis R. Rodriguez  * We need to create the usermodehelper kernel thread from a task that is affine
14623558693SLuis R. Rodriguez  * to an optimized set of CPUs (or nohz housekeeping ones) such that they
14723558693SLuis R. Rodriguez  * inherit a widest affinity irrespective of call_usermodehelper() callers with
14823558693SLuis R. Rodriguez  * possibly reduced affinity (eg: per-cpu workqueues). We don't want
14923558693SLuis R. Rodriguez  * usermodehelper targets to contend a busy CPU.
15023558693SLuis R. Rodriguez  *
15123558693SLuis R. Rodriguez  * Unbound workqueues provide such wide affinity and allow to block on
15223558693SLuis R. Rodriguez  * UMH_WAIT_PROC requests without blocking pending request (up to some limit).
15323558693SLuis R. Rodriguez  *
15423558693SLuis R. Rodriguez  * Besides, workqueues provide the privilege level that caller might not have
15523558693SLuis R. Rodriguez  * to perform the usermodehelper request.
15623558693SLuis R. Rodriguez  *
15723558693SLuis R. Rodriguez  */
call_usermodehelper_exec_work(struct work_struct * work)15823558693SLuis R. Rodriguez static void call_usermodehelper_exec_work(struct work_struct *work)
15923558693SLuis R. Rodriguez {
16023558693SLuis R. Rodriguez 	struct subprocess_info *sub_info =
16123558693SLuis R. Rodriguez 		container_of(work, struct subprocess_info, work);
16223558693SLuis R. Rodriguez 
16323558693SLuis R. Rodriguez 	if (sub_info->wait & UMH_WAIT_PROC) {
16423558693SLuis R. Rodriguez 		call_usermodehelper_exec_sync(sub_info);
16523558693SLuis R. Rodriguez 	} else {
16623558693SLuis R. Rodriguez 		pid_t pid;
16723558693SLuis R. Rodriguez 		/*
16823558693SLuis R. Rodriguez 		 * Use CLONE_PARENT to reparent it to kthreadd; we do not
16923558693SLuis R. Rodriguez 		 * want to pollute current->children, and we need a parent
17023558693SLuis R. Rodriguez 		 * that always ignores SIGCHLD to ensure auto-reaping.
17123558693SLuis R. Rodriguez 		 */
172343f4c49SEric W. Biederman 		pid = user_mode_thread(call_usermodehelper_exec_async, sub_info,
17323558693SLuis R. Rodriguez 				       CLONE_PARENT | SIGCHLD);
17423558693SLuis R. Rodriguez 		if (pid < 0) {
17523558693SLuis R. Rodriguez 			sub_info->retval = pid;
17623558693SLuis R. Rodriguez 			umh_complete(sub_info);
17723558693SLuis R. Rodriguez 		}
17823558693SLuis R. Rodriguez 	}
17923558693SLuis R. Rodriguez }
18023558693SLuis R. Rodriguez 
18123558693SLuis R. Rodriguez /*
18223558693SLuis R. Rodriguez  * If set, call_usermodehelper_exec() will exit immediately returning -EBUSY
18323558693SLuis R. Rodriguez  * (used for preventing user land processes from being created after the user
18423558693SLuis R. Rodriguez  * land has been frozen during a system-wide hibernation or suspend operation).
18523558693SLuis R. Rodriguez  * Should always be manipulated under umhelper_sem acquired for write.
18623558693SLuis R. Rodriguez  */
18723558693SLuis R. Rodriguez static enum umh_disable_depth usermodehelper_disabled = UMH_DISABLED;
18823558693SLuis R. Rodriguez 
18923558693SLuis R. Rodriguez /* Number of helpers running */
19023558693SLuis R. Rodriguez static atomic_t running_helpers = ATOMIC_INIT(0);
19123558693SLuis R. Rodriguez 
19223558693SLuis R. Rodriguez /*
19323558693SLuis R. Rodriguez  * Wait queue head used by usermodehelper_disable() to wait for all running
19423558693SLuis R. Rodriguez  * helpers to finish.
19523558693SLuis R. Rodriguez  */
19623558693SLuis R. Rodriguez static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq);
19723558693SLuis R. Rodriguez 
19823558693SLuis R. Rodriguez /*
19923558693SLuis R. Rodriguez  * Used by usermodehelper_read_lock_wait() to wait for usermodehelper_disabled
20023558693SLuis R. Rodriguez  * to become 'false'.
20123558693SLuis R. Rodriguez  */
20223558693SLuis R. Rodriguez static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_disabled_waitq);
20323558693SLuis R. Rodriguez 
20423558693SLuis R. Rodriguez /*
20523558693SLuis R. Rodriguez  * Time to wait for running_helpers to become zero before the setting of
20623558693SLuis R. Rodriguez  * usermodehelper_disabled in usermodehelper_disable() fails
20723558693SLuis R. Rodriguez  */
20823558693SLuis R. Rodriguez #define RUNNING_HELPERS_TIMEOUT	(5 * HZ)
20923558693SLuis R. Rodriguez 
usermodehelper_read_trylock(void)21023558693SLuis R. Rodriguez int usermodehelper_read_trylock(void)
21123558693SLuis R. Rodriguez {
21223558693SLuis R. Rodriguez 	DEFINE_WAIT(wait);
21323558693SLuis R. Rodriguez 	int ret = 0;
21423558693SLuis R. Rodriguez 
21523558693SLuis R. Rodriguez 	down_read(&umhelper_sem);
21623558693SLuis R. Rodriguez 	for (;;) {
21723558693SLuis R. Rodriguez 		prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
21823558693SLuis R. Rodriguez 				TASK_INTERRUPTIBLE);
21923558693SLuis R. Rodriguez 		if (!usermodehelper_disabled)
22023558693SLuis R. Rodriguez 			break;
22123558693SLuis R. Rodriguez 
22223558693SLuis R. Rodriguez 		if (usermodehelper_disabled == UMH_DISABLED)
22323558693SLuis R. Rodriguez 			ret = -EAGAIN;
22423558693SLuis R. Rodriguez 
22523558693SLuis R. Rodriguez 		up_read(&umhelper_sem);
22623558693SLuis R. Rodriguez 
22723558693SLuis R. Rodriguez 		if (ret)
22823558693SLuis R. Rodriguez 			break;
22923558693SLuis R. Rodriguez 
23023558693SLuis R. Rodriguez 		schedule();
23123558693SLuis R. Rodriguez 		try_to_freeze();
23223558693SLuis R. Rodriguez 
23323558693SLuis R. Rodriguez 		down_read(&umhelper_sem);
23423558693SLuis R. Rodriguez 	}
23523558693SLuis R. Rodriguez 	finish_wait(&usermodehelper_disabled_waitq, &wait);
23623558693SLuis R. Rodriguez 	return ret;
23723558693SLuis R. Rodriguez }
23823558693SLuis R. Rodriguez EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
23923558693SLuis R. Rodriguez 
usermodehelper_read_lock_wait(long timeout)24023558693SLuis R. Rodriguez long usermodehelper_read_lock_wait(long timeout)
24123558693SLuis R. Rodriguez {
24223558693SLuis R. Rodriguez 	DEFINE_WAIT(wait);
24323558693SLuis R. Rodriguez 
24423558693SLuis R. Rodriguez 	if (timeout < 0)
24523558693SLuis R. Rodriguez 		return -EINVAL;
24623558693SLuis R. Rodriguez 
24723558693SLuis R. Rodriguez 	down_read(&umhelper_sem);
24823558693SLuis R. Rodriguez 	for (;;) {
24923558693SLuis R. Rodriguez 		prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
25023558693SLuis R. Rodriguez 				TASK_UNINTERRUPTIBLE);
25123558693SLuis R. Rodriguez 		if (!usermodehelper_disabled)
25223558693SLuis R. Rodriguez 			break;
25323558693SLuis R. Rodriguez 
25423558693SLuis R. Rodriguez 		up_read(&umhelper_sem);
25523558693SLuis R. Rodriguez 
25623558693SLuis R. Rodriguez 		timeout = schedule_timeout(timeout);
25723558693SLuis R. Rodriguez 		if (!timeout)
25823558693SLuis R. Rodriguez 			break;
25923558693SLuis R. Rodriguez 
26023558693SLuis R. Rodriguez 		down_read(&umhelper_sem);
26123558693SLuis R. Rodriguez 	}
26223558693SLuis R. Rodriguez 	finish_wait(&usermodehelper_disabled_waitq, &wait);
26323558693SLuis R. Rodriguez 	return timeout;
26423558693SLuis R. Rodriguez }
26523558693SLuis R. Rodriguez EXPORT_SYMBOL_GPL(usermodehelper_read_lock_wait);
26623558693SLuis R. Rodriguez 
usermodehelper_read_unlock(void)26723558693SLuis R. Rodriguez void usermodehelper_read_unlock(void)
26823558693SLuis R. Rodriguez {
26923558693SLuis R. Rodriguez 	up_read(&umhelper_sem);
27023558693SLuis R. Rodriguez }
27123558693SLuis R. Rodriguez EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
27223558693SLuis R. Rodriguez 
27323558693SLuis R. Rodriguez /**
27423558693SLuis R. Rodriguez  * __usermodehelper_set_disable_depth - Modify usermodehelper_disabled.
27523558693SLuis R. Rodriguez  * @depth: New value to assign to usermodehelper_disabled.
27623558693SLuis R. Rodriguez  *
27723558693SLuis R. Rodriguez  * Change the value of usermodehelper_disabled (under umhelper_sem locked for
27823558693SLuis R. Rodriguez  * writing) and wakeup tasks waiting for it to change.
27923558693SLuis R. Rodriguez  */
__usermodehelper_set_disable_depth(enum umh_disable_depth depth)28023558693SLuis R. Rodriguez void __usermodehelper_set_disable_depth(enum umh_disable_depth depth)
28123558693SLuis R. Rodriguez {
28223558693SLuis R. Rodriguez 	down_write(&umhelper_sem);
28323558693SLuis R. Rodriguez 	usermodehelper_disabled = depth;
28423558693SLuis R. Rodriguez 	wake_up(&usermodehelper_disabled_waitq);
28523558693SLuis R. Rodriguez 	up_write(&umhelper_sem);
28623558693SLuis R. Rodriguez }
28723558693SLuis R. Rodriguez 
28823558693SLuis R. Rodriguez /**
28923558693SLuis R. Rodriguez  * __usermodehelper_disable - Prevent new helpers from being started.
29023558693SLuis R. Rodriguez  * @depth: New value to assign to usermodehelper_disabled.
29123558693SLuis R. Rodriguez  *
29223558693SLuis R. Rodriguez  * Set usermodehelper_disabled to @depth and wait for running helpers to exit.
29323558693SLuis R. Rodriguez  */
__usermodehelper_disable(enum umh_disable_depth depth)29423558693SLuis R. Rodriguez int __usermodehelper_disable(enum umh_disable_depth depth)
29523558693SLuis R. Rodriguez {
29623558693SLuis R. Rodriguez 	long retval;
29723558693SLuis R. Rodriguez 
29823558693SLuis R. Rodriguez 	if (!depth)
29923558693SLuis R. Rodriguez 		return -EINVAL;
30023558693SLuis R. Rodriguez 
30123558693SLuis R. Rodriguez 	down_write(&umhelper_sem);
30223558693SLuis R. Rodriguez 	usermodehelper_disabled = depth;
30323558693SLuis R. Rodriguez 	up_write(&umhelper_sem);
30423558693SLuis R. Rodriguez 
30523558693SLuis R. Rodriguez 	/*
30623558693SLuis R. Rodriguez 	 * From now on call_usermodehelper_exec() won't start any new
30723558693SLuis R. Rodriguez 	 * helpers, so it is sufficient if running_helpers turns out to
30823558693SLuis R. Rodriguez 	 * be zero at one point (it may be increased later, but that
30923558693SLuis R. Rodriguez 	 * doesn't matter).
31023558693SLuis R. Rodriguez 	 */
31123558693SLuis R. Rodriguez 	retval = wait_event_timeout(running_helpers_waitq,
31223558693SLuis R. Rodriguez 					atomic_read(&running_helpers) == 0,
31323558693SLuis R. Rodriguez 					RUNNING_HELPERS_TIMEOUT);
31423558693SLuis R. Rodriguez 	if (retval)
31523558693SLuis R. Rodriguez 		return 0;
31623558693SLuis R. Rodriguez 
31723558693SLuis R. Rodriguez 	__usermodehelper_set_disable_depth(UMH_ENABLED);
31823558693SLuis R. Rodriguez 	return -EAGAIN;
31923558693SLuis R. Rodriguez }
32023558693SLuis R. Rodriguez 
helper_lock(void)32123558693SLuis R. Rodriguez static void helper_lock(void)
32223558693SLuis R. Rodriguez {
32323558693SLuis R. Rodriguez 	atomic_inc(&running_helpers);
32423558693SLuis R. Rodriguez 	smp_mb__after_atomic();
32523558693SLuis R. Rodriguez }
32623558693SLuis R. Rodriguez 
helper_unlock(void)32723558693SLuis R. Rodriguez static void helper_unlock(void)
32823558693SLuis R. Rodriguez {
32923558693SLuis R. Rodriguez 	if (atomic_dec_and_test(&running_helpers))
33023558693SLuis R. Rodriguez 		wake_up(&running_helpers_waitq);
33123558693SLuis R. Rodriguez }
33223558693SLuis R. Rodriguez 
33323558693SLuis R. Rodriguez /**
33423558693SLuis R. Rodriguez  * call_usermodehelper_setup - prepare to call a usermode helper
33523558693SLuis R. Rodriguez  * @path: path to usermode executable
33623558693SLuis R. Rodriguez  * @argv: arg vector for process
33723558693SLuis R. Rodriguez  * @envp: environment for process
33823558693SLuis R. Rodriguez  * @gfp_mask: gfp mask for memory allocation
33923558693SLuis R. Rodriguez  * @init: an init function
34048207f7dSzhouchuangao  * @cleanup: a cleanup function
34123558693SLuis R. Rodriguez  * @data: arbitrary context sensitive data
34223558693SLuis R. Rodriguez  *
34323558693SLuis R. Rodriguez  * Returns either %NULL on allocation failure, or a subprocess_info
34423558693SLuis R. Rodriguez  * structure.  This should be passed to call_usermodehelper_exec to
34523558693SLuis R. Rodriguez  * exec the process and free the structure.
34623558693SLuis R. Rodriguez  *
34723558693SLuis R. Rodriguez  * The init function is used to customize the helper process prior to
34823558693SLuis R. Rodriguez  * exec.  A non-zero return code causes the process to error out, exit,
34923558693SLuis R. Rodriguez  * and return the failure to the calling process
35023558693SLuis R. Rodriguez  *
35148207f7dSzhouchuangao  * The cleanup function is just before the subprocess_info is about to
35223558693SLuis R. Rodriguez  * be freed.  This can be used for freeing the argv and envp.  The
35323558693SLuis R. Rodriguez  * Function must be runnable in either a process context or the
35423558693SLuis R. Rodriguez  * context in which call_usermodehelper_exec is called.
35523558693SLuis R. Rodriguez  */
call_usermodehelper_setup(const char * path,char ** argv,char ** envp,gfp_t gfp_mask,int (* init)(struct subprocess_info * info,struct cred * new),void (* cleanup)(struct subprocess_info * info),void * data)35623558693SLuis R. Rodriguez struct subprocess_info *call_usermodehelper_setup(const char *path, char **argv,
35723558693SLuis R. Rodriguez 		char **envp, gfp_t gfp_mask,
35823558693SLuis R. Rodriguez 		int (*init)(struct subprocess_info *info, struct cred *new),
35923558693SLuis R. Rodriguez 		void (*cleanup)(struct subprocess_info *info),
36023558693SLuis R. Rodriguez 		void *data)
36123558693SLuis R. Rodriguez {
36223558693SLuis R. Rodriguez 	struct subprocess_info *sub_info;
36323558693SLuis R. Rodriguez 	sub_info = kzalloc(sizeof(struct subprocess_info), gfp_mask);
36423558693SLuis R. Rodriguez 	if (!sub_info)
36523558693SLuis R. Rodriguez 		goto out;
36623558693SLuis R. Rodriguez 
36723558693SLuis R. Rodriguez 	INIT_WORK(&sub_info->work, call_usermodehelper_exec_work);
36823558693SLuis R. Rodriguez 
36923558693SLuis R. Rodriguez #ifdef CONFIG_STATIC_USERMODEHELPER
37023558693SLuis R. Rodriguez 	sub_info->path = CONFIG_STATIC_USERMODEHELPER_PATH;
37123558693SLuis R. Rodriguez #else
37223558693SLuis R. Rodriguez 	sub_info->path = path;
37323558693SLuis R. Rodriguez #endif
37423558693SLuis R. Rodriguez 	sub_info->argv = argv;
37523558693SLuis R. Rodriguez 	sub_info->envp = envp;
37623558693SLuis R. Rodriguez 
37723558693SLuis R. Rodriguez 	sub_info->cleanup = cleanup;
37823558693SLuis R. Rodriguez 	sub_info->init = init;
37923558693SLuis R. Rodriguez 	sub_info->data = data;
38023558693SLuis R. Rodriguez   out:
38123558693SLuis R. Rodriguez 	return sub_info;
38223558693SLuis R. Rodriguez }
38323558693SLuis R. Rodriguez EXPORT_SYMBOL(call_usermodehelper_setup);
38423558693SLuis R. Rodriguez 
38523558693SLuis R. Rodriguez /**
38623558693SLuis R. Rodriguez  * call_usermodehelper_exec - start a usermode application
38748207f7dSzhouchuangao  * @sub_info: information about the subprocess
38823558693SLuis R. Rodriguez  * @wait: wait for the application to finish and return status.
38923558693SLuis R. Rodriguez  *        when UMH_NO_WAIT don't wait at all, but you get no useful error back
39023558693SLuis R. Rodriguez  *        when the program couldn't be exec'ed. This makes it safe to call
39123558693SLuis R. Rodriguez  *        from interrupt context.
39223558693SLuis R. Rodriguez  *
39323558693SLuis R. Rodriguez  * Runs a user-space application.  The application is started
39423558693SLuis R. Rodriguez  * asynchronously if wait is not set, and runs as a child of system workqueues.
39523558693SLuis R. Rodriguez  * (ie. it runs with full root capabilities and optimized affinity).
3963740d93eSLuis Chamberlain  *
3973740d93eSLuis Chamberlain  * Note: successful return value does not guarantee the helper was called at
3983740d93eSLuis Chamberlain  * all. You can't rely on sub_info->{init,cleanup} being called even for
3993740d93eSLuis Chamberlain  * UMH_WAIT_* wait modes as STATIC_USERMODEHELPER_PATH="" turns all helpers
4003740d93eSLuis Chamberlain  * into a successful no-op.
40123558693SLuis R. Rodriguez  */
call_usermodehelper_exec(struct subprocess_info * sub_info,int wait)40223558693SLuis R. Rodriguez int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
40323558693SLuis R. Rodriguez {
404f5d39b02SPeter Zijlstra 	unsigned int state = TASK_UNINTERRUPTIBLE;
40523558693SLuis R. Rodriguez 	DECLARE_COMPLETION_ONSTACK(done);
40623558693SLuis R. Rodriguez 	int retval = 0;
40723558693SLuis R. Rodriguez 
40823558693SLuis R. Rodriguez 	if (!sub_info->path) {
40923558693SLuis R. Rodriguez 		call_usermodehelper_freeinfo(sub_info);
41023558693SLuis R. Rodriguez 		return -EINVAL;
41123558693SLuis R. Rodriguez 	}
41223558693SLuis R. Rodriguez 	helper_lock();
41323558693SLuis R. Rodriguez 	if (usermodehelper_disabled) {
41423558693SLuis R. Rodriguez 		retval = -EBUSY;
41523558693SLuis R. Rodriguez 		goto out;
41623558693SLuis R. Rodriguez 	}
41723558693SLuis R. Rodriguez 
41823558693SLuis R. Rodriguez 	/*
41923558693SLuis R. Rodriguez 	 * If there is no binary for us to call, then just return and get out of
42023558693SLuis R. Rodriguez 	 * here.  This allows us to set STATIC_USERMODEHELPER_PATH to "" and
42123558693SLuis R. Rodriguez 	 * disable all call_usermodehelper() calls.
42223558693SLuis R. Rodriguez 	 */
42323558693SLuis R. Rodriguez 	if (strlen(sub_info->path) == 0)
42423558693SLuis R. Rodriguez 		goto out;
42523558693SLuis R. Rodriguez 
42623558693SLuis R. Rodriguez 	/*
42723558693SLuis R. Rodriguez 	 * Set the completion pointer only if there is a waiter.
42823558693SLuis R. Rodriguez 	 * This makes it possible to use umh_complete to free
42923558693SLuis R. Rodriguez 	 * the data structure in case of UMH_NO_WAIT.
43023558693SLuis R. Rodriguez 	 */
43123558693SLuis R. Rodriguez 	sub_info->complete = (wait == UMH_NO_WAIT) ? NULL : &done;
43223558693SLuis R. Rodriguez 	sub_info->wait = wait;
43323558693SLuis R. Rodriguez 
43423558693SLuis R. Rodriguez 	queue_work(system_unbound_wq, &sub_info->work);
43523558693SLuis R. Rodriguez 	if (wait == UMH_NO_WAIT)	/* task has freed sub_info */
43623558693SLuis R. Rodriguez 		goto unlock;
43723558693SLuis R. Rodriguez 
438f5d39b02SPeter Zijlstra 	if (wait & UMH_FREEZABLE)
439f5d39b02SPeter Zijlstra 		state |= TASK_FREEZABLE;
440f5d39b02SPeter Zijlstra 
441eedeb787SPeter Zijlstra 	if (wait & UMH_KILLABLE) {
442eedeb787SPeter Zijlstra 		retval = wait_for_completion_state(&done, state | TASK_KILLABLE);
44323558693SLuis R. Rodriguez 		if (!retval)
44423558693SLuis R. Rodriguez 			goto wait_done;
44523558693SLuis R. Rodriguez 
44623558693SLuis R. Rodriguez 		/* umh_complete() will see NULL and free sub_info */
44723558693SLuis R. Rodriguez 		if (xchg(&sub_info->complete, NULL))
44823558693SLuis R. Rodriguez 			goto unlock;
449eedeb787SPeter Zijlstra 
450eedeb787SPeter Zijlstra 		/*
451eedeb787SPeter Zijlstra 		 * fallthrough; in case of -ERESTARTSYS now do uninterruptible
452eedeb787SPeter Zijlstra 		 * wait_for_completion_state(). Since umh_complete() shall call
453eedeb787SPeter Zijlstra 		 * complete() in a moment if xchg() above returned NULL, this
454eedeb787SPeter Zijlstra 		 * uninterruptible wait_for_completion_state() will not block
455eedeb787SPeter Zijlstra 		 * SIGKILL'ed processes for long.
456eedeb787SPeter Zijlstra 		 */
45723558693SLuis R. Rodriguez 	}
458eedeb787SPeter Zijlstra 	wait_for_completion_state(&done, state);
45923558693SLuis R. Rodriguez 
46023558693SLuis R. Rodriguez wait_done:
46123558693SLuis R. Rodriguez 	retval = sub_info->retval;
46223558693SLuis R. Rodriguez out:
46323558693SLuis R. Rodriguez 	call_usermodehelper_freeinfo(sub_info);
46423558693SLuis R. Rodriguez unlock:
46523558693SLuis R. Rodriguez 	helper_unlock();
46623558693SLuis R. Rodriguez 	return retval;
46723558693SLuis R. Rodriguez }
46823558693SLuis R. Rodriguez EXPORT_SYMBOL(call_usermodehelper_exec);
46923558693SLuis R. Rodriguez 
47023558693SLuis R. Rodriguez /**
47123558693SLuis R. Rodriguez  * call_usermodehelper() - prepare and start a usermode application
47223558693SLuis R. Rodriguez  * @path: path to usermode executable
47323558693SLuis R. Rodriguez  * @argv: arg vector for process
47423558693SLuis R. Rodriguez  * @envp: environment for process
47523558693SLuis R. Rodriguez  * @wait: wait for the application to finish and return status.
47623558693SLuis R. Rodriguez  *        when UMH_NO_WAIT don't wait at all, but you get no useful error back
47723558693SLuis R. Rodriguez  *        when the program couldn't be exec'ed. This makes it safe to call
47823558693SLuis R. Rodriguez  *        from interrupt context.
47923558693SLuis R. Rodriguez  *
48023558693SLuis R. Rodriguez  * This function is the equivalent to use call_usermodehelper_setup() and
48123558693SLuis R. Rodriguez  * call_usermodehelper_exec().
48223558693SLuis R. Rodriguez  */
call_usermodehelper(const char * path,char ** argv,char ** envp,int wait)48323558693SLuis R. Rodriguez int call_usermodehelper(const char *path, char **argv, char **envp, int wait)
48423558693SLuis R. Rodriguez {
48523558693SLuis R. Rodriguez 	struct subprocess_info *info;
48623558693SLuis R. Rodriguez 	gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
48723558693SLuis R. Rodriguez 
48823558693SLuis R. Rodriguez 	info = call_usermodehelper_setup(path, argv, envp, gfp_mask,
48923558693SLuis R. Rodriguez 					 NULL, NULL, NULL);
49023558693SLuis R. Rodriguez 	if (info == NULL)
49123558693SLuis R. Rodriguez 		return -ENOMEM;
49223558693SLuis R. Rodriguez 
49323558693SLuis R. Rodriguez 	return call_usermodehelper_exec(info, wait);
49423558693SLuis R. Rodriguez }
49523558693SLuis R. Rodriguez EXPORT_SYMBOL(call_usermodehelper);
49623558693SLuis R. Rodriguez 
497*554588e8SArnd Bergmann #if defined(CONFIG_SYSCTL)
proc_cap_handler(struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)49823558693SLuis R. Rodriguez static int proc_cap_handler(struct ctl_table *table, int write,
49932927393SChristoph Hellwig 			 void *buffer, size_t *lenp, loff_t *ppos)
50023558693SLuis R. Rodriguez {
50123558693SLuis R. Rodriguez 	struct ctl_table t;
502f122a08bSLinus Torvalds 	unsigned long cap_array[2];
503f122a08bSLinus Torvalds 	kernel_cap_t new_cap, *cap;
504f122a08bSLinus Torvalds 	int err;
50523558693SLuis R. Rodriguez 
50623558693SLuis R. Rodriguez 	if (write && (!capable(CAP_SETPCAP) ||
50723558693SLuis R. Rodriguez 		      !capable(CAP_SYS_MODULE)))
50823558693SLuis R. Rodriguez 		return -EPERM;
50923558693SLuis R. Rodriguez 
51023558693SLuis R. Rodriguez 	/*
51123558693SLuis R. Rodriguez 	 * convert from the global kernel_cap_t to the ulong array to print to
51223558693SLuis R. Rodriguez 	 * userspace if this is a read.
513e7783615SLinus Torvalds 	 *
514e7783615SLinus Torvalds 	 * Legacy format: capabilities are exposed as two 32-bit values
51523558693SLuis R. Rodriguez 	 */
516e7783615SLinus Torvalds 	cap = table->data;
51723558693SLuis R. Rodriguez 	spin_lock(&umh_sysctl_lock);
518f122a08bSLinus Torvalds 	cap_array[0] = (u32) cap->val;
519f122a08bSLinus Torvalds 	cap_array[1] = cap->val >> 32;
52023558693SLuis R. Rodriguez 	spin_unlock(&umh_sysctl_lock);
52123558693SLuis R. Rodriguez 
52223558693SLuis R. Rodriguez 	t = *table;
52323558693SLuis R. Rodriguez 	t.data = &cap_array;
52423558693SLuis R. Rodriguez 
52523558693SLuis R. Rodriguez 	/*
52623558693SLuis R. Rodriguez 	 * actually read or write and array of ulongs from userspace.  Remember
52723558693SLuis R. Rodriguez 	 * these are least significant 32 bits first
52823558693SLuis R. Rodriguez 	 */
52923558693SLuis R. Rodriguez 	err = proc_doulongvec_minmax(&t, write, buffer, lenp, ppos);
53023558693SLuis R. Rodriguez 	if (err < 0)
53123558693SLuis R. Rodriguez 		return err;
53223558693SLuis R. Rodriguez 
533f122a08bSLinus Torvalds 	new_cap.val = (u32)cap_array[0];
534f122a08bSLinus Torvalds 	new_cap.val += (u64)cap_array[1] << 32;
53523558693SLuis R. Rodriguez 
53623558693SLuis R. Rodriguez 	/*
53723558693SLuis R. Rodriguez 	 * Drop everything not in the new_cap (but don't add things)
53823558693SLuis R. Rodriguez 	 */
53923558693SLuis R. Rodriguez 	if (write) {
5408c703d66SChristophe JAILLET 		spin_lock(&umh_sysctl_lock);
541f122a08bSLinus Torvalds 		*cap = cap_intersect(*cap, new_cap);
54223558693SLuis R. Rodriguez 		spin_unlock(&umh_sysctl_lock);
5438c703d66SChristophe JAILLET 	}
54423558693SLuis R. Rodriguez 
54523558693SLuis R. Rodriguez 	return 0;
54623558693SLuis R. Rodriguez }
54723558693SLuis R. Rodriguez 
548861dc0b4SLuis Chamberlain static struct ctl_table usermodehelper_table[] = {
54923558693SLuis R. Rodriguez 	{
55023558693SLuis R. Rodriguez 		.procname	= "bset",
551e7783615SLinus Torvalds 		.data		= &usermodehelper_bset,
552f122a08bSLinus Torvalds 		.maxlen		= 2 * sizeof(unsigned long),
55323558693SLuis R. Rodriguez 		.mode		= 0600,
55423558693SLuis R. Rodriguez 		.proc_handler	= proc_cap_handler,
55523558693SLuis R. Rodriguez 	},
55623558693SLuis R. Rodriguez 	{
55723558693SLuis R. Rodriguez 		.procname	= "inheritable",
558e7783615SLinus Torvalds 		.data		= &usermodehelper_inheritable,
559f122a08bSLinus Torvalds 		.maxlen		= 2 * sizeof(unsigned long),
56023558693SLuis R. Rodriguez 		.mode		= 0600,
56123558693SLuis R. Rodriguez 		.proc_handler	= proc_cap_handler,
56223558693SLuis R. Rodriguez 	},
56323558693SLuis R. Rodriguez 	{ }
56423558693SLuis R. Rodriguez };
565861dc0b4SLuis Chamberlain 
init_umh_sysctls(void)566861dc0b4SLuis Chamberlain static int __init init_umh_sysctls(void)
567861dc0b4SLuis Chamberlain {
568861dc0b4SLuis Chamberlain 	register_sysctl_init("kernel/usermodehelper", usermodehelper_table);
569861dc0b4SLuis Chamberlain 	return 0;
570861dc0b4SLuis Chamberlain }
571861dc0b4SLuis Chamberlain early_initcall(init_umh_sysctls);
572861dc0b4SLuis Chamberlain #endif /* CONFIG_SYSCTL */
573