Bagaimana tumpukan polusi kenari dicatat?

11

Bendera GCC -fstack-protector flag memungkinkan penggunaan stack canaries untuk perlindungan stack overflow. Penggunaan bendera ini secara default lebih menonjol dalam beberapa tahun terakhir.

Jika sebuah paket dikompilasi dengan -fstack-protector, dan kami meluap buffer dalam program, kami kemungkinan akan mendapatkan kesalahan seperti:

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

Namun, "siapa" yang bertanggung jawab atas pesan kesalahan ini? Di mana pesan-pesan ini dicatat? Apakah daemon syslog memilih pesan-pesan ini?

aedcv
sumber

Jawaban:

10

Stack smashing dideteksi oleh libssp, yang merupakan bagian dari gcc. Ia berusaha sangat keras untuk menampilkan pesan ke terminal, dan hanya jika itu gagal log ke log sistem - jadi dalam praktiknya Anda akan melihat pesan buffer overflow dalam log untuk daemon dan mungkin aplikasi GUI.

Setelah mengeluarkan pesannya, libsspcobalah berbagai cara untuk keluar, termasuk menghentikan aplikasi; ini mungkin ditangkap oleh salah satu penebang yang tidak normal, tetapi itu tidak dijamin.

Stephen Kitt
sumber
1
Izinkan saya mengajukan contoh konkret sebagai cara untuk lebih mengeksplorasi penjelasan ini. Mari kita pilih nginx untuk contoh ini. Saya telah mengompilasi nginx dengan stack canaries. Ketika saya menjalankan nginx, ia memulai suatu proses tetapi tidak menampilkan apa pun ke shell. Sebagai gantinya, semua pesan dicatat dalam banyak file lognya. Jika nginx mendeteksi stack smashing, libsspakan menampilkan pesannya dengan output stderr yang digunakan oleh nginx. Kemudian, libsspmungkin mencoba untuk keluar dari proses (atau proses anak untuk nginx). Jika itu "tidak perlu" crash aplikasi, maka keluar logger abnormal tidak akan mengambil ini. Apakah ini interpretasi yang benar?
aedcv
Tidak cukup - itu akan mencoba untuk crash aplikasi, menggunakan __builtin_trap()pertama, maka jika itu gagal, mencoba untuk memprovokasi pelanggaran segmen, dan hanya jika itu gagal, keluar dengan status 127.
Stephen Kitt
Pencetakan bagian pesan tidak menjamin kesuksesan yang lebih baik daripada jalan keluar melalui metode menghasilkan inti (mis abort().).
maxschlepzig
7

Distribusi Linux modern seperti CentOS / Fedora mengatur daemon penanganan gangguan (misalnya systemd-coredumpatau abortd), secara default.

Dengan demikian, ketika program Anda berakhir dengan cara yang tidak normal (segfault, pengecualian tanpa tertangkap, dibatalkan, instruksi ilegal dll.) Acara ini terdaftar dan dicatat oleh daemon itu. Dengan demikian, Anda menemukan beberapa pesan dalam jurnal sistem dan mungkin referensi ke direktori dengan beberapa detail tambahan (misalnya file inti, log, dll.).

Contoh

$ 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]);
}

Menyusun:

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

Menjalankan:

$ ./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'

Status keluar adalah 134 yaitu 128 + 6, yaitu 128 ditambah nomor sinyal batalkan.

Jurnal sistem:

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()

Itu berarti Anda mendapatkan log dari auditddaemon audit dan para systemd-coredumphandler kecelakaan.

Untuk memverifikasi apakah daemon penanganan gangguan dikonfigurasi, Anda dapat memeriksa /proc, misalnya:

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

(semuanya diuji pada Fedora 26, x86-64)

maxschlepzig
sumber
1
Saya sangat senang Anda memposting contoh ini. Canary ditempatkan oleh gcc. (Tolong perbaiki saya jika saya salah) Saya berasumsi bahwa yang terjadi adalah sesuatu seperti: gcc menempatkan "kode tambahan" dalam program untuk mengimplementasikan fungsi kenari; selama eksekusi, dan sebelum suatu fungsi kembali, nilainya diperiksa; jika di-pollut, program akan menampilkan pesan "stack smashing terdeteksi" dan memunculkan kesalahan. Kesalahan ini diambil oleh OS, mengenali kesalahan segmentasi dan mencetak backtrace dan peta memori yang Anda poskan. Terakhir, OS membunuh aplikasi, menghasilkan dump inti, dan mencatat jurnal sys
aedcv
@ aedcv, ini ceritanya - lebih tepatnya: stack smashing memeriksa kode panggilan abort()yang menghasilkan sinyal batalkan, yaitu tidak ada kesalahan segmentasi yang terjadi. Hanya saja penangan sinyal default untuk batalkan / segmentasi kesalahan dll menghasilkan tindakan yang sama: menulis inti dan keluar dari proses dengan status keluar nol tidak sama yang juga menyandikan nomor sinyal. Penulisan inti dilakukan oleh kernel dan perilakunya dapat dikonfigurasi melalui /proc/.../core_pattern. Dalam contoh di atas bantuan ruang pengguna dikonfigurasi dan dengan demikian disebut. Kernel juga memicu audit.
maxschlepzig
@maxschlepzig itu tidak cukup abort(), menggunakan kode SSP __builtin_trap()(tetapi efeknya sama).
Stephen Kitt
1
@StephenKitt, well, lihat jejak tumpukan pada contoh di atas. Di sana Anda melihat dengan jelas bagaimana abort()namanya.
maxschlepzig
1
@maxschlepzig ya, tentu saja, tapi itu detail implementasi (kode GCC digunakan __builtin_trap()untuk menghindari ketergantungan secara eksplisit pada abort()). Distribusi lain memiliki jejak tumpukan yang berbeda.
Stephen Kitt