Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running a userspace process in user mode with Linux kernel call_usermodehelper

I tried to execute a userspace binary inside the Linux kernel module with call_usermodehelper. I found the launched application is running in root mode. Is it possible to run the application in a user mode, for example, named user1?

int alter_uid_gid(uid_t uid, gid_t gid, struct cred *new)
{
//      struct cred *new;
        new = prepare_creds();
        if (!new)
                return -ENOMEM;
        new->uid = new->euid = new->suid = new->fsuid = KUIDT_INIT(uid);
        new->gid = new->egid = new->sgid = new->fsgid = KGIDT_INIT(gid);
        return commit_creds(new);
}

static int init_func(struct subprocess_info *info, struct cred *new)
{
        printk("[%d]\n", current->pid);
        alter_uid_gid(1000, 1000, new);
        return 0;
}

static int user_process_fork(void *data)
{
    struct subprocess_info *sub_info;
    int ret = 0;
    char *path = (char *)data;
    char *argv[] = {path, 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,
            init_func, NULL, NULL);
    if (sub_info == NULL) return -ENOMEM;

    ret = call_usermodehelper_exec(sub_info, UMH_KILLABLE);
    pr_info("%s: ret %d\n", __func__, ret);
    do_exit(0);

    return ret;
}

Based on Milag's comment, I tried to update the u[g/e/s]idin the init_func() with prepare_creds() and commit_creds(new). In the kernel log, I can see current->uid has changed to 1000. But when I run ps aux, the process is still in root mode. Any idea why?

like image 949
xiaogw Avatar asked Dec 03 '25 04:12

xiaogw


2 Answers

After I read some kernel sources and posted comments above, OP later showed updates for a developed kmod.

Short answer: yes, it's possible to set different IDs for a user process launched from a kmod.

After passing an init routine to call_usermodehelper_setup(), a related kernel service calls the init routine with a (struct cred *); various uid and gid members can be changed there. For more details, see call_usermodehelper_exec_async()

There are related suggestions for kmod versatility:

  • add a pair of #define for a set of default uid and gid

  • add support for module params to set other uid and gid

  • optionally provide cmd-line params when the module is loaded

For an example, see this link .

like image 164
Milag Avatar answered Dec 04 '25 17:12

Milag


Based on @Milag's comment, the following code makes the new userspace process running in user-mode (using ps aux to inspect):

int alter_uid_gid(uid_t uid, gid_t gid, struct cred *new)
{
        new->uid = new->euid = new->suid = new->fsuid = KUIDT_INIT(uid);
        new->gid = new->egid = new->sgid = new->fsgid = KGIDT_INIT(gid);
        return 0;
}

static int init_func(struct subprocess_info *info, struct cred *new)
{
        printk("[%d]\n", current->pid);
        alter_uid_gid(1000, 1000, new);
        return 0;
}

static int user_process_fork(void *data)
{
    struct subprocess_info *sub_info;
    int ret = 0;
    char *path = (char *)data;
    char *argv[] = {path, 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,
            init_func, NULL, NULL);
    if (sub_info == NULL) return -ENOMEM;

    ret = call_usermodehelper_exec(sub_info, UMH_KILLABLE);
    pr_info("%s: ret %d\n", __func__, ret);
    do_exit(0);

    return ret;
}
like image 28
xiaogw Avatar answered Dec 04 '25 18:12

xiaogw