スタックカナリア汚染はどのように記録されますか?


11

フラグGCC -fstack-protectorフラグは、スタックオーバーフロー保護のためのスタックカナリアの使用を有効にします。このフラグのデフォルトの使用は、近年顕著になっています。

パッケージが-fstack-protectorを使用してコンパイルされている場合、プログラムでバッファーをオーバーフローすると、次のようなエラーが発生する可能性があります。

*** buffer overflow detected ***: /xxx/xxx terminated

ただし、「誰」がこれらのエラーメッセージを担当していますか。これらのメッセージはどこに記録されますか?syslogデーモンはこれらのメッセージを選択しますか?

回答:


10

スタックのスマッシングはlibssp、の一部であるによって検出されgccます。それは非常に難しいしようとする端末に出力するメッセージを、そしてそれはそれは、システムログにログインしない障害が発生した場合にのみ-ので、実際にあなたがデーモンと、おそらくGUIアプリケーションのためにログにバッファオーバーフローのメッセージが表示されます。

メッセージが出力されるlibsspと、アプリケーションのクラッシュなど、さまざまな方法で終了を試みます。これは、異常終了ロガーの1つによってキャッチされる可能性がありますが、それは保証されていません。


1
この説明をさらに詳しく調べる方法として、具体的な例を挙げましょう。この例では、nginxを選択します。スタックカナリアを使用してnginxをコンパイルしました。nginxを実行すると、プロセスが開始されますが、シェルに何も出力されません。代わりに、メッセージは複数のログファイルに記録されます。nginxがスタックの破壊を検出した場合、nginxがlibssp使用するstderr出力によってメッセージを出力します。次に、libsspプロセス(またはnginxの子プロセス)を終了しようとする場合があります。アプリケーションをクラッシュさせる必要がない場合、異常終了ロガーはこれを選択しません。これは正しい解釈ですか?
aedcv 2017年

ない非常に-それがされます使用して、アプリケーションをクラッシュしようと__builtin_trap()、ステータス127で終了、セグメント違反を挑発しようとすると、それが失敗した後ならば、まず、それが失敗した場合にのみ
スティーブン・キット

メッセージ部分の印刷は、コアのyieldメソッド(例abort())を介した終了よりも成功を保証するものではありません。
maxschlepzig 2017年

7

CentOS / Fedoraのような最新のLinuxディストリビューションは、デフォルトでクラッシュ処理デーモン(systemd-coredumpまたはabortd)をセットアップします。

したがって、プログラムが異常な方法で終了すると(segfault、キャッチされない例外、アボート、不正な命令など)、このイベントはそのデーモンによって登録され、ログに記録されます。したがって、システムジャーナルにいくつかのメッセージが見つかり、さらに詳細(コアファイル、ログなど)を含むディレクトリへの参照が見つかることもあります。

$ cat test_stack_protector.c 
#include <string.h>

int f(const char *q)
{
  char s[10];
  strcpy(s, q);
  return s[0] + s[1];
}

int main(int argc, char **argv)
{
  return f(argv[1]);
}

コンパイル:

$ gcc -Wall -fstack-protector test_stack_protector.c -o test_stack_protector

実行:

$ ./test_stack_protector 'hello world'
*** stack smashing detected ***: ./test_stack_protector terminated
======= Backtrace: =========
/lib64/libc.so.6(+0x7c8dc)[0x7f885b4388dc]
/lib64/libc.so.6(__fortify_fail+0x37)[0x7f885b4dfaa7]
/lib64/libc.so.6(__fortify_fail+0x0)[0x7f885b4dfa70]
./test_stack_protector[0x400599]
./test_stack_protector[0x4005bd]
/lib64/libc.so.6(__libc_start_main+0xea)[0x7f885b3dc50a]
./test_stack_protector[0x40049a]
======= Memory map: ========
00400000-00401000 r-xp 00000000 00:28 1151979                            /home/juser/program/stackprotect/test_stack_protector
00600000-00601000 r--p 00000000 00:28 1151979                            /home/juser/program/stackprotect/test_stack_protector
00601000-00602000 rw-p 00001000 00:28 1151979                            /home/juser/program/stackprotect/test_stack_protector
0067c000-0069d000 rw-p 00000000 00:00 0                                  [heap]
7f885b1a5000-7f885b1bb000 r-xp 00000000 00:28 1052100                    /usr/lib64/libgcc_s-7-20170915.so.1
7f885b1bb000-7f885b3ba000 ---p 00016000 00:28 1052100                    /usr/lib64/libgcc_s-7-20170915.so.1
7f885b3ba000-7f885b3bb000 r--p 00015000 00:28 1052100                    /usr/lib64/libgcc_s-7-20170915.so.1
7f885b3bb000-7f885b3bc000 rw-p 00016000 00:28 1052100                    /usr/lib64/libgcc_s-7-20170915.so.1
7f885b3bc000-7f885b583000 r-xp 00000000 00:28 945348                     /usr/lib64/libc-2.25.so
7f885b583000-7f885b783000 ---p 001c7000 00:28 945348                     /usr/lib64/libc-2.25.so
7f885b783000-7f885b787000 r--p 001c7000 00:28 945348                     /usr/lib64/libc-2.25.so
7f885b787000-7f885b789000 rw-p 001cb000 00:28 945348                     /usr/lib64/libc-2.25.so
7f885b789000-7f885b78d000 rw-p 00000000 00:00 0 
7f885b78d000-7f885b7b4000 r-xp 00000000 00:28 945341                     /usr/lib64/ld-2.25.so
7f885b978000-7f885b97b000 rw-p 00000000 00:00 0 
7f885b9b0000-7f885b9b3000 rw-p 00000000 00:00 0 
7f885b9b3000-7f885b9b4000 r--p 00026000 00:28 945341                     /usr/lib64/ld-2.25.so
7f885b9b4000-7f885b9b6000 rw-p 00027000 00:28 945341                     /usr/lib64/ld-2.25.so
7ffc59966000-7ffc59987000 rw-p 00000000 00:00 0                          [stack]
7ffc5999c000-7ffc5999f000 r--p 00000000 00:00 0                          [vvar]
7ffc5999f000-7ffc599a1000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
zsh: abort (core dumped)  ./test_stack_protector 'hello world'

