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
Related
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;
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?
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;
}
Hi I'm trying to add a custom system call to a lubuntu kernel.I'm trying to kill a process within this system call. I tried kill() system call in original ubuntu kernel. But i got compiler errors while doing that. I have no idea how to do that properly. Thanks in advance for your answers.
#define _POSIX_SOURCE
#include <linux/syscalls.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/signal.h>
#include <linux/types.h>
asmlinkage long sys_my_process_terminator (pid_t pid , int flag)
{
struct task_struct *task;
struct list_head *list;
struct list_head *siblist;
// firstly check the flag
struct task_struct *myprocess;
struct task_struct *sibchild;
myprocess = find_task_by_vpid(pid);
struct task_struct *pp;
pp =myprocess->parent;
if (flag == 0){
// this loop under this comment will kill all the children of the given process
list_for_each(list, &myprocess->children) {
task = list_entry(list, struct task_struct, sibling);
printk ("%s [%d] \n" , task->comm , task->pid);
kill(task->pid,SIGKILL);
}
}
else if (flag==1) {
list_for_each(list, &pp->children) {
task = list_entry(list, struct task_struct, sibling);
list_for_each(siblist, &task->children) {
sibchild = list_entry(siblist, struct task_struct, sibling);
printk ("%s [%d] \n" , sibchild->comm , sibchild->pid);
kill(sibchild->pid,SIGKILL);
}
if (task->pid !=pid){
printk ("%s [%d] \n" , task->comm , task->pid);
kill(task->pid,
}
You can not use the system call in a system call like that fork, kill, exit.
The kill() system call is commonly used to send to conventional process or multithreaded applications; its corresponding service routine is the sys_kill() function.
So you can use sys_kill() function on the kernel level in order to kill a process.
Usage of sys_kill() :
https://www.kernel.org/doc/htmldocs/device-drivers/API-sys-kill.html
and source book:
"Linux Kernel Development, 3rd Edition" by Robert Love (Publisher: Addison Wesley Professional, 2010)
Note : 2. Part'ı yapabildiniz mi ?? :)
Here is what I did:
A user space process uses malloc() to allocate memory on the heap and fills it with a specific pattern of characters and then spells out the address returned by the malloc().
The process id and the address of the memory chunk are passed to a kernel module that looks like this:
int init_module(void) {
int res = 0;
struct page *data_page;
struct task_struct *task = NULL;
struct vm_area_struct *next_vma;
struct mm_struct *mm;
task = pid_task(find_vpid(pid), PIDTYPE_PID);
if (pid != -1)
target_process_id = pid;
if (!task) {
printk("Could not find the task struct for process id %d\n", pid);
return 0;
} else {
printk("Found the task <%s>\n", task->comm);
}
mm = task->mm;
if (!mm) {
printk("Could not find the mmap struct for process id %d\n", pid);
return 0;
}
next_vma = find_vma(mm, addr);
down_read(&task->mm->mmap_sem);
res = get_user_pages(task, task->mm, addr, 1, 1, 1, &data_page, NULL);
if (res != 1) {
printk(KERN_INFO "get_user_pages error\n");
up_read(&task->mm->mmap_sem);
return 0;
} else {
printk("Found vma struct and it starts at: %lu\n", next_vma->vm_start);
}
flush_cache_range(next_vma,next_vma->vm_start,next_vma->vm_end);
flush_tlb_range(next_vma,next_vma->vm_start,next_vma->vm_end);
up_read(&task->mm->mmap_sem);
return 0;
}
I added printk() statement to the handle_mm_fault() function in the Linux kernel to track page faults caused by target_process_id (3rd line of code after variable definitions above). Something like this:
if (unlikely(current->pid == target_process_id))
printk("Target process <%d> generated a page fault at address %lu\n", current->pid, address);
Now, what I noticed is that the last printk() statement does not catch anything.
The function init_module is the initialization function for a kernel module. It is inserted into the running kernel using insmod...using the command insmod module.ko pid=<processId> addr=<address>
Any idea what might going wrong?