#author("2021-02-06T08:26:08+00:00","","") #author("2024-11-24T23:59:58+09:00","","") #topicpath ////////////////////////////////////////////////////////////////////////////// * 目次 [#d012f75f] #contents(); ////////////////////////////////////////////////////////////////////////////// * バッファオーバーフロー [#buffer-overflow] //============================================================================ ** -D_FORTIFY_SOURCE で検出する (GCC) [#fortify_source] - GCC の "Automatic Fortification" 機能を使って、バッファオーバーフローを起こしやすいとされている関数(gets, strcpy, memcpy など)の誤使用をコンパイル時・実行時に検出する //---------------------------------------------------------------------------- *** 使い方 [#fortify_source-usage] - 下記のオプションを付加してコンパイルする: -O1 以上 -D_FORTIFY_SOURCE=1 - これにより、次の2つのタイミングでバッファオーバーフローの検出が行われる: |~チェックするタイミング |~チェック内容 | |コンパイル時 |コンパイル時にチェック可能な明らかなバッファオーバーフロー | |実行時 |上記以外のバッファオーバーフロー | - チェックの強化 -D_FORTIFY_SOURCE=1 を -D_FORTIFY_SOURCE=2 にすると、より厳しくチェエクされるようになる。 -- 一例として、format-string bug がランタイムに検出されるようになる。 --- printf, vfprintf, syslog などの関数が "%n" を含むフォーマット文字列を引数に取って呼ばれると abort する。 //---------------------------------------------------------------------------- *** チェックされる関数の一覧 [#fortify_source-check-target] - 下記コマンドで一覧を取得出来る: $ grep -r "_chk" /usr/include/ | sed 's/.*\(__.*chk\).*/\1/' | sort | uniq //=============================================================================== ** Mudflap (GCC) [#mudflap] - Mudflap は -- GCC4 に新規実装されたデバッグ補助機能(よって、GCC4以上が動作する環境であれば、どこででも動く) -- C/C++ に対応している - 以下を検出出来る: -- バッファオーバーフロー -- メモリリーク -- ヌルポインタ参照 -- その他、ポインタの誤使用 //---------------------------------------------------------------------------- *** 使い方 [#mudflap-usage] + ビルド - ''-g'' ''-fmudflap'' を付与してコンパイルする -- マルチスレッドプログラムの場合は、''-fmudflapth'' を付与する - ''-lmudflap'' を付けてリンクする -- マルチスレッドプログラムの場合は、 ''-lmudflapth'' を付与する - ビルド時に "mf-runtime.h が見つからない" 、或いは "libmudflap が見つからない" とエラーが出る場合は、パッケージの追加が必要。 + 実行 -- 出来上がったプログラムを通常通り実行する。Mudflap によりチェックが行われ、エラーメッセージは stderr に出力される。 -- 一時的気に Mudflap を無効にしたい場合は、環境変数 MUDFLAP_OPTIONS を変更する $ MUDFLAP_OPTIONS="-mode-nop" <target-test-program> //============================================================================ ** -fstack-protector オプションによるスタックオーバーフローの検出 (GCC) [#SPP] - C/C++ コードを gcc のオプションとして ''-fstack-protector'' を付けてコンパイルすると、 SPP [stack-smashing protector] 機能が有効になり、スタックオーバーフローの検出が出来る。 - SPP によりバッファオーバーフローが検出されるのは、実行時。 - SPP によりバッファオーバーフローが検出されると、プログラムが abort する。 - SPP よって検出出来るのは、以下: -- バッファオーバーフローによるローカル変数(特にポインタ)の改竄 -- バッファオーバーフローによる return address や saved ebp の改竄 - SPP は、スタックレイアウトの調整を行い、通常の gcc でコンパイルされた場合とは異なるものにする。 - SPP と [[-D_FORTIFY_SOURCE=1>#fortify_source]] は併用しても構わない。 //============================================================================ ** AddressSanitizer でのバッファオーバーフローの検出 (clang) [#AddressSanitizer] - clang でコンパイルする際に、 "-g -fsanitize=address -fno-omit-frame-pointer" を付けることで、実行時にバッファオーバーフローを検査出来る。 ////////////////////////////////////////////////////////////////////////////// * メモリリーク [#memory-leak] //=============================================================================== ** valgrind [#valgrind] //------------------------------------------------------------------------------- *** 使い方 [#valgrind-usage] + ビルドする -- ''-g'' 又は ''--ggdb'' 付きにすること -- 最適化は最大でも -O1 までにしておくこと -- static link は避けること。これは、malloc などの関数を valgrind が置き換えられなくなる為。 + 下記コマンドで実行する $ valgrind --tool=memcheck --leak-check=yes <program-file-name> または $ valgrind --leak-check=full --leak-resolution=high --show-reachable=yes <program-file-name> //------------------------------------------------------------------------------- *** vgcore [#valgrind-vgcore] - coredump した場合、 vgcore.<PID> という名前でファイルを出力する。 - vgcore は、通常の core と同様、 gdb に読み込ませて解析に使用出来る。 //------------------------------------------------------------------------------- *** 特徴 [#valgrind-feature] - スレッドセーフである - プロセス全体の起動から終了までを調べることしか出来ないため、部分的な検査は面倒になる。 //------------------------------------------------------------------------------- *** valgrind で検出できないもの [#valgrind-undetect-errors] - valgrind はスタック上に確保されたメモリ、data/bas 領域のメモリの不正なアクセスは検出しない → [[4.6. Why doesn't Memcheck find the array overruns in this program?>http://valgrind.org/docs/manual/faq.html#faq.overruns]] -- これを検出するには、Mudflap を使う必要がある。 //=============================================================================== ** mtrace [#mtrace] //------------------------------------------------------------------------------- *** 使い方 [#mtrace-usage] + ヘッダをインクルードする #include <mcheck.h> + リークのテストを開始したい場所で ''mtrace()'' をコール + 終了したい場所で ''muntrace()'' をコールする + ''-g'' つきでコンパイル + 環境変数 ''MALLOC_TRACE'' を export する # export MALLOC_TRACE=<log-file-name> + プログラムを実行する - ${MALLOC_TRACE} に出力されたログの例 = Start @ /usr/lib/libstdc++.so.5:(_Znwj+0x2e)[0x400b22fe] + 0x8049a98 0x1 @ /usr/lib/libstdc++.so.5:(_Znwj+0x2e)[0x400b22fe] + 0x8049aa8 0x1 @ /usr/lib/libstdc++.so.5:(_ZdlPv+0x23)[0x400b0de3] - 0x8049aa8 @ /usr/lib/libstdc++.so.5:(_Znwj+0x2e)[0x400b22fe] + 0x8049ab8 0x64 = End ~ ここで、 + は new - は delete + 以下の環境変数を指定することでメモリ領域の破壊などについてはデバッグしやすくなるかもしれません。 export MALLOC_CHECK_=”値” 値は0〜3です。 MALLOC_CHECK_ = 0 何もしない MALLOC_CHECK_ = 1 標準エラー出力に診断メッセージ表示 MALLOC_CHECK_ = 2 abort MALLOC_CHECK_ = 3 1と2の両方 //------------------------------------------------------------------------------- *** 特徴 [#mtrace-feature] - スレッドセーフではない - ソース内でどこからどこの間でリークを調べたいかを指定できる //=============================================================================== ** 参考リンク [#links] - [[メモリーリークの検出:mtrace , valgrind>http://blogs.itmedia.co.jp/komata/2009/10/mtrace-valgrind.html]] - [[メモリーリーク調査方法>http://www.nianyan.net/library/memory.html]]