Properly getting parent and children process pids from a linux kernel - c

I have used linux for a few months now, and just recently got acquainted with LKM. I have a small module (or program) that is supposed to print the parent and children's pid for every process running, however, I keep getting negative values for children's pids which I don't think is a valid value for a pid.
So far this is what I have:
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/printk.h>
#include <linux/list.h>
#include <linux/sched/signal.h>
int mod_init(void){
struct task_struct *task;
struct list_head *cursor;
struct task_struct *child;
printk(KERN_INFO "Custom mod Loaded");
for_each_process(task) {
printk(KERN_INFO "Parent %d \n", task->pid);
list_for_each(cursor, &task->children) {
child = list_entry(cursor, struct task_struct, children);
printk(KERN_INFO "\t Child %s | PID: %d \n", child->comm, child->pid);
}
}
return 0;
}
void mod_exit(void){
printk(KERN_INFO "Custom mod loaded");
}
module_init( mod_init );
module_exit( mod_exit );
MODULE_DESCRIPTION("Trying not to be a noob, and failing hard");
MODULE_AUTHOR("jlarator");
MODULE_LICENSE("GPL");
this is the make file
obj-m += mod.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
This is what some of the output looks like
when I insert the module, and then call dmesg
[ 3835.687212] Parent 2029
[ 3835.687213] Child | PID: -1903591424
[ 3835.687214] Child | PID: -1903591424
[ 3835.687215] Child | PID: -1903591424
From this I can tell that I am missing something big, my main concern is why am I getting negative numbers.

Related

How do I find the RAM usage of a process using its ID?

