標準的なC言語における安全なプログラミング概論を説明します。
今回はCall by Referenceと同じメモリ配置をC言語で指定する方法を説明します。
1. 簡単なサンプルから見るCの問題点
簡単な典型的なCのサンプルを挙げます。もちろんこのプログラムにはバグがあります。
このサンプルのpass[5]にバグがあります。キーボードから5文字以上の入力が起きた時に異常終了します。キーボードから入力したデータによってはExploit(制御権乗っ取り)できます。
これが典型的なコンピュータウィルスの感染技法です。
1: #include <stdio.h>
2: void sample( )
3: {
4: char pass[5]; // 5バイト分の変数。小さ過ぎる
5: fscanf( stdin, “%s”, pass ); // キーボードからパスワード4文字入力
6: printf( “pass:%s”, pass );
7: }
このプログラムを実行すると5行目で例えばガラケーのパスワード4桁を入れてみる、”1234″を入力するとメモリには次のように配置されます。
キーボード入力したパスワードはこのようにメモリに保存します。
このサンプルの欠陥は文字列が4文字以内というチェックが入っていないことです。
そしてこのようなミスは非常に多いことです。
ここで「リターンアドレス」は次に実行するプロラムの開始アドレスです。ここを上書きすれば制御権を奪取できます。
このプログラムの4行目を次のように「static」を追加してください。この問題はこれで障害は残りますが無害化できます。
旧4: char pass[5]; // 5バイト分の変数。小さ過ぎる
↓
新4: static char pass[5]; // 5バイト分の変数。小さ過ぎる
判りやすく修正したリストを挙げます。これだけで堅牢になります。
1: #include <stdio.h>
2: void sample( )
3: {
4: static char pass[5]; // 5バイト分の変数。小さ過ぎる
5: fscanf( stdin, “%s”, pass ); // キーボードからパスワード4文字入力
6: printf( “pass:%s”, pass );
7: }
無害化の理由は図を見てください。パスワードを格納するpass[5]変数を配置するメモリ位置が比較的安全な位置に移動するからです。もちろんメモリオーバーランによるメモリ破壊は起きます。ですが「リターンアドレス」の破壊は回避できます。つまりデータが壊れるだけで制御権の乗っ取りは起きないようになるからです。
要はオーバーランが発生する変数領域をデータヒープ領域に追い出せば良いわけです。
これがC言語が多様したCall by Valueのセキュリティという観点での構造欠陥です。
「static」指定には次の制約があります。
-
- 再帰コールでは使用できない。
- マルチスレッドでは使用できない。
インターネットに曝されるサーバー用アプリケーションにおいては「static」指定を多様すること。これが一番簡単なセキュリティ対策です。