GNU/Linux >> Znalost Linux >  >> Linux

Zakažte nezarovnané přístupy k paměti na x86/x86_64

GCC i Clang mají vestavěný UndefinedBehaviorSanitizer. Jedna z těchto kontrol, alignment , lze povolit pomocí -fsanitize=alignment . Vyšle kód pro kontrolu zarovnání ukazatele za běhu a přeruší se, pokud jsou nezarovnané ukazatele dereferencovány.

Viz online dokumentaci na adrese:

  • https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html

Je to složité a osobně jsem to nedělal, ale myslím, že to můžete udělat následujícím způsobem:

CPU x86_64 (konkrétně jsem zkontroloval Intel Corei7, ale myslím, že i ostatní) mají čítač výkonu MISALIGN_MEM_REF, který počítá nesprávně zarovnané reference paměti.

Nejprve tedy můžete spustit svůj program a použít nástroj „perf“ pod Linuxem, abyste získali počet chybných přístupů, které váš kód provedl.

Ošemetnějším a zajímavějším hackem by bylo napsat modul jádra, který naprogramuje čítač výkonu tak, aby generoval přerušení při přetečení a přiměl ho k přetečení prvního nezarovnaného načtení/úložiště. Odpovězte na toto přerušení v modulu jádra, ale odešlete signál vašemu procesu.

To ve skutečnosti změní x86_64 na jádro, které nepodporuje nezarovnaný přístup.

To však nebude jednoduché – kromě vašeho kódu používají systémové knihovny také nezarovnané přístupy, takže bude složité je oddělit od vašeho vlastního kódu.


Právě jsem četl otázku Způsobuje nezarovnaný přístup k paměti vždy chyby sběrnice? který odkazoval na článek Segmentation Fault na Wikipedii.

V článku je nádherná připomínka poměrně neobvyklých příznaků AC procesorů Intel aka Alignment Check.

A zde je návod, jak to povolit (z Wikipedia's Bus Error, s opravenou chybou clobber red-zone pro x86-64 System V, takže je to bezpečné na Linuxu a MacOS a převedeno z Basic asm, což není nikdy dobrý nápad uvnitř funkcí:chcete, aby byly změny AC objednány pomocí přístupů do paměti.

#if defined(__GNUC__)
# if defined(__i386__)
    /* Enable Alignment Checking on x86 */
    __asm__("pushf\n orl $0x40000,(%%esp)\n popf" ::: "memory");
# elif defined(__x86_64__) 
     /* Enable Alignment Checking on x86_64 */
    __asm__("add $-128, %%rsp \n"    // skip past the red-zone, in case there is one and the compiler has local vars there.
            "pushf\n"
            "orl $0x40000,(%%rsp)\n"
            "popf \n"
            "sub $-128, %%rsp"       // and restore the stack pointer.
           ::: "memory");       // ordered wrt. other mem access
# endif
#endif

Po povolení to funguje podobně jako nastavení zarovnání ARM v /proc/cpu/alignment , viz odpověď Jak zachytit nezarovnaný přístup k paměti? pro příklady.

Pokud navíc používáte GCC, doporučuji povolit -Wcast-align varování. Při sestavování pro cíl s přísnými požadavky na zarovnání (například ARM) bude GCC hlásit umístění, která mohou vést k nezarovnanému přístupu k paměti.

Všimněte si však, že ručně psaný asm libc pro memcpy a další funkce bude stále provádět nezarovnané přístupy, takže nastavení AC často není praktické na x86 (včetně x86-64). GCC někdy vysílá asm, který umožňuje nezarovnané přístupy, i když to váš zdroj nedělá, např. jako optimalizace pro kopírování nebo nulování dvou sousedních prvků pole nebo členů struktury najednou.


Linux
  1. Jak vymazat mezipaměť v Linuxu

  2. Měření využití Ram programu?

  3. Proč se telefonní čísla systému Linux v x86 a x86_64 liší?

  1. Linux Out-of-Memory Killer

  2. Monitorování a správa paměti

  3. Diagnostika nedostatku paměti Windows

  1. Jak zachytit nezarovnaný přístup k paměti?

  2. Jak přidělit paměť, která je zarovnána podle velikosti stránky?

  3. Jenkins aktivní (opuštěno)