Share
Embed
When I investigated the problem of crashing Google Chrome, I met the bug in libgcrypt.
bug shooting report
Mitsutoshi NAKANO
May 23, 2013
Transcript
28 slides
-
1 Chrome が落ちる問題を 追いかけていたら libgcrypt の bug に出会った • •
@ItSANgo • http://www.facebook.com/profile.php? id=100005833863069 • http://mixi.jp/show_profile.pl?id=78975 9 -
2 発端 (2012 年 12 月 24 日 ) •
https://productforums.google.com/f orum/#!msg/chrome-ja/w4pP0DQ75Dw/p xm9Qg8YDtsJ • Xubuntu 12.04 上の Chrome が http://twtter.com/ItSANgo/ へアクセ スすると SIGABRT で落ちます。 • その他、あちこちのサイトで落ちま す。 • Linux 版 Chrome 使えねぇ (-"-) -
3 標準エラー出力 (google-chrome:10581): Pango-CRITICAL **: pango_font_description_set_size: assertion `size >= 0'
failed • chrome --flag-switches-begin --flag- switches-end: /build/buildd/cairo- 1.10.2/src/cairo-surface.c:1287: cairo_surface_set_device_offset: アサーション `status == CAIRO_STATUS_SUCCESS' に失敗し ました。 • • なんだこれは ? -
Chrome には crash report を出 す機能がある。 (12 月 26 日
) • chrome://crashes • 早速 crash report を提出。 • https://code.google.com/p/chromium/is sues/detail?id=167553 • -
Desktop 環境によっては 落ちないよ ?(12 月 30 日 ) Desktop 環境依存
? Lubuntu は Chromium が標準ブラウザ → 独自に修正が入っている ? セッション 結果 Ubuntu × GNOME × LXDE ◦ Recovery Console ◦ Xubuntu × -
同じエラーを報告している人が いた • https://code.google.com/p/chromium/is sues/detail?id=124990 • (chromium:4187): Pango-CRITICAL **: pango_font_description_set_size:
assertion `size >= 0' failed は同じメッ セージ。 • “I think the browser crashes more, when are been loaded sites which asks for username and password .” • でも本当に同じエラー ? -
助っ人登場 (1 月 2 日 ) • font 周りでは ?
• --password-store=basic では ? ← これ が大きかった ! -
gnome-keyring の Ver. Up (1 月 7 日 ) Xubuntu(Ubuntu)
Gnome-keyring 12.04 3.2.2-2 12.10 3.6.1-0 • Xubuntu ごと Upgrade しました。 • しかし問題は改善しなかった。 -
Gnome-keyring の make check が通らない • /wrap-layer/create-credential/ok_password: FAIL • •
もはや Chrome の問題ではないよ^^; • • 自分の手におえそうにないので Ubuntu 日本語フォーラムに助けを求め た。 (1 月 9 日 ) • https://forums.ubuntulinux.jp/viewtopic.php?id=14643 • 「 gnome-keyring 3.6.1-0Ubuntu1 のソースの make check が FAIL にな るのを何とかしたい」 • DELL XPS8300 (core i7-2600) 上の VirtualBox では問題が発生しない。 -
GDB で追いかける (1 月 13 日 ) • largs[0] =
success ? 0 : 1; • ここを通り過ぎたとき、 largs[0] は 0 になると予想しました が、実際には -nan になっていました。 • • (gdb) print largs[0] • $28 = -nan(0xc000000000000000) • (gdb) print success • $29 = 1 • (gdb) print test_run_success • $30 = 0 • • こんなことってある ? メモリを壊している ? • パルプンテ ! パルプンテ ! パルプンテ ! • -
まーた変な値が入っている (1 月 22 日 ) • guint32 iterations; •
/* 略. */ • /* Prepare us the iterations */ • iterations = 1000 + (int) (1000.0 * rand() / (RAND_MAX + 1.0)); /* ←これが 怪しい. */ • /* 略. */ • • if (!create_cipher (login, calgo, halgo, salt, sizeof (salt), iterations, &cipher)) /* ←ここで落ちている. */ • return FALSE; • 上記のコードなのですが私が読んだ限りではiterationsには1000から2000の値 が入ると見たのですが、実際には、 • • (gdb) print iterations • $15 = 2147484648 • パルプンテ!パルプンテ!パルプンテ! -
ふと思った (1 月 25 日 ) • 浮動小数点数まわりの扱いがおかしい のではないか ?
• IA-32 の CPU の仕様の勉強を始めた。 • 「 IA-32 インテル ® アーキテクチャソ フトウェア・デベロッパーズ・マニュ アル」 • http://www.intel.co.jp/content/www/jp /ja/developer/download.html#ia32 -
GDB で追いかける。 • Info float • 普段は Empty (gdb) info
float R7: Empty 0x4008ffffff8b0dffffff8030ffffff98000000 R6: Empty 0x00000000000000000000 R5: Empty 0x00000000000000000000 R4: Empty 0x00000000000000000000 R3: Empty 0x00000000000000000000 R2: Empty 0x00000000000000000000 R1: Empty 0x00000000000000000000 =>R0: Empty 0x00000000000000000000 • しかし… -
FPU レジスタが… • FPU レジスタが全て使われてしまって いる。 (gdb) info float =>R7:
Special 0xffffffffffffffffffffffc000000000000000 Real Indefinite (QNaN) R6: Zero 0x00000000000000000000 +0 R5: Zero 0x00000000000000000000 +0 R4: Zero 0x00000000000000000000 +0 R3: Zero 0x00000000000000000000 +0 R2: Zero 0x00000000000000000000 +0 R1: Special 0xffffffffffffffff0000000000000000 Unsupported R0: Special 0xffffffffffffffff0000000000000000 Unsupported • 何故だ ? --; • だが、問題を追いかけるトリガーが出来た。 • 後はただひたすらに処理を追いかけるだけ。 -
問題個所特定 (1 月 26 日 ) • gcry_cipher_encrypt (cipher, dest,
input- >len, input->buf, input->len) • libgcrypt11:i386 1.5.0-3ubuntu1 の関数 • 再現プログラムを書いた。 • Bug report: https://bugs.launchpad.net/ubuntu/+so urce/libgcrypt11/+bug/1105758 -
さらに問題個所を絞り込む (1 月 27 日 ) • /build/buildd/libgcrypt11-1.5.0/cipher/rijndael.cの_gcry_aes_cbc_enc () でaesni_cleanup()
を呼び出しているところで、全てのx87 FPUデータレ ジスタが使用されていました。 • • void • _gcry_aes_cbc_enc (void *context, unsigned char *iv, • void *outbuf_arg, const void *inbuf_arg, • unsigned int nblocks, int cbc_mac) • { • /* 略. */ • aesni_cleanup (); /* <- ここ. */ • • _gcry_burn_stack (48 + 2*sizeof(int)); • } -
マクロでした • # define aesni_cleanup() \ • do { asm
volatile ("pxor %%xmm0, %%xmm0\n\t" \ • "pxor %%xmm1, %%xmm1\n\t" :: ); \ • } while (0) • • pxor - http://softwaretechnique.web.fc2.com/OS_Development/Tips/I A32_MMX_Instructions/PXOR.html#PXOR • 要するに xmm0 と xmm1 を 0 クリアしているだけ。 • -
どうしてこうなるのか • 9.5.1. MMXR 命令と x87 FPU タグワードの関係 • MMXR
命令の実行後は、必ず x87 FPU タグワード 全体が Valid ( 00B )に設定されてい • る。 • 。 EMMS 命令( MMX テクノロジ・ステートのクリ ア命令)を実行すると、 x87 FPU タグワード全体 が Empty ( 11B )に設定される。 • http://www.intel.co.jp/content/dam/www/public/ij kk/jp/ja/documents/developer/IA32_Arh_Dev_Man_Vo l1_Online_i.pdf • • 要するに PXOR の後に EMMS を呼び出すのを忘れて いる ? -
パッチ書きました • # define aesni_cleanup() \ • do { asm
volatile ("pxor %%xmm0, %%xmm0\n\t" \ • "pxor %%xmm1, %%xmm1\n\t" "emms\n" :: ); \ • } while (0) • • make check はすべてクリア、 Chrome も落ちることは無くなっ た。 • 全てはこれで解決するかに見えたが… -
そのパッチ間違ってます • http://lists.gnupg.org/pipermail/gcrypt-devel/2013-January/002083.html • • Jussi Kivilinna jussi.kivilinna at mbnet.fi
• Mon Jan 28 09:49:33 CET 2013 • • Those are SSE2 instructions, not MMX. So it does not touch x87 • registers at all. • Your bug report shows that you have Pentium-III. It does not support SSE2. • • Since PXOR for MMX is encoded with '0F EF' and for SSE2 with '66 0F • EF', the SSE2 version runs as MMX version on CPUs without SSE2 • support. The 0x66 byte at front of SSE2-opcode is operand-size • override prefix and is being ignored on your CPU. • • Bug appears to be in _gcry_aes_cbc_enc(), aesni_cleanup() is called • outside '#ifdef USE_AESNI' and/or 'if (ctr->use_aesni)'. This works on • most (modern) CPUs, but not those without SSE2 support. • • -
正しいパッチが出ました (1 月 28 日 ) • 開発版 (1.6beta): http://lists.gnupg.org/pipermail/gcrypt-devel/2013-January/002084.htm
l • Version 1.5: http://lists.gnupg.org/pipermail/gcrypt-devel/2013-January/002088.htm l • • - aesni_cleanup (); • + • +#ifdef USE_AESNI • + if (ctx->use_aesni) • + aesni_cleanup (); • +#endif /*USE_AESNI*/ • • 要するにpxorを呼び出す箇所は#ifdefで囲いctx->use_aesniでチェッ ク。 -
その後当方でやったこと • パッチのテスト • パッチの当て方ドキュメント化 (1 月 30 日 )
– https://forums.ubuntulinux.jp/viewtopic.ph p?pid=96461#p96461 – https://bugs.launchpad.net/ubuntu/ +source/libgcrypt11/+bug/1105758/comme nts/3 -
その後の状況 • 正式なパッケージが出始めました。 – Debian's 1.5.0-5 • そのうち Ubuntu にも落ちてくるでしょう。
– Libgcrypt 1.5.1 released http://lists.gnupg.org/pipermail/gcrypt- devel/2013-March/002109.html – Libgcrypt 1.5.2 released … -
こうして世のポンコツ PC が救 われたのです。 • Pentium II とか III とか
http://www.ill-f.co.jp/blog/cat6/ -
所感とか • Chrome のデバッグは大変よねぇ。 • IA-32 って変態さんだ。 ( 歴史を背負っ ててぐちゃまら
) • マクロを小文字で書く文化は滅びろ w -
Chrome のプロセスについて • chrome(2910)-+-chrome(2916) • |-chrome-sandbox(2917)---chrome(2918)-+-chrome(2925)-+-chrome(2975)-+-{chrome}(2979) • | | |
|-{chrome}(2982) • | | | `-{chrome}(2992) • | | |-chrome(2985)-+-{chrome}(2989) • | | | |-{chrome}(2990) • | | | `-{chrome}(2993) • | | `-chrome(2994)-+-{chrome}(2997) • | | |-{chrome}(2998) • | | `-{chrome}(2999) • | `-nacl_helper_boo(2924) • |-{chrome}(2927) • |-{chrome}(2928) • |-{chrome}(2929) • |-{chrome}(2931) • |-{chrome}(2932) • |-{chrome}(2933) • |-{chrome}(2934) • |-{chrome}(2935) • |-{chrome}(2936) • |-{chrome}(2937) • |-{chrome}(2938) • |-{chrome}(2939) • |-{chrome}(2940) • |-{chrome}(2941) • |-{chrome}(2943) • |-{chrome}(2944) • |-{chrome}(2945) • |-{chrome}(2946) • |-{chrome}(2947) • |-{chrome}(2948) • |-{chrome}(2971) • |-{chrome}(2972) • |-{chrome}(2973) • |-{chrome}(2974) • |-{chrome}(2981) • |-{chrome}(2983) • |-{chrome}(2984) • |-{chrome}(2991) • |-{chrome}(3002) • |-{chrome}(3003) • |-{chrome}(3004) • |-{chrome}(3005) • |-{chrome}(3009) • |-{chrome}(3015) • |-{chrome}(3018) • |-{chrome}(3019) • |-{chrome}(3020) • |-{chrome}(3022) • |-{chrome}(3023) • |-{chrome}(3024) • |-{chrome}(3025) • `-{chrome}(3028) • どうデバッグしろと w https://code.google.com/p/chromium/wiki/LinuxDebuggin g