mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
Host insane unsafe usage
This commit is contained in:
42
README.md
42
README.md
@@ -4,9 +4,47 @@ Run one command, get a QEMU Buildroot BusyBox virtual machine with several minim
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 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
|
sudo apt-get build-dep qemu
|
||||||
./run
|
./run
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ ccflags-y := -Wno-declaration-after-statement -std=gnu99
|
|||||||
all: hello.ko
|
all: hello.ko
|
||||||
|
|
||||||
hello.ko: hello.c
|
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:
|
clean:
|
||||||
make -C '/lib/modules/$(shell uname -r)/build' M='$(PWD)' clean
|
$(MAKE) -C '/lib/modules/$(shell uname -r)/build' M='$(PWD)' clean
|
||||||
|
|||||||
@@ -1,35 +1,3 @@
|
|||||||
# Host
|
# Host
|
||||||
|
|
||||||
Simple things that can be demonstrated by inserting a module into the currently running host. Tested on Ubuntu 16.04.
|
Minimal host build system sanity check example.
|
||||||
|
|
||||||
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
|
|
||||||
|
|||||||
12
host/hello.c
12
host/hello.c
@@ -1,13 +1,17 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
printk(KERN_INFO "init_module\n");
|
pr_info("hello init\n");
|
||||||
return 0;
|
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");
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
obj-m += $(addsuffix .o, $(notdir $(basename $(wildcard $(BR2_EXTERNAL_KERNEL_MODULE_PATH)/*.c))))
|
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
|
ccflags-y := -DDEBUG -g -std=gnu99 -Werror -Wno-declaration-after-statement -Wframe-larger-than=1000000000
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
||||||
all:
|
all:
|
||||||
$(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' modules
|
$(MAKE) -C '/lib/modules/$(shell uname -r)/build' M='$(PWD)' modules
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' clean
|
$(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' clean
|
||||||
|
|||||||
15
kernel_module/make-host.sh
Executable file
15
kernel_module/make-host.sh
Executable file
@@ -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)) "$@"
|
||||||
@@ -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
|
IN_EXT ?= .c
|
||||||
OUT_EXT ?= .out
|
OUT_EXT ?= .out
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ OUTS := $(addsuffix $(OUT_EXT), $(basename $(wildcard *$(IN_EXT))))
|
|||||||
all: $(OUTS)
|
all: $(OUTS)
|
||||||
|
|
||||||
%$(OUT_EXT): %$(IN_EXT)
|
%$(OUT_EXT): %$(IN_EXT)
|
||||||
$(CC) -o '$@' '$<'
|
$(CCC) -o '$@' '$<'
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *'$(OUT_EXT)'
|
rm -f *'$(OUT_EXT)'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#ifndef COMMON_H
|
#ifndef COMMON_H
|
||||||
#define COMMON_H
|
#define COMMON_H
|
||||||
|
|
||||||
#define _POSIX_C_SOURCE 200809L
|
#define _XOPEN_SOURCE 700
|
||||||
#include <fcntl.h> /* open */
|
#include <fcntl.h> /* open */
|
||||||
#include <stdint.h> /* uint64_t */
|
#include <stdint.h> /* uint64_t */
|
||||||
#include <stdlib.h> /* size_t */
|
#include <stdlib.h> /* size_t */
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#define _XOPEN_SOURCE 700
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ Dump the page map of a given process PID.
|
|||||||
Data sources: /proc/PIC/{map,pagemap}
|
Data sources: /proc/PIC/{map,pagemap}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _POSIX_C_SOURCE 200809L
|
#define _XOPEN_SOURCE 700
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -63,7 +63,6 @@ int main(int argc, char **argv) {
|
|||||||
size_t x = i - 1;
|
size_t x = i - 1;
|
||||||
while (x && buffer[x] != '\n') x--;
|
while (x && buffer[x] != '\n') x--;
|
||||||
if (buffer[x] == '\n') x++;
|
if (buffer[x] == '\n') x++;
|
||||||
size_t beginning = x;
|
|
||||||
while (buffer[x] != '-' && x < sizeof buffer) {
|
while (buffer[x] != '-' && x < sizeof buffer) {
|
||||||
char c = buffer[x++];
|
char c = buffer[x++];
|
||||||
low *= 16;
|
low *= 16;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#define _XOPEN_SOURCE 700
|
#define _XOPEN_SOURCE 700
|
||||||
|
#include <assert.h>
|
||||||
#include <fcntl.h> /* creat, O_CREAT */
|
#include <fcntl.h> /* creat, O_CREAT */
|
||||||
#include <poll.h> /* poll */
|
#include <poll.h> /* poll */
|
||||||
#include <stdio.h> /* printf, puts, snprintf */
|
#include <stdio.h> /* printf, puts, snprintf */
|
||||||
@@ -6,11 +7,15 @@
|
|||||||
#include <unistd.h> /* read */
|
#include <unistd.h> /* read */
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
char buf[1024], path[1024];
|
char buf[1024];
|
||||||
int fd, i, n;
|
int fd, i, n;
|
||||||
short revents;
|
short revents;
|
||||||
struct pollfd pfd;
|
struct pollfd pfd;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "usage: %s <poll-device>\n", argv[0]);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
fd = open(argv[1], O_RDONLY | O_NONBLOCK);
|
fd = open(argv[1], O_RDONLY | O_NONBLOCK);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
perror("open");
|
perror("open");
|
||||||
@@ -23,7 +28,7 @@ int main(int argc, char **argv) {
|
|||||||
i = poll(&pfd, 1, -1);
|
i = poll(&pfd, 1, -1);
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
perror("poll");
|
perror("poll");
|
||||||
exit(EXIT_FAILURE);
|
assert(0);
|
||||||
}
|
}
|
||||||
revents = pfd.revents;
|
revents = pfd.revents;
|
||||||
if (revents & POLLIN) {
|
if (revents & POLLIN) {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ Yes!!! We read the correct value from the physical address.
|
|||||||
|
|
||||||
## /dev/mem
|
## /dev/mem
|
||||||
|
|
||||||
Firts up, this requires:
|
Firt up, this requires:
|
||||||
|
|
||||||
- CONFIG_STRICT_DEVMEM is not set.
|
- CONFIG_STRICT_DEVMEM is not set.
|
||||||
- nopat on kernel parameters
|
- nopat on kernel parameters
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ https://stackoverflow.com/questions/5748492/is-there-any-api-for-determining-the
|
|||||||
Test this out with usermem.c.
|
Test this out with usermem.c.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define _XOPEN_SOURCE 700
|
||||||
#include <stdio.h> /* printf */
|
#include <stdio.h> /* printf */
|
||||||
#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE, strtoull */
|
#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE, strtoull */
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@ Test this out with usermem.c.
|
|||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
uintptr_t vaddr, paddr;
|
uintptr_t vaddr, paddr = 0;
|
||||||
|
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
printf("Usage: %s pid vaddr\n", argv[0]);
|
printf("Usage: %s pid vaddr\n", argv[0]);
|
||||||
|
|||||||
Reference in New Issue
Block a user