Неправильные аргументы примера перехвата системных вызовов - PullRequest
4 голосов
/ 22 января 2020

Я написал пример перехвата системных вызовов из нашего Linux модуля ядра.

Обновлен открытый системный вызов в таблице системных вызовов для использования моей точки входа вместо значения по умолчанию.

#include <linux/module.h>
#include <linux/kallsyms.h>

MODULE_LICENSE("GPL");
char *sym_name = "sys_call_table";

typedef asmlinkage long (*sys_call_ptr_t)(const struct pt_regs *);
static sys_call_ptr_t *sys_call_table;
typedef asmlinkage long (*custom_open) (const char __user *filename, int flags, umode_t mode);


custom_open old_open;

static asmlinkage long my_open(const char __user *filename, int flags, umode_t mode)
{
    char user_msg[256];
    pr_info("%s\n",__func__);
    memset(user_msg, 0, sizeof(user_msg));
    long copied = strncpy_from_user(user_msg, filename, sizeof(user_msg));
    pr_info("copied:%ld\n", copied);
    pr_info("%s\n",user_msg);

    return old_open(filename, flags, mode);
}



static int __init hello_init(void)
{
    sys_call_table = (sys_call_ptr_t *)kallsyms_lookup_name(sym_name);
    old_open = (custom_open)sys_call_table[__NR_open];
    // Temporarily disable write protection
    write_cr0(read_cr0() & (~0x10000));
    sys_call_table[__NR_open] = (sys_call_ptr_t)my_open;
    // Re-enable write protection
    write_cr0(read_cr0() | 0x10000);

    return 0;
}

static void __exit hello_exit(void)
{
    // Temporarily disable write protection
    write_cr0(read_cr0() & (~0x10000));
    sys_call_table[__NR_open] = (sys_call_ptr_t)old_open;
    // Re-enable write protection
    write_cr0(read_cr0() | 0x10000);

}

module_init(hello_init);
module_exit(hello_exit);

Я написал простую пользовательскую программу для проверки.

#define _GNU_SOURCE
#include <sys/syscall.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
    int fd = syscall(__NR_open, "hello.txt", O_RDWR|O_CREAT, 0777);

    exit(EXIT_SUCCESS);
}

Файл создается в моей папке, но происходит сбой strncpy_user с неверным адресом

[  927.415905] my_open
[  927.415906] copied:-14

В чем ошибка в приведенном выше коде

Ответы [ 2 ]

3 голосов
/ 22 января 2020

OP, вероятно, использует ядро ​​/ архитектуру, которая использует «оболочки системных вызовов», где таблица системных вызовов содержит функцию-оболочку, которая вызывает настоящую функцию системного вызова (возможно, как встроенный вызов функции). В архитектуре x86_64 используются оболочки syscall начиная с версии ядра 4.17.

Для x86_64 в ядре 4.17 или новее sys_call_table[__NR_open] указывает на __x64_sys_open (с прототипом asmlinkage long __x64_sys_open(const struct pt_regs *regs)), что вызывает static function __se_sys_open (с прототипом static long __se_sys_open(const __user *filename, int flags, umode_t mode)), который вызывает встроенную функцию __do_sys_open (с прототипом static inline long __do_sys_open(const __user *filename, int flags, umode_t mode). Все они будут определены макро вызовом SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode) в "fs / open. c" и теле функции, которое следует за вызовом макроса.

SYSCALL_DEFINE3 определен в «include / linux / syscalls.h» и использует макрос SYSCALL_DEFINEx в том же файле, который использует макрос __SYSCALL_DEFINEx. Поскольку x86_64 определяет CONFIG_ARCH_HAS_SYSCALL_WRAPPER, макрос __SYSCALL_DEFINEx определяется как #include <asm/syscall_wrapper.h>, который отображается в "arch / x86 / include / asm / syscall_wrapper.h".


Информацию об этом изменении см.

Кажется, мотивация - передать указатель только на pt_regs, instea d наличие множества значений пространства пользователя в регистрах по цепочке вызовов. (Возможно, чтобы повысить устойчивость к атакам Призраков, сделав гаджеты менее полезными?)


Почему open все еще работает, хотя оболочка не :

Если OP действительно использует ядро ​​x86_64 4.17 или новее и заменяет запись sys_call_table[__NR_open] указателем на функцию, которая использует другой прототип и вызывает исходную функцию (на которую указывает old_open) с теми же параметрами, что объясняет почему не удалось дозвониться до strncpy_from_user(user_msg, filename, sizeof(user_msg)) Хотя объявленный как const char * __user filename, указатель filename фактически указывает на исходный struct pt_regs в пространстве ядра.

При последующем вызове old_open(filename, flags, mode) первый параметр filename все еще указывает на исходный struct pt_regs, поэтому старая функция (которая ожидает один параметр типа struct pt_regs *) по-прежнему работает, как и ожидалось.

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

1 голос
/ 25 января 2020

Обновление : ниже приведен рабочий код, спасибо всем за предоставленные входные данные

    #include <linux/module.h>
    #include <linux/kallsyms.h>

    MODULE_LICENSE("GPL");
    char *sym_name = "sys_call_table";

    typedef asmlinkage long (*sys_call_ptr_t)(const struct pt_regs *);
    static sys_call_ptr_t *sys_call_table;


    sys_call_ptr_t old_open;

    static asmlinkage long my_open(const struct pt_regs *regs)
    {
        char __user *filename = (char *)regs->di;
            char user_filename[256] = {0};
        long copied = strncpy_from_user(user_filename, filename, sizeof(user_filename));
        if (copied > 0)
            pr_info("%s filename:%s\n",__func__, user_filename);
        return old_open(regs);
    }



    static int __init hello_init(void)
    {
        sys_call_table = (sys_call_ptr_t *)kallsyms_lookup_name(sym_name);
        old_open = sys_call_table[__NR_open];
        // Temporarily disable write protection
        write_cr0(read_cr0() & (~0x10000));
        sys_call_table[__NR_open] = my_open;
        // Re-enable write protection
        write_cr0(read_cr0() | 0x10000);

        return 0;
    }

    static void __exit hello_exit(void)
    {
        // Temporarily disable write protection
        write_cr0(read_cr0() & (~0x10000));
        sys_call_table[__NR_open] = old_open;
        // Re-enable write protection
        write_cr0(read_cr0() | 0x10000);

    }

    module_init(hello_init);
    module_exit(hello_exit);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...