This is a basic kernel module that implements the following features:
- entry point for loading and unloading the kernel module
- debug statements that can be observed with
dmesg - optionally transmitting a parameter,
magic, when the module is loaded (otherwise a default value is used) - creation of a character device,
/dev/oracle(mknod must be invoked manually for now) - implements the
readAPI, which takes the current value ofmagicand copies it from the kernel to the user-space buffer - reacts to any
ioctlsent to the module by incrementingmagic
This was tested on Debian 7 x64.
This only needs to be done once, to prepare the compilation environment.
sudo apt-get install build-essentialssudo apt-get install linux-headers-$(uname -r)
It is expected that you already have Python, it will be needed for the user-mode program to test ioctl handling.
Get into the directory where you cloned the git repo and run make. The output will be stored in hellok.ko.
git clone https://github.com/ralienpp/hello-kernel.gitcd hello-kernelmake
You can make sure this loads and unloads correctly as follows:
sudo insmod ./hellok.korun
lsmodand it should be in the list of loaded modules, e.g.Module Size Used by hellok 12452 0
unload it with
sudo rmmod hellokrun
dmesgto see what has just happened, the debug lines should be there:[73964.820487] hellok: module license 'unspecified' taints kernel. [73964.820492] Disabling lock debugging due to kernel taint [74342.727012] Loaded hellok [74469.278069] Unloaded hellok
- You can pass a parameter at load time, e.g.
sudo insmod ./hellok.ko magic=12. If not specified, a default value will be used. - The value can be examined after the module is loaded:
cat /sys/module/hellok/parameters/magic - You can write to it (if permissions allow so), e.g. (as root)
echo 45 > /sys/module/hellok/parameters/magic
To check if the devices was created successfully, run cat /proc/devices and expect something like this:
Character devices: 100 Oracle
The number is the MAJOR defined in the code, and the name is the string we used to name the device.
Before you can interact with this device, run sudo mknod -m 666 /dev/oracle c 100 0 (create a character device, allowing everyone to do everything with it, 100 is MAJOR as defined in the code, and 0 is the minor [taken "as is" from a guide]).
To demonstrate communication between kernel-space and user-space, you can run cat /dev/oracle and the value of magic will be shown on the screen as a string.
This happens by copying this value from a buffer in the kernel's address space, into a buffer in user-space, using copy_to_user.
Alternatively, run python testusermode.py, which will send an ioctl to /dev/oracle (the driver doesn't care what command is sent, they're all handled equally). You can observe the effect by reading from /dev/oracle, the read value should be incremeted after each ioctl call.
- http://www.tldp.org/LDP/lkmpg/2.4/html/x281.htm
- https://www.apriorit.com/dev-blog/195-simple-driver-for-linux-os
- https://www.youtube.com/watch?v=Zn8mEZXr6nE
- http://www.virtsync.com/c-error-codes-include-errno
- https://lwn.net/Articles/115651/
- why
static? Other tutorials don't have that. - what is the point of having major and minor versions?
- can
mknodbe invoked automatically? catnever stops, should I add anEOFat the end? (does stop when run as root, strange)#define ENOTTY 25 /* Not a typewriter */why can't my character device handle this?- what is a safe way to avoid
MAJORcollisions?
- use
%zuforsize_tin debug statements
ioctlis used because I was aware of this concept earlier and expected it to be easier. After reading more about it while implementing it, I found it convenient that I can send avoidpayload, and use the presence of the message itself as a signal, which is sufficient for the purposes of this prototype. Otherwise, the benefit of theioctlis that it provides the possibility to send arbitrary payloads, which may be handy in the future.- clearly, the communication done via
/sys/module/hellok/parameters/magicis another form of interaction between kernel-space and user-space, which is not anioctland which appears to be a much simpler/cheaper method, because I got it "for free" (no need to write a handler for it). - when it comes to user-space, the "cheapest" way to prove it works is to read from
/dev/oraclewith any existing tool, thus there's no need to write any code at all. - however, I also wrote a Python program in order to check how the
ioctlhandler works. I used this language because it was much easier to write in, and I was thinking that if there were implementation issues it would be easier to debug them using the REPL. However, due to the simplicity of the current driver, there's not much room for something not to work.