在 linux 系统调用中查找用户名
finding the username in a linux system call
我已经向 Linux 内核添加了一个系统调用,如下所示:
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/cred.h>
#include <asm/uaccess.h>
asmlinkage int sys_os_pid_to_uid(int pid, int* puid)
{
struct task_struct* task;
rcu_read_lock();
for_each_process(task)
{
if (task->pid == (pid_t) pid)
{
copy_to_user(puid, &(task->cred->uid.val), sizeof(task->cred->uid.val));
}
}
rcu_read_unlock();
return 0;
}
它获取进程 ID (pid
) 并确定执行它的用户的用户 ID (puid
)。
现在,我的问题开始了:我想向这个系统调用添加另一个参数,即 char *username
,它将包含 ID 为 puid
的用户的用户名。我在 cred.h
header 中搜索但找不到与用户名相关的任何内容。
谁能帮我解决这个问题?
内核不知道用户名;它只处理用户 ID。将用户名解析为用户 ID,反之亦然,完全由 getpwent()
系列 libc 函数(getpwuid()
、getpwnam()
等)在用户空间中处理。
请注意,您的系统调用有些多余;通过在 /proc/$pid
上调用 stat()
或通过读取 /proc/$pid/status
.
来获取进程的用户 ID 已经很简单了
您没有找到它的原因是因为没有:task_struct
,而且内核通常不会在内存中保留与给定用户 ID 对应的用户名的相关信息。这是完全没有必要的,会增加界面和代码的混乱,并且会消耗内存而没有任何额外的好处:与用户有关的所有内容都用数字用户 ID 表示和存储。比较简单,省内存。
你不应该/不能在系统调用中这样做。
我建议您编写一个包装器 user-space 函数来调用您的系统调用,然后调用 getpwuid(3)
或 getpwuid_r(3)
将用户 ID 转换为用户名。请注意,这是在 user-space 中完成的,而不是在内核 space.
中完成的
我很确定用户名的唯一概念是在 userspace 中,基于 /etc/passwd(通常,但也可能是 NIS 或 LDAP 等其他来源)。如果您更改 /etc/passwd 中现有条目的用户名,用户会立即成为新用户名,就像更改 /etc/hosts 中的主机名条目会从本地计算机的角度更改 IP 地址的有效主机名一样。它只是一个查找/名称解析。存储对象将全部包含用户 ID,而不是用户名。
您可能想要跟踪命令 "getent" 和 "id" 等。另请查看 lib 调用 getpwuid()。通常,如果不是总是,系统调用(内核 space)处理 uids。
但这有什么意义呢?你只是在玩内核吗? uid 可以在 /proc 中找到。正如其他人所指出的,必须在用户空间中解析用户名。
我不禁要问你这个循环是从哪里来的,因为它显然非常低效。这里没有理由遍历所有进程,并且可以通过阅读也必须找到它的系统调用的来源轻松找到为给定 pid 获取 task_struct 的方法 - 例如杀死(2)
最后,我还必须注意有问题的代码显然是不正确的。 copy_to_user 可能会导致页面错误,您在 rcu 临界区中无法接受。我很确定内核会告诉你,即使没有发生错误,只要你启用了调试选项。
我已经向 Linux 内核添加了一个系统调用,如下所示:
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/cred.h>
#include <asm/uaccess.h>
asmlinkage int sys_os_pid_to_uid(int pid, int* puid)
{
struct task_struct* task;
rcu_read_lock();
for_each_process(task)
{
if (task->pid == (pid_t) pid)
{
copy_to_user(puid, &(task->cred->uid.val), sizeof(task->cred->uid.val));
}
}
rcu_read_unlock();
return 0;
}
它获取进程 ID (pid
) 并确定执行它的用户的用户 ID (puid
)。
现在,我的问题开始了:我想向这个系统调用添加另一个参数,即 char *username
,它将包含 ID 为 puid
的用户的用户名。我在 cred.h
header 中搜索但找不到与用户名相关的任何内容。
谁能帮我解决这个问题?
内核不知道用户名;它只处理用户 ID。将用户名解析为用户 ID,反之亦然,完全由 getpwent()
系列 libc 函数(getpwuid()
、getpwnam()
等)在用户空间中处理。
请注意,您的系统调用有些多余;通过在 /proc/$pid
上调用 stat()
或通过读取 /proc/$pid/status
.
您没有找到它的原因是因为没有:task_struct
,而且内核通常不会在内存中保留与给定用户 ID 对应的用户名的相关信息。这是完全没有必要的,会增加界面和代码的混乱,并且会消耗内存而没有任何额外的好处:与用户有关的所有内容都用数字用户 ID 表示和存储。比较简单,省内存。
你不应该/不能在系统调用中这样做。
我建议您编写一个包装器 user-space 函数来调用您的系统调用,然后调用 getpwuid(3)
或 getpwuid_r(3)
将用户 ID 转换为用户名。请注意,这是在 user-space 中完成的,而不是在内核 space.
我很确定用户名的唯一概念是在 userspace 中,基于 /etc/passwd(通常,但也可能是 NIS 或 LDAP 等其他来源)。如果您更改 /etc/passwd 中现有条目的用户名,用户会立即成为新用户名,就像更改 /etc/hosts 中的主机名条目会从本地计算机的角度更改 IP 地址的有效主机名一样。它只是一个查找/名称解析。存储对象将全部包含用户 ID,而不是用户名。
您可能想要跟踪命令 "getent" 和 "id" 等。另请查看 lib 调用 getpwuid()。通常,如果不是总是,系统调用(内核 space)处理 uids。
但这有什么意义呢?你只是在玩内核吗? uid 可以在 /proc 中找到。正如其他人所指出的,必须在用户空间中解析用户名。
我不禁要问你这个循环是从哪里来的,因为它显然非常低效。这里没有理由遍历所有进程,并且可以通过阅读也必须找到它的系统调用的来源轻松找到为给定 pid 获取 task_struct 的方法 - 例如杀死(2)
最后,我还必须注意有问题的代码显然是不正确的。 copy_to_user 可能会导致页面错误,您在 rcu 临界区中无法接受。我很确定内核会告诉你,即使没有发生错误,只要你启用了调试选项。