
Ubuntu日本語フォーラム

ログインしていません。
Sony PCG-SRX7S/P メモリ 512 M byteのPCに
Xubuntu 12.10 desktop i386を入れ、
その上にgnome-keyring 3.6.1-0Ubuntu1 のソースを入れて
自分でビルドしてmake checkしているのですが、
checkが途中でFAILになるので困っています。
$sudo apt-get install gnome-pkg-tools gtk-doc-tools libcap-ng-dev libgck-1-dev libgcr-3-dev libgtk-3-dev libselinux1-dev libtasn1-3-bin libglib2.0-doc
$apt-get -b source gnome-keyring
$cd gnome-keyring-3.6.1/
$make check | tee make_check.txt
make check の結果については
https://dl.dropbox.com/u/86335040/make_check.txt
PCG-SRX7S/Pの仕様については
http://www.sony.jp/products/biz/vaio/PCG-SRX7S_P/spec.html
DELL XPS 8300 メモリ16 G byte
ホストOS: Windows 7 Ultimate 64-bit (6.1, Build 7601) Service Pack 1 (7601.win7sp1_gdr.120830-0333)
のPCにVirtualBox 6.2.6 r82870を入れ
メモリ512 M byteのVMを作り
そこにインストールしたXubuntu 12.10 desktop i386は
FAILにならずに全てのcheckがOKとなります。
PCG-SRX7S/P上のgnome-keyringのmake checkを成功させるには
どうすればよいでしょうか?
試したこと:
1) gnome-keyringデーモンのkill
2) “~/.gnome2/”・“~/.local/share/keyrings/”のリネーム
3) VirtualBox上で生成した実行可能ファイルをPCG-SRX7S/Pにコピーして実行
4) gnome-keyring テスト FAIL等で検索
5) テストプログラムを単体で動かしてみる
→“gnome-keyring-3.6.1/pkcs11/wrap-layer/tests/”ディレクトリに
存在する実行可能ファイルは、
のきなみ1番目のテストでFAILになるようでした。
いずれも効果がありませんでした。
何か思い当たるところはございませんでしょうか?
gnome-keyringのソースをコンパイルするに至った経緯については
https://productforums.google.com/forum/#!msg/chrome-ja/w4pP0DQ75Dw/pxm9Qg8YDtsJ
を参照ください。
Chrome・Chromiumでpassword storeにgnome keyringを使用すると
ログインフォームが存在するページを閲覧したら
ブラウザが異常終了するというものです。
こちらについても思い当るところがございましたら、
ご指摘お願いいたします。
オフライン
この問題を追いかけていて、奇妙な現象に出くわしたので、この後どう動くべきか教えていただけたら幸いです。
問題のPC PCG-SRX7S/Pにlibglib2.0-0のソースを入れました。
$sudo mkdir /build
$cd /build
$sudo mkdir buildd
cd buildd
$sudo apt-get install dh-autoreconf libelf-dev libffi-dev
$apt-get -b source libglib2.0-0
libglib2.0-0のテストは正常に終了しました。
emacsから問題のプログラムをデバッグにかけることにしました。
$emacs test-create-credential.c &
単純化のために2~3段目のテストはコメントアウトしました。
g_test_add ("/wrap-layer/create-credential/ok_password", Test, NULL, setup, test_ok_password, teardown);
// g_test_add ("/wrap-layer/create-credential/bad_password_then_cancel", Test, NULL, setup, test_bad_password_then_cancel, teardown);
// g_test_add ("/wrap-layer/create-credential/cancel_immediately", Test, NULL, setup, test_cancel_immediately, teardown);
$make
main()の
return egg_tests_run_in_thread_with_loop ();
test_ok_password (Test *test, gconstpointer unused) の最後尾
teardown (Test *test, gconstpointer unused) の最後尾
/build/buildd/glib2.0-2.34.1/glib/gtestutils.c
のg_test_log ()の先頭行
test_case_run (GTestCase *tc)の先頭行
largs[0] = success ? 0 : 1; /* OK */ の部分
へそれぞれブレークポイントを設定し、run やcontinueを繰り返し、test_case_run (GTestCase *tc)の
largs[0] = success ? 0 : 1; /* OK */ の部分
まで達しました。
ここを通り過ぎたとき、largs[0]は0になると予想しましたが、実際には-nanになっていました。
(gdb) print largs[0]
$28 = -nan(0xc000000000000000)
(gdb) print success
$29 = 1
(gdb) print test_run_success
$30 = 0
その後、step実行を繰り返した結果、
g_test_log (G_TEST_LOG_STOP_CASE, NULL, NULL, G_N_ELEMENTS (largs), largs);
へ入り、g_test_log()の中で
static void
g_test_log (GTestLogType lbit,
const gchar *string1,
const gchar *string2,
guint n_args,
long double *largs)
{
gboolean fail = lbit == G_TEST_LOG_STOP_CASE && largs[0] != 0;
/* 略 */
switch (lbit)
{
/* 略 */
case G_TEST_LOG_STOP_CASE:
if (g_test_verbose())
g_print ("GTest: result: %s\n", fail ? "FAIL" : "OK");
else if (!g_test_quiet())
g_print ("%s\n", fail ? "FAIL" : "OK");
if (fail && test_mode_fatal)
abort(); /* ここ. */
break;
/* 略 */
}
/* 略 */
}
abort()を呼び出し、異常終了しました。
VirtualBox 6.2.6 r82870上のVMにも同様の環境を作り、動作を確認しましたが、largs[0]には0が入り、テストもOKになっていました。
もしやと思い、junk.c
#include <stdio.h>
#include <stdlib.h>
static void
test_log(unsigned n_args, long double *largs)
{
int fail = largs[0] != 0;
if (fail)
abort();
}
int
main(void)
{
int success = 1;
long double largs[3];
largs[0] = success ? 0 : 1; /* OK */
largs[1] = 10;
largs[2] = 100;
test_log(sizeof largs / sizeof largs[0], largs);
return 0;
}
というのを書いて問題のPCG-SRX7S/P上で実行しましたが、成功終了しました。
このあと私はどう動くべきでしょうか?
http://d.hatena.ne.jp/Itisango/20130113
http://d.hatena.ne.jp/Itisango/searchdiary?word=%2A%5Bgnome-keyring%5D
も参考までに載せておきます。
わかりにくい文章で申し訳ないのですが、正直途方に暮れています。
オフライン
PCG-SRX7S/Pに入れたXubuntu 12.10上で
gnome-keyring 3.6.1-0Ubuntu1のソースのmake checkがFAILになる件で進展がありました。
glib2.0-2.34.1のソースを最適化を切ってコンパイルしたら、今までFAILで落ちていたテストがOKになりました。
やったこと:
$cd ~/src/gnome-keyring/gnome-keyring-3.6.1/
$make -k check | tee make-k-check.txt
$ egrep FAIL make-k-check.txt
/wrap-layer/create-credential/ok_password: FAIL
/secret-store/collection/load_unlock_encrypted: FAIL
/xdg-store/trust/create_assertion_complete_on_token: FAIL
/gnome2-store/gnome2-file/write_private_with_login: FAIL
→4つのテストがFAILとなっていることを確認。
$cd /build/buildd/glib2.0-2.34.1
$vi Makefile
CFLAGS = -g -O2 -Wall
を
CFLAGS = -g -O0 -Wall
に変更。
$cd glib
$vi Makefile
CFLAGS = -g -O2 -Wall
を
CFLAGS = -g -O0 -Wall
に変更。
$make clean
$cd ..
$make
$sudo make install → /usr/local/lib に glibがインストールされる。
$ls -lt /usr/local/lib
合計 13332
-rwxr-xr-x 1 root root 1135 1月 20 21:00 libgio-2.0.la
lrwxrwxrwx 1 root root 22 1月 20 21:00 libgio-2.0.so -> libgio-2.0.so.0.3400.1
lrwxrwxrwx 1 root root 22 1月 20 21:00 libgio-2.0.so.0 -> libgio-2.0.so.0.3400.1
-rwxr-xr-x 1 root root 5677040 1月 20 21:00 libgio-2.0.so.0.3400.1
-rwxr-xr-x 1 root root 1065 1月 20 20:59 libgobject-2.0.la
lrwxrwxrwx 1 root root 26 1月 20 20:59 libgobject-2.0.so -> libgobject-2.0.so.0.3400.1
lrwxrwxrwx 1 root root 26 1月 20 20:59 libgobject-2.0.so.0 -> libgobject-2.0.so.0.3400.1
-rwxr-xr-x 1 root root 1165448 1月 20 20:59 libgobject-2.0.so.0.3400.1
-rwxr-xr-x 1 root root 1026 1月 20 20:59 libgthread-2.0.la
lrwxrwxrwx 1 root root 26 1月 20 20:59 libgthread-2.0.so -> libgthread-2.0.so.0.3400.1
lrwxrwxrwx 1 root root 26 1月 20 20:59 libgthread-2.0.so.0 -> libgthread-2.0.so.0.3400.1
-rwxr-xr-x 1 root root 9128 1月 20 20:59 libgthread-2.0.so.0.3400.1
-rwxr-xr-x 1 root root 1031 1月 20 20:59 libgmodule-2.0.la
lrwxrwxrwx 1 root root 26 1月 20 20:59 libgmodule-2.0.so -> libgmodule-2.0.so.0.3400.1
lrwxrwxrwx 1 root root 26 1月 20 20:59 libgmodule-2.0.so.0 -> libgmodule-2.0.so.0.3400.1
-rwxr-xr-x 1 root root 41632 1月 20 20:59 libgmodule-2.0.so.0.3400.1
-rwxr-xr-x 1 root root 978 1月 20 20:59 libglib-2.0.la
lrwxrwxrwx 1 root root 23 1月 20 20:59 libglib-2.0.so -> libglib-2.0.so.0.3400.1
lrwxrwxrwx 1 root root 23 1月 20 20:59 libglib-2.0.so.0 -> libglib-2.0.so.0.3400.1
-rwxr-xr-x 1 root root 2541284 1月 20 20:59 libglib-2.0.so.0.3400.1
drwxr-xr-x 2 root root 4096 1月 20 20:59 pkgconfig
drwxr-xr-x 3 root root 4096 1月 14 07:39 gio
drwxr-xr-x 3 root root 4096 1月 14 07:39 gdbus-2.0
drwxr-xr-x 3 root root 4096 1月 14 07:39 glib-2.0
-rw-r--r-- 1 root root 443550 1月 13 19:03 libbreakpad_client.a
-rw-r--r-- 1 root root 3704712 1月 13 19:03 libbreakpad.a
drwxr-xr-x 3 root root 4096 1月 7 17:29 site_ruby
drwxrwsr-x 3 root staff 4096 1月 7 17:01 python3.2
drwxrwsr-x 4 root staff 4096 1月 7 17:01 python2.7
drwxr-xr-x 2 root root 4096 1月 2 08:57 xrdp
$cd /etc/ld.so.conf.d
$sudo vi 0local.conf
/usr/local/lib と記述
$sudo ldconfig
$cd ~/src/gnome-keyring/gnome-keyring-3.6.1/pkcs11/wrap-layer/tests
$ldd ./test-create-credential
linux-gate.so.1 => (0xb7783000)
libgcrypt.so.11 => /lib/i386-linux-gnu/libgcrypt.so.11 (0xb76db000)
libgcr-base-3.so.1 => /usr/lib/libgcr-base-3.so.1 (0xb7657000)
libgio-2.0.so.0 => /usr/local/lib/libgio-2.0.so.0 (0xb74f6000)
libgobject-2.0.so.0 => /usr/local/lib/libgobject-2.0.so.0 (0xb74a8000)
libglib-2.0.so.0 => /usr/local/lib/libglib-2.0.so.0 (0xb736e000)
libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb7352000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb71a8000)
libgpg-error.so.0 => /lib/i386-linux-gnu/libgpg-error.so.0 (0xb71a3000)
libgck-1.so.0 => /usr/lib/libgck-1.so.0 (0xb716c000)
libp11-kit.so.0 => /usr/lib/i386-linux-gnu/libp11-kit.so.0 (0xb7158000)
libgmodule-2.0.so.0 => /usr/local/lib/libgmodule-2.0.so.0 (0xb7152000)
libz.so.1 => /lib/i386-linux-gnu/libz.so.1 (0xb7139000)
libselinux.so.1 => /lib/i386-linux-gnu/libselinux.so.1 (0xb711a000)
libresolv.so.2 => /lib/i386-linux-gnu/libresolv.so.2 (0xb7103000)
libffi.so.6 => /usr/lib/i386-linux-gnu/libffi.so.6 (0xb70fc000)
librt.so.1 => /lib/i386-linux-gnu/librt.so.1 (0xb70f2000)
/lib/ld-linux.so.2 (0xb7784000)
libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xb70ed000)
→/usr/local/lib のlibglib-2.0.so.0が読まれていることを確認。
$cd ~/src/gnome-keyring/gnome-keyring-3.6.1/
$make -k check | tee make-k-check2.txt
$egrep FAIL make-k-check2.txt
/gnome2-store/import/pkcs12: FAIL
$egrep wrap-layer make-k-check2.txt
Making check in wrap-layer
make[2]: ディレクトリ `/home/mitsutos/src/gnome-keyring/gnome-keyring-3.6.1/pkcs11/wrap-layer' に入ります
make[3]: ディレクトリ `/home/mitsutos/src/gnome-keyring/gnome-keyring-3.6.1/pkcs11/wrap-layer' に入ります
make[3]: ディレクトリ `/home/mitsutos/src/gnome-keyring/gnome-keyring-3.6.1/pkcs11/wrap-layer' から出ます
make[3]: ディレクトリ `/home/mitsutos/src/gnome-keyring/gnome-keyring-3.6.1/pkcs11/wrap-layer/tests' に入ります
make[4]: ディレクトリ `/home/mitsutos/src/gnome-keyring/gnome-keyring-3.6.1/pkcs11/wrap-layer/tests' に入ります
make[4]: ディレクトリ `/home/mitsutos/src/gnome-keyring/gnome-keyring-3.6.1/pkcs11/wrap-layer/tests' から出ます
make[4]: ディレクトリ `/home/mitsutos/src/gnome-keyring/gnome-keyring-3.6.1/pkcs11/wrap-layer/tests' に入ります
/wrap-layer/create-credential/ok_password: OK
/wrap-layer/init-pin/ok_password: OK
/wrap-layer/login-auto/specific: OK
/wrap-layer/login-auto/user_token: OK
/wrap-layer/login-auto/unlock_keyring: OK
/wrap-layer/login-hints/did_unlock_fail: OK
/wrap-layer/login-keyring/is_usable: OK
/wrap-layer/login-keyring/usable_fail_open_session: OK
/wrap-layer/login-keyring/usable_fail_not_trusted: OK
/wrap-layer/login-keyring/usable_fail_locked: OK
/wrap-layer/login-keyring/lookup_secret_no_match: OK
/wrap-layer/login-keyring/lookup_secret_and_match: OK
/wrap-layer/login-keyring/lookup_store_secret: OK
/wrap-layer/login-keyring/lookup_store_secret_overwrite: OK
/wrap-layer/login-keyring/lookup_store_null_secret: OK
/wrap-layer/login-keyring/lookup_store_no_attributes_not_stored: OK
/wrap-layer/login-keyring/lookup_remove_present: OK
/wrap-layer/login-keyring/lookup_remove_no_attributes: OK
/wrap-layer/login-specific/ok_password: OK
/wrap-layer/login-specific/bad_password_then_cancel: OK
/wrap-layer/login-specific/cancel_immediately: OK
/wrap-layer/login-user/fail_unsupported_so: OK
/wrap-layer/login-user/skip_prompt_because_pin: OK
/wrap-layer/login-user/ok_password: OK
/wrap-layer/login-user/bad_password_then_cancel: OK
/wrap-layer/login-user/cancel_immediately: OK
/wrap-layer/login-user/fail_get_session_info: OK
/wrap-layer/login-user/fail_get_token_info: OK
/wrap-layer/set-pin/ok_passwords: OK
make[4]: ディレクトリ `/home/mitsutos/src/gnome-keyring/gnome-keyring-3.6.1/pkcs11/wrap-layer/tests' から出ます
make[3]: ディレクトリ `/home/mitsutos/src/gnome-keyring/gnome-keyring-3.6.1/pkcs11/wrap-layer/tests' から出ます
make[2]: ディレクトリ `/home/mitsutos/src/gnome-keyring/gnome-keyring-3.6.1/pkcs11/wrap-layer' から出ます
→今までFAILだった/wrap-layer/create-credential/ok_passwordがOKになっていることを確認。
というわけで、考えにくいのですが、glib2.0-2.34.1の最適化によるバグのように見えます。
この後わたしはどう動けばよいでしょうか?
とりあえず、残り1つのFAILである
/gnome2-store/import/pkcs12: FAIL
を追いかけてみます。
make-k-check.txt https://dl.dropbox.com/u/86335040/make-k-check.txt
make-k-check2.txt https://dl.dropbox.com/u/86335040/make-k-check2.txt
をDropboxに上げて置きます。
オフライン
Sony PCG-SRX7S/P メモリ 512 M byteのPCにXubuntu 12.10 desktop i386を入れ、その上にgnome-keyring 3.6.1-0Ubuntu1 のソースを入れて自分でビルドしてmake checkするとcheckが途中でFAILになる件ですが、
残り1つのFAILである
/gnome2-store/import/pkcs12: FAIL
を追いかけてみたところ、また奇妙な現象に出くわしたので報告いたします。
FAILになってSIGABRTでcoreを吐いて落ちているので、coreをgdbにかけてみました。
gdb ./test-import core
backtrace full をかけて、frameを追いかけた結果
~/src/gnome-keyring/gnome-keyring-3.6.1/pkcs11/gnome2-store/gkm-gnome2-file.c のencrypt_buffer()の中で怪しい動きを見つけました。
ソースの詳細は http://d.hatena.ne.jp/Itisango/20130121/1358754891 を見てください。
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
という大きな値が入っており、その先の関数でint型にキャストされ、ループカウンタが負の値になっているので
** (test-import:6646): CRITICAL **: egg_symkey_generate_simple: assertion `iterations >= 1' failed
Trace/breakpoint trap (コアダンプ)
というassertionに引っかかって落ちていました。
不可解なので、上記iterations代入文を
double r = rand();
r *= 1000;
r /= (RAND_MAX + 1.0);
iterations = (int) r;
iterations += 1000;
の5文に分けてgdbで追いかけたところ、rand()は仕様通りの値1815410400等が入っているのにrが何故か
(gdb) print r
$8 = -nan(0x8000000000000)
になる事がわかりました。
その-nanの値を持ったrが1000倍されて-nan、 (RAND_MAX + 1.0)で割られて-nan、 (int)にキャストされたことで
(gdb) print iterations
$11 = 2147483648
になり、1000足されて2147484648になっていました。
iterations = (int) r;
のintへのキャストを外して
iterations = r;
としたところ、-nanは0に変換され、結果的にiterationsはrand()の値にかかわらず1000になり、testはOKになるようになりました。
ただ、処理の流れから言って、これが正しい動きだとは思えません。
1) 対処方法があれば教えてください。
2) また類似の現象で困った経験をお持ちの方がいらっしゃったら体験を教えてください。
3) この後私はどう動くべきでしょうか?
gnome-keyringのコンパイルの最適化を切る(-O0)のを試してみましたが、効果はありませんでした。
http://d.hatena.ne.jp/Itisango/20130121/1358778093
http://d.hatena.ne.jp/Itisango/20130122/1358812104
も参考までに載せておきます。
オフライン
2013-01-22 17:56:27 に奇妙な動作報告をさせていただきましたが、たった今、さらに奇妙な動作に気が付きました。
double r = rand();
r *= 1000;
r /= (RAND_MAX + 1.0);
iterations = (int) r;
iterations += 1000;
の「rand()」を「(int) 1」に変えたところ
double r = (int) 1;
r *= 1000;
r /= (RAND_MAX + 1.0);
iterations = (int) r;
iterations += 1000;
1回目にこの関数に飛び込んだ時には
(gdb) print r
$1 = 1
と、コード通りに1が入っているのですが、2回目にこの関数に飛び込んで、「double r = (int) 1」を通り過ぎたとき
(gdb) print r
$6 = -nan(0x8000000000000)
と-nanが入ってきました。
正直何が起こっているのか理解に苦しんでいるのですが、
1) このような奇妙な現象に遭遇されたことのある方はいらっしゃらないでしょうか?
2) バグシュートしたいのですが、このような現象の場合どこを追いかけていくべきでしょうか?
とても困っています。そして困惑しています。
オフライン
https://forums.ubuntulinux.jp/viewtopic.php?pid=96347#p96347 の件の経過報告です。
~/src/gnome-keyring/gnome-keyring-3.6.1/pkcs11/gnome2-store/gkm-gnome2-file.cのencrypt_buffer()の
iterations = 1000 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
で、とんでもない値が返ってくる件について、浮動小数点数の扱いがおかしいのではないかと思い、以下の資料を参照しながらIA-32のx87 FPU周りを調べ始めました。
[資料]
http://www.intel.co.jp/content/www/jp/ja/developer/download.html#ia32
http://www.intel.co.jp/content/dam/www/public/ijkk/jp/ja/documents/developer/IA32_Arh_Dev_Man_Vol1_Online_i.pdf
http://www.intel.co.jp/content/dam/www/public/ijkk/jp/ja/documents/developer/IA32_Arh_Dev_Man_Vol2A_i.pdf
問題の個所を1回目に通った時には以下のようにx87 FPUデータレジスタは空っぽです。
(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
Status Word: 0x0020 PE
TOP: 0
Control Word: 0x037f IM DM ZM OM UM PM
PC: Extended Precision (64-bits)
RC: Round to nearest
Tag Word: 0xffff
Instruction Pointer: 0x73:0x0805a3d3
Operand Pointer: 0x7b:0xbffff05c
Opcode: 0xdb5c
しかし、2回目に通るときには
(gdb) info float
R7: Valid 0x4008ffffff8b0dffffff8030ffffff98000000 +556.2109490856528282
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
Status Word: 0x0020 PE
TOP: 0
Control Word: 0x037f IM DM ZM OM UM PM
PC: Extended Precision (64-bits)
RC: Round to nearest
Tag Word: 0x155a
Instruction Pointer: 0x73:0x0805a3d3
Operand Pointer: 0x7b:0xbffff05c
Opcode: 0xdb5c
とデータレジスタを使い切っており、問題の個所を通り過ぎる時に
(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
Status Word: 0x3a61 IE PE SF C1
TOP: 7
Control Word: 0x037f IM DM ZM OM UM PM
PC: Extended Precision (64-bits)
RC: Round to nearest
Tag Word: 0x955a
Instruction Pointer: 0x73:0x0805a3af
Operand Pointer: 0x7b:0xb6ffec5c
Opcode: 0xdb44
とIE SF C1のフラグが立ち、http://www.intel.co.jp/content/dam/www/public/ijkk/jp/ja/documents/developer/IA32_Arh_Dev_Man_Vol1_Online_i.pdf
の「8.5.1.1.」によればスタックオーバーフローを起こしているように見えます。
不思議なのは、
https://forums.ubuntulinux.jp/viewtopic.php?pid=96074#p96074 で言及したVirtualBox上に構築したXubuntu 12.10ではそんな問題は起こらず、データレジスタの殆どはずっと空きになっているということです。
2回目に問題の個所を通り抜ける直前の状態:
(gdb) info float
R7: Empty 0x4008ffffffeb0e2b4dffffff9c000000
R6: Empty 0x401effffff8000000000000000
R5: Empty 0x00000000000000000000
R4: Empty 0x00000000000000000000
R3: Empty 0x00000000000000000000
R2: Empty 0x00000000000000000000
R1: Empty 0x00000000000000000000
=>R0: Empty 0x00000000000000000000
Status Word: 0x0020 PE
TOP: 0
Control Word: 0x037f IM DM ZM OM UM PM
PC: Extended Precision (64-bits)
RC: Round to nearest
Tag Word: 0xffff
Instruction Pointer: 0x73:0x080579c5
Operand Pointer: 0x7b:0xbfffed30
Opcode: 0x0000
2回目に問題の個所を通り抜けた直後の状態:
(gdb) info float
R7: Empty 0x4006ffffff8bffffffd679fffffff920000000
R6: Empty 0x401effffff8000000000000000
R5: Empty 0x00000000000000000000
R4: Empty 0x00000000000000000000
R3: Empty 0x00000000000000000000
R2: Empty 0x00000000000000000000
R1: Empty 0x00000000000000000000
=>R0: Empty 0x00000000000000000000
Status Word: 0x0020 PE
TOP: 0
Control Word: 0x037f IM DM ZM OM UM PM
PC: Extended Precision (64-bits)
RC: Round to nearest
Tag Word: 0xffff
Instruction Pointer: 0x73:0x080579c5
Operand Pointer: 0x7b:0xb6ffebd0
Opcode: 0x0000
1) FPUデータレジスタを使い切らないようにするにはどうすればよいでしょうか?
コンパイルオプション等で回避できないでしょうか?
2) そもそもFPUデータレジスタを使い切るというのはコンパイラの設計上あり得ることなのでしょうか?
3) 類似の現象でお困りの方がいらっしゃったら、体験を教えていただけないでしょうか?
4) この問題をシューティングしたいと考えております。この後私は何をすべきでしょうか?
とりあえず私はコードを前方から追いかけFPUデータレジスタを使い続けていく箇所を特定しようと考えております。
もっと良い方法があったら教えてください。
参考までにこの件について書いたBLOGを掲示しておきます。
http://d.hatena.ne.jp/Itisango/20130125/1359082149
http://d.hatena.ne.jp/Itisango/searchdiary?word=%2A%5Bgnome-keyring%5D
皆様のお知恵をお貸しください。
オフライン
一部の環境で
gnome-keyring-3.6.1/pkcs11/gnome2-store/gkm-gnome2-file.cのencrypt_buffer()の
iterations = 1000 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
で、とんでもない値が返ってくる件について、報告と、皆さんへのお願いです。
1. *** 報告 ***
1.1. x87 FPUデータレジスタを使い切っている個所を特定しました。
gnome-keyring-3.6.1/pkcs11/gnome2-store/gkm-gnome2-file.cのencrypt_buffer()の
gcry = gcry_cipher_encrypt (cipher, dest, input->len, input->buf, input->len);
という個所を通り過ぎたときに問題の起こるPCではデータレジスタを8つすべて使い切った状態になることを確認しました。
これはlibgcrypt11:i386 1.5.0-3ubuntu1というパッケージの/lib/i386-linux-gnu/libgcrypt.so.11.7.0という共有オブジェクトで定義されている関数です。
現在このパッケージの中を追いかけて、さらに問題を起こしている個所を突き止めようとしています。
またできれば、問題の起こるPCと起きない環境の違いを特定したいと考えています。
参考までに私のBLOGのURLを載せておきます。
http://d.hatena.ne.jp/Itisango/searchdiary?word=%2A%5Bgnome-keyring%5D
1.2. 再現プログラムを書きました。
encrypt_buffer()でやっていることを見よう見まねで再現プログラムを書きました。
私のPC上で問題を確認しました。
また別のPC上に構築したVirtualBox上の環境では問題が再現しないことも確認しました。
皆さんの環境でも再現するか否かを調べていただきたいと思っています。
1.3. バグレポートを書く予定です。
http://packages.ubuntu.com/quantal/libgcrypt11
http://packages.ubuntu.com/quantal/gnome-keyring
を調べて、同様のバグが報告されていなければバグ報告するつもりです。
いや、まだ早い、と考える方は是非一報願います。
2. *** 皆さんへのお願い ***
この問題が起こる環境の条件を調べたいと思います。
再現プログラムを下記へ置きました。
https://dl.dropbox.com/u/86335040/bug.tar.gz
皆さんの環境で、このプログラムを実行して、現象が再現するか否かを確認し、レポートをくださるようお願いいたします。
2.1. レポートはこのトピックへ投稿するか、または私へメールをいただけるようお願いいたします。
(メールアドレスはREADME.txtの中に記述しました。)
2.2. レポートには以下の情報を記述してください。
1) 再現の可否
2) 皆さんの環境の詳細
・PCの機種・CPU・チップセット・マザーボード・メモリの情報
(メーカー製PCの場合、SPEC表へのURLがあると嬉しいです)
・lsb_release -aの情報
・uname -aの情報(ホスト名を除いて)
等々
また、ご意見のある方はご連絡ください。
皆さんのご協力をお願いいたします。
オフライン
この件、Bug Reportを書きました。
https://bugs.launchpad.net/ubuntu/+source/libgcrypt11/+bug/1105758
対処していただけますように。
こんな破綻した英語で通じるのでしょうか^^ ?
引き続きソースを追いかける予定です。
オフライン
一部の環境で
gnome-keyring-3.6.1/pkcs11/gnome2-store/gkm-gnome2-file.cのencrypt_buffer()の
iterations = 1000 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
で、とんでもない値が返ってくる件について、経過報告です。
1. 問題個所を特定しました。
/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));
}
aesni_cleanup()はマクロで以下のようにMMX命令であるpxorを呼び出していました。
/* Two macros to be called prior and after the use of AESNI
instructions. There should be no external function calls between
the use of these macros. There purpose is to make sure that the
SSE regsiters are cleared and won't reveal any information about
the key or the data. */
#ifdef USE_AESNI
# define aesni_prepare() do { } while (0)
# define aesni_cleanup() \
do { asm volatile ("pxor %%xmm0, %%xmm0\n\t" \
"pxor %%xmm1, %%xmm1\n\t" :: ); \
} while (0)
/* 略 */
#else
# define aesni_prepare() do { } while (0)
# define aesni_cleanup() do { } while (0)
#endif
http://www.intel.co.jp/content/dam/www/public/ijkk/jp/ja/documents/developer/IA32_Arh_Dev_Man_Vol1_Online_i.pdf によれば
9.5.1. MMXR 命令とx87 FPU タグワードの関係
MMXR 命令の実行後は、必ずx87 FPU タグワード全体がValid(00B)に設定されてい
る。EMMS命令(MMXテクノロジ・ステートのクリア命令)を実行すると、x87 FPU
タグワード全体がEmpty(11B)に設定される。
とのことなので、ここでx87 FPUデータレジスタ全体が使用されてしまい、その後のdouble型データの処理でx87 FPUデータレジスタの「スタック・オーバーフロー例外」が発生したのだと思われます。
2. パッチを書きました。
そこで以下のパッチを書き、EMMS命令を呼び出すように変更しました。
$diff -u rijndael.c.orig rijndael.c >rijndael.c.diff
--- rijndael.c.orig 2013-01-26 18:55:44.731570123 +0900
+++ rijndael.c 2013-01-27 07:49:58.110132242 +0900
@@ -140,7 +140,7 @@
# define aesni_prepare() do { } while (0)
# define aesni_cleanup() \
do { asm volatile ("pxor %%xmm0, %%xmm0\n\t" \
- "pxor %%xmm1, %%xmm1\n" :: ); \
+ "pxor %%xmm1, %%xmm1\n\t" "emms\n" :: ); \
} while (0)
# define aesni_cleanup_2_4() \
do { asm volatile ("pxor %%xmm2, %%xmm2\n\t" \
これを適用して
$make
$make check
$sudo make install
してた結果/gnome2-store/import/pkcs12のテストは通りました。
結論として
1) glibcのコンパイル最適化のOff
2) 上記パッチの適応
でgnome-keyringの全てのテストはFAILにならなくなりました。
また https://forums.ubuntulinux.jp/viewtopic.php?pid=96074#p96074 で述べた「Chrome・Chromium」が異常終了する件も再現しなくなりました。
3. 気がかりなこと
ですが気がかりなことがいくつかあります。
1) この修正は正しいのか?
2) 漏れはないのか?
3) そもそもi386アーキテクチャでMMX命令を呼び出すのは正しいのか?
「1)」について、私はアセンブリ言語の経験がないし、IA-32についても詳しくないので正直自信がありません。
本当はこうすべきだというあるべき姿があれば、教えてください。
「2)」について、私はコードの全てを読んだわけではなく、またその技能もないので他に類似の処理があっても見つけ出すことができません。
gnome-keyringやlibgcrypt11:i386に詳しい方のアドバイスをお願いします。
「3)」についてlibgcrypt11:i386はその名の通りi386アーキテクチャのライブラリだと思うのですが、MMXは「Pentium II」や「MMXテクノロジPentium プロセッサ」で導入された技術だと聞いております。
そもそもi386の付くパッケージでMMXの命令を呼び出すことはありなのでしょうか?
これらのことについて皆さんのご見解を聞かせてください。
4. 今後について
4.1. とりあえず報告
とりあえず以上のようなことを簡単な英語にして、パッチも含めて https://bugs.launchpad.net/ubuntu/+source/libgcrypt11/+bug/1105758 に報告しようと思います。
4.2. glibcのコンパイル最適化の再開
glibcのコンパイル最適化のOffはトリッキーな操作だと考えていますので、時間があればコンパイル最適化を復活させて、処理を追いかけたいと思います。
長文をお読みくださりありがとうございます。何かご意見ございましたらコメントお願いいたします。
オフライン
ItSANgo による投稿:
4.2. glibcのコンパイル最適化の再開
glibcのコンパイル最適化のOffはトリッキーな操作だと考えていますので、時間があればコンパイル最適化を復活させて、処理を追いかけたいと思います。
と書きましたが、最適化を復活させてもgnome-keyringのテストはFAILにならないことを確認しました。
また「Chrome・Chromium」が異常終了する件も再現しなくなりました。
つまり、1箇所の修正で全部治ってしまったかのように見えます。
https://bugs.launchpad.net/ubuntu/+source/libgcrypt11/+bug/1105758 にもパッチを投げておきましたので、これを機に処理が見直され、早急にlibgcrypt11:i386が正しく修正されることを望みます。
というようなことを
https://productforums.google.com/forum/#!category-topic/chrome-ja/%E5%95%8F%E9%A1%8C%E3%81%AE%E5%A0%B1%E5%91%8A/w4pP0DQ75Dw や
http://code.google.com/p/chromium/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Pri%20Mstone%20ReleaseBlock%20OS%20Area%20Feature%20Status%20Owner%20Summary&groupby=&sort=&id=124990
にも報告しておこうと思います。
オフライン
2. パッチを書きました。
パッチの件について gcrypt-devel ML ( http://lists.gnupg.org/mailman/listinfo/gcrypt-devel ) で、この修正は正しくない、と指摘されました。
# define aesni_cleanup() \
do { asm volatile ("pxor %%xmm0, %%xmm0\n\t" \
"pxor %%xmm1, %%xmm1\n\t" :: ); \
} while (0)
のpxorの箇所を私はMMX命令の呼び出しとみて、EMMS命令の呼び忘れかと思いパッチを書いたのですが、これはMMX命令ではなくSSE2の命令だとのことです。
SSE2をサポートしていない古いCPU(Pentium II やIII)でMMX命令と解釈されてx87 FPUレジスタが使われてしまうそうです。
正しいpatchがML上に流れたので、そのうちパッケージが更新されると思います。私のように古いPCを動かしている方はもうしばらくお待ちください。
またはソースにパッチを当てるかですね。
オフライン
MLでパッチが公開されましたので、問題が起きていて急いでlibgcrypt-1.5.0を更新したい人向けにパッチ適用の方法を公開しておきます。
(Xubuntu 12.10 で動作確認済みです。)
この情報を必要としている人がどれだけいるのか不明ですがご参考ということで。
1. ソースを入手
$ apt-get -b source libgcrypt11
NOTE: このとき追加のパッケージを要求され、エラーが出るかもしれない。そのときは指示に従う。
ex) $ sudo apt-get install dpkg-dev
$ sudo apt-get install debhelper texlive-latex-base texlive-generic-recommended texinfo cdbs libgpg-error-dev autotools-dev
$ cd libgcrypt11-1.5.0
2. パッチを入手
2.1. ブラウザで http://marc.info/?l=gcrypt-devel&m=135944673925649&w=2 にアクセス。
2.2. エディッタを起動
$vi mail.patch
2.3. メールメッセージ全文をcopy&paste
2.4. 保存
NOTE: このとき横着してwgetでpatchを得ようとしてはいけない。
(誤ったパッチが生成される。)
3. パッチを適用
$ cd libgcrypt11-1.5.0
$ patch -p1 -b <mail.patch
4. 更新を確認
$ diff cipher/rijndael.c.orig cipher/rijndael.c | less
5. ビルド
$ make
6. テスト
$ make check
$ echo $?
0
7. インストール
$ sudo make install
$ sudo ldconfig
8. 問題の起きていたアプリケーションをテスト
ex) $ chromium-browser --password-store=gnome
以上です。
オフライン
http://www.ring.gr.jp/pub/net/gnupg/libgcrypt/ にアクセスしてlibgcrypt-1.4.6.tar.gzとlibgcrypt-1.5.0.tar.gzをダウンロードしてソースを見比べてみました。
問題のマクロaesni_cleanup()は1.4.6には定義されておらず、1.5でエンバグしたのだと思われます。
https://bugs.launchpad.net/ubuntu/+source/libgcrypt11/+bugs を見るに
Raring (1.5.0-3ubuntu2.1): main/libs
Lucid-updates (1.4.4-5ubuntu2.1): main/libs
Precise-updates (1.5.0-3ubuntu0.1): main/libs
Oneiric-proposed (1.5.0-1ubuntu0.1): main/libs
Quantal (1.5.0-3ubuntu1): main/libs
Precise (1.5.0-3): main/libs
Oneiric (1.5.0-1): main/libs
Lucid (1.4.4-5ubuntu2): main/libs
Hardy (1.2.4-2ubuntu7): main/libs
とありますので、1.5系列のlibgcryptを使っているUbuntuに影響が出るはずです。(特にPentium II&IIIマシンに)
https://bugs.launchpad.net/ubuntu/+source/libgcrypt11/+bug/1105758 は「In Progress」にステータスが変わりました。
オフライン
https://bugs.launchpad.net/ubuntu/+source/libgcrypt11/+bug/1105758/comments/4
によれば、「This included in Debian's 1.5.0-5.」とのこのなので、まもなく、正式な修正が入るものと思われます。
また、 http://lists.gnupg.org/pipermail/gcrypt-devel/2013-March/002109.html によれば「Libgcrypt 1.5.1 released」とのことなので、この問題はまもなく正式に解決することになると思います。
オフライン