Ramsey Alsheikh
Ramsey Alsheikh

Reputation: 329

How does the kernel use task_struct?

I am a student doing research involving Linux processes, and I need to learn more about them to proceed with my experiment. In reading a couple books and things online, I've come across task_struct, which I'm not sure I'm understanding fully, and would like confirmation/correction onto my existing thought.

From what I think I've understood, task_struct is the C structure that acts as the process descriptor, holding everything the kernel might need to know about a processes. At the end of the process kernel stack lives another struct, thread_info, which has a pointer to the processes task_struct.

Another question: how does one access the task_struct of a process? Is there a calculation to find the location of it's thread_info? Is there a macro/function within the kernel?

Upvotes: 13

Views: 21935

Answers (3)

Ahab Devoid
Ahab Devoid

Reputation: 47

Here's an example of a kernel module that uses task_struct to determine if a process of a certain name exists upon module insertion:

/*
 * File Name : test.c
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm_types.h>
#include <linux/sched/signal.h>

rwlock_t tasklist_lock;

static int __init Init(void){
    struct task_struct *p = current;
    read_lock(&tasklist_lock);
    for_each_process(p){
        if(!strncmp((const char *)p->comm, "Slay999", 16)){
            printk(KERN_INFO "Found target program\n");

            break;
        }
    }   
    read_unlock(&tasklist_lock);
    return 0;
}

static void __exit Exit(void){
    printk(KERN_INFO "Module removed.\n");
}

MODULE_DESCRIPTION("Experements in privlege escalation.");
MODULE_AUTHOR("a name");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.0");

module_init(Init);
module_exit(Exit);

By obtaining a pointer to an valid task_struct address we can get information about a process that we can then use for statistical purposes and reconfiguration purposes.

For example, you can see the entire definition of task_struct using the following bash command (obtainable through apt-get install pahole):

pahole -C task_struct

Some quick side notes;

  1. current I believe contains the active kernel process's data.
  2. The struct variable task_struct.comm, shown as p->comm contains the running program's name.
  3. There exists a variable called pid that contains the process ID, there also exists a function to get a pointer to a task_struct using a pid_t directly.
  4. Through variables in the task_struct structure you can obtain things like struct mm_struct *active_mm which from what I understand can give you the current memory address of a running process.

Here is the accompanying make file for the module:

obj-m += test.o
all:
        make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
clean:
        make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean

Upvotes: 0

Dražen Grašovec
Dražen Grašovec

Reputation: 802

Let me try answer second question.

On the top of each process kernel stack there is a structure thread_info.

To get address of/pointer to thread_info, different architectures have different solutions, but on x86 it looks something like this:

To get pointer to thread_info just mask 13 bits of the stack pointer value:

movl $0xFFFFE000, %eax
andl %esp, %eax

Now we have pointer, and this structure has pointer for task_struct structure.

To get it, there is a current macro, which looks something like this:

#define current (current_thread_info()->task)

and it gives you pointer (address of) task_struct

Upvotes: 1

Hadi Brais
Hadi Brais

Reputation: 23719

Yes, the task_struct structure contains all the information about a process. You can obtain a pointer to the structure that describes the current process using the current macro as follows:

struct task_struct *p = current;

If you want to get the structure that describes a process given a pid, you can use the find_task_by_vpid function as follows:

read_lock(&tasklist_lock);
p = find_task_by_vpid(pid);
if (p) get_task_struct(p);
read_unlock(&tasklist_lock);
if (p == NULL) {
    // Task not found.
}

// Later, once you're finished with the task, execute:
put_task_struct(p);

Finally, if you want to iterate over all processes, you can use for_each_process as follows:

read_lock(&tasklist_lock);
for_each_process(p) {
    // p is a pointer to a task_struct instance.
}
read_unlock(&tasklist_lock);

If you want to an exclusive access to the task list to be able to make changes to one or more fields in the structure, write_lock_irqsave must be used instead of read_lock.

Upvotes: 11

Related Questions