Loadable kernel module not compiles correctly on different computers - c

I'm trying to make loadable kernel module for ARM achitecture. Just for example I'm made simple hello.c
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
static int __init hello_start(void)
{
printk(KERN_INFO "Loading hello module...\n");
return 0;
}
static void __exit hello_end(void)
{
printk(KERN_INFO "Goodbye Mr.\n");
}
module_init(hello_start);
module_exit(hello_end);
And created Makefile
obj-m := hello.o
PWD := $(shell pwd)
ARCH=arm
CROSS_COMPILE_LINARO=/home/cooperok/mk908/gcc-linaro-arm-linux-gnueabihf-4.7-2013.01-20130125_linux/bin/arm-linux-gnueabihf-
KERNEL_ROCKCHIP=/home/cooperok/mk908/kernel/
default:
make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE_LINARO) -C $(KERNEL_ROCKCHIP) M=$(PWD) modules
clean:
make CROSS_COMPILE=$(CROSS_COMPILE_LINARO) -C $(KERNEL_ROCKCHIP) M=$(PWD) clean
Cross compiler and kernel sources are the same on both computers. When I'm running make on first machine compiled hello.ko file is successfully installed with insmod command, but when I'm compiling module on second machine and trying to install that module I'm getting error "insmod: error inserting 'hello.ko': -1 Invalid module format"
As I understand module is compiling with crosscompiler which I'm specified in CROSS_COMPILE (arm-linux-gnueabihf-gcc and others) and only it will make module without any specific libraries installed on computers, is it?
First computer have 64bit OS (Ubuntu 12.04), and second 32bit OS (Linux Mint 12), this is main difference, so make util is different. But is it realy main reason why module correctly compiling only on 64bit OS? If so is it problem in make, or it's really deals with different libraries?

Related

Cannot use a Makefile to comple kernel files in Ubuntu Linux on WSL

