Подтвердить что ты не робот

Переопределение функциональности модулей в ядре Linux

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

Я могу (сравнительно) сделать это прямо в ядре, просто бросив свой код в соответствующие функции, но мне было интересно, знает ли кто-нибудь немного C-магии, которая не обязательно является ужасной практикой кодирования ядра (или C), которая может достичь того же результата.

Мысли о #defines и typedefs приходят на ум, но я не могу его взломать в голове.

Вкратце: кто-нибудь знает способ эффективного переопределения функций в ядре Linux (из модуля)?

EDIT: поскольку мне было предложено, я действительно хочу записать определенные функции (создание/удаление каталогов и т.д.) изнутри ядра, но для здравого смысла загружаемый модуль, похоже, имеет смысл, вместо того, чтобы писать большой патч к коду ядра и перекомпилировать при каждом изменении. Минимальное количество добавленного кода для ядра в порядке, но я хочу разгрузить большую часть работы в модуль.

4b9b3361

Ответ 1

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

Ответ 2

Вероятно, вы захотите подключить системные вызовы (PDF-ссылку), что позволит вам эффективно регистрировать пользовательские процессы, вызывающие функции ядра. Если вы действительно хотите, чтобы ядро ​​использовало функции ядра, вы хотите посмотреть в трассировку функций ядра.

Ответ 3

Я не совсем уверен, что понимаю, что вы хотите сделать, но я думаю, что ksplice может быть хорошим решением. Он все еще находится в стадии разработки, поэтому я не знаю, находится ли он в каком-либо удобном для использования состоянии.

Ответ 4

Вы рассматривали развертывание своей функции с помощью LD_PRELOAD?

Ваша функция будет развернута через общую библиотеку lib, которая будет жить в каталоге, указанном переменной окружения LD_PRELOAD.

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

Может быть, взгляните на статью " Создавать библиотечные библиотеки для удовольствия и прибыли". Хотя он и является специфичным для Solaris, он также применим к Linux.

BTW Таким образом, большинство инструментов анализа памяти, например, Очистите, работайте.

Ответ 5

В ядре была проделана большая работа, чтобы убедиться, что этого не происходит, особенно для того, чтобы не подвергать таблицу syscall модулям. Единственным поддерживаемым механизмом для доступа к файлу является LSM, но он ориентирован на безопасность и имеет неопределенный будущее. Здесь - это PDF-документ, который документирует API, но может быть не последним.

inotify - намного лучший способ контролировать создание, удаление и изменение файлов, чем пытаться подорвать функции syscall ядра, но он работает из пользовательского пространства.

Цитата из Википедии (http://en.wikipedia.org/wiki/Inotify): Некоторые из событий, за которыми можно отслеживать, следующие:

* IN_ACCESS - read of the file
* IN_MODIFY - last modification
* IN_ATTRIB - attributes of file change
* IN_OPEN and IN_CLOSE - open or close of file
* IN_MOVED_FROM and IN_MOVED_TO - when the file is moved or renamed
* IN_DELETE - a file/directory deleted
* IN_CREATE - a file/directory created
* IN_DELETE_SELF - file monitored is deleted

inotify существует в ядре с 2.6.13, его предшественник dnotify (http://en.wikipedia.org/wiki/Dnotify).

Ответ 6

Я думаю, вы можете использовать audit для этого

Ответ 7

Это может оказаться полезным для вас.

В принципе, поскольку таблица системных вызовов напрямую не экспортируется в новые ядра, вам необходимо выполнить поиск, чтобы определить его местоположение самостоятельно. Затем вы можете перехватить свои системные вызовы выбора и манипулировать ими. Однако замена других функций ядра будет намного сложнее, если некоторые из них не будут организованы так же, как системные вызовы (они появляются в какой-либо таблице диспетчеризации и т.д.), Что совсем не является общим.

Ответ 8

Большая часть работы с файловой системой уже выполняется в модулях, предполагая, что код файловой системы был построен как модуль, а не встроен в ядро ​​(что означает, что "реальный" ответ зависит от вариантов сборки ядра).

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

Если эти предположения неверны или не могут быть правдоподобными, тогда ситуация становится более сложной, и я действительно не мог бы указать вам гораздо дальше.

Ответ 9

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

Также вполне возможно, что кто-то еще уже сделал работу над добавлением для вас крючков.

Ответ 10

Вы не хотите изменять существующие системные вызовы, вы хотите их использовать. Это то, что для SystemTap. Если вы действительно хотите сделать это сложным способом и перехватить системные вызовы, закодировав свой собственный модуль, я предлагаю вам прочитать некоторую руткитовую литературу, но у меня нет никакой ссылки (хотя phrack приходит на ум).

Ответ 12

В соответствии с KernelTrap.org вы можете сделать простой патч и перекомпилировать ядро ​​для экспорта переменной sys_call_table:

// add the following in the file arch/i386/kernel/i386_ksyms.c
extern void* sys_call_table[];
EXPORT_SYMBOL(sys_call_table);

Затем просто следуйте эту процедуру для замены системных вызовов в Руководстве по программированию модуля ядра Linux:

Исходный код здесь является примером такой модуль ядра. Мы хотим "шпионить", для определенного пользователя и printk() a когда пользователь открывает файл. С этой целью мы заменяем системный вызов для открытия файла с помощью нашего собственной функции, называемой our_sys_open. Эта функция проверяет uid (пользовательский id) текущего процесса, и если он равен uid, на который мы следим, это вызывает printk(), чтобы отобразить имя файл, который нужно открыть. Затем либо путь, он вызывает оригинал open()функции с теми же параметрами, чтобы фактически открыть файл.

Функция init_module заменяет соответствующее местоположение в sys_call_tableи сохраняет исходный указатель в переменная. Функция cleanup_moduleиспользует эту переменную для восстановления все возвращается к норме. Эта подход опасен из-за возможность использования двух модулей ядра изменение одного и того же системного вызова. Представить у нас есть два модуля ядра: A и B. Системный вызов <<28 > будет A_openи B будет B_open. Теперь, когда A вставляется в ядро, система вызов заменяется на A_open, что будет вызывать оригинал sys_open, когда это было сделано. Затем B вставляется в ядро, которое заменяет систему звоните с помощью B_open, который вызовет он считает исходным системным вызовом, A_open, когда это будет сделано.

Ответ 13

Если разделяемые библиотеки вызывают системный вызов, вы собираетесь создать модуль, который изменяет этот вызов sysltem. Для получения дополнительной информации об изменении системных вызовов вы можете посмотреть здесь http://www.xml.com/ldd/chapter/book/ есть что-то там в том, как они меняют то, что вызывает система open(). Пример здесь http://tldp.org/LDP/lkmpg/x931.html