diff --git a/1_Livepatch/1.1_kpatch/README.md b/1_Livepatch/1.1_kpatch/README.md new file mode 100644 index 0000000..6bba3cf --- /dev/null +++ b/1_Livepatch/1.1_kpatch/README.md @@ -0,0 +1,26 @@ +# Linux Kernel Hacking + +## 1.1: Kpatch Example + +In order to patch existing kernel functions, you have to be able to resolve relocatable symbols in the currently running kernel. Doing this manually would be very difficult and time-consuming, so [kpatch](https://github.com/dynup/kpatch) was created. + +Kpatch works by first building the kernel tree normally, then rebuilding it with a patch provided as a source diff. Next, it takes the object files that changed, and rebuilds them again (both with and without the patch) with the GCC options `-ffunction-sections` and `-fdata-sections`. These two options cause all functions and data items to get their own sections, so that they can be found more easily without having to know precise offsets. Now the ELF relocation table can be built for the patched object file, and the kernel module is generated. + +Setting up kpatch: +* `apt install dpkg-dev devscripts elfutils ccache` +* `apt build-dep linux` +* `git clone git@github.com:dynup/kpatch.git` +* `cd kpatch; make install` +* Download the debug kernel image from [http://ddebs.ubuntu.com/ubuntu/pool/main/l/linux/](http://ddebs.ubuntu.com/ubuntu/pool/main/l/linux/). The file you need is called `linux-image-unsigned--generic-dbgsym__amd64.ddeb` +* Install with `dpkg -i ` + +To use: +* Check the output of `grep -i vmallocchunk /proc/meminfo` +* Build with `kpatch-build -t vmlinux --vmlinux /lib/debug/boot/vmlinux-$(uname -r) meminfo-string.patch` +* Load the kernel module with `insmod livepatch-meminfo-string.ko` +* Check the output of `grep -i vmallocchunk /proc/meminfo` again - notice that it's now in all-caps +* Disable the livepatch with `echo 0 | sudo tee /sys/kernel/livepatch/livepatch-meminfo-string/enabled` +* Unload from the kernel with `rmmod livepatch-meminfo-string.ko` + +> Tested on Ubuntu 20.04 running under Vagrant. +> Helful Source: [https://ruffell.nz/programming/writeups/2020/04/20/everything-you-wanted-to-know-about-kernel-livepatch-in-ubuntu.html](https://ruffell.nz/programming/writeups/2020/04/20/everything-you-wanted-to-know-about-kernel-livepatch-in-ubuntu.html). diff --git a/1_Livepatch/1.1_kpatch/livepatch-sample.c b/1_Livepatch/1.1_kpatch/livepatch-sample.c new file mode 100644 index 0000000..160dfea --- /dev/null +++ b/1_Livepatch/1.1_kpatch/livepatch-sample.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * livepatch-sample.c - Kernel Live Patching Sample Module + * + * Copyright (C) 2014 Seth Jennings + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + +/* + * This (dumb) live patch overrides the function that prints the + * kernel boot cmdline when /proc/cmdline is read. + * + * Example: + * + * $ cat /proc/cmdline + * + * + * $ insmod livepatch-sample.ko + * $ cat /proc/cmdline + * this has been live patched + * + * $ echo 0 > /sys/kernel/livepatch/livepatch_sample/enabled + * $ cat /proc/cmdline + * + */ + +#include + +/* This is the replacement function that we are going to override with */ +static int livepatch_cmdline_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "%s\n", "this has been live patched"); + return 0; +} + +/* We have to provide the livepatch API with the following struct + * that indicates which kernel function we are overwriting and with what */ +static struct klp_func funcs[] = { + { + .old_name = "cmdline_proc_show", + .new_func = livepatch_cmdline_proc_show, + }, { } +}; + +/* The struct above gets passed as a field in the following klp_object + * (kernel live patch)_object. */ +static struct klp_object objs[] = { + { + /* name being NULL means vmlinux */ + .funcs = funcs, + }, { } +}; + +/* Again, the struct above gets passed a field to the following klp_patch + * object. The address of this object in memory will be passed to the + * klp_enable_patch() function */ +static struct klp_patch patch = { + .mod = THIS_MODULE, + .objs = objs, +}; + +/* Initialize our patch */ +static int livepatch_init(void) +{ + return klp_enable_patch(&patch); +} + +static void livepatch_exit(void) +{ +} + +module_init(livepatch_init); +module_exit(livepatch_exit); +MODULE_LICENSE("GPL"); +/* We have to tell the kernel that this LKM is a livepatch module */ +MODULE_INFO(livepatch, "Y"); diff --git a/1_Livepatch/1.1_kpatch/meminfo-string.patch b/1_Livepatch/1.1_kpatch/meminfo-string.patch new file mode 100644 index 0000000..def646c --- /dev/null +++ b/1_Livepatch/1.1_kpatch/meminfo-string.patch @@ -0,0 +1,13 @@ +diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c +index 8c1f1bb1a5ce..3053c1bce50d 100644 +--- a/fs/proc/meminfo.c ++++ b/fs/proc/meminfo.c +@@ -117,7 +117,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v) + seq_printf(m, "VmallocTotal: %8lu kB\n", + (unsigned long)VMALLOC_TOTAL >> 10); + show_val_kb(m, "VmallocUsed: ", vmalloc_nr_pages()); +- show_val_kb(m, "VmallocChunk: ", 0ul); ++ show_val_kb(m, "VMALLOCCHUNK: ", 0ul); + show_val_kb(m, "Percpu: ", pcpu_nr_pages()); + + #ifdef CONFIG_MEMORY_FAILURE