Recommended
PDF
Intel AVX-512/富岳SVE用SIMDコード生成ライブラリsimdgen
PDF
Intro to SVE 富岳のA64FXを触ってみた
PPTX
PDF
PDF
PDF
PPTX
PDF
PDF
PDF
PDF
Wavelet matrix implementation
PDF
汎用性と高速性を目指したペアリング暗号ライブラリ mcl
PDF
WASM(WebAssembly)入門 ペアリング演算やってみた
PDF
PDF
PDF
PDF
PDF
PDF
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
KEY
関東GPGPU勉強会 LLVM meets GPU
PDF
本当にわかる Spectre と Meltdown
PDF
PPTX
PPT
PDF
Cプログラマのためのカッコつけないプログラミングの勧め
PDF
Effective Modern C++ 読書会 Item 35
PDF
PDF
PDF
PDF
リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー
More Related Content
PDF
Intel AVX-512/富岳SVE用SIMDコード生成ライブラリsimdgen
PDF
Intro to SVE 富岳のA64FXを触ってみた
PPTX
PDF
PDF
PDF
PPTX
PDF
What's hot
PDF
PDF
PDF
Wavelet matrix implementation
PDF
汎用性と高速性を目指したペアリング暗号ライブラリ mcl
PDF
WASM(WebAssembly)入門 ペアリング演算やってみた
PDF
PDF
PDF
PDF
PDF
PDF
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
KEY
関東GPGPU勉強会 LLVM meets GPU
PDF
本当にわかる Spectre と Meltdown
PDF
PPTX
PPT
PDF
Cプログラマのためのカッコつけないプログラミングの勧め
PDF
Effective Modern C++ 読書会 Item 35
PDF
PDF
Similar to ゆるバグ
PDF
PDF
リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー
PDF
KEY
PPTX
センパイ!このプログラムクラッシュするんですけど。。。
PDF
PDF
PDF
【学習メモ#3rd】12ステップで作る組込みOS自作入門
PPTX
PDF
PDF
PDF
PDF
ODP
PDF
PDF
PDF
StackExchangeで見たシステムプログラミング案件
PDF
PDF
CLRの基礎 - プログラミング .NET Framework 第3版 読書会
PDF
More from MITSUNARI Shigeo
PDF
PDF
PDF
PDF
PDF
PDF
PDF
PDF
PDF
PDF
PDF
PDF
PDF
深層学習フレームワークにおけるIntel CPU/富岳向け最適化法
PDF
PDF
PDF
Lifted-ElGamal暗号を用いた任意関数演算の二者間秘密計算プロトコルのmaliciousモデルにおける効率化
PDF
PDF
PDF
ElGamal型暗号文に対する任意関数演算・再暗号化の二者間秘密計算プロトコルとその応用
PDF
ゆるバグ 1. 2. • Windows Xpのバグ
• gdbのバグ
• objdumpのバグ
• Windowsのstackの仕様
• Linux on Travis-CIでだけエラー
• inline化される?
• Visual Studioのバグ
• PHPのバグ
遭遇したもの
2 / 36
3. • 発端
• 当時(2001) Windows 2000でとあるコーデックを開発中
• ソースコードのインデントがおかしかったのでツールで整形
• 一部手動でスペースをタブに変換するなど
• コーデック自体の挙動が変わるはずはない
• しかし
• 実行するとWindows 2000が突如再起動
• ???
• Windows 98みたいにすぐ落ちることはあまりないんだけど
• もう一度試してもやっぱり再起動
• 整形までだとちゃんと動く
• ???
整形したらえらいことになった
3 / 36
4. 5. • 文字を出力するだけ
• 後にループしなくてもOKと判明
• 発売直前の(開発用)Windows Xpでも発生
• こんなのでOSが落ちるの?
コード最小化
#include <stdio.h>
int main(void)
{
for (;;) {
printf("hung up¥t¥t¥b¥b¥b¥b¥b¥b");
}
return 0;
}
5 / 36
6. • ML(メーリングリスト) ; 今のTwitterみたいなもの
• fj.os.ms-windows.programming
• https://groups.google.com/forum/#!msg/fj.os.ms-
windows.programming/0c2WdfjwK4Q/fC7sHDh2jkgJ
• omp.os.ms-windows.programmer.win32
• https://groups.google.com/forum/#!msg/comp.os.ms-
windows.programmer.win32/uZd_19YEdRM/JXBR0FTsV2sJ
• 反応
• this is not just a joke
• NT4でも落ちた
• printf("¥t¥b¥b");だけでも落ちた
• Perlでも落ちた / ○○でも落ちた / 言語に依らない
• 実は結構なセキュリティホールだったかも
fjなどのニュースグループに投稿
6 / 36
7. • よくある日常
• あるプログラムが落ちたのでデバッグしようとgdb上で起動
• まずはrで実行して落ちたところでバックトレース(bt)
• あれ、Command not foundって何?
• よくみるとコマンドプロンプトに戻ってる
いつもと違うgdb
% gdb ./a.out
GNU gdb (GDB) 7.7
Copyright (C) 2014 Free Software Foundation, Inc.
...
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...Segmentation fault (core dumped)
% r
r: Command not found.
% bt
bt: Command not found.
%
7 / 36
8. • 再掲
• dmesgを見てみる
よく見ると落ちているのはgdb
Reading symbols from
./a.out...Segmentation fault (core dumped)
% dmesg | tail
[8895844.655909] gdb[18402]: segfault at 7ffc284a1ff8
ip 0000000000741fc7 sp 00007ffc284a1fc0 error 6 in
gdb[400000+5a0000]
8 / 36
9. 10. • 中身に意味はないがgdb 7.7が落ちるコード
削られたコード
#include <utility>
#include <stdio.h>
struct BaseHolder { };
template<class Func>
struct Holder : public BaseHolder {
Func func;
explicit Holder(Func&& func):func(std::forward<Func>(func)) {}
};
struct Runner {
BaseHolder *holder_;
template<class Func>
explicit Runner(Func && func):holder_(new Holder<Func>(func)) {}
~Runner() { delete holder_; }
};
template<class T>void f(T &) {
auto g =[&](){};
Runner{g};
}
int main() {
int a = 0;
f(a);
}
10 / 36
11. 12. 13. • 原因判明
• 同じバイト列なのに逆アセンブル結果が違う
• vcvtpd2dqxとvcvtpd2dq / vcvtpd2dqyとvcvtpd2dq
• 途中に(Z)のバイト列が入るとそのあと間違えるバグ
• 逆アセンブラが状態を持つとは思わなかった
時々間違えるobjdump (2.3.0)
% objdump -M x86-64 -D -b binary -m i386 vcvtpd2dq.bin
vcvtpd2dq.bin: file format binary
Disassembly of section .data:
00000000 <.data>:
0: 67 c5 fb e6 40 20 vcvtpd2dqx 0x20(%eax),%xmm0 ; (X)
6: 67 c5 ff e6 40 20 vcvtpd2dqy 0x20(%eax),%xmm0 ; (Y)
c: 67 62 f1 ff 18 e6 40 vcvtpd2dq 0x20(%eax){1to2},%xmm0 ; (Z)
13: 04
14: 67 c5 fb e6 40 20 vcvtpd2dq 0x20(%eax),%xmm0 ; (X')
1a: 67 c5 ff e6 40 20 vcvtpd2dq 0x20(%eax),%xmm0 ; (Y')
13 / 36
14. 15. 16. 17. 18. • 関数のプロローグ
• 元のコードが時々落ちていたのは
• 普段は他のコードがスタックを利用してスタック領域が伸び
ていた大丈夫
• 通常と異なるパスでスタックがあまり伸びてないときに突入
• 落ちる
専用の関数__chkstkがある
foo:
mov [rsp+8], ecx
mov eax, STACK_SIZE
call __chkstk
sub rsp, rax
...
18 / 36
19. 20. 21. • 何かのツールがchar [][8]のパースに失敗してる?
• でもなんで??? 詳しい人プリーズ
違い
// bls.cgo1.goのOKなとき
v := (_Cfunc_blsFunc)((*[8] _Ctype_char)(unsafe.Pointer(&buf[0])))
// ERRなとき
v := func() _Ctype_int{
_cgoIndex0 := &buf;
_cgo0 := (*[8]_Ctype_char)(unsafe.Pointer(&(*_cgoIndex0)[0]));
_cgoCheckPointer(_cgo0, *_cgoIndex0); ...
}()
// bls.cgo2.cのOKなとき
_cgo_..._Cfunc_blsFunc(void *v) {
struct { __typeof__(char const[8])* p0; ...
// ERRなとき
_cgo_..._Cfunc_blsFunc(void *v) {
struct { void* p0; ...
21 / 36
22. • gccのバージョンを上げたらある処理が4倍遅くなった
• gccが生成する関数のそれぞれのasm出力は問題なさそう
• バージョンが変わっても大差ない
• 謎のベンチマーク挙動
• ベンチマークの後ろに
exit()を挿入すると速度が変わる
• 挿入箇所と効果の関係は?
• (B)でexitすると遅いまま
• (C)でexitすると速い
• (D)でexitすると(C)より少し遅い
• (E)でexitすると(C)よりもう少し遅い
おかしな因果関係?
void bench() {
(A)ベンチマークコード
// (B)
}
int main() {
bench();
// (C)
unitTest1();
// (D)
unitTest2();
// (E)
unitTest3();
}
22 / 36
23. • gccはinline対象関数の総量を管理している
• --param max-inline-insns-single=N オプション
• この範囲内でinline化する関数を選んでいる
• 原因判明
• gccのバージョンが上がってinline対象となる関数が増えた
• bench内の関数がinline対象外となり遅くなった
• 単体でみるとそれは分からない
• exitすると速くなったり遅くなったりした理由
• mainの途中でexitした後のコードは生成されない
• inline対象が減るのでbenchがinline化されて速くなる
• bench内でexitしてもmain内でのinline対象は減らなかった
• benchは速くならない
• -Winlineで該当関数がinlineされているか確認
inlineされるかされないか
23 / 36
24. • Visual Studioでsinやexpが遅くなる現象
• 理由がさっぱり分からない
• とても苦労して見つけた再現コード
• struct A notUsedを作るとmainの中のsin等が遅くなる
• ループ回数の8を7にすると遅くならない
何故か遅くなる数学関数
const struct A {
float a[8];
A() {
const float x = log(2.0);
for (int i = 0; i < 8; i++) a[i] = x;
}
} notUsed;
int main() {
...
}
24 / 36
25. 26. • レジスタの形
• SSEは128bitレジスタxmm
• AVXは256bitレジスタymm
• ymmの下位128bitがxmmレジスタ
• SSEの命令padddはxmmレジスタ同士の足し算
• AVXの命令vpadddはymmレジスタ同士の足し算
• SSE命令はymmの上位128bitの存在を知らない
• その部分(d7:d6:d5:d4)は変更されない
SSEとAVX
xmm0 [d3:d2:d1:d0] ; diは32bit
ymm0 [d7:d6:d5:d4:d3:d2:d1:d0]
26 / 36
27. 28. 29. 30. • Intelシステムプログラミングガイド
• Performance Monitoring Events
• C1H:08H ; OTHER_ASSISTS.AVX_TO_SSE
• CPU内でAVX→SSEでペナルティを受けた回数を記録してる
• perf stat -e r08c1 -e r10c1 ./実行ファイル
• perfが動かない場合(VM上など)はsdeを使う
• https://software.intel.com/en-us/articles/intel-software-development-emulator
• sde -oast out.txt -- ./実行ファイル
• # AVX_to_SSE_transition_instances: 10000005
perfやsdeによる検出方法
Ice Lakeでは無くなった
30 / 36
31. 32. • malloc/freeだけではない
• memalign, aligned_alloc, posix_memalignなど
• 偽陽性が高い?
• mallocしてないのにfreeに渡される知らないポインタ
• strdupもラップが必要だった
• -Dmalloc=my_malloc –Dfree=my_free ...
• 偽陽性消える
• 作業中にPHPのバグをいくつか見つける
• いろいろなmalloc/free
• Apache APR, MySQL由来のpstrdupなどの外部ライブラリ
• PHP内部のfree, interned_free, ...
• 整合性を保つよう調整
ラップが難しい(1/2)
32 / 36
33. • dlopen
• dlopenの中でもmalloc
• デバッグ用にfprintfするとfprintfで先にmallocされて順序が変
わる
• 戦略
• (コードレベルで)全てのmalloc, freeを置き換える
• LD_PRELOADで自前のmalloc/freeに置き換え
• これで普通のプログラムは落ちなくなった
• ASanで落ちていた(ASanの誤動作)の場所も判明
ラップが難しい(2/2)
33 / 36
34. • 泥臭い方法
• ASLRを無効化しておく
• sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"
• 実行
• おかしなfreeを受けたところでそのポインタを記録
• そのポインタをmallocした箇所でbreak & btで該当ソース
• 主な結論
• PHPのオプションのfast_shutdownが有効なときに
malloc/freeの不一致コードに突入
• コードがカオスなので修正時間は無い
• いくつかバグ報告したしまあいいか
• fast_shutdown=0で回避可能
当時の解決
34 / 36
35. • clang
• dlopenにRTLD_DEEPBINDをつけるとエラー
• 昔はこれで誤検知?
• typo発見 incompatibe → incompatible
• macOSのdlopenは最初からRTLD_DEEPBIND相当の挙動
• gccのdlopenにはこの制約はなさそう
最近のclang/gcc
shared library with RTLD_DEEPBIND flag which is
incompatibe with sanitizer runtime (see
https://github.com/google/sanitizers/issues/611 for
details).
35 / 36
36. • RTLD_DEEPBIND
• dlopenするライブラリのシンボルの参照領域を
グローバル領域よりも前に配置する
• 例
• RTLD_DEEPBINDなし ; clock()は123を返す
• RTLD_DEEPBINDあり ; clock()はオリジナルの値を返す
補足
main.c
h = dlopen("sub.so");
f = dlsym(h, "sub");
f();
sub.c // sub.so
void sub() {
int t = (int)clock();
printf("clock()=%d¥n", t);
}
pred.c // pred.so
clock_t clock() { return 123; }
LD_PRELOAD=./pred.so ./main
36 / 36