GNU/Linux >> Znalost Linux >  >> Linux

Proč je v Linuxu potřeba upravovat tabulky systémových volání?

Můžete zkontrolovat, zda jsou pouze pro čtení, vyhledáním symbolů jádra. "R" znamená pouze pro čtení.

$ grep sys_call_table /proc/kallsyms
0000000000000000 R sys_call_table
0000000000000000 R ia32_sys_call_table
0000000000000000 R x32_sys_call_table

Takže jsou pouze pro čtení a jsou od jádra 2.6.16. Nicméně, jádrový rootkit má schopnost učinit je znovu zapisovatelnými. Vše, co potřebuje udělat, je provést funkci jako je tato v režimu jádra (přímo nebo prostřednictvím dostatečně flexibilních ROP gadgetů, kterých je spousta) s každou adresou jako argumentem:

static void set_addr_rw(const unsigned long addr)
{
    unsigned int level;
    pte_t *pte = lookup_address(addr, &level);

    if (pte->pte &~ _PAGE_RW)
        pte->pte |= _PAGE_RW;

    local_flush_tlb();
}

Tím se změní oprávnění tabulky syscall a bude možné ji upravit. Pokud to z jakéhokoli důvodu nefunguje, ochranu proti zápisu v jádře lze globálně deaktivovat pomocí následujícího ASM:

cli
mov %cr0, %eax
and $~0x10000, %eax
mov %eax, %cr0
sti

To deaktivuje přerušení, zakáže bit WP (Write-Protect) v CR0 a znovu povolí přerušení. Použití sestavení to umožňuje fungovat navzdory write_cr0(read_cr0() & ~0x10000) selhání kvůli předdefinované funkci pro zápis do CR0 nyní připíná citlivé bity. Ujistěte se však, že WP poté znovu povolíte!

Proč je tedy označen jako pouze pro čtení, když je tak snadné jej zakázat? Jedním z důvodů je, že existují zranitelnosti, které umožňují upravovat paměť jádra, ale ne nutně přímo spouštět kód. Označením kritických oblastí jádra jako pouze pro čtení je obtížnější je využít bez nalezení dalšího zranitelnost označit stránky jako zapisovatelné (nebo úplně zakázat ochranu proti zápisu). Nyní to neposkytuje příliš silné zabezpečení, takže hlavním důvodem, proč je označeno jako pouze pro čtení, je usnadnit zastavení náhodného přepíše, aby způsobil katastrofální a neopravitelné selhání systému.

* Uvedený konkrétní příklad je pro procesor x86_64. První tabulka je pro systémová volání v nativním 64bitovém režimu (x64). Druhý je pro systémová volání v 32bitovém režimu (IA32). Třetí je pro zřídka používané x32 syscall ABI, které umožňuje programům používat všechny funkce 64bitového režimu (např. SSE místo x87 pro operace s pohyblivou řádovou čárkou) při použití 32bitových ukazatelů a hodnot.

† ​​Interní API jádra se neustále mění, takže tato přesná funkce nemusí fungovat na starších nebo novějších jádrech. Globální deaktivace CR0.WP v ASM je však zaručeno, že bude fungovat na všech x86 systémech bez ohledu na verzi jádra.


Jak poznamenal Forest, moderní Linux to neumožňuje, ale je snadné to přepsat.

Historicky to však bylo užitečné (a možná stále je) z bezpečnostních důvodů:hot-patching proti zranitelnostem. Kdykoli v devadesátých letech a na začátku roku 2000 byla oznámena nová zranitelnost pro systémové volání, které jsem absolutně nepotřeboval (ptrace bylo tehdy opravdu běžné), napsal bych modul jádra, který přepíše adresu funkce v tabulce syscall adresou funkce, která právě provedla return -ENOSYS; . To eliminovalo útočnou plochu, dokud nebylo k dispozici upgradované jádro. U některých pochybných systémových volání, která jsem nepotřeboval a která měla opakovaně zranitelná místa, jsem to pro ně preventivně provedl a modul jsem nechal celou dobu zapnutý.


Linux
  1. Proč mě moje potřeba kontroly přiměla přejít na Linux

  2. Jak zvládnout paniku linuxového jádra

  3. Linux – Proč v systému není přítomen žádný souborový systém Rootfs?

  1. Linux – Proč Linux Utils nepoužívají systémové volání k získání aktuálního času?

  2. Linux – metody vyvolání systémového volání v novém jádru?

  3. Linux – Proč existuje zásada jádra Linuxu, která nikdy nenaruší uživatelský prostor?

  1. Tabulka systémových volání Linux nebo cheatsheet pro shromáždění

  2. Jak odstranit systém Linux?

  3. Proč je Linux podobný Unixu, když je jeho jádro monolitické?