From 0bb3e8519ad74d83c7d4509bc49bb0d2790f38af Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Thu, 3 Aug 2017 04:32:06 +0100 Subject: [PATCH] Host insane unsafe usage --- README.md | 42 ++++++++++++++++++++++++-- host/Makefile | 4 +-- host/README.md | 34 +-------------------- host/hello.c | 12 +++++--- kernel_module/Makefile | 6 ++-- kernel_module/make-host.sh | 15 +++++++++ kernel_module/user/Makefile | 6 ++-- kernel_module/user/common.h | 2 +- kernel_module/user/mmap.c | 1 + kernel_module/user/pagemap_dump.c | 3 +- kernel_module/user/poll.c | 9 ++++-- kernel_module/user/usermem.c | 2 +- kernel_module/user/virt_to_phys_user.c | 3 +- 13 files changed, 85 insertions(+), 54 deletions(-) create mode 100755 kernel_module/make-host.sh diff --git a/README.md b/README.md index 4c6add7..3760f9a 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,47 @@ Run one command, get a QEMU Buildroot BusyBox virtual machine with several minim ![](screenshot.png) -## Getting started +## Insane unsafe host super fast quickstart -Usage: + cd kernel_module + ./make-host.sh + +If the compilation of any of the C files fails (because of kernel or toolchain differences that we don't control on the host), just rename it to remove the `.c` extension and try again: + + mv broken.c broken.c~ + ./build_host + +Once you manage to compile, try it out with: + + sudo insmod hello.ko + + # Our module is there. + sudo lsmod | grep hello + + # Last message should be: hello init + dmest -T + + sudo rmmod hello + + # Last message should be: hello exit + dmesg -T + + # Not present anymore + sudo lsmod | grep hello + +Why this is very bad and you should be ashamed: + +- bugs can easily break you system. E.g.: + - segfaults can trivially lead to a kernel crash, and require a reboot + - your disk could get erased. Yes, this can also happen with `sudo` from userland. But you should not use `sudo` when developing newbie programs. And for the kernel you don't have the choice not to use `sudo` + - even more subtle problems like [not being able to rmmod](https://unix.stackexchange.com/questions/78858/cannot-remove-or-reinsert-kernel-module-after-error-while-inserting-it-without-r) +- can't control which kernel version to use. So some of the modules may simply not compile because of kernel API changes, since [the Linux kernel does not have a stable kernel module API](https://stackoverflow.com/questions/37098482/how-to-build-a-linux-kernel-module-so-that-it-is-compatible-with-all-kernel-rele/45429681#45429681). +- can't control which hardware is are using, notably the CPU architecture +- can't step debug it with GDB easily + +The only advantage of using your host machine, is that you don't have to wait 2 hours and use up 8 Gigs for the build. But you will soon find out that this is a very reasonable price to pay. + +## Do the right thing and use a virtual machine sudo apt-get build-dep qemu ./run diff --git a/host/Makefile b/host/Makefile index 2de3b3d..6783b2b 100644 --- a/host/Makefile +++ b/host/Makefile @@ -6,7 +6,7 @@ ccflags-y := -Wno-declaration-after-statement -std=gnu99 all: hello.ko hello.ko: hello.c - make -C '/lib/modules/$(shell uname -r)/build' M='$(PWD)' modules + $(MAKE) -C '/lib/modules/$(shell uname -r)/build' M='$(PWD)' modules clean: - make -C '/lib/modules/$(shell uname -r)/build' M='$(PWD)' clean + $(MAKE) -C '/lib/modules/$(shell uname -r)/build' M='$(PWD)' clean diff --git a/host/README.md b/host/README.md index d603ce0..5aa9580 100644 --- a/host/README.md +++ b/host/README.md @@ -1,35 +1,3 @@ # 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) - -## 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 - - sudo insmod hello.ko - - # Our module should be there. - sudo lsmod | grep hello - - # Last message should be: init_module - dmest -T - - sudo rmmod hello - - # Last message should be: cleanup_module - dmest -T +Minimal host build system sanity check example. diff --git a/host/hello.c b/host/hello.c index 716c628..36a9651 100644 --- a/host/hello.c +++ b/host/hello.c @@ -1,13 +1,17 @@ #include #include -int init_module(void) +static int myinit(void) { - printk(KERN_INFO "init_module\n"); + pr_info("hello init\n"); return 0; } -void cleanup_module(void) +static void myexit(void) { - printk(KERN_INFO "cleanup_module\n"); + pr_info("hello exit\n"); } + +module_init(myinit) +module_exit(myexit) +MODULE_LICENSE("GPL"); diff --git a/kernel_module/Makefile b/kernel_module/Makefile index d409eef..0c512e3 100644 --- a/kernel_module/Makefile +++ b/kernel_module/Makefile @@ -1,10 +1,10 @@ -obj-m += $(addsuffix .o, $(notdir $(basename $(wildcard $(BR2_EXTERNAL_KERNEL_MODULE_PATH)/*.c)))) -ccflags-y := -DDEBUG -g -std=gnu99 -Werror -Wno-declaration-after-statement +obj-m += $(addsuffix .o, $(notdir $(basename $(filter-out %.mod.c, $(wildcard $(BR2_EXTERNAL_KERNEL_MODULE_PATH)/*.c))))) +ccflags-y := -DDEBUG -g -std=gnu99 -Werror -Wno-declaration-after-statement -Wframe-larger-than=1000000000 .PHONY: all clean all: - $(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' modules + $(MAKE) -C '/lib/modules/$(shell uname -r)/build' M='$(PWD)' modules clean: $(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' clean diff --git a/kernel_module/make-host.sh b/kernel_module/make-host.sh new file mode 100755 index 0000000..e08f866 --- /dev/null +++ b/kernel_module/make-host.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# We can almost do everything from the Makefile itself by using default values for +# +# LINUX_DIR ?= "/lib/modules/$(uname -r)/build" +# BR2_EXTERNAL_KERNEL_MODULE_PATH="$(pwd)" +# +# The problem with that is that if you define those variables in your environment, +# the build breaks, so this is more portable. +# +# Trying to add `-i` to overcome incompatible modules will fail, +# because any build failure prevents the generation of all `.mod.c` files. + +make -j $(($(nproc) - 2)) BR2_EXTERNAL_KERNEL_MODULE_PATH="$(pwd)" LINUX_DIR="/lib/modules/$(uname -r)/build" "$@" +make -C user/ -j $(($(nproc) - 2)) "$@" diff --git a/kernel_module/user/Makefile b/kernel_module/user/Makefile index 71296d6..8fd4545 100644 --- a/kernel_module/user/Makefile +++ b/kernel_module/user/Makefile @@ -1,6 +1,6 @@ -.PHONY: clean +.PHONY: all clean -CC ?= gcc -ggdb3 -O0 -std=c99 -Wall -Werror -Wextra +CCC ?= gcc -ggdb3 -O0 -std=c99 -Wall -Werror -Wextra IN_EXT ?= .c OUT_EXT ?= .out @@ -9,7 +9,7 @@ OUTS := $(addsuffix $(OUT_EXT), $(basename $(wildcard *$(IN_EXT)))) all: $(OUTS) %$(OUT_EXT): %$(IN_EXT) - $(CC) -o '$@' '$<' + $(CCC) -o '$@' '$<' clean: rm -f *'$(OUT_EXT)' diff --git a/kernel_module/user/common.h b/kernel_module/user/common.h index 3d4c27f..e76acfb 100644 --- a/kernel_module/user/common.h +++ b/kernel_module/user/common.h @@ -1,7 +1,7 @@ #ifndef COMMON_H #define COMMON_H -#define _POSIX_C_SOURCE 200809L +#define _XOPEN_SOURCE 700 #include /* open */ #include /* uint64_t */ #include /* size_t */ diff --git a/kernel_module/user/mmap.c b/kernel_module/user/mmap.c index 7577277..77f17fe 100644 --- a/kernel_module/user/mmap.c +++ b/kernel_module/user/mmap.c @@ -1,3 +1,4 @@ +#define _XOPEN_SOURCE 700 #include #include #include diff --git a/kernel_module/user/pagemap_dump.c b/kernel_module/user/pagemap_dump.c index 9fd66a9..ca12717 100644 --- a/kernel_module/user/pagemap_dump.c +++ b/kernel_module/user/pagemap_dump.c @@ -11,7 +11,7 @@ Dump the page map of a given process PID. Data sources: /proc/PIC/{map,pagemap} */ -#define _POSIX_C_SOURCE 200809L +#define _XOPEN_SOURCE 700 #include #include #include @@ -63,7 +63,6 @@ int main(int argc, char **argv) { size_t x = i - 1; while (x && buffer[x] != '\n') x--; if (buffer[x] == '\n') x++; - size_t beginning = x; while (buffer[x] != '-' && x < sizeof buffer) { char c = buffer[x++]; low *= 16; diff --git a/kernel_module/user/poll.c b/kernel_module/user/poll.c index 0ba3da0..dca5aad 100644 --- a/kernel_module/user/poll.c +++ b/kernel_module/user/poll.c @@ -1,4 +1,5 @@ #define _XOPEN_SOURCE 700 +#include #include /* creat, O_CREAT */ #include /* poll */ #include /* printf, puts, snprintf */ @@ -6,11 +7,15 @@ #include /* read */ int main(int argc, char **argv) { - char buf[1024], path[1024]; + char buf[1024]; int fd, i, n; short revents; struct pollfd pfd; + if (argc < 2) { + fprintf(stderr, "usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } fd = open(argv[1], O_RDONLY | O_NONBLOCK); if (fd == -1) { perror("open"); @@ -23,7 +28,7 @@ int main(int argc, char **argv) { i = poll(&pfd, 1, -1); if (i == -1) { perror("poll"); - exit(EXIT_FAILURE); + assert(0); } revents = pfd.revents; if (revents & POLLIN) { diff --git a/kernel_module/user/usermem.c b/kernel_module/user/usermem.c index 61985ad..0bccb43 100644 --- a/kernel_module/user/usermem.c +++ b/kernel_module/user/usermem.c @@ -39,7 +39,7 @@ Yes!!! We read the correct value from the physical address. ## /dev/mem -Firts up, this requires: +Firt up, this requires: - CONFIG_STRICT_DEVMEM is not set. - nopat on kernel parameters diff --git a/kernel_module/user/virt_to_phys_user.c b/kernel_module/user/virt_to_phys_user.c index 08ea221..4ded48a 100644 --- a/kernel_module/user/virt_to_phys_user.c +++ b/kernel_module/user/virt_to_phys_user.c @@ -6,6 +6,7 @@ https://stackoverflow.com/questions/5748492/is-there-any-api-for-determining-the Test this out with usermem.c. */ +#define _XOPEN_SOURCE 700 #include /* printf */ #include /* EXIT_SUCCESS, EXIT_FAILURE, strtoull */ @@ -14,7 +15,7 @@ Test this out with usermem.c. int main(int argc, char **argv) { pid_t pid; - uintptr_t vaddr, paddr; + uintptr_t vaddr, paddr = 0; if (argc < 3) { printf("Usage: %s pid vaddr\n", argv[0]);