組込みもセキュリティが重要とのことで、H8でSSPを試してみます。
ただし、攻撃の検知ではなく、"off-by-one"のようなバグを検知する例を示します。 (バグ退治にも有効そう。)
$ h8300-elf-gcc -v Using built-in specs. Target: h8300-elf Configured with: /home/kpit/fsfsrc/gcc-4.2-20060812/configure --build=i686-pc-linux-gnu --host=i386-pc-mingw32msvc --enable-languages=c,c++ --target=h8300-elf --with-newlib --prefix=/usr/share/mingwgnuh8300_v0603_elf-1 Thread model: single gcc version 4.2-GNUH8_v0603
$ tar jxvf ssp-h8-test.tbz2
以下は、main.cというファイルの中身です。
fooという関数の中でのstrcpyによりバッファオーバーフローが起きます。
#include <string.h> #include <stdio.h> #include "sci.h" void foo(void) { char buf[16]; strcpy(buf, "ABCDEFGHIJKLMNOPQ"); printf("DONE\n"); } int main(void) { SCIInit(1, SCI_57600); foo(); return 0; }
$ cd ssp-h8-test $ make clean all rm -f *.o *.d ssp-h8-test *.syms *.bin *.lst *.elf *.mot *.map h8300-elf-gcc -DCPU_HZ=20 -I. -mh -mint32 -mrelax -c -pipe -O2 -Wall -g vector.S -o vector.o h8300-elf-gcc -DCPU_HZ=20 -I. -mh -mint32 -mrelax -c -pipe -O2 -Wall -g crt0.s -o crt0.o h8300-elf-gcc -DCPU_HZ=20 -I. -mh -mrelax -c -pipe -O2 -Wall -mint32 -g main.c -o main.o h8300-elf-gcc -DCPU_HZ=20 -I. -mh -mrelax -c -pipe -O2 -Wall -mint32 -g sci.c -o sci.o h8300-elf-gcc -DCPU_HZ=20 -I. -mh -mrelax -c -pipe -O2 -Wall -mint32 -g string.c -o string.o h8300-elf-gcc -DCPU_HZ=20 -I. -mh -mrelax -c -pipe -O2 -Wall -mint32 -g stdio.c -o stdio.o h8300-elf-gcc -mh -mint32 -mrelax -nostartfiles -Wl,-Map,ssp-h8-test.map -Wl,-T./aki-h8lan.x -nodefaultlibs -nostdlib -o ssp-h8-test.elf vector.o crt0.o main.o sci.o string.o stdio.o -lgcc -lc h8300-elf-objcopy -O srec -S ssp-h8-test.elf ssp-h8-test.mot h8300-elf-objcopy -O binary ssp-h8-test.elf ssp-h8-test.bin $
MONIX Ver.0.1 (Jan 25 2007, 19:56:00) BootMode: 0x00 1:tftp 192.168.0.2 ssp-h8-test.bin EtherInit DONE. Ethernet Address : 00:02:cb:01:55:b1 BOOTP DONE. my_ip=192.168.0.3, bootfile=, server_ip(BOOTP)=192.168.0.1 ==> my_ip=192.168.0.3, bootfile=ssp-h8-test.bin, server_ip(TFTP)=192.168.0.2, loadaddr=0x400000 TFTP Start...(11 blocks) DONE. 1:go vONE →DONEと出るはずなのだが、バッファオーバーフローしたので化けている。
$ cd ssp-h8-test $ make clean all DEFS="-DH8 -DCPU_HZ=20 -DSSP" rm -f *.o *.d ssp-h8-test *.syms *.bin *.lst *.elf *.mot *.map h8300-elf-gcc -DH8 -DCPU_HZ=20 -DSSP -I. -mh -mint32 -mrelax -c -pipe -O2 -Wall -g vector.S -o vector.o h8300-elf-gcc -DH8 -DCPU_HZ=20 -DSSP -I. -mh -mint32 -mrelax -c -pipe -O2 -Wall -g crt0.s -o crt0.o h8300-elf-gcc -DH8 -DCPU_HZ=20 -DSSP -I. -mh -mrelax -c -pipe -O2 -Wall -mint32 -g -fstack-protector-all main.c -o main.o h8300-elf-gcc -DH8 -DCPU_HZ=20 -DSSP -I. -mh -mrelax -c -pipe -O2 -Wall -mint32 -g -fstack-protector-all sci.c -o sci.o h8300-elf-gcc -DH8 -DCPU_HZ=20 -DSSP -I. -mh -mrelax -c -pipe -O2 -Wall -mint32 -g -fstack-protector-all string.c -o string.o h8300-elf-gcc -DH8 -DCPU_HZ=20 -DSSP -I. -mh -mrelax -c -pipe -O2 -Wall -mint32 -g -fstack-protector-all stdio.c -o stdio.o h8300-elf-gcc -DH8 -DCPU_HZ=20 -DSSP -I. -mh -mrelax -c -pipe -O2 -Wall -mint32 -g -fstack-protector-all ssp.c -o ssp.o h8300-elf-gcc -mh -mint32 -mrelax -nostartfiles -Wl,-Map,ssp-h8-test.map -Wl,-T./aki-h8lan.x -nodefaultlibs -nostdlib -o ssp-h8-test.elf vector.o crt0.o main.o sci.o string.o stdio.o ssp.o -lgcc -lc -lssp h8300-elf-objcopy -O srec -S ssp-h8-test.elf ssp-h8-test.mot h8300-elf-objcopy -O binary ssp-h8-test.elf ssp-h8-test.bin
MONIX Ver.0.1 (Jan 25 2007, 19:56:00) BootMode: 0x00 1:tftp 192.168.0.2 ssp-h8-test.bin EtherInit DONE. Ethernet Address : 00:02:cb:01:55:b1 BOOTP DONE. my_ip=192.168.0.3, bootfile=, server_ip(BOOTP)=192.168.0.1 ==> my_ip=192.168.0.3, bootfile=ssp-h8-test.bin, server_ip(TFTP)=192.168.0.2, loadaddr=0x400000 TFTP Start...(14 blocks) DONE. 1:go ハDONE *** stack smashing detected ***: terminated →検知された!!
#include <stdio.h> #include <stdlib.h> #include <string.h> static unsigned long next = 1; int rand(void) { return (int)((next = next * 1103515245 + 12345) % ((unsigned long)RAND_MAX + 1)); } void srand(unsigned int seed) { next = (unsigned long)seed; } void *__stack_chk_guard = 0; static void __attribute__ ((constructor)) __guard_setup (void) { unsigned char *p; if (__stack_chk_guard != 0) return; __stack_chk_guard = (void *)rand(); /* If a random generator can't be used, the protector switches the guard to the "terminator canary". */ p = (unsigned char *) &__stack_chk_guard; p[sizeof(__stack_chk_guard)-1] = 255; p[sizeof(__stack_chk_guard)-2] = '\n'; p[0] = 0; } static void fail (const char *msg1, size_t msg1len, const char *msg3) { #ifdef __GNU_LIBRARY__ extern char * __progname; #else static const char __progname[] = ""; #endif static const char msg2[] = " terminated\n"; size_t progname_len, len; char *buf, *p; int i; progname_len = strlen (__progname); len = msg1len + progname_len + sizeof(msg2)-1 + 1; p = buf = alloca (len); memcpy (p, msg1, msg1len); p += msg1len; memcpy (p, __progname, progname_len); p += progname_len; memcpy (p, msg2, sizeof(msg2)); for (i = 0; i < len; i++) putchar(buf[i]); for (;;) ; } void __stack_chk_fail (void) { const char *msg = "*** stack smashing detected ***: "; fail (msg, strlen (msg), "stack smashing detected: terminated"); } void __chk_fail (void) { const char *msg = "*** buffer overflow detected ***: "; fail (msg, strlen (msg), "buffer overflow detected: terminated"); } #ifdef HAVE_HIDDEN_VISIBILITY void __attribute__((visibility ("hidden"))) __stack_chk_fail_local (void) { __stack_chk_fail (); } #endif
バックトレースが表示されたりするともっとうれしいかも