I would like to retrieve caller process' PID (Userspace) in Linux Driver.
At first, I could find pid
attribute so easy from the struct task_struct
in Linux Source Code (include/linux/sched.h
) I used current->pid
to retrieve userspace PID.
However, I read some articles telling that the pid
in Kernel and Userspace context are different. In other words, so called userspace PID is in fact tgid
which is also an attribute of struct task_struct
.
Moreover, when I look into the source code getpid()
system call expecting this should return task_struct.pid
or task_struct.tgid
, it turns out that it returned unexpected function- task_tgid_vnr
- ultimately uses the signal
inside task_struct
.
As my ultimate goal was so simple- to find out the exact same PID retrieved from getpid()
system call in Linux kernel- I am very confused.
In conclusion, among all the options above, which way is the recommended way to retrieve the caller process' userspace PID?
Most of the times, you shouldn't access the task structure directly to get this kind of information. There are several problems in doing so:
struct pid
) that can be referenced by multiple tasks. Note that even though the name of the struct is pid
, it is used to refer to all kind of PIDs (PID, TGID, PGID, SID).task->field
. PID structures for example are RCU protected.The kernel vs user space terminology is also confusing, so make sure to understand the difference. In general, when coding kernel modules, only kernel terminology is used. What the kernel calls "PID" is a unique number associated with every task in the namespace. A task is a single thread, therefore a PID in kernel space is what you would call TID (thread ID) in user space. A TGID (thread group ID) in kernel space is what you would call a PID (process ID) in user space. All tasks with the same TGID belong to the same process. Only one task will have a PID equal to its TGID, and that is the main thread.
Looking at getpid
syscall code is a good start. In this case, getpid
wants to return the virtual TGID to user space, so it uses task_tgid_vnr()
. You can see a comment explaining the meaning of the various pid helpers in linux/pid.h
:
/*
* the helpers to get the task's different pids as they are seen
* from various namespaces
*
* task_xid_nr() : global id, i.e. the id seen from the init namespace;
* task_xid_vnr() : virtual id, i.e. the id seen from the pid namespace of
* current.
* task_xid_nr_ns() : id seen from the ns specified;
*
* see also pid_nr() etc in include/linux/pid.h
*/
You shold use one of the above functions depending on your needs:
task_tgid_nr()
;task_tgid_vnr()
;task_tgid_nr_ns()
.