mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
0
This commit is contained in:
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
*.cmd
|
||||||
|
*.ko
|
||||||
|
*.mod.c
|
||||||
|
*.o
|
||||||
|
*.out
|
||||||
|
*.tmp
|
||||||
|
.tmp_versions
|
||||||
|
Module.symvers
|
||||||
|
modules.order
|
||||||
7
README.md
Normal file
7
README.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Linux Kernel Module Cheat
|
||||||
|
|
||||||
|
1. [Introduction](introduction.md)
|
||||||
|
1. [Build](build.md)
|
||||||
|
1. [kmod](kmod.md)
|
||||||
|
1. Examples
|
||||||
|
1. [Host](host/)
|
||||||
15
build.md
Normal file
15
build.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Build
|
||||||
|
|
||||||
|
The module building system.
|
||||||
|
|
||||||
|
Kernel modules are built using a makefile located at:
|
||||||
|
|
||||||
|
/lib/modules/$(uname -r)/build
|
||||||
|
|
||||||
|
## includes
|
||||||
|
|
||||||
|
Header files come from the same directory as the makefile: `/lib/modules/$(uname -r)/build`.
|
||||||
|
|
||||||
|
TODO how is that different from: `/usr/src/linux-headers-$(uname -r)/` ?
|
||||||
|
|
||||||
|
Those come directly from the kernel source tree.
|
||||||
33
host/Makefile
Normal file
33
host/Makefile
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
OUT_EXT := .ko
|
||||||
|
OBJ_EXT := .o
|
||||||
|
RUN := hello
|
||||||
|
RUN_EXT := $(RUN)$(OUT_EXT)
|
||||||
|
|
||||||
|
obj-m += hello.o
|
||||||
|
ccflags-y := -Wno-declaration-after-statement -std=gnu99
|
||||||
|
|
||||||
|
.PHONY: clean ins log rm run my-ins
|
||||||
|
|
||||||
|
all: $(RUN_EXT) ins_rm_mod.out
|
||||||
|
|
||||||
|
hello.ko: hello.c
|
||||||
|
make -C /lib/modules/$(shell uname -r)/build M="$(PWD)" modules
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C /lib/modules/$(shell uname -r)/build M="$(PWD)" clean
|
||||||
|
rm -f *.out
|
||||||
|
|
||||||
|
ins: all
|
||||||
|
sudo insmod '$(RUN_EXT)'
|
||||||
|
|
||||||
|
log:
|
||||||
|
dmesg
|
||||||
|
|
||||||
|
rm:
|
||||||
|
if lsmod | grep -Eq '^$(RUN) '; then sudo rmmod '$(RUN_EXT)'; fi
|
||||||
|
|
||||||
|
ins_rm_mod.out: ins_rm_mod.c
|
||||||
|
gcc -Wall -std=gnu99 -o '$@' '$<'
|
||||||
|
|
||||||
|
ins_rm_run: ins_rm_mod.out $(RUN_EXT)
|
||||||
|
sudo ./ins_rm_mod.out
|
||||||
34
host/README.md
Normal file
34
host/README.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Host
|
||||||
|
|
||||||
|
Simple things that can be demonstrated by inserting a module into the currently running host. Tested on Ubuntu 16.04.
|
||||||
|
|
||||||
|
1. [hello](hello.c)
|
||||||
|
1. [ins_rm_mod.c](ins_rm_mod.c)
|
||||||
|
|
||||||
|
## Rationale
|
||||||
|
|
||||||
|
This method easier to setup, but it is not recommended for development, as:
|
||||||
|
|
||||||
|
- it may break your system.
|
||||||
|
- you can't control which kernel version to use
|
||||||
|
|
||||||
|
Use VMs instead.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
We only use it for super simple examples.
|
||||||
|
|
||||||
|
Build, insert and remove a hello world module:
|
||||||
|
|
||||||
|
make ins
|
||||||
|
make rm
|
||||||
|
make log
|
||||||
|
|
||||||
|
The last lines of the log should contain:
|
||||||
|
|
||||||
|
init_module
|
||||||
|
cleanup_module
|
||||||
|
|
||||||
|
Insert and remove a module from a C program:
|
||||||
|
|
||||||
|
make ins_rm_run
|
||||||
13
host/hello.c
Normal file
13
host/hello.c
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
|
int init_module(void)
|
||||||
|
{
|
||||||
|
printk(KERN_INFO "init_module\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup_module(void)
|
||||||
|
{
|
||||||
|
printk(KERN_INFO "cleanup_module\n");
|
||||||
|
}
|
||||||
36
host/ins_rm_mod.c
Normal file
36
host/ins_rm_mod.c
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
http://stackoverflow.com/questions/5947286/how-can-linux-kernel-modules-be-loaded-from-c-code/38606527#38606527
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <assert.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
|
||||||
|
#define delete_module(name, flags) syscall(__NR_delete_module, name, flags)
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int fd = open("hello.ko", O_RDONLY);
|
||||||
|
struct stat st;
|
||||||
|
fstat(fd, &st);
|
||||||
|
size_t image_size = st.st_size;
|
||||||
|
void *image = malloc(image_size);
|
||||||
|
read(fd, image, image_size);
|
||||||
|
close(fd);
|
||||||
|
if (init_module(image, image_size, "") != 0) {
|
||||||
|
perror("init_module");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
free(image);
|
||||||
|
if (delete_module("hello", O_NONBLOCK) != 0) {
|
||||||
|
perror("delete_modul");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
66
introduction.md
Normal file
66
introduction.md
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# Introduction
|
||||||
|
|
||||||
|
There are things which are hard to do from regular user programs such as directly talking to hardware.
|
||||||
|
|
||||||
|
Some operations can be done via system calls, but if you want flexibility and speed, using the kernel ring is fundamental
|
||||||
|
|
||||||
|
However:
|
||||||
|
|
||||||
|
- it would be very complicated to recompile the kernel and reboot every time you make some modification
|
||||||
|
- the kernel would be huge if it were to support all possible hardware
|
||||||
|
|
||||||
|
Modules overcome those two problems exactly because they can be loaded into the kernel *while it is running* and use symbols that the kernel chooses to export TODO which
|
||||||
|
|
||||||
|
It then runs in the same address space as the kernel and with the same permissions as the kernel (basically do anything)
|
||||||
|
|
||||||
|
Compiled modules are special object files that have a `.ko` extension instead of `.o` they also contain module specific metadata
|
||||||
|
|
||||||
|
Device drivers (programs that enables the computer to talk to hardware) are one specific type of kernel modules
|
||||||
|
|
||||||
|
Two devices can map to the same hardware!
|
||||||
|
|
||||||
|
## Stable kernel interface
|
||||||
|
|
||||||
|
Kernel modules can use any internal interface of the kernel, although some are more visible than others.
|
||||||
|
|
||||||
|
But there is no stable kernel API for modules: if you don't add your driver to the kernel tree, it can break any time: <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/stable_api_nonsense.txt?id=v4.0>
|
||||||
|
|
||||||
|
## Configuration files
|
||||||
|
|
||||||
|
If file it gets read, if dir, all files in dir get read:
|
||||||
|
|
||||||
|
sudo ls /etc/modprobe.d
|
||||||
|
sudo ls /etc/modprobe.conf
|
||||||
|
|
||||||
|
Modules loaded at boot:
|
||||||
|
|
||||||
|
sudo cat /etc/modules
|
||||||
|
|
||||||
|
## Hardware communication
|
||||||
|
|
||||||
|
Talking to hardware always comes down to writing bytes in specific registers at a given memory addresses.
|
||||||
|
|
||||||
|
Some processors implement a single address space for memory and other hardware devices, and others do not.
|
||||||
|
|
||||||
|
However, since x86 is the most popular and it separates address spaces, every architecture must at least mimic this separation.
|
||||||
|
|
||||||
|
On x86, the following specialized instructions exist for port IO:
|
||||||
|
|
||||||
|
- `IN`: Read from a port
|
||||||
|
- `OUT`: Write to a port
|
||||||
|
- `INS/INSB`: Input string from port/Input byte string from port
|
||||||
|
- `INS/INSW`: Input string from port/Input word string from port
|
||||||
|
- `INS/INSD`: Input string from port/Input `doubleword` string from port
|
||||||
|
- `OUTS/OUTSB`: Output string to port/Output byte string to port
|
||||||
|
- `OUTS/OUTSW`: Output string to port/Output word string to port
|
||||||
|
- `OUTS/OUTSD`: Output string to port/Output `doubleword` string to port
|
||||||
|
|
||||||
|
However, you should avoid using those instructions directly in your device driver code since Linux functions abstract over multiple architectures (when possible) making your code more portable.
|
||||||
|
|
||||||
|
Those instructions cannot be used from an user space program since the kernel prevents those from accessing hardware directly.
|
||||||
|
|
||||||
|
The memory space for non-memory locations is called I/O ports or I/O space.
|
||||||
|
|
||||||
|
To use a port, you must first reserve it. To see who reserved what:
|
||||||
|
|
||||||
|
sudo cat /proc/ioports
|
||||||
105
kmod.md
Normal file
105
kmod.md
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
# kmod
|
||||||
|
|
||||||
|
Implements `lsmod`, `insmod`, `rmmod`, and other tools.
|
||||||
|
|
||||||
|
The other tools are just symlinks to it.
|
||||||
|
|
||||||
|
## module-init-tools
|
||||||
|
|
||||||
|
Name of a predecessor set of tools.
|
||||||
|
|
||||||
|
## package version
|
||||||
|
|
||||||
|
From any of the commands, `--version`:
|
||||||
|
|
||||||
|
modinfo --version
|
||||||
|
|
||||||
|
Package that provides utilities
|
||||||
|
|
||||||
|
## lsmod
|
||||||
|
|
||||||
|
List loaded kernel modules.
|
||||||
|
|
||||||
|
Info is taken from `/proc/modules`
|
||||||
|
|
||||||
|
lsmod
|
||||||
|
|
||||||
|
Sample output:
|
||||||
|
|
||||||
|
cfg80211 175574 2 rtlwifi,mac80211
|
||||||
|
^^^^^^^^ ^^^^^^ ^ ^^^^^^^,^^^^^^^^
|
||||||
|
1 2 3 4 5
|
||||||
|
|
||||||
|
1. Name.
|
||||||
|
|
||||||
|
2. Size.
|
||||||
|
|
||||||
|
3. Number of running instances.
|
||||||
|
|
||||||
|
If negative, TODO
|
||||||
|
|
||||||
|
4. Depends on 1.
|
||||||
|
|
||||||
|
5. Depends on 2.
|
||||||
|
|
||||||
|
To get more info:
|
||||||
|
|
||||||
|
cat /proc/modules
|
||||||
|
|
||||||
|
Also contains two more columns:
|
||||||
|
|
||||||
|
- status: Live, Loading or Unloading
|
||||||
|
- memory offset: 0x129b0000
|
||||||
|
|
||||||
|
## modinfo
|
||||||
|
|
||||||
|
Get info about a module by filename or by module name:
|
||||||
|
|
||||||
|
modinfo ./a.ko
|
||||||
|
modinfo a
|
||||||
|
|
||||||
|
TODO must take a `.ko` file?
|
||||||
|
|
||||||
|
## insmod
|
||||||
|
|
||||||
|
sudo insmod hello.ko
|
||||||
|
|
||||||
|
Loads the module.
|
||||||
|
|
||||||
|
Does not check for dependencies.
|
||||||
|
|
||||||
|
## rmmod
|
||||||
|
|
||||||
|
Remove a module. Takes either the module name or the `.ko` file:
|
||||||
|
|
||||||
|
sudo rmmod hello
|
||||||
|
sudo rmmod ./hello.ko
|
||||||
|
|
||||||
|
## modprobe
|
||||||
|
|
||||||
|
List available modules relative path to `/lib/modules/VERSION/`:
|
||||||
|
|
||||||
|
sudo modprobe -l
|
||||||
|
|
||||||
|
Load the module:
|
||||||
|
|
||||||
|
sudo modprobe $m
|
||||||
|
|
||||||
|
Checks for dependencies.
|
||||||
|
|
||||||
|
Load module under different name to avoid conflicts:
|
||||||
|
|
||||||
|
sudo modprobe vmhgfs -o vm_hgfs
|
||||||
|
|
||||||
|
Remove module:
|
||||||
|
|
||||||
|
sudo modprobe -r $m
|
||||||
|
|
||||||
|
Check if dependencies are OK:
|
||||||
|
|
||||||
|
sudo depmod -a
|
||||||
|
|
||||||
|
Get info about given `.ko` module file:
|
||||||
|
|
||||||
|
m=a
|
||||||
|
sudo rmmod $m
|
||||||
Reference in New Issue
Block a user