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