Я хочу добавить новый системный вызов в ядро Linux 3.2.x, но в качестве загружаемого модуля ядра (поскольку я не хочу перекомпилировать ядро снова и снова)
Я прочитал много постов в Интернете, а также в SO, и некоторые места утверждают, что реализация системных вызовов в качестве загружаемых модулей невозможна, в то время как другие говорят, что это возможно.
Что он? Как это сделать, если это возможно?
ioctl()
s для задачи, они легко модульные. Афайк - главная причина, по которой это делается настолько сложно, насколько это возможно, потому что количество системных вызовов является очень жестко закодированной вещью, и никто не хочет хаоса, каким он попадет в картину. Но существует множество интерфейсов ядра для достижения той же функциональности, например, sysfs, ioctls или тому подобное.Ответы:
Это невозможно, потому что таблица системных вызовов (называемых
sys_call_table
) является массивом статического размера. И его размер определяется во время компиляции по количеству зарегистрированных системных вызовов. Это означает, что нет места для другого.Вы можете проверить реализацию, например, для архитектуры x86 в
arch/x86/kernel/syscall_64.c
файле, гдеsys_call_table
это определено. Его размер точно__NR_syscall_max+1
.__NR_syscall_max
определяетсяarch/x86/kernel/asm-offsets_64.c
какsizeof(syscalls) - 1
(это номер последнего системного вызова), гдеsyscall
находится таблица со всеми системными вызовами.Одним из возможных решений является повторное использование некоторого существующего (или устаревшего, если у вашей архитектуры есть, см.,
sys_setaltroot
Например) номер системного вызова с вашим, так как для этого не потребуется больше места в памяти. Некоторые архитектуры также могут иметь дыры в таблице системных вызовов (например, 64-битная версия x86), так что вы также можете использовать это.Вы можете использовать эту технику, если вы разрабатываете новый системный вызов и просто хотите избежать перезагрузки во время экспериментов. Вам нужно будет определить новый системный вызов, найти существующую запись в таблице системных вызовов, а затем заменить ее из вашего модуля.
Делать это из модуля ядра нетривиально, поскольку ядро не экспортирует
sys_call_table
в модули начиная с версии 2.6 (последняя версия ядра, в которой был экспортирован этот символ2.5.41
).Один из способов обойти это - изменить свое ядро, чтобы экспортировать
sys_call_table
символ в модули. Чтобы сделать это, вы должны добавить следующие две строкиkernel/kallsyms.c
( не делайте этого на производственных машинах ):Другой метод заключается в динамическом поиске таблицы системных вызовов. Вы перебираете память ядра, сравнивая каждое слово с указателем на известную функцию системного вызова. Поскольку вы знаете смещение этого известного системного вызова в таблице, вы можете вычислить начальный адрес таблицы.
источник
К сожалению, вы не можете добавлять системные вызовы в ядро как загружаемые модули. Вы должны взять на себя задачу компиляции ядра каждый раз, когда добавляете новый системный вызов.
источник