问题
I have added a system call to Linux kernel that looks like this:
#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;
}
It gets a process ID (pid
) and determines the user ID (puid
) of the user who is executing it.
Now, my problem begins: I want to add another argument to this system call, that is, char *username
, which will contain the username of the user whose ID is puid
. I searched in the cred.h
header but was unable to find anything concerned with the username.
Can anyone help me solve this?
回答1:
The reason you didn't find it is because there isn't one: task_struct
, and the kernel in general, does not keep in-memory information about the username corresponding to a given user ID. That is utterly unnecessary, would add clutter to the interfaces and code, and would consume memory without any added benefit: everything regarding users is represented and stored with numeric user ids. Comparison is easy and memory is saved.
You shouldn't / can't do this in a syscall.
I suggest you write a wrapper user-space function that invokes your syscall and then calls getpwuid(3)
or getpwuid_r(3)
to convert from the user ID to the username. Note that this is to be done in user-space, not in kernel space.
回答2:
The kernel is not aware of usernames; it only deals with user IDs. Resolving usernames to user IDs and vice versa is handled entirely in userspace by the getpwent()
family of libc functions (getpwuid()
, getpwnam()
, etc).
Note that your system call is somewhat redundant; it's already trivial to get the user ID of a process by calling stat()
on /proc/$pid
, or by reading /proc/$pid/status
.
回答3:
I'm pretty sure the only concept of username is in userspace, based on the /etc/passwd (usually, but could be other sources like NIS or LDAP). If you change the username of an existing entry in /etc/passwd, the user immediately becomes that new username, much like changing a hostname entry in /etc/hosts changes the effective hostname of an IP address from your local computer's perspective. Its just a lookup / name resolution. Storage objects will all contain the user ID, not the username.
You may want to trace the commands "getent" and "id" among others. Also look at lib call getpwuid(). Usually, if not always, syscalls (kernel space) handle uids.
回答4:
But what is the point of this? Are you just playing with the kernel? uid can be found in /proc. As was noted by others, username has to be resolved in userspace.
I cannot help but ask where did you take this loop from, as it is obviously terribly inefficient. There is 0 reason to iterate over all processes here, and the way to obtain task_struct for a given pid can be easily found by reading sources of a syscall which also has to find it - e.g. kill(2)
Finally, I also have to note the code in question is obvoiusly incorrect. copy_to_user can result in a page fault which you cannot take while in rcu critical section. I'm pretty sure the kernel would have told you that even without the fault occuring if only you had debug options enabled.
来源:https://stackoverflow.com/questions/31149539/finding-the-username-in-a-linux-system-call