Идентификация Загружаемых Модулей Ядра Linux [Часть 1]: Исходные Коды

В этом посте я расскажу о своих поисках признаков того, как можно определить, что создается из некоторых исходных файлов.

загружаемый модуль ядра Linux (LKM) , а не обычный исполняемый файл.

Предположим, что информации о назначении исходного кода нет или ее пытаются намеренно скрыть.

Обновить : Объем кода > 4 ГБ и необходимо быстро выбирать только те исходники, которые реализуют модули ядра.



Идентификация загружаемых модулей ядра Linux [часть 1]: исходные коды



#01 __ЯДРО__

При построении исходных кодов определяется символ препроцессора.

__ЯДРО__ .

Как пишут в книге Алессандро Рубини и Джонатан Корбет «Драйверы устройств в Linux»:

«Поскольку модуль не связан ни с одной из стандартных библиотек, исходники модуля не должны включать обычные заголовочные файлы.

Модули ядра могут использовать только функции, экспортированные ядром.

Все заголовочные файлы, относящиеся к ядру, расположены в каталогах include/linux и include/asm внутри дерева каталогов исходного кода ядра (обычно каталог /usr/src/linux).

Ранние версии Linux (на основе libc версии 5 и более ранних) устанавливали символические ссылки из /usr/include/linux и /usr/include/asm на реальные каталоги из исходных текстов ядра, поэтому дерево заголовков libc могло ссылаться на файлы заголовков ядра.

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

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

Однако большинство определений в файлах заголовков ядра зависят от ядра и «невидимы» для обычных приложений, поскольку доступ к этим определениям заключен в блоки #ifdef __KERNEL__. Кстати, это одна из причин, почему при сборке модуля необходимо определять символ __KERNEL__».

Например, make-файл может содержать строку «CFLAGS = -D__KERNEL__».

Или «-D__KERNEL__» можно найти в журналах сборки.



#02 МОДУЛЬ

Если модуль не связан статически с ядром, то переменная CFLAGS обязательно будет содержать строку «-DMODULE».

Этот символ препроцессора должен быть определен перед включением файла.

Linux/module.h .



#03 Все имена объявляются как статический и иметь уникальный префикс

Таким образом разработчик избегает «загрязнения» пространства имен ядра — иначе при отладке ему пришлось бы вылавливать имена своего модуля среди всех имен ядра.

Использование префикса избавляет вас от необходимости придумывать уникальные имена, которые не будут совпадать с именами, уже присутствующими в пространстве имен ядра.



#04 печатьк()

В исходном коде вместо функции printf() используется функция printk().

«Драйверы устройств в Linux» говорят:

«Функция printk определена в ядре, и ее поведение напоминает функцию printf из стандартной библиотеки C. Так зачем же ядру нужна собственная функция? Все просто — ядро — это самостоятельный код, который собирается без вспомогательных библиотек C».



#05 init_module И Cleanup_module

«Драйверы устройств в Linux» говорят: «Приложение работает как комплексная задача, от начала до конца.

Модуль просто регистрируется в ядре, готовя его к обслуживанию возможных запросов, а его «основная» функция завершает свою работу сразу после вызова.

Другими словами, задача функции init_module (точки входа) — подготовить функции модуля к последующим вызовам.

Она словно говорит до глубины души: «Ой!» Я здесь! Вот что я могу сделать!».

Вторая точка входа в модуль, cleanup_module, вызывается непосредственно перед выгрузкой модуля.

Она говорит ядру: «Я ухожу!» Больше ни о чем меня не проси!»

Обновление: Более достоверный признак – наличие функции в тексте.

Cleanup_module , поскольку функции с таким именем встречаются примерно в 20 раз реже, чем с именем « init_module «Видимо, имя» init_module "популярен не только среди авторов модулей ядра.



#06 Использование текущий->

«Драйверы устройств в Linux» говорят: "<.

> Код ядра может определить текущий процесс, обращающийся к модулю через глобальный элемент. текущий - указатель на структура Task_struct , который в ядре 2.4 объявлен в файле .

Указатель текущий относится к текущему пользовательскому процессу.

При выполнении системных вызовов, таких как читать или писать , процесс, выполнивший этот вызов, считается текущим.

Ядро может получить доступ к информации о текущем процессе с помощью указателя.

текущий , если возникнет такая необходимость.

<.

> На самом деле текущий больше не является глобальной переменной ядра, как это было раньше.

Разработчики оптимизировали доступ к структуре, описывающей текущий процесс, переместив ее в стек.

Реализацию тока вы найдете в файле .

Но прежде чем приступить к изучению этого файла, следует помнить, что Linux — это SMP-совместимая система (от англ.

SMP — симметричная многопроцессорная обработка) и поэтому простая глобальная переменная здесь просто неприменима.

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

и обратитесь к указателю текущий .

С точки зрения модуля, текущий - обычная внешняя ссылка, например принтк .

Модуль имеет доступ текущий всякий раз, когда он сочтет это необходимым.

Например, следующий код выведет идентификатор процесса и имя команды, запустившей процесс: printk("Это процесс \"%s\" (pid %i)\n", current-> comm, current-> pid); Имя команды сохраняется в поле ток-> связь и является именем программного файла.

Какие еще различия между модулем ядра и исполняемым файлом на уровне исходного кода вы знаете?

Хабралинки по теме:
«Написание собственного драйвера для Linux» от изнакурнож «Написание драйвера ЖК-дисплея для встроенного Linux» от Алексзойдберг «Обзор шины SPI и разработка драйвера ведомого устройства SPI для встроенного Linux (Часть первая, обзор)» от Лампус «Обзор шины SPI и разработка драйвера ведомого устройства SPI для встроенного Linux (Часть вторая, практическая)» от Лампус Работа с модулями ядра в Linux от Ворб Научимся писать модуль ядра (Netfilter) или прозрачный прокси для HTTPS. от синдо «Написание файловой системы в ядре Linux» от кму1990 «Легкая маскировка модуля ядра Linux с помощью DKOM» от милабс Теги: #linux #kernel #загружаемый модуль ядра #аудит кода #информационная безопасность #C++
Вместе с данным постом часто просматривают: