Как писать на защищенные страницы в ядре Linux? - PullRequest
1 голос
/ 23 октября 2019

Я пытаюсь добавить системный вызов в модуль. Мое обоснование:

  1. Это для исследовательского проекта, поэтому точная реализация не имеет значения.
  2. Добавление системных вызовов в ядро ​​ядра занимает слишком много времени для повторной компиляции,Я могу смириться с компиляцией один раз с расширенной таблицей системных вызовов, но не каждый раз. Даже при инкрементной компиляции связывание и архивирование конечного двоичного файла занимает много времени.
  3. Поскольку проект чувствителен к синхронизации, использование kprobes для перехвата обработчика системного вызова приведет к замедлению обработчика системного вызова.

Я все еще открыт для других способов добавления системного вызова, но по вышеуказанным причинам я думаю, что запись в sys_call_table в модуле - это самый чистый способ сделать то, что я пытаюсь сделать.

Я получил адрес таблицы системных вызовов из System.map, отключенный kaslr, и я пытаюсь снять защиту страниц, но некоторая защита от записи все еще удерживает меня.

// following https://web.iiit.ac.in/~arjun.nath/random_notes/modifying_sys_call.html

// clear cr0 write protection
write_cr0 (read_cr0 () & (~ 0x10000));

// clear page write protection
sys_call_table_page = virt_to_page(&sys_call_table[__NR_execves]);
set_pages_rw(sys_call_table_page, 1);

// do write
sys_call_table[__NR_execves] = sys_execves;

Тем не менее, я все еще получаю ошибку разрешения, но я не знаю механизм, с помощью которого она применяется:

[   11.145647] ------------[ cut here ]------------
[   11.148893] CR0 WP bit went missing!?
[   11.151539] WARNING: CPU: 0 PID: 749 at arch/x86/kernel/cpu/common.c:386 native_write_cr0+0x3e/0x70
...
Here was a call trace pointing to the write of sys_call_table
...
[   11.332825] ---[ end trace c20c95651874c08b ]---
[   11.336056] CPA  protect  Rodata RO: 0xffff888002804000 - 0xffff888002804fff PFN 2804 req 8000000000000063 prevent 0000000000000002
[   11.343934] CPA  protect  Rodata RO: 0xffffffff82804000 - 0xffffffff82804fff PFN 2804 req 8000000000000163 prevent 0000000000000002
[   11.351720] BUG: unable to handle page fault for address: ffffffff828040e0
[   11.356418] #PF: supervisor write access in kernel mode
[   11.359908] #PF: error_code(0x0003) - permissions violation
[   11.363665] PGD 3010067 P4D 3010067 PUD 3011063 PMD 31e29063 PTE 8000000002804161
[   11.368701] Oops: 0003 [#1] SMP KASAN PTI

full dmesg

Есть догадки о том, как это отключить?

1 Ответ

0 голосов
/ 24 октября 2019

В ядре есть код для защиты от такого рода действий.

Во-первых, ядро ​​по умолчанию не позволяет удалить защиту от записи из регистра cr0. Он проверяет, что в arch / x86 / kernel / cpu / common.c: native_write_cr0

if (static_branch_likely(&cr_pinning)) {
    if (unlikely((val & X86_CR0_WP) != X86_CR0_WP)) {
        bits_missing = X86_CR0_WP;
        val |= bits_missing;
        goto set_register;
    }
    /* Warn after we've set the missing bits. */
    WARN_ONCE(bits_missing, "CR0 WP bit went missing!?\n");
}

Во-вторых, таблица страниц не позволяет вам установить страницу, которая должна читатьсятолько для чтения-записи. Это делает эту проверку arch / x86 / mm / pageattr.c: static_protections

/* Check the PFN directly */
res = protect_rodata(pfn, pfn + npg - 1);
check_conflict(warnlvl, prot, res, start, end, pfn, "Rodata RO");
forbidden |= res;

Если вы отключите эти две проверки, удалив оба больших двоичных объекта, код для изменения таблицы будет работать.

...