組込みもセキュリティが重要とのことで、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
バックトレースが表示されたりするともっとうれしいかも