コラム9.  バッファーオーバーフロー

バッファーオーバーフローとは何か?

アプリケーションソフトにセキュリティホールが見つかって、「悪意のあるコードが実行される可能性がある」というような内容のニュースを聞いたことがある人は少なくないでしょう。そもそも、この「悪意のあるコード」とは一体何なのでしょうか?

コンピュータウイルスやワーム、バックドア、キーロガーなどが代表的で、情報システムや提供するサービスの妨害など、悪影響を及ぼすコードが含まれるプログラムのことで、文字通りシステムに「害悪」をもたらすことを目的とした者によって作成されたプログラムのことです。

そしてそういった悪意のあるコードが、システムを攻撃する手段としてよく用いられるのが、この「バッファーオーバーフロー」という手法なのです。

バッファーとその仕組み

バッファーオーバーフローについて説明する前に、そもそも「バッファー」とは何かということから説明しましょう。

コンピュータのプログラムは、情報を格納するための領域をメモリ上に確保します。特に、文字情報を格納する場合、その文字数に応じて連続したメモリ領域を確保します。このように、同じ形式のデータを複数個格納するためにメモリ上に確保する領域のことをバッファ領域と言います。

バッファへの情報の格納方法としては、ネットワークからの入力、ファイルからの入力、キーボードなどの入力デバイスを介してのユーザーからの入力などがあります。

バッファオーバーフローの仕組み

しかし、言うまでもないことですがこのバッファーの容量には限界があります。バッファ領域の上限はプログラムが規定出来ても、プログラムを実行するCPUはバッファ領域の上限がわかりません。

そのため、情報をバッファ領域に格納する際、格納する情報の大きさがバッファ領域の上限を超えてしまうことがあります。すると、CPUはバッファ領域を超えて情報を格納してしまいます。これが、バッファーオバーフローです。

バッファオーバーフローが起こってしまうと、メモリ上の不正な場所に情報を格納することになってしまうため、プログラムが誤動作したり、ほかの領域に保存されている大事なデータを破壊してしまったりします。

バッファーオーバフローによるセキュリティーホール

クラッカーは、このバッファオーバーフローをわざと起こしてデータの改竄・コンピュータシステムの損壊につながる操作をおこなうことから、ソフトウェアでバッファオーバーフローの脆弱性が発見されると、高い優先度で修正が行われ、更新バージョンのプログラムや修正パッチの公開・配布などが行われます。

それだけ、バッファーオーバフローによる攻撃はやっかいなのです。

C言語とバッファーオーバーフロー

実はC言語は、このバッファーオーバフローが起こりやすい仕組みを持っている、という致命的な欠点を持っているのです。

例えば、C言語の標準入出力関数であるscanf関数やgets関数はバッファ長のチェックを行わないで標準入力をバッファに書き込むので、バッファーオーバーフローを起こしやすくなっています。

C言語の歴史はたいへん古く、インターネットが現在のように普及するはるか以前に作られた言語ですから、言語の仕様の中にそういった欠点があるのはある意味仕方がないのとかもしれません。そういったこともあり、C言語は新しいバージョンであるC11でこういった問題に対処するために、gets関数を排除するなどの対策をしています。(コラム3. C言語の規格参照)

しかし、メールサーバーなどで用いられるsendmailと呼ばれるプログラムは、C言語でかかれ、古いライブラリ関数を多用していることから、頻繁に修正されていましたが、ついにはセキュリティ上の問題などでsendmailを標準プログラムから排除する動きがあり、いくつかのOSの標準セットからsendmailは取り除かれてしました。

セキュアなコード

こういったバッファーオーバフローなどによる脆弱性への対策を行っているコードのことを、「セキュアなコード」と言います。またそのようなコードのプログラミングを行うことを「セキュアプログラミング」と言います。

セキュアなコードをかくための方法は大きく分けて二つあります。一つは、従来の枠組みのなかでできるだけ「セキュア」にプログラミングをする方法、そしてもう一つは「セキュアな関数」を用いてプログラミングを行う方法です。

たとえば、マイクロソフトは、自社が開発したVisualC++コンパイラで、危険性のあるscanfのかわりに、scanf_sという「セキュアな」scanfを用意して、バッファーオーバランを回避する工夫をしています。これにより、以前よりもセキュアなコードを作成しやすくなりましたが、「完全」な対策を行うことは不可能です。

ただ、セキュアなコードをかく方法に関しては、研究が進んでおり、ネットなどでも多くの情報を得ることができます。プログラマーは、そういった情報を絶えずチェックして、脆弱性の低いプログラム作りを心掛ける必要がります。