いけむランド

はてダからやってきました

gcc4 on cygwin

gcc-4.3.2 が試験的にとはいえ、リリースされたということで新 (というか BINARY HACKS で紹介されている) 機能が使えるかどうか試してみる。

ftrapv

コンパイル時にオプション -ftrapv を指定すると、符号付整数演算をしている箇所にオーバーフローが発生した場合に abort(3) する処理を挿入する。

実際に機能するかどうかを確認するために以下のようなサンプルをコンパイル→実行してみる。機能しているならば add の中で abort が呼ばれるはず。

#include <stdio.h>
#include <limits.h>

int add(int a, int b)
{
  return a + b;
}

int main(int argc, char** argv)
{
  printf("%d\n", add(INT_MAX, INT_MAX));
}
% gcc-4 -g -ftrapv ftrapv.c -o ftrapv.exe
% ./ftrapv.exe 
Segmentation fault (core dumped)
%


abort するどころかセグった。gdb で調べる。

% gdb ./ftrapv.exe
GNU gdb 6.8.0.20080328-cvs (cygwin-special)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-cygwin"...
(gdb) run
Starting program: /cygdrive/c/home/ftrapv.exe 
[New thread 3752.0xf0c]
[New thread 3752.0xf60]

Program received signal SIGSEGV, Segmentation fault.
[Switching to thread 3752.0xf60]
0x61016583 in stack_info::walk () from /usr/bin/cygwin1.dll
(gdb) info threads
* 2 thread 3752.0xf60  0x61016583 in stack_info::walk ()
   from /usr/bin/cygwin1.dll
  1 thread 3752.0xf0c  0x7c94e4f4 in ntdll!LdrAccessResource ()
   from /cygdrive/c/WINDOWS/system32/ntdll.dll
warning: Couldn't restore frame in current thread, at frame 0
0x7c812aeb in RaiseException () from /cygdrive/c/WINDOWS/system32/kernel32.dll
(gdb) where
#0  0x7c812aeb in RaiseException ()
   from /cygdrive/c/WINDOWS/system32/kernel32.dll
#1  0x7c85acd0 in OutputDebugStringA ()
   from /cygdrive/c/WINDOWS/system32/kernel32.dll
#2  0x40010006 in ?? ()
#3  0x00000000 in ?? ()
(gdb) thread 1
[Switching to thread 1 (thread 3752.0xf0c)]#0  0x7c94e4f4 in ntdll!LdrAccessResource () from /cygdrive/c/WINDOWS/system32/ntdll.dll
(gdb) where
#0  0x7c94e4f4 in ntdll!LdrAccessResource ()
   from /cygdrive/c/WINDOWS/system32/ntdll.dll
#1  0x7c94df3c in ntdll!ZwWaitForSingleObject ()
   from /cygdrive/c/WINDOWS/system32/ntdll.dll
#2  0x7c8025db in WaitForSingleObjectEx ()
   from /cygdrive/c/WINDOWS/system32/kernel32.dll
#3  0x00000718 in ?? ()
#4  0x00000000 in ?? ()
(gdb) 


なんか cygwin1.dll の中で落ちてる。ちなみに gcc-3 でも同じようにセグることから、(残念なことに) もともときちんと移植されていなかったことがわかる。

ちなみに abort 自体はきちんと呼ばれている。どうも cygwin だと、それ以降も動いて cygwin1.dll まで進んでしまうということだろう。

% gdb ./ftrapv.exe
GNU gdb 6.8.0.20080328-cvs (cygwin-special)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-cygwin"...
(gdb) break abort
Breakpoint 1 at 0x401210
(gdb) run
Starting program: /cygdrive/c/home/ftrapv.exe 
[New thread 2052.0xedc]
[New thread 2052.0x594]

Breakpoint 1, 0x00401210 in abort ()
(gdb) where
#0  0x00401210 in abort ()
#1  0x0040118c in __addvsi3 (a=2147483647, b=2147483647)
    at /gnu/gcc/release/gcc4-4.3.2-1/src/gcc-4.3.2/libgcc/../gcc/libgcc2.c:90
#2  0x00401118 in add (a=2147483647, b=2147483647) at ftrapv.c:6
#3  0x00401144 in main () at ftrapv.c:11
(gdb) 

Mudflap

Mudflap は動的にメモリの不正を検出できる機能である。この機能を使うには

  • オプション -fmudflap
  • リンク時にはリンクオプション -lmudflap

を指定する。

% gcc-4 -fmudflap mudflap.c -o mudflap.exe -lmudflap
cc1: error: mf-runtime.h: No such file or directory
%


主要な Linux ディストリビューションの場合は mf-runtime.h がない時は libmudflap-devel パッケージに含まれていることが多いが、cygwin ではそのようなものはない。

たしか cygwin の場合は gcc の configure で mudflap 機能は無効にされていたような気もするが、いずれにせよ、試せないようである。

Automatic Fortification

プロプロセッサマクロ _FORTIFY_SOURCE を指定することでバッファオーバーフローコンパイル時および実行時に検出することができる。

実際に機能するかどうかを確認するために以下のようなサンプルをコンパイル→実行してみる。機能しているならばメッセージが出力されるはずである。

#include <string.h>

char buf[6];

int main(int argc, char** argv)
{
  strcpy(buf, argv[1]);
  strcpy(buf, "Hello!")
  return 0;
}
% gcc-4 -O1 -D_FORTIFY_SOURCE=1 fortify.c -o fortify.exe
% ./fortify.exe 1
% ./fortify.exe 1234567
%


コンパイルしても実行しても、明らかにメモリを破壊しているにもかかわらず何も表示されない。

たしかに stdio.h などの標準ヘッダは gcc-3 のもので _FORTIFY_SOURCE を定義しておいてもセキュアな *_chk 関数群に置換されないし、*_chk は libc に含まれているらしいから、cygwin でこの機能を使えるようになる可能性は低そう。

SSP

SSP はスタックオーバーフローを検出する機能である。この機能を使うにはオプション -fstack-protector を指定する。

int main(int argc, char** argv)
{
  char buf[6];
  char *s = argv[1], *d = buf;
  while (*s) *d++=*s++;
  return 0;
}
% gcc-4 -fstack-protector ssp.c -o ssp.exe
% ./ssp.exe 1234567
%


Automatic Fortification と同様に何も表示されない。

BINARY HACKS によると __stack_chk_fail という関数が挿入されると書いてあるため、-S でアセンブリコードを吐いてみたが、オプションがあっても、この関数は挿入されていなかったことから、この機能も cygwin では無効になっている可能性が高い。

まとめ

結局、cygwin では gcc から提供されている数々の素敵なデバッグ機能はほぼ使い物にならないという結論が出てしまった。(´・ω・`)