JPCERT コーディネーションセンター

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

   

このルールの違反を検出できる。limits.h がインクルードされている場合、誤った警告を出す場合がある。

Coverity*

6.5

NEGATIVE_RETURNS


REVERSE_NEGATIVE

MISRA_CAST

配列アクセス、ループ範囲、そのほか、予期しない動作につながるおそれのある暗黙の整数変換が含まれている式を検出する。

負の値が別の場所で使われた後で、負かどうかのチェックが生じるような事例を検出できる。

整数式が暗黙的に幅の狭い整数型に変換される、暗黙的に符号付き/無し整数型に変換される、または暗黙的に複雑な式の型に変換される事例を検出できる。

Fortify SCA

5.0

 

CERT C Rule Packを使ってこのルールの違反を検出できる。

Klocwork

V. 9.1

PRECISION.LOSS

 

LDRA tool suite

V. 8.5.4

93 S
433 S
434 S

実装済み
PRQA QA-C 8.1

2850 (C)
2851 (D)
2852 (A)
2853 (S)
2900 (C)
2901 (D)
2902 (A)
2903 (S)
2905 (C)
2906 (D)
2907 (A)
2908 (S)
3758
3759
3760
3769
3770
3780
3781
3782
3783

部分的に実装済み

* 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
Rule 10.3
Rule 10.5
Rule 12.9

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)

Top へ

Topへ
最新情報(RSSメーリングリストTwitter