Проблемы с перехватом системных вызовов - PullRequest
3 голосов
/ 27 сентября 2011

Я использую следующий код модуля для перехвата системного вызова (код, зачисляемый кому-то еще, например, Ядро Linux: Пример перехвата системного вызова ).

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/unistd.h>
#include <asm/semaphore.h>
#include <asm/cacheflush.h>

void **sys_call_table;

asmlinkage int (*original_call) (const char*, int, int);

asmlinkage int our_sys_open(const char* file, int flags, int mode)
{
   printk(KERN_ALERT "A file was opened\n");
   return original_call(file, flags, mode);
}

int set_page_rw(long unsigned int _addr)
{
   struct page *pg;
   pgprot_t prot;
   pg = virt_to_page(_addr);
   prot.pgprot = VM_READ | VM_WRITE;
   return change_page_attr(pg, 1, prot);
}

int init_module()
{
    // sys_call_table address in System.map
    sys_call_table = (void*)0xffffffff804a1ba0;
    original_call = sys_call_table[1024];
    set_page_rw(sys_call_table);
    sys_call_table[1024] = our_sys_open;
    return 0;
}

void cleanup_module()
{
   // Restore the original call
   sys_call_table[1024] = original_call;
}

Когда insmod скомпилированный файл .ko, терминал выдает «Killed». При просмотре файла 'cat / proc / modules' я получаю статус загрузки.

my_module 10512 1 - Loading 0xffffffff882e7000 (P)

Как и ожидалось, я не могу rmmod этого модуля, так как он жалуется на его использование. Система перезагружается, чтобы получить статус чистого листа.

Позже, после комментирования двух строк кода в приведенном выше источнике sys_call_table[1024] = our_sys_open; и sys_call_table[1024] = original_call;, он может успешно выполнить insmod. Что еще интереснее, когда раскомментируем эти две строки (возвращаемся к исходному коду), скомпилированный модуль может быть успешно выгружен. Я не совсем понимаю, почему это происходит? И есть ли способ успешно скомпилировать код и напрямую его импортировать?

Я сделал все это на Redhat с ядром Linux 2.6.24.6.

1 Ответ

1 голос
/ 07 ноября 2011

Думаю, вам стоит взглянуть на API kprobes, который хорошо документирован в Documentation / krpobes.txt.Это дает вам возможность установить обработчик на каждый адрес (например, запись системного вызова), чтобы вы могли делать то, что вы хотите.Дополнительным бонусом является то, что ваш код будет более переносимым.

Если вы заинтересованы только в отслеживании этих системных вызовов, вы можете использовать подсистему аудита, кодирующую свой собственный пользовательский демон, который сможет получать события на сокете NETLINK.из аудита kthread.libaudit предоставляет простой API для регистрации / чтения событий.

Если у вас есть веская причина не использовать kprobes / audit, я бы посоветовал вам проверить, что значение, которое вы пытаетесь записать, не вышестраница, которую вы установили для записи.Быстрый расчет показывает, что:

offset_in_sys_call_table * sizeof(*sys_call_table) = 1024 * 8 = 8192

, что составляет две страницы после той, которую вы устанавливаете для записи, если используете страницы 4K.

...