Программирование в Linux: Linux Kernel Modules (исходники)

Источник: wmate

Итак, из чего состоит модуль? Как уже говорилось, модуль - такая же программа как и обычные, с одной лишь разницей - она добавляет/изменяет некоторый код ядра. Из чего следует, что тело программы-модуля должно состоять по крайней мере из двух функций: одна для добавления/изменения функции (кода), вторая для отката (возврата) к состоянию до изменений в ядре. Если в обычной программе на С/С++ точкой входа в программу служит функция main, то для модуля это именно эти две функции. Названий этих функций соответствующие: int init_module() и void cleanup_module(). Возвращаемые значения у этих функций играют не последнюю роль: если в первой функции возвращаемое значение не 0, то модуль попросту не устанавливается; что же касается второй функции, то тип возвращаемого значения не определен, что говорит о том, что проверить на существование ошибок не представляется доступным. По этой причине следует делать массу проверок, так как может сложится ситуация в которой, к примеру, будет происходить обращение к устройству (файлу), драйвер которого в виде модуля будет удален из ядра. В этом случае управление может получить другая функция другого модуля установленного на место старого, что неизбежно приведет к ошибочному выполнению произвольного кода.Во избежание таких случаев существеут множество макросов и счетчиков, которыми следует пользоваться.

Пожалуй следует перейти от слов к делу. Для начала напишем самую популярную и многоплатформенную программу (господи, на что она только ни портировалась и на каких языках ее ни писали) - Hello world. Программа будет выполненна в виде модуля, главной целью которого будет вывод строки "Hello World" на экран при установке и "finished" при удалении его из ядра.

--------------------------------------------------CODE_START----------
#first.c
/*
Здесь идет подключение необходимых ХЭДов
*/
#include 
#include 

#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include 
#endif

/*
Здесь происходит инициализация модуля
*/
int
init_module()
{
	printk("Hello world!n");
	return 0; //помните, это обязательно!
}

/*
А вот здесь должно происходить обратное действие установке
*/
void
cleanup_module()
{
	printk("finishedn");
}

--------------------------------------------------CODE_ENDS-----------

В данном модуле используется функция printk(), она позволит нам говорить от имени ядра (kernel). Так как это "не обычная программа", компилируется она так же не совсем обычно. Компилировать нужно с флагом -с. Но помимо этого используются еще некоторые ключи. Вот некоторые из них:
__KERNEL__ - говорит о том, что данная программа будет работать как ядро, а не обычный процесс.
MODULE - соответствующие определения для модуля ядра.
LINUX - не совсем понятно, но скорее всего для компиляции "зависимых от ОС" частей программы.

В компиляции вам может пригодиться утилита make. Вот исходный текст Makefile'а

--------------------------------------------------CODE_START----------
CC=gcc
FLAGS:= -Wall -DMODULE -D_KERNEL__ -DLINUX
first.o:	first.c /usr/include/linux/version.h
	$(CC) $(FLAGS) -c first.c

--------------------------------------------------CODE_ENDS-----------

Для загрузки/выгрузки модуля в код ядра используйте команду insmod/rmmod first.o

Следует оговорить некоторые особенности:

1) компиляция происходит не из-под рута.
2) загрузка и выгрузка происходит не из-под Х.

Согласен, что в данной статье было изложенно мало полезного для опытного хакера, но для человека, которого данная тема только начала интересовать, статья может показаться полезной... обещаю продолжить цикл посвященный данной теме.


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=1941