ARR32-C. 可変長配列のサイズ引数は適切な範囲内にあることを保証する
可変長配列(VLA) は基本的に従来の C の配列と同じであるが、異なる点としては、整数定数式ではないサイズで宣言する点と、宣言する際はブロックスコープまたは関数プロトタイプスコープでかつ無結合である点が挙げられる。可変長配列は次のように宣言できる。
{ /* ブロックスコープ */ char vla[size]; }
整数式 size
と vla
の宣言は、どちらも実行時に評価される。可変長配列に渡されるサイズ引数が正の整数でない場合、未定義の動作となる(C 言語規格 附属書 J 「未定義の動作」の 75 を参照)。また、引数が大きすぎる場合、プログラムが予期せぬ動作をする可能性がある。攻撃者は、この動作を悪用し、重要なプログラムデータを上書きできるかもしれない [Griffiths 2006]。プログラマは、可変長配列に与えるサイズ引数が、適切な範囲に収まる値であることを保証しなくてはならない。特に、信頼のないデータから取得した値である場合はそうである。
違反コード
下記のコード例では、サイズが size
である可変長配列が宣言されている。size
は「INT01-C. オブジェクトのサイズを表現する整数値には rsize_t もしくは size_t を使用する」に従い size_t
型として宣言されている。
void func(size_t size) { int vla[size]; /* ... */ }
しかし、size
の値がサイズ引数として適切な値であるという保証はなく、セキュリティ上の脆弱性を引き起こす可能性がある。
適合コード
下記の解決法では、vla
のメモリ割当てに使用する引数 size
が適切な範囲に収まること(1 からプログラマ定義の最大値)を保証している。適切な範囲に収まらない場合は、動的メモリ割り当てを行う。
#include <stdlib.h> enum { MAX_ARRAY = 1024 }; extern void do_work(int *array, size_t size); void func(size_t size) { if (0 < size && size < MAX_ARRAY) { int vla[size]; do_work(vla, size); } else { int *array = (int *)malloc(size * sizeof(int)); if (array == NUL) { /* エラー処理 */ } do_work(array, size); free(array); } }
処理系固有の詳細
Microsoft
可変長配列は Microsoft のコンパイラではサポートされていない。
GCC
GCC での可変長配列の使用は慎重に行うべきである。新しいバージョンの GCC は可変長配列の機能を取り込んでいるが、完全には C 言語規格に準拠していない。C言語規格のこの機能について、GCCは不完全かつ限定的なサポートしかしていないが、-std=c11
または -std=iso9899:2011
でこの機能を有効にできる。
たとえば、Intel 32ビットプラットフォームの Debian GNU/Linux 上の GCC 4.2.2 では、可変長配列のサイズは32ビット符号付き整数として解釈される。サイズとして、負の値を渡すとプログラムスタックが破壊される可能性が、大きな正の値を渡すとスタックオーバーフローが発生する可能性がある。今後の GCC のバージョンアップでこの状況は変化するかもしれないので注意してほしい。
リスク評価
可変長配列のサイズを適切に指定しないと、任意のコードが実行されたり、スタックオーバーフローにつながる可能性がある。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
ARR32-C |
高 |
中 |
高 |
P6 |
L2 |
自動検出(最新の情報はこちら)
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
Coverity | 6.5 | REVERSE_NEGATIVE | 実装済み |
PRQA QA-C | 8.1 | 1051 | 部分的に実装済み |
関連するガイドライン
CERT C セキュアコーディングスタンダード | INT01-C. オブジェクトのサイズを表現するすべての整数値に rsize_t もしくは size_t を使用する |
ISO/IEC TR 24772:2013 | Unchecked Array Indexing [XYZ] |
ISO/IEC TS 17961 | Tainted, potentially mutilated, or out-of-domain integer values are used in a restricted sink [taintsink] |
参考資料
[Griffiths 2006] |
翻訳元
これは以下のページを翻訳したものです。
ARR32-C. Ensure size arguments for variable length arrays are in a valid range (revision 120)