플래그 GCC -fstack-protector 플래그는 스택 카나리아를 사용하여 스택 오버플로 보호를 허용합니다. 최근 몇 년 동안 이 플래그를 기본적으로 사용하는 것이 더욱 두드러졌습니다.
패키지가 -fstack-protector로 컴파일되고 프로그램에서 버퍼가 오버플로되면 다음과 같은 오류가 발생할 수 있습니다.
*** buffer overflow detected ***: /xxx/xxx terminated
그러나 이러한 오류 메시지에 대한 책임은 "누구"에게 있습니까? 이 메시지는 어디에 기록되나요? syslog 데몬이 이러한 메시지를 수집합니까?
답변1
스택 스매싱은 계측에 의해 수행되며 libssp
이는 의 일부입니다 gcc
. 그것매우 열심히 일한다메시지는 터미널에 출력되고 실패 시 시스템 로그에만 기록됩니다. 따라서 실제로는 데몬 로그와 GUI 응용 프로그램의 로그에서 버퍼 오버플로 메시지를 볼 수 있습니다.
메시지를 출력한 후에는 libssp
애플리케이션 충돌을 포함하여 다양한 종료 방법을 시도합니다. 이는 예외 종료 로거 중 하나에 의해 포착될 수 있지만 이것이 보장되지는 않습니다.
답변2
최신 Linux 배포판(예: CentOS/Fedora)에는 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에서 테스트되었습니다.)