4

通常のコードがオーバーフローする可能性があることはわかっています。

文字列[9];

scanf("%s", 文字列)。

しかし、scanf("%8s", string) をオーバーフローさせることは可能ですか? 8はほんの一例です。

「%8s」が区切りのように機能することは知っていますが、8 文字を超える文字列を入力すると、次の理由でプログラムが終了することにも気付きました。

* スタック破壊が検出されました * : ./a.out が終了しました

======= バックトレース: =========

...

明らかに、GCC によってデフォルトでオンになっているスタック破壊を検出するフラグがあります。これはスタック破壊であるため、オーバーフローして任意のコードを実行する可能性はまだあると思います。

scanf("%s") の呼び出し元を台無しにする通常のオーバーフローとは対照的に、scanf("%8s") がオーバーフローする可能性がある場合は、scanf 関数内でオーバーフローするため、scanf が戻ろうとすると制御が取得されます。

しかし、scanf はモード切り替え (ユーザー モードからカーネル モードへの切り替え) を必要とする syscall であり、内部的には標準入力への読み取りなどを呼び出します。そのため、カーネル モードなどでオーバーフローする可能性があるかどうかはわかりません。

コメント大歓迎です!!

更新 >>

上記の例では、char string[9] が想定されています。次の実際のコードの char string[8]。

問題は、スタック破壊による安全な scanf("%8s") と GCC の中止の間の矛盾するように見える話についてです。

簡略化されたコード:

void foo(pass some pointer) {
char input[8];
int input_number = 0;

while (1) { // looping console
   printf some info;
   scanf("%8s", input);

   input_number = atoi(input);

   if ((strlen(input) == 1) && (strncmp(input, "q", 1) == 0)) {
       input_number = -1;
   }
   switch (input_number) {
       case -1: to quit the console if input = 'q';
       default: to print info that pointer refers to;
       ...
   } 

}

}

ノート:

  1. foo は他の誰かによって呼び出されます。
  2. string は実際のコードでは "%8s" で 8 バイトですが、これがスマッシングにつながることはないと思います。
4

4 に答える 4

9

http://www.opengroup.org/onlinepubs/009695399/functions/scanf.htmlを参照してください。

各ディレクティブは、次のいずれかで構成されます...最大フィールド幅を指定するオプションのゼロ以外の 10 進整数。


空白文字ではない一連のバイトに一致します。アプリケーションは、対応する引数が、char、signed char、または unsigned char の配列の最初のバイトへのポインタであることを保証しなければなりません。これは、シーケンスと、自動的に追加される終端の null 文字コードを受け入れるのに十分な大きさです。

したがって、9 バイトの文字列バッファーをオーバーフローすることはありません。

于 2009-11-24T05:21:21.600 に答える
3

入力を堅牢にしたい場合は、絶対使用しないでください。scanffscanf

fgets(または同様に「バッファオーバーフローから保護された」バリアント)を使用してから、それを使用する必要sscanfがあります。

との主な問題はscanffscanf行が予期された形式でない場合 (つまり、 がscanf失敗した場合)、ファイル ポインタが不確定な位置になる可能性があることです。この方法を使用すると、ファイルを使用したり移動したりするfgets/sscanfことなく、行の境界にいることを保証するのがはるかに簡単になります。ftellfseek

バッファがオーバーフローするかどうかに関する特定のクエリに関して、C 標準には次のように記載されています。

...対応する引数は、シーケンスを受け入れるのに十分な大きさの文字配列の最初の要素へのポインタと、自動的に追加される終端のヌル文字でなければなりません。

したがって、"%8s"フォーマットには 9 文字の配列が必要です。

コードに他の問題があると思われます。テスト プログラムの場合:

#include <stdio.h>
int main(int argc, char* argv[]) {
    char x1;
    char a[9];
    char x2;
    x1 = x2 = ' ';
    scanf ("%s",a);
    printf ("[%c] [%s] [%c]\n",x1,a,x2);
    return 0;
}

私は得る:

pax> ./qq.exe
dfjdhadgha...lghjdfgjhd
[s] [dfjdhadgha...lghjdfgjhd] [ ]
  6 [main] qq 4744 _cygtls::handle_exceptions: Error while dumping state
  (probably corrupted stack)
  Segmentation fault (core dumped)

同じプログラムを use に変更すると"%8s"、(まったく同じ入力に対して)次のようになります。

pax> ./qq.exe
dfjdhadgha...lghjdfgjhd
[ ] [dfjdhadg] [ ]
于 2009-11-24T05:19:58.310 に答える
1

文字列が8チャーター未満に割り当てられている場合、それは確かにバッファーを上書きし、scanfはnullターミネーターを追加しません。ただし、文字列に値を入力するのに十分なスペースがある限り、上書きされないようにする必要があります。

于 2009-11-24T05:13:15.610 に答える
1

ysth が指摘したように、配列には文字列終端のヌル文字を含めることができる必要があるため、8 バイト配列を使用すると (特にコード内のようにスタックに割り当てられている場合)、混乱する可能性が非常に高くなります。上。

于 2009-11-24T06:14:09.340 に答える