CS.ABV.EXCEPT
範囲外の配列インデックスの使用を試みるときの IndexOutOfRange 例外
C/C++ と異なり、C# 言語にはマネージドヒープに割り当てられた配列とコンテナーの範囲外の読み取りおよび作成に対する組み込みの保護機能があります。この保護機能が有効になっていると、範囲外メモリの読み取りまたは作成の試みは成功しません。しかし、無効なアクセスインデックスを使用すると、配列アクセス演算子によって IndexOutOfRangeException がスローされます。
CS.ABV.EXCEPT チェッカーはインデックスアクセス操作を調べ、インデックス値が無効である可能性がある状況にフラグを立てます。
脆弱性とリスク
マネージドヒープに割り当てられた配列にバッファオーバーランが起きることはありえませんが、未処理の例外や不正確に処理された例外は、プログラム終了を引き起こしたり、予期しない方法で制御フローを変更したりする可能性があります。IndexOutOfRange 例外が適切に処理されている場合でも、インデックス値が配列の範囲外である可能性があるということは、不正なプログラム結果を招きうる論理エラーを強く示唆しています。
脆弱コード例 1
namespace n {
class C
{
void foo()
{
int[] A = new int[5];
int ind = 4;
++ind;
A[ind] = 10; // CS.ABV.EXCEPT
}
}
}
この基本的な例では、サイズ 5 の配列 'A' が割り当てられ、配列要素を参照するためにインデックス 'ind' (アクセスサイトでは 5 に等しい) が使用されています。このコードが実行されると、実行時に IndexOutRangeException がスローされます。Klocwork は、この問題を CS.ABV.EXCEPT 欠陥として報告します。
修正コード例 1
namespace n {
class C
{
void foo()
{
int[] A = new int[6];
int ind = 4;
++ind;
A[ind] = 10;
}
}
}
この問題は、配列アクセスロジックの正確性を検証することによって修正できます。上記の修正例では、アクセスインデックスが配列の範囲内に収まるように配列サイズが調整されています。
脆弱コード例 2
namespace n
{
class C
{
static void Main(string[] args)
{
int[] E = { 1, 2, 3, 4, 5, 6, 7, 8, 9 , 10 };
int ind1 = 5;
for (int i = 0; i < args.Length; i++)
{
++ind1;
if (i == 10)
{
break;
}
}
E[ind1] = 0; // CS.ABV.EXCEPT
}
}
}
この例では、暗黙に型指定がなされるサイズ 10 の配列を使用して 'E' が初期化されます。アクセスインデックスの 'Main' 値に渡される 'args' の長さに応じてループ内で最大 11 回反復が起きる可能性があり、その結果、'ind1' の値は範囲 [5;16] 内のいずれかになります。Klocwork は、この問題を CS.ABV.EXCEPT 欠陥として報告し、IndexOutRangeException がスローされる可能性のあるアクセスインデックス範囲の部分を示します。
修正コード例 2
例 1 と同様に、この問題は可能性のあるインデックス値と配列サイズを慎重に評価することによっても対処できます。
namespace n
{
class C
{
static void Main(string[] args)
{
int[] E = { 1, 2, 3, 4, 5, 6, 7, 8, 9 , 10 };
int ind1 = 5;
for (int i = 0; i < args.Length; i++)
{
++ind1;
if (i == 3) // Fixed here in this example.
{
break;
}
}
E[ind1] = 0;
}
}
}
この修正例では、'ind1' の値が配列の範囲内になるように対策されています。
制限事項
Klocwork 2021.3 では、CS.ABV.EXCEPT チェッカーは、値と型の要素の配列に対する配列アクセスの手続き内解析のみをサポートします。
関連チェッカー
セキュリティトレーニング
Secure Code Warrior が提供しているアプリケーションセキュリティトレーニング教材。