Переопределение функциональности с помощью модулей в ядре Linux - PullRequest
20 голосов
/ 14 ноября 2008

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

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

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

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

РЕДАКТИРОВАТЬ: Так как это было задано, я, по сути, хочу регистрировать определенные функции (создание / удаление каталогов и т. Д.) изнутри ядра , но для здравомыслия, загружаемый модуль, кажется, имеет смысл вместо того, чтобы писать большой патч для кода ядра и перекомпилировать при каждом изменении. Минимальное количество добавляемого кода в ядро ​​это нормально, но я хочу перенести большую часть работы в модуль.

Ответы [ 13 ]

6 голосов
/ 10 ноября 2011

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

4 голосов
/ 14 ноября 2008

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

3 голосов
/ 29 июля 2009

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

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

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

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

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

3 голосов
/ 14 ноября 2008

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

1 голос
/ 05 ноября 2009

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

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

1 голос
/ 19 ноября 2008

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

1 голос
/ 17 ноября 2008

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

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

Цитируется из Википедии (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).

0 голосов
/ 10 сентября 2015

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

0 голосов
/ 05 ноября 2009

Согласно 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. open системный вызов A будет A_open и B будет B_open. Теперь, когда А вставил в ядро ​​систему вызов заменяется на A_open, который вызовет оригинал sys_open, когда это сделано. Затем B вставляется в ядро, которое заменяет систему позвонить с B_open, который будет называть то, что он думает, что это оригинальный системный вызов, A_open, когда это будет сделано.

0 голосов
/ 11 декабря 2008
...