Linux Kernel NX Support
たまにはLinux Kernelの話も書こうということで昨日もちょっとふれた、NXサポートのお話。NXというのはLinuxのページに実行不可の属性を付ける機能だ。なんでそんな機能が必要かというと最近問題になっているワームとかウイルスみたいな外部からの悪意を持って送り込まれるコードの実行を防止できる場合があるからだ。
バッファーオーバフローの脆弱性を利用した攻撃の場合、悪意のあるコードは例えばスタック領域あたりにおかれるのだけれど、スタック領域を実行不可にできれば、ウイルスないしワームのコードは実行できなくなる。と、そーゆー話である。
Intelの32ビットアーキテクチャ(よくX86とか、IA32とかよばれるやつ)はあるページが実行可能かどうかを示すフラグがなかったのだけれど、IA32Eとよばれる64ビット拡張のアーキテクチャから実行不可のフラグが追加された。(XD -- eXecution Disable) IA32Eより先にAMD64で導入されたらしい。
それようのパッチが
http://people.redhat.com/mingo/nx-patches/nx-2.6.7-rc2-bk2-AE
にあるのでちょっと読んでみる。
--- linux/include/asm-i386/pgtable.h.orig +++ linux/include/asm-i386/pgtable.h @@ -110,6 +110,7 @@ void paging_init(void); #define _PAGE_BIT_UNUSED1 9 /* available for programmer */ #define _PAGE_BIT_UNUSED2 10 #define _PAGE_BIT_UNUSED3 11 +#define _PAGE_BIT_NX 63 #define _PAGE_PRESENT 0x001 #define _PAGE_RW 0x002 @@ -126,28 +127,51 @@ void paging_init(void); #define _PAGE_FILE 0x040 /* set:pagecache unset:swap */ #define _PAGE_PROTNONE 0x080 /* If not present */ +#ifdef CONFIG_X86_PAE +#define _PAGE_NX (1ULL<<_PAGE_BIT_NX) +#else +#define _PAGE_NX 0 +#endif
NXのビットが63ビット目(#define _PAGE_BIT_NX 63)だということが分かる。
_PAGE_NXが1だと実行不可である。ページテーブルの属性に_PAGE_NXが立っていると実行できない。
--- linux/arch/i386/mm/fault.c.orig +++ linux/arch/i386/mm/fault.c @@ -406,6 +406,21 @@ no_context: bust_spinlocks(1); +#ifdef CONFIG_X86_PAE + { + pgd_t *pgd; + pmd_t *pmd; + + + + pgd = init_mm.pgd + pgd_index(address); + if (pgd_present(*pgd)) { + pmd = pmd_offset(pgd, address); + if (pmd_val(*pmd) & _PAGE_NX) + printk(KERN_CRIT "kernel tried to access NX-protected page - exploit attempt? (uid: %d)\n", current->uid); + } + } +#endif
ここでpgdはページグローバルディレクトリ、pmdはページミドルディレクトリであるページにアクセスする時に利用する。そのページに_PAGE_NXフラグが立っているとKERN_CRITというカーネルエラーを出す。
Linuxカーネルの詳細に関しては詳解LINUXカーネル(第二版)ISBN:4873111331。ページテーブルの話は64ページあたりに載っている。
プログラムのコードをそのまま表示するにはどうしたらいいのでしょう>教えてはてなダイアリー