mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
kprobes
This commit is contained in:
22
README.adoc
22
README.adoc
@@ -2682,7 +2682,7 @@ TODO: why does this produce no output?
|
||||
* https://serverfault.com/questions/199654/does-anyone-know-a-simple-way-to-monitor-root-process-spawn
|
||||
* https://unix.stackexchange.com/questions/260162/how-to-track-newly-created-processes
|
||||
|
||||
==== CONFIG_PROC_EVENTS aarch64
|
||||
===== CONFIG_PROC_EVENTS aarch64
|
||||
|
||||
0111ca406bdfa6fd65a2605d353583b4c4051781 was failing with:
|
||||
|
||||
@@ -2831,6 +2831,26 @@ TODO: what do `+` and `!` mean?
|
||||
|
||||
Each `enable` under the `events/` tree enables a certain set of functions, the higher the `enable` more functions are enabled.
|
||||
|
||||
==== Kprobes
|
||||
|
||||
Inject arbitrary code at a given address in a trap instruction. Oh the good old kernel. :-)
|
||||
|
||||
....
|
||||
./build -c 'CONFIG_KPROBES=y'
|
||||
./run -F 'insmod /kprobe_example.ko && sleep 4 & sleep 4 &'
|
||||
....
|
||||
|
||||
Outcome: every fork spits out some extra printks of type:
|
||||
|
||||
....
|
||||
<6>[ 2.011117] <_do_fork> pre_handler: p->addr = 0x00000000e1360063, ip = ffffffff810531d1, flags = 0x246
|
||||
<6>[ 2.011622] <_do_fork> post_handler: p->addr = 0x00000000e1360063, flags = 0x246
|
||||
<6>[ 2.021860] <_do_fork> pre_handler: p->addr = 0x00000000e1360063, ip = ffffffff810531d1, flags = 0x246
|
||||
<6>[ 2.022331] <_do_fork> post_handler: p->addr = 0x00000000e1360063, flags = 0x246
|
||||
....
|
||||
|
||||
Docs: https://github.com/torvalds/linux/blob/v4.16/Documentation/kprobes.txt
|
||||
|
||||
==== Count boot instructions
|
||||
|
||||
* https://www.quora.com/How-many-instructions-does-a-typical-Linux-kernel-boot-take
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
.. link:kstrto.c[]
|
||||
. Hardening
|
||||
.. link:strlen_overflow.c[]
|
||||
. Tracing
|
||||
.. link:kprobe_example.c[]
|
||||
. Arch
|
||||
.. x86
|
||||
... link:ring0.c[]
|
||||
|
||||
127
kernel_module/kprobe_example.c
Normal file
127
kernel_module/kprobe_example.c
Normal file
@@ -0,0 +1,127 @@
|
||||
/* Upstream: https://github.com/torvalds/linux/blob/v4.16/samples/kprobes/kprobe_example.c */
|
||||
|
||||
/*
|
||||
* NOTE: This example is works on x86 and powerpc.
|
||||
* Here's a sample kernel module showing the use of kprobes to dump a
|
||||
* stack trace and selected registers when _do_fork() is called.
|
||||
*
|
||||
* For more information on theory of operation of kprobes, see
|
||||
* Documentation/kprobes.txt
|
||||
*
|
||||
* You will see the trace data in /var/log/messages and on the console
|
||||
* whenever _do_fork() is invoked to create a new process.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kprobes.h>
|
||||
|
||||
#define MAX_SYMBOL_LEN 64
|
||||
static char symbol[MAX_SYMBOL_LEN] = "_do_fork";
|
||||
module_param_string(symbol, symbol, sizeof(symbol), 0644);
|
||||
|
||||
/* For each probe you need to allocate a kprobe structure */
|
||||
static struct kprobe kp = {
|
||||
.symbol_name = symbol,
|
||||
};
|
||||
|
||||
/* kprobe pre_handler: called just before the probed instruction is executed */
|
||||
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
#ifdef CONFIG_X86
|
||||
pr_info("<%s> pre_handler: p->addr = 0x%p, ip = %lx, flags = 0x%lx\n",
|
||||
p->symbol_name, p->addr, regs->ip, regs->flags);
|
||||
#endif
|
||||
#ifdef CONFIG_PPC
|
||||
pr_info("<%s> pre_handler: p->addr = 0x%p, nip = 0x%lx, msr = 0x%lx\n",
|
||||
p->symbol_name, p->addr, regs->nip, regs->msr);
|
||||
#endif
|
||||
#ifdef CONFIG_MIPS
|
||||
pr_info("<%s> pre_handler: p->addr = 0x%p, epc = 0x%lx, status = 0x%lx\n",
|
||||
p->symbol_name, p->addr, regs->cp0_epc, regs->cp0_status);
|
||||
#endif
|
||||
#ifdef CONFIG_TILEGX
|
||||
pr_info("<%s> pre_handler: p->addr = 0x%p, pc = 0x%lx, ex1 = 0x%lx\n",
|
||||
p->symbol_name, p->addr, regs->pc, regs->ex1);
|
||||
#endif
|
||||
#ifdef CONFIG_ARM64
|
||||
pr_info("<%s> pre_handler: p->addr = 0x%p, pc = 0x%lx,"
|
||||
" pstate = 0x%lx\n",
|
||||
p->symbol_name, p->addr, (long)regs->pc, (long)regs->pstate);
|
||||
#endif
|
||||
#ifdef CONFIG_S390
|
||||
pr_info("<%s> pre_handler: p->addr, 0x%p, ip = 0x%lx, flags = 0x%lx\n",
|
||||
p->symbol_name, p->addr, regs->psw.addr, regs->flags);
|
||||
#endif
|
||||
|
||||
/* A dump_stack() here will give a stack backtrace */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* kprobe post_handler: called after the probed instruction is executed */
|
||||
static void handler_post(struct kprobe *p, struct pt_regs *regs,
|
||||
unsigned long flags)
|
||||
{
|
||||
#ifdef CONFIG_X86
|
||||
pr_info("<%s> post_handler: p->addr = 0x%p, flags = 0x%lx\n",
|
||||
p->symbol_name, p->addr, regs->flags);
|
||||
#endif
|
||||
#ifdef CONFIG_PPC
|
||||
pr_info("<%s> post_handler: p->addr = 0x%p, msr = 0x%lx\n",
|
||||
p->symbol_name, p->addr, regs->msr);
|
||||
#endif
|
||||
#ifdef CONFIG_MIPS
|
||||
pr_info("<%s> post_handler: p->addr = 0x%p, status = 0x%lx\n",
|
||||
p->symbol_name, p->addr, regs->cp0_status);
|
||||
#endif
|
||||
#ifdef CONFIG_TILEGX
|
||||
pr_info("<%s> post_handler: p->addr = 0x%p, ex1 = 0x%lx\n",
|
||||
p->symbol_name, p->addr, regs->ex1);
|
||||
#endif
|
||||
#ifdef CONFIG_ARM64
|
||||
pr_info("<%s> post_handler: p->addr = 0x%p, pstate = 0x%lx\n",
|
||||
p->symbol_name, p->addr, (long)regs->pstate);
|
||||
#endif
|
||||
#ifdef CONFIG_S390
|
||||
pr_info("<%s> pre_handler: p->addr, 0x%p, flags = 0x%lx\n",
|
||||
p->symbol_name, p->addr, regs->flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* fault_handler: this is called if an exception is generated for any
|
||||
* instruction within the pre- or post-handler, or when Kprobes
|
||||
* single-steps the probed instruction.
|
||||
*/
|
||||
static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
|
||||
{
|
||||
pr_info("fault_handler: p->addr = 0x%p, trap #%dn", p->addr, trapnr);
|
||||
/* Return 0 because we don't handle the fault. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init kprobe_init(void)
|
||||
{
|
||||
int ret;
|
||||
kp.pre_handler = handler_pre;
|
||||
kp.post_handler = handler_post;
|
||||
kp.fault_handler = handler_fault;
|
||||
|
||||
ret = register_kprobe(&kp);
|
||||
if (ret < 0) {
|
||||
pr_err("register_kprobe failed, returned %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
pr_info("Planted kprobe at %p\n", kp.addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit kprobe_exit(void)
|
||||
{
|
||||
unregister_kprobe(&kp);
|
||||
pr_info("kprobe at %p unregistered\n", kp.addr);
|
||||
}
|
||||
|
||||
module_init(kprobe_init)
|
||||
module_exit(kprobe_exit)
|
||||
MODULE_LICENSE("GPL");
|
||||
Reference in New Issue
Block a user