終了ステータスは134で、128 + 6、つまり128に打ち切りシグナル番号を加えたものです。

システムジャーナル:

Oct 16 20:57:59 example.org audit[17645]: ANOM_ABEND auid=1000 uid=1000 gid=1000 ses=3 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 pid=17645 comm="test_stack_prot" exe="/home/juser/program/stackprotect/test_stack_protector" sig=6 res=1
Oct 16 20:57:59 example.org systemd[1]: Started Process Core Dump (PID 17646/UID 0).
Oct 16 20:57:59 example.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=systemd-coredump@21-17646-0 comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
Oct 16 20:57:59 example.org systemd-coredump[17647]: Process 17645 (test_stack_prot) of user 1000 dumped core.

                           Stack trace of thread 17645:
                           #0  0x00007f885b3f269b raise (libc.so.6)
                           #1  0x00007f885b3f44a0 abort (libc.so.6)
                           #2  0x00007f885b4388e1 __libc_message (libc.so.6)
                           #3  0x00007f885b4dfaa7 __fortify_fail (libc.so.6)
                           #4  0x00007f885b4dfa70 __stack_chk_fail (libc.so.6)
                           #5  0x0000000000400599 f (test_stack_protector)
                           #6  0x00000000004005bd main (test_stack_protector)
                           #7  0x00007f885b3dc50a __libc_start_main (libc.so.6)
                           #8  0x000000000040049a _start (test_stack_protector)
Oct 16 20:57:59 example.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=systemd-coredump@21-17646-0 comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
Oct 16 20:58:00 example.org abrt-notification[17696]: Process 17645 (test_stack_protector) crashed in __fortify_fail()

手段は、あなたからログを取得することauditd、監査デーモンsystemd-coredumpクラッシュハンドラ。

クラッシュ処理デーモンが構成されているかどうかを確認するには、をチェックします/proc。例:

$ cat /proc/sys/kernel/core_pattern
|/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %e

(Fedora 26、x86-64でテスト済みのすべて)


1
この例を投稿できてとても嬉しいです。カナリアはgccによって配置されます。(私が間違っている場合は修正してください)私は何が起こるかと思います:gccはカナリア機能を実装するためにプログラムに「余分なコード」を入れます。実行中、および関数が戻る前に、値がチェックされます。汚染されている場合、プログラムは「スタックスマッシングが検出されました」というメッセージを出力し、エラーを発生させます。このエラーはOSによって検出され、セグメンテーションエラーを認識し、投稿したバックトレースとメモリマップを出力します。最後に、OSはアプリケーションを強制終了し、コアダンプを生成し、sysジャーナルにログを記録します
aedcv

@aedcv、これはほとんど話です-より正確abort()に言うと、アボート信号を生成するチェックコード呼び出しを破壊するスタック、つまり、進行中のセグメンテーションエラーはありません。中止/セグメンテーション違反などのデフォルトのシグナルハンドラーが同じアクションを生成するだけです。コアを書き込み、シグナル番号もエンコードする終了ステータスが等しくないゼロでプロセスを終了します。コアの書き込みはカーネルによって行われ、その動作はを介して構成可能/proc/.../core_patternです。上記の例では、ユーザー空間ヘルパーが構成され、呼び出されます。カーネルは監査もトリガーします。
maxschlepzig 2017年

@maxschlepzig完全ではありません。SSP abort()コードが使用します__builtin_trap()(ただし、効果は同じです)。
スティーブンキット

1
@StephenKitt、まあ、上の例のスタックトレースを見てください。そこに、どのようabort()に呼ばれるかがはっきりとわかります。
maxschlepzig

1
@maxschlepzigはい、もちろんですが、これは実装の詳細です(GCCコードは__builtin_trap()への明示的な依存関係を回避するために使用しますabort())。他のディストリビューションには異なるスタックトレースがあります。
スティーブンキット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.