I am really new to this Kernel stuff. I went here and I found this code that outputs process information like its ID.
main.c:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched/signal.h>
#include <linux/sched.h>
struct task_struct *task; /* Structure defined in sched.h for tasks/processes */
struct task_struct *task_child; /* Structure needed to iterate through task children */
struct list_head *list; /* Structure needed to iterate through the list in each task->children struct */
int iterate_init(void) /* Init Module */
{
printk(KERN_INFO "%s","LOADING MODULE\n"); /* good practice to log when loading/removing modules */
for_each_process( task ){ /* for_each_process() MACRO for iterating through each task in the os located in linux\sched\signal.h */
printk(KERN_INFO "\nPARENT PID: %d PROCESS: %s STATE: %ld",task->pid, task->comm, task->state);/* log parent id/executable name/state */
list_for_each(list, &task->children){ /* list_for_each MACRO to iterate through task->children */
task_child = list_entry( list, struct task_struct, sibling ); /* using list_entry to declare all vars in task_child struct */
printk(KERN_INFO "\nCHILD OF %s[%d] PID: %d PROCESS: %s STATE: %ld",task->comm, task->pid, /* log child of and child pid/name/state */
task_child->pid, task_child->comm, task_child->state);
}
printk("-----------------------------------------------------"); /*for aesthetics*/
}
return 0;
} /* End of Init Module */
void cleanup_exit(void) /* Exit Module */
{
printk(KERN_INFO "%s","REMOVING MODULE\n");
} /* End of Exit Module */
module_init(iterate_init); /* Load Module MACRO */
module_exit(cleanup_exit); /* Remove Module MACRO */
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ITERATE THROUGH ALL PROCESSES/CHILD PROCESSES IN THE OS");
MODULE_AUTHOR("Laerehte");
Makefile:
obj-m += main.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
Executed with ./ins (with chmod +x)
Code:
sudo insmod main.ko
sudo rmmod main
sudo dmesg -c
I looked up how to find how much memory a process uses, and I found this question: Memory usage of current process in C.
Correct me if I'm wrong here, but I'm thinking that you can read the current RAM usage of these processes by looking in /proc/[process_id]/status. I found out from another place(forgot where) that within this file, there is something called VmRSS that would hold the current RAM usage of the process.
You can apparently use:
ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos);
to read a file, but I have not been able to modify main.c with this successfully. I need to find the size of the file, but I also have not been able to use vfs_stat correctly. When I just try some constant integer, I get all 0s in the buffer anyway. I don't know how to use these functions properly. I'm trying to modify main.c so that I will see the RAM usage of these processes along with the other information. Much of the information I found was outdated. Can anyone help?
While you can technically open and read files from kernel space, it's usually a bad idea for multiple reasons. Whatever information is provided under /proc is already available to the kernel, you just need to figure out where it is and how to obtain it, and you will be able to do everything in your module without reading any file.
You are interested in knowing how much RAM is a particular process using given its PID, and you are correct that this statistic is available in /proc/<PID>/status: in fact, it is labeled as "VmRSS" which means "virtual memory resident set size". If we take a look at the kernel source code, we can see exactly how that number is calculated:
The kernel function called when reading /proc/<PID>/status is proc_pid_status() in fs/proc/array.c, which then calls (among the other things) task_mem().
// ...
anon = get_mm_counter(mm, MM_ANONPAGES);
file = get_mm_counter(mm, MM_FILEPAGES);
shmem = get_mm_counter(mm, MM_SHMEMPAGES);
// ...
hiwater_rss = total_rss = anon + file + shmem;
// ...
SEQ_PUT_DEC(" kB\nVmHWM:\t", hiwater_rss);
SEQ_PUT_DEC(" kB\nVmRSS:\t", total_rss); // <===== here it is
SEQ_PUT_DEC(" kB\nRssAnon:\t", anon);
// ...
You can therefore obtain this information in the same way. First get ahold of the task_struct of the process you want to check, then inspect the ->mm field like get_mm_counter() does, or simply using get_mm_rss() from include/linux/mm.h, which does exactly what we want.
Note that:
The value obtained from get_mm_counter() or get_mm_rss() is the number of pages, you will have to multiply this by the page size (simply shift left by PAGE_SHIFT).
You will only be able to do this if your kernel was compiled with MMU support (CONFIG_MMU=y), you can check this in your module code with a simple #ifdef or #ifndef.
Here's a working example module to do this for all processes:
// SPDX-License-Identifier: GPL-3.0
#include <linux/kernel.h> // printk(), pr_*()
#include <linux/module.h> // THIS_MODULE, MODULE_VERSION, ...
#include <linux/init.h> // module_{init,exit}
#include <linux/sched/task.h> // struct task_struct, {get,put}_task_struct()
#include <linux/sched/signal.h> // for_each_process()
#include <linux/sched/mm.h> // get_task_mm(), mmput()
#include <linux/mm.h> // get_mm_rss()
/* Tested on kernel 5.6, qemu-system-aarch64
* Usage: sudo insmod task_rss
* sudo modprobe task_rss
*/
#ifdef pr_fmt
#undef pr_fmt
#endif
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
static int __init modinit(void)
{
struct task_struct *tsk;
struct mm_struct *mm;
unsigned long rss;
char comm[TASK_COMM_LEN];
#ifndef CONFIG_MMU
pr_err("No MMU, cannot calculate RSS.\n");
return -EINVAL;
#endif
for_each_process(tsk) {
get_task_struct(tsk);
get_task_comm(comm, tsk);
mm = get_task_mm(tsk);
// https://www.kernel.org/doc/Documentation/vm/active_mm.rst
if (mm) {
rss = get_mm_rss(mm) << PAGE_SHIFT;
mmput(mm);
pr_info("PID %d (\"%s\") VmRSS = %lu bytes\n", tsk->pid, comm, rss);
} else {
pr_info("PID %d (\"%s\") is an anonymous process\n", tsk->pid, comm);
}
put_task_struct(tsk);
}
return 0;
}
static void __exit modexit(void)
{
// This function is only needed to be able to unload the module.
}
module_init(modinit);
module_exit(modexit);
MODULE_VERSION("0.1");
MODULE_DESCRIPTION("Silly test module to calculare task RSS of all running tasks.");
MODULE_AUTHOR("Marco Bonelli");
MODULE_LICENSE("GPL");
Output on my machine (qemu-system-aarch64):
/ # insmod task_rss.ko
[ 7.306284] task_rss: loading out-of-tree module taints kernel.
[ 7.312912] task_rss: PID 1 ("init") VmRSS = 4096 bytes
[ 7.313295] task_rss: PID 2 ("kthreadd") is an anonymous process
[ 7.314039] task_rss: PID 3 ("rcu_gp") is an anonymous process
...
[ 7.330169] task_rss: PID 146 ("sh") VmRSS = 1363968 bytes
[ 7.330554] task_rss: PID 147 ("insmod") VmRSS = 1339392 bytes

