Kernel Module Init and Exit functions being called in wrong order - c

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

Related

Error while implementing hello world system call in Lunix

I am compiling my kernel for my hello world system call but getting following error:
ld: arch/x86/entry/syscall_64.o:(.rodata+0xdc0): undefined reference to __x64_sys_hello' ld: arch/x86/entry/syscall_x32.o:(.rodata+0xdc0): undefined reference to __x64_sys_hello' make: *** [Makefile:1139: vmlinux] Error 1 site:stackoverflow.com
Following are the changes i made to add my hello world system call:
Current kernel version=5.11.0.40
linux-5.8.1/hello/hello.c:
#include <linux/kernel.h>
#include <linux/syscalls.h>
asmlinkage long sys_hello(void)
{
printk("Hello world\n");
return 0;
}
linux-5.8.1/Makefile:
ifeq ($(KBUILD_EXTMOD),)
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ hello/
linux-5.8.1/include/linux$ gedit syscalls.h
asmlinkage long sys_hello(void);
linux-5.8.1/arch/x86/entry/syscalls$ gedit syscall_64.tbl
440 common hello sys_hello
Looking forward for your responses.Thanks in advance.
This code:
asmlinkage long sys_hello(void)
{
printk("Hello world\n");
return 0;
}
needs to be changed to:
SYSCALL_DEFINE0(hello)
{
printk("Hello world\n");
return 0;
}
The SYSCALL_DEFINE0(sname) macro is defined by #include <linux/syscalls.h>. It is defined differently depending on whether CONFIG_ARCH_HAS_SYSCALL_WRAPPER is defined in the kernel config. It is defined for some architectures, but not for others.

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

add-symbol-file returns -s invalid argument when trying to add module's object file

I'm debugging vmlinux with gdb vmlinux /proc/kcore, and I want to add a symbol file, I installed a module and then check the location of .bss, .data and .init in /sys/module/simple_module/sections. When I try to use the add-symbol-file with the object file of my module and also the section's locations, gdb returns Unrecognized argument " -s". But from help add-symbol-file, I can see that -s actually a valid argument.
add-symbol-file simple_module.ko 0xc0ce9000 \ -s .bss 0xc0d833c0 \ -s .data 0xc0d83000
I don't think that the code of my module really necessary, but whatever
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("whoami");
MODULE_DESCRIPTION("Simple LKM");
int i; // non-init variable
char text[20] = "Hello, World!";
static int __init initialization_function(void)
{
pr_info("Module: my message!\n");
return 0;
}
static void __exit cleanup_funcion(void)
{
pr_info("Module: Cleanup done, exiting.\n");
}
module_init(initialization_function);
module_exit(cleanup_funcion);

Undefined functions while compiling linux kernel module

I am trying to work with linux softirq. A have a simple program that uses linux system calls defined in linux/interrupt.h:
//
// Created by kivi on 24.09.16.
//
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/stat.h>
#define SHARED_IRQ 17
static int irq = SHARED_IRQ, my_dev_id, irq_counter = 0;
module_param( irq, int, S_IRUGO );
/* The interrupt handler */
static irqreturn_t xxx_interrupt( int irq, void *dev_id ) {
printk( KERN_INFO "In the top-half: counter = %d\n", irq_counter );
raise_softirq( XXX_SOFT_IRQ );
return IRQ_HANDLED;
}
/* The bottom half */
void xxx_analyze(struct softirq_action *str) {
irq_counter++;
printk( KERN_INFO "In the bottom-half: counter = %d\n", irq_counter );
}
static int __init my_init( void ) {
request_irq( irq, xxx_interrupt, 0, "xxx", NULL );
open_softirq( XXX_SOFT_IRQ, xxx_analyze);
printk( KERN_INFO "Successfully set softirq handler on IRQ %d\n", irq );
return 0;
}
static void __exit my_exit( void ) {
synchronize_irq( irq );
free_irq( irq, &my_dev_id );
printk( KERN_INFO "Successfully unloading, irq_counter = %d\n", irq_counter );
}
module_init( my_init );
module_exit( my_exit );
MODULE_LICENSE( "GPL v2" );
When I try to compile this module I get linker errors that functions open_softirq() and raise_softirq() are not defined:
kivi#kivi-pc:~/sp_labs/irq_exc/softirq$ make
make -C /lib/modules/4.7.5-custom/build M=/home/kivi/sp_labs/irq_exc/softirq modules
make[1]: Entering directory '/home/kivi/Downloads/linux-4.7.5'
Building modules, stage 2.
MODPOST 1 modules
WARNING: "open_softirq" [/home/kivi/sp_labs/irq_exc/softirq/softirq.ko] undefined!
WARNING: "raise_softirq" [/home/kivi/sp_labs/irq_exc/softirq/softirq.ko] undefined!
make[1]: Leaving directory '/home/kivi/Downloads/linux-4.7.5'
The interesting thing is that functions request_irq() e.t.c. are also defined in interrupt.h file, but they don't cause any problem.
Here is my Makefile:
obj-m += softirq.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
So can anyone help me please with my problem.
P.S. i googled my problem and found some advice that I should add KBUILD_EXTRA_SYMBOLS=*module path*/Module.symvers when compiling, but it didn't help.
The problem is that the open_softirq and raise_softirq functions are not exported, and so you cannot link to them. Exported functions are marked with the EXPORT_SYMBOL or EXPORT_SYMBOL_GPL macros.
On the other side, you will see how request_irq is exported (actually, it is inlined to request_threaded_irq, which is exported).
You can find plenty of information about the EXPORT_SYMBOL macros. For instance, here's an explanation from Robert Love.
Now, you are probably wondering why those functions aren't exported. Well, softirqs are a low-level mechanism, meant to be used by other higher-level facilities, so the intention is to prevent its usage in non-core kernel code.
Modules should use higher-level facilities instead (timers for instance).
It is interesting to check how many softirqs users the kernel has.
$ git grep open_softirq
block/blk-softirq.c: open_softirq(BLOCK_SOFTIRQ, blk_done_softirq);
include/linux/interrupt.h:extern void open_softirq(int nr, void (*action)(struct softirq_action *));
kernel/rcu/tiny.c: open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
kernel/rcu/tree.c: open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
kernel/sched/fair.c: open_softirq(SCHED_SOFTIRQ, run_rebalance_domains);
kernel/softirq.c:void open_softirq(int nr, void (*action)(struct softirq_action *))
kernel/softirq.c: open_softirq(TASKLET_SOFTIRQ, tasklet_action);
kernel/softirq.c: open_softirq(HI_SOFTIRQ, tasklet_hi_action);
kernel/time/timer.c: open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
lib/irq_poll.c: open_softirq(IRQ_POLL_SOFTIRQ, irq_poll_softirq);
net/core/dev.c: open_softirq(NET_TX_SOFTIRQ, net_tx_action);
net/core/dev.c: open_softirq(NET_RX_SOFTIRQ, net_rx_action);
Just 12!
This pattern repeats across the kernel: stuff that maintainers consider lowish-level is not exported and meant for core kernel code only.

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.

Resources