2013-09-30 9 views
8

スタックスマッシングを検出するには、-fstack-protector-strong gccにオプションがあるためです。しかし、スタック・バッファ・オーバーフローを常に検出できるわけではありません。最初の関数funcでは、10文字以上の文字列を入力すると、プログラムがクラッシュするとは限りません。私の質問は、スタックバッファオーバーフローを検出する方法があるところです。GCCスタックバッファオーバーフローを検出する方法

void func() 
{ 
    char array[10]; 
    gets(array); 
} 

void func2() 
{ 
    char buffer[10]; 
    int n = sprintf(buffer, "%s", "abcdefghpapeas"); 
    printf("aaaa [%d], [%s]\n", n, buffer); 
} 

int main() 
{ 
    func(); 
    func2(); 
} 
+4

なぜC++の質問にタグを付けて、そのようなコードを書いていますか? –

+0

それを避けるのはもっと論理的ではないでしょうか?例えば、 'snprintf(buffer、sizeof(buffer)、"%s "、...)のように使用します。 – mvp

+2

バッファがオーバーフローしたかどうかを検出するのではなく、文字数を増やしてください。 –

答えて

6

オーバーフローを検出する検出が困難または非常に高価のどちらかである - あなたの毒を選びました。一言で言えば

、あなたはこの持っている:

char a,b; 
char *ptr=&a; 
ptr[1] = 0; 

が、これは技術的に合法である:関数に属するスタックに割り当てられたスペースがあります。それはちょうど非常に危険です。

したがって、解決策は、abの間にギャップを追加し、それをパターンで埋めることです。しかし、まあ、実際には上記のようにコードを書く人もいます。したがって、コンパイラはそれを検出する必要があります。

また、コードが実際に割り当てたすべてのバイトのビットマップを作成し、このマップに対してチェックするすべてのコードをインストルメントすることができます。非常に安全で、かなり遅く、あなたのメモリ使用量を膨らませます。ポジティブな面では、これを助けるツールがあります(Valgrindなど)。

私はどこに行くのですか?

結論:C言語では、言語とAPIがしばしば乱雑すぎるため、多くのメモリの問題を自動的に検出する良い方法はありません。解決策は、パラメータを厳密にチェックし、常に適切なものにチェックし、優れた単体テストカバレッジを持つヘルパ関数にコードを移動することです。

選択肢がある場合は、常にsnprintf()バージョンの機能を使用してください。古いコードで安全でないバージョンが使用されている場合は、変更してください。スタックバッファオーバーフローを検出する方法がある場合

+0

+1 '古いコードで安全でないバージョンが使用されている場合は、変更してください。' – Degustaf

2

あなたはValgrindの

と呼ばれるツールを使用することができ、スタック上の

http://valgrind.org/

+0

これは間違っています。 Valgrindは素晴らしいツールですが、スタックベースのバッファオーバーフローを検出しません**。こちらをご覧ください:http://stackoverflow.com/a/29842977/4467665 – thatWiseGuy

+0

住所は、より良い選択肢になります。スタックオーバーフローを行うことができます。 – yugr

+0

Valgrindはスタックオーバーフローを検出することができます。たとえば、 'スレッド#1のスタックオーバーフロー:スタックを伸ばすことはできません。 –

1

私の質問は、あなたがGCCを使用しているので、あなたがFORTIFY_SOURCESを使用することができます

void func() 
{ 
    char array[10]; 
    gets(array); 
} 

void func2() 
{ 
    char buffer[10]; 
    int n = sprintf(buffer, "%s", "abcdefghpapeas"); 
    printf("aaaa [%d], [%s]\n", n, buffer); 
} 

...です。

FORTIFY_SOURCEは、memcpy,strcpygetsなどのリスクの高い機能の「より安全な」バリアントを使用します。コンパイラは、宛先バッファサイズを推測できるときに、より安全なバリアントを使用します。コピーが宛先バッファ・サイズを超える場合、プログラムはabort()を呼び出します。コンパイラが宛先バッファサイズを推測できない場合、「より安全な」バリアントは使用されません。

テストのためにFORTIFY_SOURCEを無効にするには、プログラムを-U_FORTIFY_SOURCEまたは-D_FORTIFY_SOURCE=0でコンパイルする必要があります。


CスタンダードはISO/IEC TR 24731-1, Bounds Checking Interfacesでより安全です。適合プラットフォームでは、gets_ssprintf_sと呼ぶことができます。(文字列が常にNULLであることを保証するなど)一貫性のある戻り値(成功した場合は0、errno_tなど)を提供します。

残念ながら、gccとglibcはC標準に準拠していません。境界検査インターフェイスと呼ばれるUlrich Drepper(glibcの管理者の1人)は、"horribly inefficient BSD crap"の境界チェックインターフェイスと呼ばれ、決して追加されませんでした。うまくいけば、それは将来変化します。

0

最初にgetを使用しないでください。ほぼすべての人が、getで発生するすべてのセキュリティと信頼性の問題を認識しています。しかし、それは歴史的な理由からもここに含まれています。なぜなら、それは悪いプログラミングの非常に良い例だからです。コードですべての問題で

見てみましょう:

// Really bad code 
char line[100]; 
gets(line); 

メモリを上書きします100文字を超える文字列を境界チェックを行いません取得しますので。あなたが運が良ければ、プログラムはちょうどクラッシュするか、それは奇妙な動作を示すかもしれません。

get関数は非常に悪いので、GNU gccリンカーは使用されるたびに警告を出します。

/tmp/ccI5WJ5m.o(.text+0x24): In function `main': 
: warning: the `gets' function is dangerous and should not be used. 

配列がアサート

C/C++は、境界チェックを行いません

にアクセスし保護します。例えば

int data[10] 

i = 20 
data[20] = 100 //Memory Corruption 

使用assert関数上のコードのための

#include<assert.h> 


int data[10]; 
i=20 

assert((i >= 0) && (i < sizeof(data)/sizeof(data[0]))); // throws 

data[i] = 100 

アレイオーバーフローは、最も一般的なプログラミングエラーの一つであり、試してみて、見つけることが非常にイライラしています。このコードはそれらを排除するものではありませんが、問題を非常に簡単に見つけ出す方法で、バグのあるコードを早期に中断させます。

Snprintf(バッファ、sizeof(バッファ)、 "%s"、 "abcdefghpapeas")とvalgrind、GDBなどのツールを使用してください。

希望します。

関連する問題