This is an old revision of the document!


Fundamentals of Linux kernel usermodehelper functionality.

Links (coming soon):

#define UMH_NO_WAIT     0       /* don't wait at all */
#define UMH_WAIT_EXEC   1       /* wait for the exec, but not the process */
#define UMH_WAIT_PROC   2       /* wait for the process to complete */
#define UMH_KILLABLE    4       /* wait for EXEC/PROC killable */
struct subprocess_info {
        struct work_struct work;
        struct completion *complete;
        const char *path;
        char **argv;
        char **envp;
        struct file *file;
        int wait;
        int retval;
        pid_t pid;
        int (*init)(struct subprocess_info *info, struct cred *new);
        void (*cleanup)(struct subprocess_info *info);
        void *data;
} __randomize_layout;

Most common variations:

extern struct subprocess_info *
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 *), void *data);
                          
extern int
call_usermodehelper_exec(struct subprocess_info *info, int wait);

extern int
call_usermodehelper(const char *path, char **argv, char **envp, int wait);
struct subprocess_info *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)
{
	struct subprocess_info *sub_info;
	sub_info = kzalloc(sizeof(struct subprocess_info), gfp_mask);
	if (!sub_info)
		goto out;

	INIT_WORK(&sub_info->work, call_usermodehelper_exec_work);

#ifdef CONFIG_STATIC_USERMODEHELPER
	sub_info->path = CONFIG_STATIC_USERMODEHELPER_PATH;
#else
	sub_info->path = path;
#endif
	sub_info->argv = argv;
	sub_info->envp = envp;

	sub_info->cleanup = cleanup;
	sub_info->init = init;
	sub_info->data = data;
  out:
	return sub_info;
}
int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
{
	DECLARE_COMPLETION_ONSTACK(done);
	int retval = 0;

	if (!sub_info->path) {
		call_usermodehelper_freeinfo(sub_info);
		return -EINVAL;
	}
	helper_lock();
	if (usermodehelper_disabled) {
		retval = -EBUSY;
		goto out;
	}

	/*
	 * If there is no binary for us to call, then just return and get out of
	 * here.  This allows us to set STATIC_USERMODEHELPER_PATH to "" and
	 * disable all call_usermodehelper() calls.
	 */
	if (strlen(sub_info->path) == 0)
		goto out;

	/*
	 * Set the completion pointer only if there is a waiter.
	 * This makes it possible to use umh_complete to free
	 * the data structure in case of UMH_NO_WAIT.
	 */
	sub_info->complete = (wait == UMH_NO_WAIT) ? NULL : &done;
	sub_info->wait = wait;

	queue_work(system_unbound_wq, &sub_info->work);
	if (wait == UMH_NO_WAIT)	/* task has freed sub_info */
		goto unlock;

	if (wait & UMH_KILLABLE) {
		retval = wait_for_completion_killable(&done);
		if (!retval)
			goto wait_done;

		/* umh_complete() will see NULL and free sub_info */
		if (xchg(&sub_info->complete, NULL))
			goto unlock;
		/* fallthrough, umh_complete() was already called */
	}

	wait_for_completion(&done);
wait_done:
	retval = sub_info->retval;
out:
	call_usermodehelper_freeinfo(sub_info);
unlock:
	helper_unlock();
	return retval;
}
int call_usermodehelper(const char *path, char **argv, char **envp, int wait)
{
	struct subprocess_info *info;
	gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;

	info = call_usermodehelper_setup(path, argv, envp, gfp_mask,
					 NULL, NULL, NULL);
	if (info == NULL)
		return -ENOMEM;

	return call_usermodehelper_exec(info, wait);
}
config STATIC_USERMODEHELPER
        bool "Force all usermode helper calls through a single binary"
        help
          By default, the kernel can call many different userspace
          binary programs through the "usermode helper" kernel
          interface.  Some of these binaries are statically defined
          either in the kernel code itself, or as a kernel configuration
          option.  However, some of these are dynamically created at
          runtime, or can be modified after the kernel has started up.
          To provide an additional layer of security, route all of these
          calls through a single executable that can not have its name
          changed.

          Note, it is up to this single binary to then call the relevant
          "real" usermode helper binary, based on the first argument
          passed to it.  If desired, this program can filter and pick
          and choose what real programs are called.

          If you wish for all usermode helper programs are to be
          disabled, choose this option and then set
          STATIC_USERMODEHELPER_PATH to an empty string.

config STATIC_USERMODEHELPER_PATH
        string "Path to the static usermode helper binary"
        depends on STATIC_USERMODEHELPER
        default "/sbin/usermode-helper"
        help
          The binary called by the kernel when any usermode helper
          program is wish to be run.  The "real" application's name will
          be in the first argument passed to this program on the command
          line.

          If you wish for all usermode helper programs to be disabled,
          specify an empty string here (i.e. "").
#ifdef CONFIG_STATIC_USERMODEHELPER
        sub_info->path = CONFIG_STATIC_USERMODEHELPER_PATH;
#else
        sub_info->path = path;
#endif
  • lk_usermodehelper.1550095195.txt.gz
  • Last modified: 2019/02/13 21:59
  • by rpjday