Invoking specific kernel functions (system calls) is a natural part of application development on GNU/Linux. But what about going in the other direction, kernel space calling user space? It turns out that there are a number of applications for this feature that you likely use every day. For example, when the kernel finds a device for which a module needs to be loaded, how does this process occur? Dynamic module loading occurs from the kernel through the usermode-helper process.

Data structure that is used for the API is struct subprocess_info.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/linux/include/kmod.h

struct subprocess_info {
struct work_struct work;
struct completion* complete;
const char* path;
char** argv;
char** envp;
int wait;
int retval;
int (*init)(struct subprocess_info* info, struct cred* new);
void (*cleanup)(struct subprocess_info* info);
void* data;
};

Simple example from the reference:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static int umh_test( void )
{
struct subprocess_info ∗sub_info;
char ∗argv[] = { "/usr/bin/logger", "help!", NULL };
static char ∗envp[] = {
"HOME=/",
"TERM=linux",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL };

sub_info = call_usermodehelper_setup( argv[0], argv, envp, GFP_ATOMIC );
if (sub_info == NULL) return ‑ENOMEM;

return call_usermodehelper_exec( sub_info, UMH_WAIT_PROC );
}

This code will executes /usr/bin/logger executable file. It should be called from device driver, or another kernel space.

Simpler version of process creation is as follows.

1
2
3
4
5
6
7
8
9
10
static int umh_test( void )
{
char ∗argv[] = { "/usr/bin/logger", "help!", NULL };
static char ∗envp[] = {
"HOME=/",
"TERM=linux",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL };

return call_usermodehelper( argv[0], argv, envp, UMH_WAIT_PROC );
}

参考资料:

  1. Invoking user-space applications from the kernel
  2. Usermode Helper API