Значение l требуется в качестве левого операнда присваивания - указатель на функцию - PullRequest
0 голосов
/ 31 октября 2019

Я работаю над домашней работой по программированию ядра и классам управления памятью. Мне нужно динамически получить адрес sys_call_table и установить простой хук, который вызывает оригинальный sys_call (в данном случае sys_read) сразу после печати некоторого текста.

Для начала я жестко закодировалsys_call_table адрес, который я получил с помощью grep и /boot/System.map и следовал за некоторыми примерами кода, которые я нашел в Интернете:

  1. https://gajastechnologies.blogspot.com/2016/12/basics-of-making-rootkit-from-syscall.html
  2. https://syprog.blogspot.com/2011/10/hijack-linux-system-calls-part-iii.html

Сообщения предлагают разные варианты адресов sys_call_table, а именно один использует один указатель, а другой - двойной. Однако в обоих случаях я получаю ошибку lvalue required as left operand of assignment для назначения original_read = table[__NR_read];

  • Где моя ошибка? Что-то изменилось для более новых ядер?

  • Вы заметите, что я оставил два метода для отключения защиты памяти только для чтения, оба подходят для более новых 32-битных ядер 5.X?

  • Как можно получить динамическое получение sys_call_table внутри кода, что будет использоваться в качестве ссылки? Я не смог найти информацию об экспортированных sys_calls для более новых версий. Я обнаружил, что sys_close используется часто, но компилятор не распознает его и предлагает вместо него использовать ksys_close.

Код:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/printk.h>
#include <linux/fs.h>
#include <linux/syscalls.h>
#include <linux/kallsyms.h>
#include <linux/compat.h>
#include <asm/uaccess.h>
#include <uapi/asm/unistd.h>

#include <asm/cacheflush.h>
#include <linux/highmem.h>
#include <asm/pgtable_types.h>

#define DISABLE_W_PROTECTED_MEMORY \
    preempt_disable(); \
    barrier(); \
    write_cr0(read_cr0() & (~ 0x00010000));

#define ENABLE_W_PROTECTED_MEMORY \
    write_cr0(read_cr0() | 0x00010000); \
    barrier(); \
    preempt_enable();

MODULE_LICENSE("GPL");

asmlinkage long *original_read(unsigned int fd, char __user *buf, size_t count);
asmlinkage long modified_read(unsigned int fd, char __user *buf, size_t count) {
    pr_info("sys_read\n");
    return original_read(fd, buf, count);
}

void **table = (void *)0xc16e7180;

/*Make page writeable*/

int make_rw(unsigned long address){
    unsigned int level;
    pte_t *pte = lookup_address(address, &level);
    if(pte->pte &~_PAGE_RW){
        pte->pte |=_PAGE_RW;
    }
    return 0;
}

/* Make the page write protected */

int make_ro(unsigned long address){
    unsigned int level;
    pte_t *pte = lookup_address(address, &level);
    pte->pte = pte->pte &~_PAGE_RW;
    return 0;
}

static int __init mod_init(void)
{
    make_rw((unsigned long)table);
    original_read = table[__NR_read];
    table[__NR_read] = modified_read;
    return 0;
}
static void __exit mod_exit(void)
{
    table[__NR_read] = original_read;
    make_ro((unsigned long)table);
}

module_init(mod_init);
module_exit(mod_exit);

РЕДАКТИРОВАТЬ:

Я применил исправление к указателю функции и отредактировал код в соответствии с кодом, представленным ввторая ссылка. Печать из modified_read никогда не появляется в dmesg, несмотря на запуск некоторого примера кода C с read(). Кроме того, если я удаляю макросы для памяти, защищенной от записи (и оставляю make_ro, make_rw), код падает на insmod. Я оставил оба там, для справки. Есть предложения?

#define DISABLE_W_PROTECTED_MEMORY \
    preempt_disable(); \
    barrier(); \
    write_cr0(read_cr0() & (~ 0x00010000));

#define ENABLE_W_PROTECTED_MEMORY \
    write_cr0(read_cr0() | 0x00010000); \
    barrier(); \
    preempt_enable();

asmlinkage long (*original_read)(unsigned int fd, char __user *buf, size_t count);
asmlinkage long modified_read(unsigned int fd, char __user *buf, size_t count) {
    pr_info("sys_read\n");
    return original_read(fd, buf, count);
}

unsigned long *table = (unsigned long*)0xc16e7180;

int make_rw(unsigned long address){
    unsigned int level;
    pte_t *pte = lookup_address(address, &level);
    if(pte->pte &~_PAGE_RW){
        pte->pte |=_PAGE_RW;
    }
    return 0;
}

int make_ro(unsigned long address){
    unsigned int level;
    pte_t *pte = lookup_address(address, &level);
    pte->pte = pte->pte &~_PAGE_RW;
    return 0;
}

static int __init mod_init(void)
{
    DISABLE_W_PROTECTED_MEMORY
    make_rw((unsigned long)table);
    original_read = (void*)*(table + __NR_read);
    *(table + __NR_read) = (unsigned long) modified_read;
    make_ro((unsigned long)table);
    ENABLE_W_PROTECTED_MEMORY
    return 0;
}
static void __exit mod_exit(void)
{
    DISABLE_W_PROTECTED_MEMORY
    make_rw((unsigned long)table);
    *(table + __NR_read) = (unsigned long) original_read;
    make_ro((unsigned long)table);
    ENABLE_W_PROTECTED_MEMORY
}

module_init(mod_init);
module_exit(mod_exit);

1 Ответ

3 голосов
/ 31 октября 2019

original_read - это функция. Вы не можете назначить функцию. Например, вы не можете сделать printf = something;

Кажется, вы подразумевали, что original_read будет указателем на функцию. Чтобы объявить указатель на функцию, вам нужен дополнительный набор скобок:

    asmlinkage long (*original_read)(unsigned int fd, char __user *buf, size_t count);
                    ^              ^
...