运行 用户模式下的用户空间进程,带有 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。
我试图用 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。