Энциклопедия разработчика модулей ядра Linux | страница 28
Функция init_module меняет соответствующее место в sys_call_table и сохраняет первоначальный указатель в переменной. Функция cleanup_module использует эту переменную, чтобы восстановить все назад к норме. Этот подход опасен, из-за возможности существования двух модулей, меняющих один и тот же системный вызов. Вообразите, что мы имеем два модуля, А и B. Системный вызов open модуля А назовем A_open и такой же вызов модуля B назовем B_open. Теперь, когда вставленный в ядро системный вызов заменен на A_open, который вызовет оригинал sys_open, когда сделает все, что ему нужно. Затем, B будет вставлен в ядро, и заменит системный вызов на B_open, который вызовет то, что как он думает, является первоначальным системным вызовом, а на самом деле является A_open.
Теперь, если B удален первым, все будет хорошо: это просто восстановит системный вызов на A_open, который вызывает оригинал. Однако, если удален А, и затем удален B, система разрушится. Удаление А восстановит системный вызов к оригиналу, sys_open, вырезая B из цикла. Затем, когда B удален, он восстановит системный вызов к тому, что он считает оригиналом, На самом деле вызов будет направлен на A_open, который больше не в памяти. На первый взгляд кажется, что мы могли бы решать эту специфическую проблему, проверяя, если системный вызов равен нашей функции open и если так, не менять значение этого вызова (так, чтобы B не изменил системный вызов, когда удаляется), но это вызовет еще худшую проблему. Когда А удаляется, он видит, что системный вызов был изменен на B_open так, чтобы он больше не указывал на A_open, так что он не будет восстанавливать указатель на sys_open прежде, чем будет удалено из памяти. К сожалению, B_open будет все еще пробовать вызывать A_open, который больше не в памяти, так что даже без удаления B система все равно рухнет.
Я вижу два способа предотвратить эту проблему. Первое: восстановить обращение к первоначальному значению sys_open. К сожалению, sys_open не является частью таблицы ядра системы в /proc/ksyms, так что мы не можем обращаться к нему. Другое решение состоит в том, чтобы использовать счетчик ссылки, чтобы предотвратить выгрузку модуля. Это хорошо для обычных модулей, но плохо для «образовательных» модулей.
>/* syscall.c
>*
>* System call "stealing" sample
>*/
>/* Copyright (C) 1998-99 by Ori Pomerantz */
>/* The necessary header files */
>/* Standard in kernel modules */
>#include