mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-27 12:04:27 +01:00
Merge branch 'master' of github.com:cirosantilli/linux-kernel-module-cheat
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
# Extensions and prefixes.
|
# Extensions and prefixes.
|
||||||
*.tmp
|
*.tmp
|
||||||
|
tmp.*
|
||||||
*~
|
*~
|
||||||
?*.gitignore
|
?*.gitignore
|
||||||
gitignore*
|
gitignore*
|
||||||
|
|||||||
143
README.adoc
143
README.adoc
@@ -487,7 +487,7 @@ except that you don't need to know what is the maximum level.
|
|||||||
|
|
||||||
....
|
....
|
||||||
head kernel_module/modulename.c
|
head kernel_module/modulename.c
|
||||||
grep 'modulename\.' README.adoc
|
grep 'insmod /modulename\.ko' README.adoc
|
||||||
....
|
....
|
||||||
|
|
||||||
Many of the modules have userland test scripts / executables with the same name as the module, e.g. form inside the guest:
|
Many of the modules have userland test scripts / executables with the same name as the module, e.g. form inside the guest:
|
||||||
@@ -730,7 +730,7 @@ ls /lib/modules/*/extra/
|
|||||||
Kernel modules built from the Linux mainline tree with `CONFIG_SOME_MOD=m`, are automatically available with `modprobe`, e.g.:
|
Kernel modules built from the Linux mainline tree with `CONFIG_SOME_MOD=m`, are automatically available with `modprobe`, e.g.:
|
||||||
|
|
||||||
....
|
....
|
||||||
modprobe dummy-irq
|
modprobe dummy-irq irq=1
|
||||||
....
|
....
|
||||||
|
|
||||||
==== myinsmod
|
==== myinsmod
|
||||||
@@ -2638,6 +2638,131 @@ insmod /warn_on.ko
|
|||||||
|
|
||||||
Can also be activated with the `panic_on_warn` boot parameter.
|
Can also be activated with the `panic_on_warn` boot parameter.
|
||||||
|
|
||||||
|
=== IRQ
|
||||||
|
|
||||||
|
==== irq.ko
|
||||||
|
|
||||||
|
Brute force monitor every shared interrupt that will accept us:
|
||||||
|
|
||||||
|
....
|
||||||
|
./run -F 'insmod /irq.ko' -x
|
||||||
|
....
|
||||||
|
|
||||||
|
Now try the following:
|
||||||
|
|
||||||
|
* press a keyboard key and then release it after a few seconds
|
||||||
|
* press a mouse key, and release it after a few seconds
|
||||||
|
* move the mouse around
|
||||||
|
|
||||||
|
Outcome: dmesg shows which IRQ was fired for each action throug messages of type:
|
||||||
|
|
||||||
|
....
|
||||||
|
handler irq = 1 dev = 250
|
||||||
|
....
|
||||||
|
|
||||||
|
`dev` is the character device for the module and never changes, as can be confirmed by:
|
||||||
|
|
||||||
|
....
|
||||||
|
cat /proc/devices | grep lkmc_irq
|
||||||
|
....
|
||||||
|
|
||||||
|
The IRQs that we observe are:
|
||||||
|
|
||||||
|
* `1` for keyboard press and release.
|
||||||
|
+
|
||||||
|
If you hold the key down for a while, it starts firing at a constant rate. So this happens at the hardware level!
|
||||||
|
* `12` mouse actions
|
||||||
|
|
||||||
|
This only works if for IRQs for which the other handlers are registered as `IRQF_SHARED`.
|
||||||
|
|
||||||
|
We can see which ones are those, either via dmesg messages of type:
|
||||||
|
|
||||||
|
....
|
||||||
|
genirq: Flags mismatch irq 0. 00000080 (myirqhandler0) vs. 00015a00 (timer)
|
||||||
|
request_irq irq = 0 ret = -16
|
||||||
|
request_irq irq = 1 ret = 0
|
||||||
|
....
|
||||||
|
|
||||||
|
which indicate that `0` is not, but `1` is, or with:
|
||||||
|
|
||||||
|
....
|
||||||
|
cat /proc/interrupts
|
||||||
|
....
|
||||||
|
|
||||||
|
which shows:
|
||||||
|
|
||||||
|
....
|
||||||
|
0: 31 IO-APIC 2-edge timer
|
||||||
|
1: 9 IO-APIC 1-edge i8042, myirqhandler0
|
||||||
|
....
|
||||||
|
|
||||||
|
so only `1` has `myirqhandler0` attached but not `0`.
|
||||||
|
|
||||||
|
TODO: properly understand how each IRQ maps to what number.
|
||||||
|
|
||||||
|
==== dummy-irq
|
||||||
|
|
||||||
|
The Linux kernel v4.16 mainline also has a `dummy-irq` module at `drivers/misc/dummy-irq.c` for monitoring a single IRQ.
|
||||||
|
|
||||||
|
We build it by default with:
|
||||||
|
|
||||||
|
....
|
||||||
|
CONFIG_DUMMY_IRQ=m
|
||||||
|
....
|
||||||
|
|
||||||
|
And then you can do
|
||||||
|
|
||||||
|
....
|
||||||
|
./run -x
|
||||||
|
....
|
||||||
|
|
||||||
|
and in guest:
|
||||||
|
|
||||||
|
....
|
||||||
|
modprobe dummy-irq irq=1
|
||||||
|
....
|
||||||
|
|
||||||
|
Outcome: when you click a key on the keyboard, dmesg shows:
|
||||||
|
|
||||||
|
....
|
||||||
|
dummy-irq: interrupt occurred on IRQ 1
|
||||||
|
....
|
||||||
|
|
||||||
|
However, this module is intended to fire only once as can be seen from its source:
|
||||||
|
|
||||||
|
....
|
||||||
|
static int count = 0;
|
||||||
|
|
||||||
|
if (count == 0) {
|
||||||
|
printk(KERN_INFO "dummy-irq: interrupt occurred on IRQ %d\n",
|
||||||
|
irq);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
....
|
||||||
|
|
||||||
|
and furthermore interrupt `1` and `12` happen immediately TODO why, were they somehow pending?
|
||||||
|
|
||||||
|
So so see something interesting, you need to monitor an interrupt that is more rare than the keyboard, e.g. <<platform_device>>.
|
||||||
|
|
||||||
|
==== /proc/interrupts
|
||||||
|
|
||||||
|
In the guest on <<graphic-mode>>:
|
||||||
|
|
||||||
|
....
|
||||||
|
watch -n 1 cat /proc/interrupts
|
||||||
|
....
|
||||||
|
|
||||||
|
Then see how clicking the mouse and keyboard affect the interrupt counts.
|
||||||
|
|
||||||
|
This confirms that:
|
||||||
|
|
||||||
|
* 1: keyboard
|
||||||
|
* 12: mouse click and drags
|
||||||
|
|
||||||
|
The module also shows which handlers are registered for each IRQ, as we have observed at <<irq-ko>>
|
||||||
|
|
||||||
|
When in text mode, we can also observe interrupt line 4 with handler `ttyS0` increase continuously as IO goes through the UART.
|
||||||
|
|
||||||
=== Linux kernel tracing
|
=== Linux kernel tracing
|
||||||
|
|
||||||
Good overviews:
|
Good overviews:
|
||||||
@@ -3361,6 +3486,19 @@ devmem 0x101e9000 w 0x12345678
|
|||||||
|
|
||||||
which touches the register from userland through `/dev/mem`.
|
which touches the register from userland through `/dev/mem`.
|
||||||
|
|
||||||
|
We can also observe the interrupt with <<dummy-irq>>:
|
||||||
|
|
||||||
|
....
|
||||||
|
modprobe dummy-irq irq=34
|
||||||
|
insmod /platform_device.ko
|
||||||
|
....
|
||||||
|
|
||||||
|
The IRQ number `34` was found by on the dmesg after:
|
||||||
|
|
||||||
|
....
|
||||||
|
insmod /platform_device.ko
|
||||||
|
....
|
||||||
|
|
||||||
==== gem5 educational hardware models
|
==== gem5 educational hardware models
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
@@ -5684,6 +5822,7 @@ Theory:
|
|||||||
* https://rwmj.wordpress.com/ awesome red hatter
|
* https://rwmj.wordpress.com/ awesome red hatter
|
||||||
* https://lwn.net
|
* https://lwn.net
|
||||||
* http://www.makelinux.net
|
* http://www.makelinux.net
|
||||||
|
* https://notes.shichao.io/lkd/
|
||||||
|
|
||||||
Awesome lists:
|
Awesome lists:
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ CONFIG_VIRTIO_NET=y
|
|||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
|
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
|
||||||
|
CONFIG_DUMMY_IRQ=m
|
||||||
|
|
||||||
## Networking
|
## Networking
|
||||||
|
|
||||||
@@ -177,21 +178,6 @@ CONFIG_GPIOLIB=y
|
|||||||
CONFIG_GPIO_SYSFS=y
|
CONFIG_GPIO_SYSFS=y
|
||||||
CONFIG_GPIO_PL061=y
|
CONFIG_GPIO_PL061=y
|
||||||
|
|
||||||
# In target:
|
|
||||||
#
|
|
||||||
# modprobe dummy-irq irq=34
|
|
||||||
# insmod /platform_device.ko
|
|
||||||
#
|
|
||||||
# Outcome:
|
|
||||||
#
|
|
||||||
# lkmc_platform_device_write offset=0 value=12345678 size=4
|
|
||||||
# dummy-irq: interrupt occurred on IRQ 34
|
|
||||||
#
|
|
||||||
# When the device generates an IRQ, the dummy module also snoops it.
|
|
||||||
#
|
|
||||||
# The IRQ number 34 was found by via dmesg on a previous "insmod /platform_device.ko".
|
|
||||||
CONFIG_DUMMY_IRQ=m
|
|
||||||
|
|
||||||
# Like CONFIG_X86_PTDUMP for ARM.
|
# Like CONFIG_X86_PTDUMP for ARM.
|
||||||
CONFIG_ARM64_PTDUMP=y
|
CONFIG_ARM64_PTDUMP=y
|
||||||
|
|
||||||
|
|||||||
@@ -1,42 +1,10 @@
|
|||||||
/*
|
|
||||||
Brute force monitor every shared interrupt that will accept us.
|
|
||||||
|
|
||||||
I.e. only works if for IRQs for which the other handlers are registered as IRQF_SHARED.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
|
|
||||||
1. insmod and then use the keyboard and mouse. Those handlers are shared,
|
|
||||||
and the messages show up whenever you do something.
|
|
||||||
|
|
||||||
Does not work in text mode of course.
|
|
||||||
|
|
||||||
2. insmod some module that generates interrupts after insmod irq.,
|
|
||||||
e.g. pci_min or platform_device.
|
|
||||||
|
|
||||||
TODO: why does insmod in ARM lead to infinitely many interrupts handler irq = 45 dev = 252
|
|
||||||
and blocks the board? Is the ARM timer shared, and x86 isn't?
|
|
||||||
|
|
||||||
TODO: properly understand how each IRQ maps to what.
|
|
||||||
|
|
||||||
The Linux kernel mainline also has dummy-irq for monitoring a single IRQ.
|
|
||||||
|
|
||||||
Inside QEMU, also try:
|
|
||||||
|
|
||||||
watch -n 1 cat /proc/interrupts
|
|
||||||
|
|
||||||
Then see how clicking the mouse and keyboard affect the interrupts. This will point you to:
|
|
||||||
|
|
||||||
- 1: keyboard
|
|
||||||
- 12: mouse click and drags
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/uaccess.h> /* copy_from_user, copy_to_user */
|
#include <linux/uaccess.h> /* copy_from_user, copy_to_user */
|
||||||
|
|
||||||
#define NAME "lkmc_character_device"
|
#define NAME "lkmc_irq"
|
||||||
#define MAX_IRQS 256
|
#define MAX_IRQS 256
|
||||||
|
|
||||||
static int irqs[MAX_IRQS];
|
static int irqs[MAX_IRQS];
|
||||||
|
|||||||
Reference in New Issue
Block a user