Как правильно извлечь строку из указателя пространства пользователя в пространстве ядра? - PullRequest
2 голосов
/ 16 января 2020

Я написал ловушку для системного вызова execve и в начале, когда писал ее для печати "hi", каждый раз, когда выполняется файл. Это работало нормально, но когда я попытался напечатать filename, который передается системному вызову, это привело к взлому sh и, конечно, мне пришлось перезагрузить компьютер.

Это мой код:

static asmlinkage long our_execl(const char __user * filename,
            const char __user * const __user * argv,
            const char __user * const __user * envp) {
    printk("%s\n",filename);
    return original_execl(filename, argv, envp);
}

Вот как я внедряю новый системный вызов:

static int lkm_example_init(void)
{

    printk("new new new 2");

    write_cr0(read_cr0()&(~ 0x10000));

    sys_call_table = (void*)0xdd8c4240//the syscall address from the   /proc/kallsyms ;

    execl= sys_call_table[__NR_execve];
    sys_call_table[__NR_execve]=our_execl;

    write_cr0(read_cr0() | 0X10000);
    return 0;
}

Ответы [ 2 ]

5 голосов
/ 16 января 2020

Скорее всего, здесь происходит то, что SMAP ( Предотвращение доступа в режиме супервизора ) препятствует доступу ядра к необработанному указателю пространства пользователя, вызывая пани c.

. правильный способ доступа к строке из пространства пользователя - сначала скопировать ее содержимое, используя strncpy_from_user(). Кроме того, будьте осторожны и убедитесь, что строка правильно завершена.

static asmlinkage long our_execl(const char __user * filename,
            const char __user * const __user * argv,
            const char __user * const __user * envp) {
    char buf[256];
    buf[255] = '\0';

    long res = strncpy_from_user(buf, filename, 255);
    if (res > 0)
        printk("%s\n", buf);

    return original_execl(filename, argv, envp);
}

В этом случае, поскольку мы конкретно говорим о имени файла, вы можете использовать getname() и putname() функций, которые работают с использованием struct filename.

static asmlinkage long our_execl(const char __user * filename,
            const char __user * const __user * argv,
            const char __user * const __user * envp) {

    struct filename *fname = getname(filename);
    if (!IS_ERR(fname)) {
        printk("%s\n", fname->name);
        putname(fname);
    }

    return original_execl(filename, argv, envp);
}
3 голосов
/ 16 января 2020

Просто в дополнение к ответу Марко.
Если что-то идет не так, вы всегда можете посмотреть, как это уже реализовано. К счастью, источники открыты, и любой может получить к ним доступ.

В частности, здесь вы хотите использовать некоторую «строку» (указатель на char) в обработчике syscall, который поступает из пользовательского режима. Таким образом, вы можете взглянуть на то, как обрабатываются такие строки в реальных системных вызовах. Например, do_execve() для execve системного вызова:

SYSCALL_DEFINE3(execve,
        const char __user *, filename,
        const char __user *const __user *, argv,
        const char __user *const __user *, envp)
{
    return do_execve(getname(filename), argv, envp);
}

принимает filename, возвращенное функцией getname(), которая в конечном итоге вызывает strncpy_from_user():

struct filename *
getname_flags(const char __user *filename, int flags, int *empty)
{

    //...
    len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX);
    if (unlikely(len < 0)) {
        __putname(result);
        return ERR_PTR(len);
    }
    //...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...