Inhaltsverzeichnis

Linux-Kernel-Hacking

:!: Noch in Rekonstruktion :!:

Im Dezember 2012 hat Yu vorgeschlagen, einen tieferen Einblick in die Programmierung von Modulen für den Linux-Kernel zu geben.

Am 9. Februar 2013 trafen wir uns und haben gemeinsam ein einfaches Modul für den Linux-Kernel erstellt. Dies legt ein Char-Device an. Darüber kann man die Ausgabe eines Zählers abfragen.

Shownotes

Einstieg in das Kernelbauen

Yu hat für den Vortrag ein paar Folien zusammengestellt, die es hier gibt und einige der Grundlagen zusammen fassen.

Das Minimal-Kernel-Modul

Als Anfang das simpelste Kernelmodul.

Benötigte Utensilien:

  1. Ein Linux (Header nicht vergessen)
  2. Editor/Terminal
  3. C-Code und passenden Compiler (aka GCC)
  4. Makefile

(Nicht unbedingt in dieser Reihenfolge)

Ist alles zur Hand, kann es losgehen. Das einfachste Kernelmodul sieht ungefähr so aus:

geruest.c
// The simplest kernel module.
 
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>	
#include <linux/init.h>	
#include <linux/stat.h>
 
int init_module(void)
{
	printk(KERN_INFO "Hello world!\n");
	return 0;
}
 
void cleanup_module(void)
{
	printk(KERN_INFO "Goodbye world!\n");
}

Es macht im Grunde nichts anderes, als beim Laden via insmod geruest.ko die Nachricht Hello world! in das Log zu schreiben. Wenn man es mit rmmod geruest wieder entlädt, wird die Nachricht Goodbye world! in das Log geschrieben.

Um es aber zu übersetzen, benötigt man ein Makefile (benötigt man nicht, macht die Sache aber einfacher). Dieses könnte ungefähr so aussehen:

Makefile
obj-m += geruest.o
 
all:
	make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
 
clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean

Damit kann durch die Aufruf von make das Modul übersetzen. Damit kann durch die Aufruf von make das Modul übersetzen und über insmod bzw rmmod laden und entladen.

Im nächsten Schritt soll das Modul noch ein paar Informationen erhalten, die z.B. mit modinfo ausglesen werden können. Dazu kann man diese Zeilen, natürlich mit sinvollem Inhalt gefüllt, in die Quellen einbauen:

MODULE_AUTHOR("Dein Name")
MODULE_LICENSE("Name der Lizenz, z.B. GPL")
MODULE_DESCRIPTION("Beschreibung, was dein Modul so macht")
MODULE_SUPPORTED_DEVICE("Gerad unwichtig. Zur Dokumentationszwecken nutzbar")

Variablen im Kernelland

Der Kernel definiert zum Teil seine eigenen Variablentypen. Diese könnten z.B. sein:

Diese kann man nutzen, um Parameter vom Terminal einzulesen, die z.B. beim Laden des Moduls mit übergeben werden.

Um Parameter vom Terminal einzulesen nutzt man:

/* Prototyp */
module_param(variablenname, type, permission);
 
/* Hauptsächlich für modinfo */
MODULE_PARM_DESC(variablenname, "Beschreibung");

Um tatsächlich auf das neu geschaffene Device zugreifen zu können, muss man ein device in /dev erstellen. Dies geht ungefähr so:

dev_t devnr = MKDEV(int majornr, int minornr);

In dem konrketen Beispiel sollten wobei majornr 120 und minornr 1 sein.

Als nächstes braucht man ein struct, welches die character-device-Struktur des Kernels beinhaltet.

struct cdev *char_dev;

Sowie noch einen int fuer den Rückgabewert, sowie den Names des Devices als char*.

Dies könnte dann ungefähr so aussehen:

// ..
dev_t devnr = MKDEV(120, 1);
struct cdev *char_dev;
int rv;
char* name = "device_name";
//..