运行 用户模式下的用户空间进程,带有 Linux 内核 call_usermodehelper

Running a userspace process in user mode with Linux kernel call_usermodehelper

我试图用 call_usermodehelper 在 Linux 内核模块中执行用户空间二进制文件。我发现启动的应用程序在根模式下 运行ning。是否可以运行用户模式下的应用程序,例如命名为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;
}

根据 Milag 的评论,我尝试用 prepare_creds()commit_creds(new) 更新 init_func() 中的 u[g/e/s]id。在内核日志中,我可以看到 current->uid 已更改为 1000。但是当我 运行 ps aux 时,进程仍处于 root 模式。知道为什么吗?

根据@Milag 的评论,以下代码使新用户空间进程 运行 处于用户模式(使用 ps aux 检查):

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;
}

在我阅读了一些内核源代码并在上面发表评论后,OP 后来显示了开发的 kmod 的更新。

简短回答:是的,可以为从 kmod 启动的用户进程设置不同的 ID。

将 init 例程传递给 call_usermodehelper_setup() 后,相关内核服务使用 (struct cred *) 调用 init 例程;可以在那里更改各种 uid 和 gid 成员。有关详细信息,请参阅 call_usermodehelper_exec_async()

kmod通用性有相关建议:

  • 添加一对#define为一组默认uid和gid

  • 添加对模块参数的支持以设置其他 uid 和 gid

  • 可选地在加载模块时提供 cmd 行参数

有关示例,请参阅 this link