技術コラム集

メモリを壊してみましょう(1)

前回の連載中に「スタックアンダーフローというのは何ですか?」
という質問をもらったので、今回はそれから説明していくね。

スタックアンダーフローバッファ・オーバーフロー

前回の「スタックってなあに?」シリーズで説明したように、スタックオーバーフローとは、スタックメモリのサイズを超えてpushしてしまうことだったよね。
これに対しスタックアンダーフローは、

スタックが空の状態で、さらにPOPしようとした。

場合のことを指すことになる。

通常、C言語などの関数呼び出しに使われているスタック構造では、こういった状況は起こらないはずなんだ。
なぜなら、「スタックが空」というのは「タスクが関数を何も呼びだしていない状態」であり、
これをさらにPopさせる手段がないからなんだ。
もし起こるとすれば、言語処理系(コンパイラなど)に問題がある可能性が考えられる。

ただし、アセンブラ言語で書かれたプログラムなら起こりえるんだ。
これは言語として関数呼び出しの構造を持っていないため、
スタックのpush/pop制御をプログラマが意識して行う必要があるからなんだ。
アセンブラ言語については、またの機会で詳しく取り上げる予定だよ。

バッファ・オーバーフロー

「セキュリティホールが見つかりました」というニュースを耳にしたことがあると思うんだけど、知っているかな。
セキュリティホールとは、悪用される可能性のある「ソフトウエアの穴」が空いていることを言うんだ。

その中でも最も多いのが「バッファ・オーバーフロー」という類のもの。
バッファ・オーバーフローが発生すると、任意のコードを実行される恐れがあって、
非常に危険な脆弱性とされているんだ。

これはどういうものなのかわかるかな。
組込みにも非常に重要だから、簡単なコード例で説明するね。

バッファ・オーバーフロー
以下のソースコード(overflow1.c)を見てみよう。

overflow1.c ソースコード

このソースコードをLinuxでコンパイルして実行した結果が下のようになるよ。
$が、bashのプロンプトを示している。

ソースコード中では配列a[]に対しては何も操作していないにもかかわらず、
内容が書き換わってしまっているよね。
どうして、こんなことが起こったのだろうか?

原因は、配列b[]に対するstrcpy()なんだ。
b[]は8バイト分の領域として宣言されているけど、
strcpy()で「それを超える」16バイト分(15文字+終端文字'\0')の
書き込みをしているためにa[]の内容が侵害されてしまったんだ。

ここで新たな疑問が浮かんでくるね。
配列サイズを超えて書き込むのが良くないのはわかるけど、
なぜb[]の領域を超えて書き込みをしたら、a[]が壊れてしまうのだろうか?

メモリを壊してみましょう(2)へ続く

七の巻:スタックってなあに? 九の巻:コードが消える?-最適化の罠-

このページの上へ