Upgrade to Pro — share decks privately, control downloads, hide ads and more …

When I investigated the problem of crashing Goo...

When I investigated the problem of crashing Google Chrome, I met the bug in libgcrypt.

bug shooting report

Mitsutoshi NAKANO

May 23, 2013
Tweet

More Decks by Mitsutoshi NAKANO

Other Decks in Technology

Transcript

  1. 1 Chrome が落ちる問題を 追いかけていたら libgcrypt の bug に出会った • •

    @ItSANgo • http://www.facebook.com/profile.php? id=100005833863069 • http://mixi.jp/show_profile.pl?id=78975 9
  2. 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. 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' に失敗し ました。 • • なんだこれは ?
  4. Chrome には crash report を出 す機能がある。 (12 月 26 日

    ) • chrome://crashes • 早速 crash report を提出。 • https://code.google.com/p/chromium/is sues/detail?id=167553 •
  5. Desktop 環境によっては 落ちないよ ?(12 月 30 日 ) Desktop 環境依存

    ? Lubuntu は Chromium が標準ブラウザ → 独自に修正が入っている ? セッション 結果 Ubuntu × GNOME × LXDE ◦ Recovery Console ◦ Xubuntu ×
  6. 同じエラーを報告している人が いた • 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 .” • でも本当に同じエラー ?
  7. 助っ人登場 (1 月 2 日 ) • font 周りでは ?

    • --password-store=basic では ? ← これ が大きかった !
  8. gnome-keyring の Ver. Up (1 月 7 日 ) Xubuntu(Ubuntu)

    Gnome-keyring 12.04 3.2.2-2 12.10 3.6.1-0 • Xubuntu ごと Upgrade しました。 • しかし問題は改善しなかった。
  9. 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 では問題が発生しない。
  10. 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 • • こんなことってある ? メモリを壊している ? • パルプンテ ! パルプンテ ! パルプンテ ! •
  11. まーた変な値が入っている (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 • パルプンテ!パルプンテ!パルプンテ!
  12. ふと思った (1 月 25 日 ) • 浮動小数点数まわりの扱いがおかしい のではないか ?

    • IA-32 の CPU の仕様の勉強を始めた。 • 「 IA-32 インテル ® アーキテクチャソ フトウェア・デベロッパーズ・マニュ アル」 • http://www.intel.co.jp/content/www/jp /ja/developer/download.html#ia32
  13. 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 • しかし…
  14. 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 • 何故だ ? --; • だが、問題を追いかけるトリガーが出来た。 • 後はただひたすらに処理を追いかけるだけ。
  15. 問題個所特定 (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
  16. さらに問題個所を絞り込む (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)); • }
  17. マクロでした • # 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 クリアしているだけ。 •
  18. どうしてこうなるのか • 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 を呼び出すのを忘れて いる ?
  19. パッチ書きました • # define aesni_cleanup() \ • do { asm

    volatile ("pxor %%xmm0, %%xmm0\n\t" \ • "pxor %%xmm1, %%xmm1\n\t" "emms\n" :: ); \ • } while (0) • • make check はすべてクリア、 Chrome も落ちることは無くなっ た。 • 全てはこれで解決するかに見えたが…
  20. そのパッチ間違ってます • 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. • •
  21. 正しいパッチが出ました (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でチェッ ク。
  22. その後当方でやったこと • パッチのテスト • パッチの当て方ドキュメント化 (1 月 30 日 )

    – https://forums.ubuntulinux.jp/viewtopic.ph p?pid=96461#p96461 – https://bugs.launchpad.net/ubuntu/ +source/libgcrypt11/+bug/1105758/comme nts/3
  23. その後の状況 • 正式なパッケージが出始めました。 – 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 …
  24. 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