Confusion about list_head children of linux kernel - linux

I want to traverse all the processes and try to show pid,ppid,first children pid as well as the next sibling pid of each process.
It seems that some children pids showed in my test result are incorrect.
For example,process 3,4,5,...,16,17,..are all children of process 2. But from the data it also shows that process 4,5,14,18..their first child refer to process 16!
My code attached here:
struct prinfo p;
p.state = t->state; /* get state */
p.pid = t->pid; /* get pid */
p.parent_pid = t->parent->pid; /* get parent pid */
struct list_head *chd; /* get first child_task */
chd = &(t->children);
struct task_struct *child_task;
child_task = list_entry(chd->next, struct task_struct, sibling);
p.first_child_pid = child_task->pid;
struct list_head *sbl; /* get next sibling_task */
sbl = &(t->sibling);
struct task_struct *sibling_task;
sibling_task = list_entry(sbl->next, struct task_struct, sibling);
p.next_sibling_pid = sibling_task->pid;
p.uid = t->cred->uid; /* get uid */
Can anyone help me out here?

Related

How can I retrieve a task's sessionid in an eBPF program?

I want to retrieve the sessionid from a task struct in an eBPF program. I have the following code in my eBPF program:
struct task_struct *task;
u32 sessionid;
task = (struct task_struct *)bpf_get_current_task();
sessionid = task->sessionid;
This runs, but the sessionid always ends up being -1. I read in this answer that I can use task_session to retrieve it, but I get an error about invalid memory access. I believe I need to use bpf_probe_read to move the task_struct that task points to onto the stack, but I can't get it to work. Is there anything I'm missing?
After a bit more digging through the task_struct struct I realised you could do this:
struct task_struct *task;
struct pid_link pid_link;
struct pid pid;
unsigned int sessionid;
task = (struct task_struct *)bpf_get_current_task();
bpf_probe_read(&pid_link, sizeof(pid_link), (void *)&task->group_leader->pids[PIDTYPE_SID]);
bpf_probe_read(&pid, sizeof(pid), (void *)pid_link.pid);
sessionid = pid.numbers[0].nr;

Linux process data structure

According to GNU website the linux shell uses the following data structure for a process :
typedef struct process
{
struct process *next; /* next process in pipeline */
char **argv; /* for exec */
pid_t pid; /* process ID */
char completed; /* true if process has completed */
char stopped; /* true if process has stopped */
int status; /* reported status value */
} process;
Why can't the shell use the task_struct data structure for a process when it is already present in the kernel. Why use a separate data structure ?

Retrieve parent pid

I am new to kernel module progrmming. In my program I need to display the process name and its parent's pid.
The following is my simple_init() function
int simple_init(void){
printk(KERN_INFO "--------------Starting module--------------\n");
struct task_struct *intask = &init_task;
struct list_head fd = intask->children;
struct list_head *list;
struct task_struct *task;
int k =0;
list_for_each(list, &fd){
task = list_entry(list, struct task_struct, sibling);
struct task_struct *parent = task->parent;
pid_t parent_pid = parent -> pid;
printk(KERN_INFO "Name: %s ---- %d ----Parent: %d\n",task->comm, task->pid, parent_pid);
if (k==2) break;
k++;
}
return 0;
}
Problem is that after I added the line:
struct task_struct *parent = task->parent;
Now, when I run the insmod command it says Segementation fault, and I have to restart the machine (virtual machine) to try again.
Can anyone of you show me what's wrong with this?
Kernel code, in particular module initialization code, is not always running on behave of some process. Both interrrupt & scheduler related code is running without any particular process.
So I guess that your task could be NULL

i am creating a kernel module to find the resident pages for all the process

I am creating a kernel module to find the resident pages for all the process. I am using get_mm_rss() and for_each_process but it works
only for init process / first time after first iteration it doesn't work.
int __init schedp(void){
struct task_struct *p;
for_each_process(p) {
int pid = task_pid_nr(p);
printk("Process: %s (pid = %d) , (rpages : %lu)\n",
p->comm, pid, get_mm_rss(p->mm));
}
return 0;
}
Results:
BUG: unable to handle kernel NULL pointer dereference at 00000160,
You're probably getting NULL in p->mm, because some tasks may have invalid mm pointer because they are exiting or don't have mm (because they are kernel-threads, not sure).
When you confused on how to use kernel API, always look for examples inside kernel itself. Quick search with cross-reference tool gave me kernel/cpu.c:
for_each_process(p) {
struct task_struct *t;
/*
* Main thread might exit, but other threads may still have
* a valid mm. Find one.
*/
t = find_lock_task_mm(p);
if (!t)
continue;
cpumask_clear_cpu(cpu, mm_cpumask(t->mm));
task_unlock(t);
}
Note that you need to call find_lock_task_mm() and task_unlock() and explicitly check for NULL.
finally it works after creating a function which checks a mm_struct is valid or not for_each_process
struct task_struct *task_mm(struct task_struct *p){
struct task_struct *t;
rcu_read_lock();
for_each_thread(p, t) {
task_lock(t);
if (likely(t->mm))
goto found;
task_unlock(t);
}
t = NULL;
found:
rcu_read_unlock();
return t;
}

Where do_fork() defines the "prio" field for the newly allocated task_struct?

That includes other fields like static_prio and policy. I know that by definition the child process inherits them from the father, but where does it happens in the code of do_fork() ?
The “prio” field for the newly allocated task_struct is defined in sched_fork() function.
The call flow for sched_fork() function is fork() -> sys_fork() -> do_fork() -> copy_process() -> sched_fork().
for your reference here is the sched_fork() function below. ( kernel version 3.7.5 )
void sched_fork(struct task_struct *p)
{
unsigned long flags;
int cpu = get_cpu();
__sched_fork(p);
/*
* We mark the process as running here. This guarantees that
* nobody will actually run it, and a signal or other external
* event cannot wake it up and insert it on the runqueue either.
*/
p->state = TASK_RUNNING;
/*
* Make sure we do not leak PI boosting priority to the child.
*/
p->prio = current->normal_prio;
/*
* Revert to default priority/policy on fork if requested.
*/
if (unlikely(p->sched_reset_on_fork)) {
if (task_has_rt_policy(p)) {
p->policy = SCHED_NORMAL;
p->static_prio = NICE_TO_PRIO(0);
p->rt_priority = 0;
} else if (PRIO_TO_NICE(p->static_prio) < 0)
p->static_prio = NICE_TO_PRIO(0);
p->prio = p->normal_prio = __normal_prio(p);
set_load_weight(p);
/*
* We don't need the reset flag anymore after the fork. It has
* fulfilled its duty:
*/
p->sched_reset_on_fork = 0;
}
.....
......
}

Resources