INT31-C. 整数変換によってデータの消失や解釈間違いが発生しないことを保証する
整数変換は、暗黙的、明示的(キャスト)にかかわらず、データの消失や解釈間違いにつながらないことが保証されなければならない。信頼できない入力源から取得した整数値が次のように利用されるケースでは特に重要である。
- 配列インデックス
- ポインタ算術演算
- オブジェクトの長さまたはサイズ
- 配列の境界(たとえば、ループカウンタ)
- メモリ割り当て関数の引数
- セキュリティ上重要な意味を持つコード
すべてのデータ値および規格合致処理系 (conforming implementation) において、唯一安全が保証されている整数型変換は、符号の有無が同じでより幅の広い型への変換のみである。C 言語規格 セクション 6.3.1.3 には次のように規定されている[ISO/IEC 9899:2011]。
整数型の値を
_Bool
型以外の他の整数型に変換する場合、その値が新しい型で表現可能なとき、値は変化しない。新しい型で表現できない場合、新しい型が符号無し整数型であれば、新しい型で表現しうる最大の数に1加えた数を加えることまたは減じることを、新しい型の範囲に入るまで繰り返すことによって得られる値に変換する。
そうでない場合、すなわち、新しい型が符号付き整数型であって、値がその型で表現できない場合は、結果が 処理系定義の値 となるか、または処理系定義のシグナルを生成するかのいずれかとする。
通常、ある整数をより小さな型に変換すると、上位ビットが切り捨てられる。
違反コード (符号無し型から符号付き型への変換)
符号無し整数型から符号付き整数型へ変換する場合、データの消失 (切り捨て) や符号の消失 (符号エラー) などの型範囲エラーが発生する可能性がある。次のコード例は、ほとんどの処理系において切り捨てエラーにつながる。
unsigned long int ul = ULONG_MAX; signed char sc; sc = (signed char)ul; /* キャストによりコンパイラの警告は出ない */
適合コード (符号無し型から符号付き型への変換)
符号無し整数型から符号付き整数型への変換を行う場合には、変換する値が安全に変換できる範囲におさまっていることを確認せよ。たとえば unsigned long int
から signed char
への変換を行う場合には次のようなコードを使用できる。
unsigned long int ul = ULONG_MAX; signed char sc; if (ul <= SCHAR_MAX) { sc = (signed char)ul; /* キャストによりコンパイラの警告は出ない */ } else { /* エラー処理 */ }
違反コード (符号付き型から符号無し型への変換)
符号付き整数型から符号無し整数型への変換を行う場合、データの消失 (切り捨て) や符号の消失 (符号エラー) などの型範囲エラーが発生する可能性がある。次のコード例では、演算の結果、符号が失われてしまう。
signed int si = INT_MIN; unsigned int ui = (unsigned int)si; /* キャストによりコンパイラの警告は出ない */
適合コード (符号付き型から符号無し型への変換)
符号付き整数型から符号無し整数型への変換を行う場合には、変換する値が安全に変換できる範囲におさまっていることを確認せよ。たとえば signed int
から unsigned int
への変換を行う場合には次のようなコードを使用できる。
signed int si = INT_MIN; unsigned int ui; if (si < 0) { /* エラー処理 */ } else { ui = (unsigned int)si; /* キャストによりコンパイルエラーは出ない */ }
注: 通常、符号無し整数型は対応する符号付き整数型のすべての正の値を表現できるが、この関係は C言語規格では保証されていない。
違反コード (符号付き整数型、精度の消失)
符号付き整数型をより精度の低い符号付き整数型へ変換する場合、データの消失 (切り捨て) が発生する可能性がある。次のコード例では切り捨てエラーが発生する。
signed long int sl = LONG_MAX; signed char sc = (signed char)sl; /* キャストによりコンパイラの警告は出ない */
適合コード (符号付き整数型、精度の消失)
ある符号付き整数型をより精度の低い符号付き整数型へ変換する場合、変換する値が安全に変換できる範囲におさまっていることを確認せよ。たとえば signed long int
から signed char
への変換を行う場合には次のようなコードを使用できる。
signed long int sl = LONG_MAX; signed char sc; if ( (sl < SCHAR_MIN) || (sl > SCHAR_MAX) ) { /* エラー処理 */ } else { sc = (signed char)sl; /* キャストによりコンパイラの警告は出ない */ }
精度の高い符号付き整数型から精度の低い符号付き整数型への変換を行う場合、範囲の上限と下限を確認する必要がある。
違反コード (符号無し整数型、精度の消失)
符号無し整数型をより精度の低い符号無し整数型へ変換する場合、データの消失 (切り捨て) が発生する可能性がある。次のコード例は、ほとんどの処理系において切り捨てエラーが発生する。
unsigned long int ul = ULONG_MAX; unsigned char uc = (unsigned char)ul; /* キャストによりコンパイラの警告は出ない */
適合コード (符号無し整数型、精度の消失)
符号無し整数型からより精度の低い符号無し整数型への変換を行う場合、変換する値が安全に変換できる範囲におさまっていることを確認せよ。たとえば unsigned long int
から unsigned char
への変換を行う場合には次のようなコードを使用できる。
unsigned long int ul = ULONG_MAX; unsigned char uc; if (ul > UCHAR_MAX) ) { /* エラー処理 */ } else { uc = (unsigned char)ul; /* キャストによりコンパイラの警告は出ない */ }
符号無し整数型を精度のより低い符号無し整数型へ変換する場合に確認が必要なのは、範囲の上限のみである。
例外
INT31-EX1: C 言語規格では、標準整数型に対して最小範囲を定義している。たとえば、unsigned short int
型のオブジェクトの最小範囲は 0 から 65,535 であるが、int
型の最小範囲は、−32,768 から +32,767 である。これはつまり、必ずしもすべての unsigned short int
の値を int
の値として表現できるわけではないことを意味する。しかし、たとえば IA-32 アーキテクチャでは、実際の整数範囲は −2,147,483,648 から +2,147,483,647 までであり、unsigned short int
のすべての値を int
で表現できる。結果として、IA-32 アーキテクチャでこの変換を行う場合は検査を行う必要はない。しかし一般には、処理系における型の精度がわからなければ、型変換を安全に行えるかどうかはあらかじめ想定できない。型の精度に関する一定の想定のもとに範囲検査を行わないコードでは、型の精度に関する条件を明確にドキュメント化しておく必要がある。この条件が当てはまらないシステムにはコードを安全に移植できないからである。このような想定をドキュメント化するための良い方法は静的アサートを使用することである。(「DCL03-C. 定数式の値をテストするには静的アサートを使う」を参照。)
リスク評価
整数の切り捨てエラーは、バッファオーバーフローや攻撃者による任意のコード実行につながる恐れがある。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
INT31-C |
高 |
中 |
高 |
P6 |
L2 |
自動検出(最新の情報はこちら)
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
Compass/ROSE |
このルールの違反を検出できる。 |
||
Coverity* |
6.5 |
NEGATIVE_RETURNS
MISRA_CAST |
配列アクセス、ループ範囲、そのほか、予期しない動作につながるおそれのある暗黙の整数変換が含まれている式を検出する。 負の値が別の場所で使われた後で、負かどうかのチェックが生じるような事例を検出できる。 整数式が暗黙的に幅の狭い整数型に変換される、暗黙的に符号付き/無し整数型に変換される、または暗黙的に複雑な式の型に変換される事例を検出できる。 |
Fortify SCA |
5.0 |
CERT C Rule Packを使ってこのルールの違反を検出できる。 |
|
V. 9.1 |
PRECISION.LOSS |
||
LDRA tool suite |
V. 8.5.4 |
93 S |
実装済み |
PRQA QA-C | 8.1 |
2850 (C) |
部分的に実装済み |
* Coverity Preventは、このルールの違反をすべて検出できるわけではないため、さらなる検証が必要である。
関連する脆弱性
CVE-2009-1376 はこのルールへの違反の結果である。Pidgin バージョン2.5.5 では、符号無し整数(offset
)は64ビット符号無し整数として扱われ、切り捨てが発生する場合がある[xorl 2009]。攻撃者は、この値をうまく選んでバッファオーバーフローを引き起こすことで、任意のコードを実行できる。
関連するガイドライン
CERT C++ Secure Coding Standard | INT31-CPP. Ensure that integer conversions do not result in lost or misinterpreted data |
Java セキュアコーディングスタンダード CERT/Oracle 版 | NUM12-J. 数値型の値を幅の狭い型へ変換する際データの消失や解釈間違いが発生しないことを保証する |
ISO/IEC TR 24772:2013 | Numeric Conversion Errors [FLC] |
MISRA-C |
Rule 10.1 |
MITRE CWE | CWE-192, Integer coercion error CWE-197, Numeric truncation error CWE-681, Incorrect conversion between numeric types |
参考資料
[Dowd 2006] | Chapter 6, "C Language Issues" ("Type Conversions," pp. 223–270) |
[ISO/IEC 9899:2011] | Section 6.3.1.3, "Signed and Unsigned Integers" |
[Seacord 2013b] | Chapter 5, "Integer Security" |
[Viega 2005] | Section 5.2.9, "Truncation Error" Section 5.2.10, "Sign Extension Error" Section 5.2.11, "Signed to Unsigned Conversion Error" Section 5.2.12, "Unsigned to Signed Conversion Error" |
[Warren 2002] | Chapter 2, "Basics" |
[xorl 2009] | "CVE-2009-1376: Pidgin MSN SLP Integer Truncation" |
翻訳元
これは以下のページを翻訳したものです。
INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data (revision 125)