Есть ли способ для модуля ядра найти адреса разделов другого загруженного модуля?

В системе x86 у меня есть модуль ядра Linux («модуль-наблюдатель»), который получает уведомление от ядра каждый раз, когда загружается определенный модуль ядра («цель»). Почти любой модуль ядра может быть целью. Я использую это в системе инструментов, над которой работаю.

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

Конечно, я мог бы, вероятно, получить содержимое соответствующих файлов в /sys/module/<target_name>/sections/ в пользовательском пространстве, как только цель будет загружена, а затем каким-то образом передать эти данные в модуль наблюдателя, но это слишком неуклюже. Я хотел бы найти способ получить эту информацию непосредственно в пространстве ядра.

Насколько я видел в исходниках загрузчика модулей, он не хранит адреса разделов в struct module, просто создает для разделов файлы sysfs. Может быть, можно как-то найти объекты ядра, соответствующие этим файлам, и прочитать нужные данные из этих объектов? Или, возможно, использовать какой-то другой подход?


person Eugene    schedule 21.10.2011    source источник
comment
Похоже, что kobject, содержащийся в struct module (поле mkobj.kobj), участвует в представлении модуля в sysfs. Я буду копаться в этом дальше, когда у меня будет время. Можно получить доступ к атрибутам, содержащим имена и адреса разделов, используя этот kobject в качестве отправной точки.   -  person Eugene    schedule 23.10.2011


Ответы (2)


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

Вкратце идея такая. Мой модуль ядра использует вспомогательный API пользовательского режима для запуска процесса пользовательского пространства (на самом деле это оболочка, выполняющая мой скрипт). Этот процесс получает в качестве параметра имя «целевого» модуля ядра и собирает информацию о его разделах из sysfs (/sys/module/<target_name>/sections/). Из пользовательского пространства эту информацию можно легко получить. После этого он передает собранные данные моему модулю ядра в виде строки через файл в debugfs. Модуль анализирует строку и проверяет ее содержимое. Если все в порядке, имена и начальные адреса разделов ELF будут доступны.

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

Я подготовил пример реализации описанного выше подхода — см. "Sections " пример.

Подробнее о вспомогательном API пользовательского режима см. в коде <linux/kmod.c> и <linux/kmod.h> в исходниках ядра, а именно в определении call_usermodehelper(). Примеры, а также объяснение типичного использования API доступны в эту статью.

Обратите внимание, что примеры из этой статьи немного неточны: функция инициализации модуля возвращает там результат call_usermodehelper(). Последний, однако, возвращает 2-байтовый код состояния (по крайней мере, при вызове с UMH_WAIT_PROC), а не 0 или отрицательный код ошибки, который, как ожидается, будет возвращать функция инициализации. Это может привести к предупреждениям во время выполнения. Что на самом деле возвращает call_usermodehelper(), объясняется здесь.

person Eugene    schedule 06.11.2011

В файле linux/kernel/module.c есть некоторые нестатические функции (но без EXPORT_SYMBOL впереди), такие как module_address_lookup(), но эти функции используют такие вещи, как preempt_disable() и _enable(). Я бы предпочел не использовать эти функции и предложил бы вместо этого использовать sysfs-interface, хотя ваш драйвер уже находится в режиме ядра.

person Community    schedule 21.10.2011
comment
Спасибо за ответ. Да, я знаю про module_address_lookup() и тому подобное. Они используются в системе kallsyms для поиска символов и тому подобного. Но мне нужно другое, адреса разделов модуля (.text, .devinit.text, .exit.text и т.д.), а не символы. Я могу получить адреса начальной и основной областей модуля, но каждая из них может содержать более одного раздела ELF. - person Eugene; 23.10.2011
comment
Из исходного кода загрузчика видно, что к моменту выдачи уведомлений о загрузке информация о разделах только что загруженного модуля доступна только в sysfs. Если я не ошибаюсь, каждый файл в sysfs поддерживается объектом ядра. Если у вас есть идея, как мой модуль может найти такие объекты, соответствующие файлам в /sys/module/<target_name>, это было бы здорово. - person Eugene; 23.10.2011
comment
Я не вижу способа получить эту информацию из ядра, если только вы не измените файл kernel/module.c для экспорта символа или функции. Вы можете попытаться отправить патч с разумным сообщением, почему вы хотите, чтобы это было так. - person ott--; 24.10.2011
comment
Да, модульная штуковина сама по себе этого не позволяет. Я, вероятно, нашел решение, но оно не очень надежно. struct module содержит kobject, соответствующий нужному каталогу в sysfs. Есть экспортированные функции для обхода таких каталогов. Когда вы попадаете в dentry для раздела, можно вызвать метод show() упомянутого объекта kobject для получения содержимого необходимого атрибута в виде строки, которую затем можно проанализировать с помощью функций, подобных strtoul. Это может сработать, но для этого требуются определения из fs/sysfs/sysfs.h, внутреннего заголовочного файла. - person Eugene; 24.10.2011
comment
(продолжение) Я бы предпочел держаться подальше от этого внутреннего API. Может быть, мне сойдет с рук call_usermodehelper материал, создав таким образом процесс пользовательского пространства, заставить его получать данные и передавать их обратно ядру. Вспомогательный API пользовательского режима довольно стабилен и уже используется для многих задач в ядре. Я, вероятно, рассмотрю этот подход. - person Eugene; 24.10.2011