- 追加された行はこの色です。
- 削除された行はこの色です。
* Linux カーネル 0 day exploit 祭り [#y36aa1a1]
[ http://slashdot.jp/linux/article.pl?sid=09/07/22/0121226 Linux カーネルの zero-day exploit コード、リリースされる] (slashdot Japan)
要するに,注意が足りないコードに gcc の最適化が重なって生じた穴だそうである.
** 注意が足りない [#cac72dc8]
問題のコード.
http://mirror.celinuxforum.org/gitstat/commit-detail.php?commit=33dccbb050bbe35b88ca8cf1228dcf3e4d4b3554
static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
{
struct tun_file *tfile = file->private_data;
struct tun_struct *tun = __tun_get(tfile);
+ struct sock *sk = tun->sk;
+ unsigned int mask = 0;
if (!tun)
return POLLERR;
ポインタが NULL かどうかチェックする前にそのポインタの指し示す構造体のメンバにアクセスしてしまっている.
** gcc の最適化 [#db282de9]
上記のソースであるが,
- tun == NULL であるならば *sk = tun->sk で Segmentation fault が生じ,if 文のところまで到達しない
- tun != NULL ならば if (!tun) の中身は実行されない
ということで,gcc の最適化で if 文全体が削られてしまうそうなのである.
exploit では,ここで 0x00000000 に mmap() でメモリを割り当ててこの例外の起きる条件を変えて…ということらしい.
** 手元の環境では [#r68d6dc3]
試しに似たようなコードを書いてみた.
$ cat exploit.c
struct hoge {
int a, b, c, d;
};
int foo ( struct hoge *h )
{
int x = h->b;
if ( !h )
return 0;
return x;
}
gcc のバージョンはこんな感じ.
$ gcc --version
gcc (Debian 4.3.3-13) 4.3.3
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
コンパイルして,オブジェクトファイルをディスアセンブル.
$ gcc -O0 -c exploit.c
$ objdump -d exploit.o | sed 's/^/ /'
exploit.o: file format elf32-i386
Disassembly of section .text:
00000000 <foo>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 14 sub $0x14,%esp
6: 8b 45 08 mov 0x8(%ebp),%eax
9: 8b 40 04 mov 0x4(%eax),%eax
c: 89 45 fc mov %eax,-0x4(%ebp)
f: 83 7d 08 00 cmpl $0x0,0x8(%ebp)
13: 75 09 jne 1e <foo+0x1e>
15: c7 45 ec 00 00 00 00 movl $0x0,-0x14(%ebp)
1c: eb 06 jmp 24 <foo+0x24>
1e: 8b 45 fc mov -0x4(%ebp),%eax
21: 89 45 ec mov %eax,-0x14(%ebp)
24: 8b 45 ec mov -0x14(%ebp),%eax
27: c9 leave
28: c3 ret
if 文相当の 0 との比較は残っている.
最適化オプションを付けてコンパイル,ディスアセンブル.
$ gcc -O2 -c exploit.c
$ objdump -d exploit.o
exploit.o: file format elf32-i386
Disassembly of section .text:
00000000 <foo>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 8b 45 08 mov 0x8(%ebp),%eax
6: 5d pop %ebp
7: 8b 40 04 mov 0x4(%eax),%eax
a: c3 ret
if 文部分がざっくり消えてしまっている.
** ARM では [#i309efe8]
ARM のクロスコンパイラで試してみた.
$ arm-linux-gnueabi-gcc --version
arm-linux-gnueabi-gcc (GCC) 4.2.4 (Debian 4.2.4-6)
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
最適化オプション付きでコンパイル,ディスアセンブル.
$ arm-linux-gnueabi-gcc -O2 -c exploit.c
$ arm-linux-gnueabi-objdump -d exploit.o | sed 's/^/ /'
exploit.o: file format elf32-littlearm
Disassembly of section .text:
00000000 <foo>:
0: e5900004 ldr r0, [r0, #4]
4: e12fff1e bx lr
これも if 文がざっくり削られてますね.
x86 以外でも気をつけたほうがいいかもしれません.