How to find execution time in kernel space [duplicate]

This question already has answers here:
How can i print current time in kernel?
(2 answers)
Closed 1 year ago.
I want to find the execution time of a kernel level thread in linux kernel version 5.11.0. the program is in C and I am using do_gettimeofday function for the same.
code: a C file named task-1.c
//to create kernel level threads and measure the time of completion
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/times.h>
#include <linux/delay.h>
static struct task_struct *thread_st;
int thread_fn(void *i) // Function executed by kernel thread
{
printk(KERN_INFO "In thread1");
return 0;
}
// Module Initialization
static int __init init_thread(void)
{
struct timeval t0,t1;
double temp;
//for calculating time take to create a thread
do_gettimeofday(&t0,NULL);
printk(KERN_INFO "Creating Thread\n");
thread_st = kthread_run(thread_fn, NULL, "mythread1003");
do_gettimeofday(&t1, NULL);
if (thread_st)
{
temp = ((t1.tv_sec - t0.tv_sec)*1000000 + (t1.tv_usec -
t0.tv_usec));
printk(KERN_INFO "Thread (Name: mythread1003) Created successfully and Time Take (to create thread is ) %.2f \n",temp);
}
else
printk(KERN_ERR "Thread creation failed\n");
return 0;
}
// Module Exit
static void __exit cleanup_thread(void)
{
printk(KERN_INFO "Cleaning Up\n");
if (thread_st)
{
kthread_stop(thread_st);
printk(KERN_INFO "Thread stopped");
}
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xyz");
MODULE_DESCRIPTION("A Simple Module for the k.threads");
module_init(init_thread);
module_exit(cleanup_thread);
Makefile:
obj-m += task-1.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
but when I am trying to execute the above using make command it give me the following error
make -C /lib/modules/5.11.0/build M=/home/jayant/Desktop/cse2005/lab-7-kernel-threads/TASK-1 modules
make[1]: Entering directory '/home/jayant/Downloads/linux-5.11'
CC [M] /home/jayant/Desktop/cse2005/lab-7-kernel-threads/TASK-1/task-1.o
/home/jayant/Desktop/cse2005/lab-7-kernel-threads/TASK-1/task-1.c: In function ‘init_thread’:
/home/jayant/Desktop/cse2005/lab-7-kernel-threads/TASK-1/task-1.c:21:20: error: storage size of ‘t0’ isn’t known
struct timeval t0,t1;
^~
/home/jayant/Desktop/cse2005/lab-7-kernel-threads/TASK-1/task-1.c:21:23: error: storage size of ‘t1’ isn’t known
struct timeval t0,t1;
^~
/home/jayant/Desktop/cse2005/lab-7-kernel-threads/TASK-1/task-1.c:25:5: error: implicit declaration of function ‘do_gettimeofday’; did you mean ‘do_settimeofday64’? [-Werror=implicit-function-declaration]
do_gettimeofday(&t0,NULL);
^~~~~~~~~~~~~~~
do_settimeofday64
/home/jayant/Desktop/cse2005/lab-7-kernel-threads/TASK-1/task-1.c:21:23: warning: unused variable ‘t1’ [-Wunused-variable]
struct timeval t0,t1;
^~
/home/jayant/Desktop/cse2005/lab-7-kernel-threads/TASK-1/task-1.c:21:20: warning: unused variable ‘t0’ [-Wunused-variable]
struct timeval t0,t1;
^~
cc1: some warnings being treated as errors
scripts/Makefile.build:279: recipe for target '/home/jayant/Desktop/cse2005/lab-7-kernel-threads/TASK-1/task-1.o' failed
make[2]: *** [/home/jayant/Desktop/cse2005/lab-7-kernel-threads/TASK-1/task-1.o] Error 1
Makefile:1800: recipe for target '/home/jayant/Desktop/cse2005/lab-7-kernel-threads/TASK-1' failed
make[1]: *** [/home/jayant/Desktop/cse2005/lab-7-kernel-threads/TASK-1] Error 2
make[1]: Leaving directory '/home/jayant/Downloads/linux-5.11'
Makefile:3: recipe for target 'all' failed
make: *** [all] Error 2
what I think is that, the problem is with do_gettimeofday command. Is there any other way to calculate the execution time of kernel level thread also I tried using clock() but still couldn't find the solution for the same.
In kernel you can use jiffies (http://books.gigatux.nl/mirror/kerneldevelopment/0672327201/ch10lev1sec3.html) to measure time lapses http://www.makelinux.net/ldd3/chp-7-sect-1.shtml - 7.1. Measuring Time Lapses
Are you using Yocto or Bitbake directly ?

creating a simple kernel module using VirtualBox which outputs the elements of a C struct

I am attempting to create a simple kernel module using Oracle VirtualBox. The module simply instantiates instances of a C struct and outputs the elements of those struct instances using a printk statement. The problem is that I am getting no output of the elements of my struct instances
the make file code is as follows:
obj-m += simple.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=S(PWD) clean
the companion file is named simple.c and is as follows:
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/list.h>
#include<linux/types.h>
struct birthday{
int day;
int month;
int year;
struct list_head list;
}
//defines and initializes the variable birthday_list of type struct list_head
static LIST_HEAD(birthday_list);
//create and initialize instances of struct birthday
struct birthday *person2;
person2 = kmalloc(sizeof(*person2), GFP_KERNEL);
person2->day = 11;
person2->month = 9;
person2->year = 1985;
INIT_LIST_HEAD(&person2->list);
//this function is called when the module is loaded
int simple_init(void){
printk(KERN_INFO "Loading Module\n");
printk(KERN_INFO "Person 2 day is: %d \n", person2->day);
printk(KERN_INFO "Person 2 month is: %d \n", person2->month);
printk(KERN_INFO "person 2 year is: %d \n", person2->year);
return 0;
}
//this function is called when the module is removed
int simple_exit(void){
printk(KERN_INFO "Removing module\n");
}
//macros for registering module entry and exit points
module_init(simple_init);
module_exit(siple_exit);
}
The problem is that the only output I am getting is the first print statement "Loading Module", the other print statements which are supposed to output the elements of the instance of my struct do not output anything at all. Is something wrong with my syntax?
The procedure I am using, is:
type, on the command line, the command: "make" in order to compile the file simple.c
Next, type the command: "sudo insmod simple.ko" to load the kernel module.
Next, type the command: "dmesg" to see the output of my printk statements.
When I follow this procedure, the only output I get is: "Loading Module" I get no output from the instance of my struct

Jprobe to 'do_execve' on Ubuntu 14 doesn't work but work on Ubuntu 12

I am trying to perform a hook to the function 'do_execve()' on Linux kernel using Jprobes, but I'm having issues with certain systems. I tried using this code I found online on an Ubuntu 12, 64 bit (Kernel Version 3.11):
Hook.c:
/* Trace do_execv. Taken basically from Documentation/kprobes.txt */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kprobes.h>
#include <linux/kallsyms.h>
/*
* Pre-entry point for do_execve.
*/
static int my_do_execve(char * filename,
char __user *__user *argv,
char __user *__user *envp,
struct pt_regs * regs)
{
printk("do_execve for %s from %s\n", filename, current->comm);
/* Always end with a call to jprobe_return(). */
jprobe_return();
/*NOTREACHED*/
return 0;
}
static struct jprobe my_jprobe = {
.entry = (kprobe_opcode_t *) my_do_execve
};
int init_module(void)
{
int ret;
my_jprobe.kp.addr =
(kprobe_opcode_t *) kallsyms_lookup_name("do_execve");
if (!my_jprobe.kp.addr) {
printk("Couldn't find %s to plant jprobe\n", "do_execve");
return -1;
}
if ((ret = register_jprobe(&my_jprobe)) <0) {
printk("register_jprobe failed, returned %d\n", ret);
return -1;
}
printk("Planted jprobe at %p, handler addr %p\n",
my_jprobe.kp.addr, my_jprobe.entry);
return 0;
}
void cleanup_module(void)
{
unregister_jprobe(&my_jprobe);
printk("jprobe unregistered\n");
}
MODULE_LICENSE("GPL");
Makefile:
# This is taken straight from Documentation/kprobes.txt
obj-m := trace-exec.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
rm -f *.mod.c *.ko *.o
The module worked as expected. It was first compiled correctly on the system, and then inserted with the function 'insmod' (with ROOT privileges). Running dmesg shows the correct output:
Planted Jprobes at [ADDRESS HERE], handler addr [ADDRESS HERE]
do_execve for /bin/sh from wcstatusd [PRINTED FOR ANY EXECUTED PROCESS]
The problem occurred when I tried the same code on Ubuntu 14, 64 bit (kernel version 3.13) system. I recompiled it on the system and inserted it just as I did on the previous system, however it didn't work this time. I don't get any errors, and the success message ("Planted jprobe at [ADDRESS WAS HERE], handler addr [ADDRESS WAS HERE]") is printed, but the 'do_execve' line isn't printed. I scanned Google but couldn't find an explanation or a solution. Any ideas?
NOTE: I also tried hooking 'do_fork()' on Ubuntu 14 and it worked! It's just something with 'do_execve()' and I can't figure what!
Definition for do_execve() is in exec.c
http://lxr.free-electrons.com/source/fs/exec.c?v=3.11#L1584
Here is the code for do_execve(). Just add a line after
int do_execve(struct filename *filename,const char __user *const __user *__argv,const char __user *const __user *__envp)
{
struct user_arg_ptr argv = { .ptr.native = __argv };
struct user_arg_ptr envp = { .ptr.native = __envp };
return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
}
EXPORT_SYMBOL(do_execve); // Add this line.
This file will be in linux/fs/exec.c. Add the EXPORT_SYMBOL() line after the fuction.And after that do make, make install, and reboot.
Its almost like the hooking because we have to build and install the kernel again. Given that you are not intercepting the call by modifying the systemcall address at runtime.

Kernel Module Init and Exit functions being called in wrong order

I'm making a very simple hello world kernel module and getting some crazy behavior. This worked until I upgraded to kernel 3.3.8 and now it... Well, it's calling the init function on exit, and the exit function on initialize. I've made sure my names are correct
// Needed for module definitions
#include <linux/module.h>
// Needed for initilization modules
#include <linux/init.h>
// Must declare some license
MODULE_LICENSE("Dual BSD/GPL");
// Function to be called on insmod
// Returns 0 on success
static int __init mymod_init(void)
{
// Prints kernel alert. Check /var/log/syslog
printk(KERN_ALERT "Module was loaded, this is the printk.");
return 0;
}
// Function to be called on rmmod
static void __exit mymod_exit(void)
{
// Prints kernel alert. Check /var/log/syslog
printk(KERN_ALERT "Module was unloaded, this is the printk");
}
// Register these functions
module_init(mymod_init);
module_exit(mymod_exit);
Sample output:
root#cop4610:/home/cop4610/Downloads/linux-3.3.8/mymodule# insmod
mymodule.ko root#cop4610:/home/cop4610/Downloads/linux-3.3.8/mymodule#
tail /var/log/syslog Oct 12 10:08:20 cop4610 kernel: [ 633.567832]
Module was unloaded, this is the printk
The following is a video of this happening live:
http://www.youtube.com/watch?v=8aJNSpCd7as&feature=youtu.be
It needed a newline!!!!!! Arrggg!!!
printk(KERN_ALERT "Module was unloaded, this is the printk\n");
and
printk(KERN_ALERT "Module was loaded, this is the printk\n");
It seems it wasn't really doing them out of order, it just appeared to, because the first one was not showing up until the second one was issued as the buffer was not flushed.
This is my basic example:
#include <linux/module.h>
#include <linux/kernel.h>
#define MODULE_NAME "hello_md"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("B3h3m0th");
MODULE_DESCRIPTION("Basic LKM; hello world module");
MODULE_VERSION("0.0");
static int __init insert_mod(void)
{
printk(KERN_ALERT "[%s] Init: \"Hello World\"\n", MODULE_NAME);
return 0;
}
static void __exit remove_mod(void)
{
printk(KERN_ALERT "[%s] Exit\n", MODULE_NAME);
}
module_init(insert_mod);
module_exit(remove_mod);
My basic Makefile:
obj-m += basic_module.o
KERNELVERSION = $(shell uname -r)
all:
$(MAKE) -C /lib/modules/$(KERNELVERSION)/build M=$(PWD) modules
clean:
$(MAKE) -C /lib/modules/$(KERNELVERSION)/build M=$(PWD) clean

Resources