I have some C code and a Makefile for that C code. The C program is called simple.c and the the makefile is just called Makefile.
Here are the contents of simple.c
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
/* This function is called when the module is loaded. */
int simple_init(void)
{
printk(KERN_INFO "Loading Kernel Module\n");
return 0;
}
/* This function is called when the module is removed. */
void simple_exit(void)
{
printk(KERN_INFO "Removing Kernel Module\n");
}
/* Macros for registering module entry and exit points. */
module_init(simple_init);
module_exit(simple_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Simple Module");
MODULE_AUTHOR("SGG");
And this is the content of the Makefile:
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=$(PWD) clean
I have both of them in the same directory and I use the instruction make to compile it however it does not work and I get this error message:
make -C /lib/modules/5.15.79.1-microsoft-standard-WSL2/build M=/home/eddie modules make[1]: *** /lib/modules/5.15.79.1-microsoft-standard-WSL2/build: No such file or directory. Stop. make: *** [Makefile:3: all] Error 2
I have tried to install some things I have seen online for linux kernal but they do not seem to work.
I have tried the following:
sudo apt install linux-tools-virtual hwdata
sudo apt-get install linux-headers-$(uname -r)
It's important to note that these all do sucessfully install. When I use lsmod to list all current kernal modules nothing is listed.
Am I doing anything wrong? Missing a command to install something? I am using Ubuntu Linux subsystem for linux on windows 11

Does Writing Linux Kernel Module Require Compiling Own Kernel?

I have a simple hello world kernel module on Ubuntu x86_64:
#include <linux/module.h>
static int
mod_init(void)
{
printk(KERN_INFO "RYANhello world\n");
return 0;
}
static void
mod_exit(void)
{
printk(KERN_INFO "RYANgoodbye world\n");
}
MODULE_LICENSE("GPL");
module_init(mod_init);
module_exit(mod_exit);
Makefile:
KERNEL_DIR := /lib/modules/$(shell uname -r)/build
CUR_DIR := $(shell pwd)
obj-m := module.o
default:
$(MAKE) -C $(KERNEL_DIR) M=$(CUR_DIR) modules
When I sudo insmod module.ko I get insmod: ERROR: could not insert module module.ko: Invalid parameters. Inspecting dmesg:
loading out-of-tree module taints kernel
module verification failed: signature and/or required key missing - tainting kernel
Repeating insmod yields module is already loaded however /var/log/syslog shows no trace of it loading (i.e printk messages not present). Also, running sudo rmmod module.ko:
rmmod: ERROR: ../libkmod/libkmod-module.c:1941 kmod_module_get_holders() could not open '/sys/module/module/holders': No such file or directory
rmmod: ERROR: Module unloading is not supported
This seems to indicate it's not loaded, even though dmesg says it is?
Addressing common issues; my host kernel and gcc version are the same as ones I compiling with.
So, this leads me to think that the module not being signed is the issue. To disable this do I have to compile and install my own kernel with appropriate .config? In other words, to write and test your own kernel modules on a modern GNU/Linux OS with enforced signing, do you have to compile and install your own kernel?
EDIT
CONFIG_MODULE_SIG_FORCE is not set in my /boot/config-5.8.0-53-generic, so it seems I should be able to load my module albeit with a tainted kernel message. So, why would I be getting Invalid parameters?
Inspecting dmesg on first insmod it was saying that the module was already loaded. As I had never loaded this before, this prompted me to think that this name was already taken.
Low and behold, renaming module.c/module.o --> example.c/example.o fixed the problem. The invalid parameters message was what threw me.

How to compile / link / build a small sized Loadable Kernel Module ( LKM )?

I successfully built this trivial LKM with gcc but the resulting binary is of size 70kB.
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
static int __init LinuxKernelModule_init(void)
{
printk("LinuxKernelModule: Hello, world!\n");
return 0;
}
static void __exit LinuxKernelModule_exit(void)
{
printk("LinuxKernelModule: Goodbye, world!\n");
}
module_init(LinuxKernelModule_init);
module_exit(LinuxKernelModule_exit);
What CFLAGS and make arguments would you suggest to make it smaller?
The standard Linux kernel is compiled in an optimal way already unless it's a debug version or some very specific options are turned on. So the simplest Makefile for an external kernel module which doesn't add any compiler of linker options on top of those used to build the kernel should be sufficient and should produce an optimal kernel module.
For this trivial LKM (let's call it lkm.c) the simplest Makefile below produces a kernel module that is 3986 bytes in size on my system. gcc version is 7.4.0, ldd version is 2.27, the kernel is 4.15.0-66-generic, the distro is Ubuntu.
KERNEL = /lib/modules/$(shell uname -r)/build
obj-m += lkm.o
all:
${MAKE} -C ${KERNEL} M=$(PWD) modules
clean:
${MAKE} -C ${KERNEL} M=$(PWD) clean
Try to just make Makefile with following contents:
obj-m += test.o
and rename your module to test.c in the same directory.
Then make the module:
make -C /usr/src/linux M=`pwd`
and tell us what is the size of your output .ko file.
It is also possible that your .config of the kernel has enabled debugging symbols and it increases size of your module.

GMP in kernel Module

I'm quiet new to module coding and I need to run some calculation that uses the GMP library in a module.
So the first question: is it generally possible to run GMP in kernel?
For testing, I wrote this Module:
#include <linux/init.h>
#include <linux/module.h>
#include <gmp.h>
int hallo_init(void)
{
mpz_t testFactor;
mpz_init( testFactor, NULL);
mpz_set_str(testFactor, "19", 10);
int length = (int) mpz_sizeinbase(testFactor,2);
printk(KERN_ALERT "That is testFactor: %x \n",length);
return 0;
}
void hallo_exit(void)
{
printk(KERN_ALERT "exit \n");
}
module_init(hallo_init);
module_exit(hallo_exit);
I run it with the following command:
sudo make -C /lib/modules/$(uname -r)/build M=$PWD modules -lgmp
The makefile consists of
obj-m := gmpFile.o
I also tried to use the -lgmp in the makefile:
obj-m := halloGmp.o
ccflags-y := -lgmp
But I always get a Fatal error: gmp.h: No such file or directory
Any suggestions? Would be thankful for help!
I'm not familiar with GMP but it's unlikely that you can dynamically link a library to a kernel module.
The reason is that the kernel is a standalone program and don't know about any system library that you are used (such glib...) and very likely GMP uses those.
The only solution that I can think of is that you do a kernel module that communicate with a program in the userland and link the GMP to the userland part of your application.

"Segmentation fault" when `rmmod` or `modprobe -r`

Trying the simplest kernel module from LDD3 without any modification on custom built kernel v4.1.0-rc6 for Beagle Bone board with BusyBox v1.23.0. The code for the module is as follows:
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
The Makefile is:
ARCH := arm
CROSS_COMPILE := arm-cortex_a8-linux-gnueabi-
obj-m := hello.o
all:
make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C /path/to/linux/source/tree M=$(PWD) modules
clean:
make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C /path/to/linux/source/tree M=$(PWD) clean
The module is compiling and installing on the rootfs just fine. also it is loading:
$ insmod hello.ko
[ 30.692404] Hello, world
But when trying to remove it, I am getting:
$ rmmod hello.ko
Segmentation fault
$modprobe -r hello.ko
Segmentation fault
$ lsmod
hello 813 0 - Live 0xbf000000 (O)
The kernel is compiled with module unloading (both regular and forced) support enabled.
What can be the possible cause of this issue? What is the way to approach the investigation of it?
Update:
As suggested in the comments I have tried including linux/kernel.h, defining the MODULE,LINUX and __KERNEL__ symbols. Added the__init and __exit prefixes to the functions. Removed the static modifiers. Removed the printk lines. The result the same. dmesg shows only the initial greeting. Loading and unloading of the kernel's modules such a gpio_keys or crypto/ccm is working, surprisingly. So the only thing remaining to suspect is the way the module is compiled..
Update 2
Updating the kernel to the freshest snapshot didn't help. Compiled the module with different optimization settings didn't help. Next step, I guess, I am going to modify the BusyBox's rmmod to have some indication of the problem location..
Have a look at these tutorials:
http://www.tldp.org/HOWTO/Module-HOWTO/x839.html
http://www.tldp.org/LDP/lkmpg/2.4/html/x281.htm
Try adding:
#define MODULE
#define LINUX
#define __KERNEL__
#include <linux/kernel.h> /* Needed for KERN_ALERT */
I have managed to work around this problem. Using strace I've found out that the segfault is occurring somewhere when reading the BusyBox specific modules.dep.bb file. This file is used by BusyBox when it is compiled with the "Simplified modutils" option (CONFIG_MODPROBE_SMALL). By disabling the option, selecting the utils to be installed and rebuilding BusybBox I've got the module unloading work. I believe the problem root is near the fact the test module is compiled and stored outside the /lib/..../modules directory, so busybox with the simplified modutils is just getting confused.

Resources