функция обмена в таблице системных вызовов в x86

Я пытаюсь переопределить системный вызов для sys_open и отслеживать с его помощью поведение пользователя. Я использую ядро ​​Linux 4.13.0-041300. Это мой код до сих пор

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/syscalls.h>

MODULE_LICENSE ("GPL");

//this is where the original sys_open call position will be saved
asmlinkage long (*original_open)(const char __user *filename, int flags, umode_t mode);

unsigned long **sys_call_table;
//this is to track how often my replaced function was called...
static int zeug = 0;

//this is my open function that i want to be replaced in the sys_call_table
asmlinkage long replaced_open(const char __user *filename, int flags, umode_t mode)
{
    printk ("replaced wurde aufgerufen...\n");
    zeug++;
    return original_open(filename, flags, mode);
}

static void enable_page_protection(void)
{
    unsigned long value;
    asm volatile("mov %%cr0, %0" : "=r" (value));

    if((value & 0x00010000))
        return;

    asm volatile("mov %0, %%cr0" : : "r" (value | 0x00010000));
}

static void disable_page_protection(void)
{
    unsigned long value;
    asm volatile("mov %%cr0, %0" : "=r" (value));

    if(!(value & 0x00010000))
        return;

    asm volatile("mov %0, %%cr0" : : "r" (value & ~0x00010000));
}

//the function to get the system_call_table
static unsigned long **aquire_sys_call_table(void)
{
    unsigned long int offset = PAGE_OFFSET;
    unsigned long **sct;

    while (offset < ULLONG_MAX) {
        sct = (unsigned long **)offset;

        if (sct[__NR_close] == (unsigned long *) sys_close)
            return sct;

        offset += sizeof(void *);
    }

    return NULL;
}

static int __init minit (void)
{
    printk ("minit: startet...\n");

    if(!(sys_call_table = aquire_sys_call_table()))
            return -1;

    printk ("minit: sys_call_table ersetzt...\n");

    disable_page_protection(); 
    {
        //here i print the function name of the current function in sys_call_table
        printk ("minit: eintrag vor ersetzen:%pF\n", sys_call_table[__NR_open]);

        //here i store the real sys_open function and change to my func
        original_open =(void * )xchg(&sys_call_table[__NR_open],(unsigned long *)replaced_open);

}
    enable_page_protection();
    return 0;
}

static void mexit (void)
{
    printk ("mexit gestartet.\n");
    printk ("Open was called %d times...\n",zeug);
    if(!sys_call_table) return;

    //here i print the stored function again
    printk ("bei exit:%pF\n", sys_call_table[__NR_open]);

    disable_page_protection();
    {
            //change back to original sys_open function
            xchg(&sys_call_table[__NR_open], (unsigned long *)original_open);
    }
    printk ("nach zurücksetzen:%pF\n", sys_call_table[__NR_open]);
    enable_page_protection();
}

module_init(minit);
module_exit(mexit);

Мой план: после вставки этого модуля в ядро ​​каждый системный вызов sys_open будет «перенаправляться» на мою функцию replace_open. Эта функция подсчитает свои вызовы, а затем вызовет исходную открытую функцию.

После rmmod моего модуля снова будет использован исходный файл system_call open.

Вроде замена работает. Итак, после insmmmod я получаю результат replace_open+0x0/0x40 [kroot]. Это означает, что исходная функция sys_open была заменена на мою replace_open, верно? и после удаления моего модуля я получаю сообщение SyS_open+0x0/0x20.

Так вроде замена работает.

Моя проблема: я не вижу никаких печатных сообщений из моей функции replace_open. Также кажется, что подсчет не работает.

Такое ощущение, что функция не была заменена должным образом.

У вас есть помощь для меня?


person Levin S    schedule 23.02.2019    source источник
comment
Вероятно, вам следует изучить возможность использования перехватчиков модуля безопасности Linux. Он был разработан именно для этого, хотя и в целях безопасности, таких как добавление дополнительных проверок к системным вызовам, которые делает SELinux. Еще одна вещь, которую вам нужно решить: системные вызовы ядра должны быть многопоточными. Ваш приращение zeug++; не является атомарным - это фактически считанное значение, добавьте 1 к значению, сохраните значение. Это просто приведет к неправильному подсчету в вашем коде, но для чего-то критичного, например, подсчета ссылок inode, это может вызвать серьезные проблемы.   -  person Andrew Henle    schedule 23.02.2019
comment
Вы успешно нашли таблицу системных вызовов? Это кажется наиболее вероятным провалом. Вы смотрели на этот вопрос: stackoverflow.com/questions/39502198/   -  person Nick ODell    schedule 23.02.2019
comment
Возможно, вам следует перепроверить, действительно ли вы нашли таблицу системных вызовов, например, проверив sys_close и sys_fork или тому подобное.   -  person Ctx    schedule 23.02.2019
comment
когда я запускаю printk (bei exit:%pF\n, sys_call_table[__NR_open]), я получаю в результате SyS_open+0x0/0x20. так должно быть правильно я думаю. Я получаю тот же результат, когда запускаю это, прежде чем что-либо менять.   -  person Levin S    schedule 23.02.2019
comment
sys_fork и sys_open и так далее неизвестны. я могу проверить SCT только с помощью sys_close.   -  person Levin S    schedule 23.02.2019
comment
Ваш код работает у меня здесь, должен быть ваш sct, чтобы найти неправильный, вы можете напечатать адрес указателя sct, сравнить с правильным sys_call_table на ядре. Можете ли вы использовать kallsyms_lookup_name(sys_call_table)?   -  person ccxxshow    schedule 25.02.2019