146 lines
5.2 KiB
Markdown
146 lines
5.2 KiB
Markdown
|
|
The process of [kernel modules compilation](https://www.kernel.org/doc/html/v5.6/kbuild/modules.html) depends heavily on accessibility of header files provided by kernel. There are exist no guarantees on ABI compatibility even between minor kernel versions. This is [deliberate design choice](https://github.com/torvalds/linux/blob/v4.9/Documentation/stable_api_nonsense.txt) made by kernel developers. Kernel module compilation *depends* on kernel headers.
|
|
|
|
> But what to do if, for the variety of reasons, for the kernel you are interest in, headers are unavailable?
|
|
|
|
This article focuses on Android, but most of information and techniques discussed here can be easily applied to generic Linux kernel as well.
|
|
|
|
# ELF symbols stealing
|
|
|
|
The main idea, is to use Android NDK to compile generic Linux kernel module. And embed it with ELF symbols collected from some existing kernel module (see `/vendor/lib/modules/*.ko`). In such a way, that the loader would be able to recognise and resolve all necessary dependencies and definitions.
|
|
|
|
## .modinfo
|
|
|
|
```bash
|
|
objdump -s -j .modinfo $KMODULE
|
|
met.ko: file format elf64-little
|
|
|
|
Contents of section .modinfo:
|
|
0000 7061726d 74797065 3d6d6574 5f6d696e parmtype=met_min
|
|
0010 6f723a69 6e740061 7574686f 723d4454 or:int.author=DT
|
|
0020 5f444d35 00646573 63726970 74696f6e _DM5.description
|
|
0030 3d4d4554 5f434f52 45006c69 63656e73 =MET_CORE.licens
|
|
0040 653d4750 4c007665 726d6167 69633d34 e=GPL.vermagic=4
|
|
0050 2e31342e 3138362d 70657266 2d303032 .14.186-perf-002
|
|
0060 38382d67 37646633 34643261 65366462 88-g7df34d2ae6db
|
|
0070 20534d50 20707265 656d7074 206d6f64 SMP preempt mod
|
|
0080 5f756e6c 6f616420 6d6f6476 65727369 _unload modversi
|
|
0090 6f6e7320 61617263 68363400 6e616d65 ons aarch64.name
|
|
00a0 3d6d6574 00646570 656e6473 3d007372 =met.depends=.sr
|
|
00b0 63766572 73696f6e 3d353333 42423745 cversion=533BB7E
|
|
00c0 35383636 45353246 36334239 41434342 5866E52F63B9ACCB
|
|
00d0 00
|
|
```
|
|
|
|
This ELF section essentially is collection of 'TAG=VALUE' entries separated by NULL character '\0'. The most important part is `vermagic`, since loader is using it do identify which kernel headers were used for module compilation.
|
|
|
|
```bash
|
|
cat /proc/version
|
|
```
|
|
|
|
## .gnu.linkonce.this_module
|
|
|
|
This ELF section contains information that the LKM loader used to identify:
|
|
- name of the module
|
|
- a pointer to the initialization procedure `module_init`
|
|
- a pointer to the de-initialization procedure `module_cleanup`
|
|
|
|
### section size
|
|
|
|
```bash
|
|
objdump -h $KMODULE | grep .gnu.linkonce.this_module
|
|
.gnu.linkonce.this_module 00000340 0000000000000000 0000000000000000 ....
|
|
^^^^^^^^ section size
|
|
```
|
|
|
|
### name offset
|
|
|
|
```bash
|
|
objdump -s $KMODULE -j .gnu.linkonce.this_module
|
|
Contents of section .gnu.linkonce.this_module:
|
|
0000 00000000 00000000 00000000 00000000 ................
|
|
0010 00000000 00000000 6d657400 00000000 ........met.....
|
|
^^^^^^^^ offset 0x18 bytes
|
|
```
|
|
|
|
### entry points
|
|
|
|
```bash
|
|
readelf -a $KMODULE -W
|
|
Relocation section '.rela.gnu.linkonce.this_module' at offset 0x109b40 contains 2 entries:
|
|
<--- Offset ---> Info Type Symbol's Value Symbol's Name + Addend
|
|
0000000000000150 000006c500000101 R_AARCH64_ABS64 0000000000000000 init_module + 0
|
|
0000000000000310 000006ee00000101 R_AARCH64_ABS64 0000000000000000 cleanup_module + 0
|
|
```
|
|
|
|
|
|
## \_\_versions
|
|
|
|
In its essence is a byte-array for declaring external dependencies required by the module:
|
|
- first 4 bytes of [CRC](https://mjmwired.net/kernel/Documentation/kbuild/modules.txt#429) encoded function signature
|
|
- a ASCII encoded function name
|
|
|
|
```bash
|
|
objdump -s $KMODULE -j '__versions' #dump in binary form
|
|
met.ko: file format elf64-little
|
|
|
|
Contents of section __versions:
|
|
0000 e8d6fc68 00000000 6d6f6475 6c655f6c ...h....module_l
|
|
0010 61796f75 74000000 00000000 00000000 ayout...........
|
|
0020 00000000 00000000 00000000 00000000 ................
|
|
0030 00000000 00000000 00000000 00000000 ................
|
|
0040 6c9bdf85 00000000 73747273 65700000 l.......strsep..
|
|
0050 00000000 00000000 00000000 00000000 ................
|
|
0060 00000000 00000000 00000000 00000000 ................
|
|
0070 00000000 00000000 00000000 00000000 ................
|
|
0080 1ee414e9 00000000 73747263 70790000 ........strcpy..
|
|
0090 00000000 00000000 00000000 00000000 ................
|
|
00a0 00000000 00000000 00000000 00000000 ................
|
|
00b0 00000000 00000000 00000000 00000000 ................
|
|
```
|
|
|
|
```bash
|
|
modprobe --dump-modversions $KMODULE #dump in readable form
|
|
```
|
|
### module_layout
|
|
|
|
A default first entry of a section. Used by LKM loader to determine ABI of a module (the one used during it's compile time)
|
|
|
|
### printk()
|
|
|
|
In order for module to use any externally declared symbol module must:
|
|
|
|
1. Use a C-style function declaration in it's source code
|
|
```c
|
|
int printk(const char *fmt, ...);
|
|
```
|
|
|
|
2. Add another entry to the `__versions` section
|
|
|
|
# Misc
|
|
|
|
## Module loading
|
|
|
|
```bash
|
|
insmod module_name.ko
|
|
```
|
|
|
|
## List loaded modules
|
|
|
|
```bash
|
|
lsmod
|
|
```
|
|
|
|
## Logs
|
|
|
|
```bash
|
|
dmesg | grep insmod
|
|
```
|
|
|
|
## Module unloading
|
|
|
|
```bash
|
|
rmmod MODULE_NAME # from .gnu.linkonce.this_module section
|
|
```
|
|
|