Linux カーネル 0 day exploit 祭り

Linux カーネルの zero-day exploit コード、リリースされる (slashdot Japan)

要するに,注意が足りないコードに gcc の最適化が重なって生じた穴だそうである.

注意が足りない

問題のコード.

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 の最適化

上記のソースであるが,

  • tun == NULL であるならば *sk = tun->sk で Segmentation fault が生じ,if 文のところまで到達しない
  • tun != NULL ならば if (!tun) の中身は実行されない

ということで,gcc の最適化で if 文全体が削られてしまうそうなのである.

exploit では,ここで 0x00000000 に mmap() でメモリを割り当ててこの例外の起きる条件を変えて…ということらしい.

手元の環境では

試しに似たようなコードを書いてみた.

$ 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 では

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 以外でも気をつけたほうがいいかもしれません.


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2009-07-23 (木) 22:29:55 (5483d)