home > GCC 4.xのSSP (Stack Smashing Protector)をH8で使ってみる

GCC 4.xのSSP (Stack Smashing Protector)をH8で使ってみる

2007/01/27

はじめに

GCC 4.1以降、SSP (Stack Smashing Protector)が入っています。 (それより前は、パッチだった。)

組込みもセキュリティが重要とのことで、H8でSSPを試してみます。

ただし、攻撃の検知ではなく、"off-by-one"のようなバグを検知する例を示します。 (バグ退治にも有効そう。)


環境


テストプロ

ssp-h8-test.tbz2 をダウンロードします。 以下のコマンドで展開します。
$ 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;
}

SSPを使わない例 (-fstack-protector-allオプションを指定せず)

ビルド

$ 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と出るはずなのだが、バッファオーバーフローしたので化けている。

SSPを使ってみた例 (-fstack-protector-all オプションを指定)

ビルド

$ 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 →検知された!!

参:ssp.c の実装

gccに含まれるssp.cをいじったものです。
#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

感想

イイ!!かも

バックトレースが表示されたりするともっとうれしいかも


Shuji KUWAHARA
$Id: index.html 226 2007-03-24 17:47:09Z kuwa $