CWE Rule 131
説明
ルールの説明
The software does not correctly calculate the size to be used when allocating a buffer, which could lead to a buffer overflow.
Polyspace 実装
ルール チェッカーは以下の問題をチェックします。
配列が範囲外にアクセス
汚染されたサイズでのメモリの割り当て
範囲外にアクセスするポインター
汚染された符号変化の変換
可変長配列の汚染されたサイズ
sizeof において使用された誤った型
例
この問題は、配列へのアクセス中に配列のインデックスが範囲 [0...array_size-1]
を外れた場合に発生します。
配列の範囲外へのアクセスは未定義の動作です。予測不能な値を読み取ったり、許可されていない位置へのアクセスを試みてセグメンテーション違反が発生したりする可能性があります。
修正方法は欠陥の根本原因によって異なります。たとえば、ループ内の配列にアクセスする際、次のいずれかの状況が発生したとします。
ループの上限が大きすぎる。
ループ インデックスより 1 小さい配列インデックスを使用せずに、ループ インデックスと同じ配列インデックスを使用している。
この問題を修正するには、ループの範囲または配列インデックスを変更する必要があります。
配列インデックスが配列範囲を超える別の理由として、事前に行われた符号付き整数から符号なし整数への変換が考えられます。この変換はインデックス値のラップ アラウンドを発生させる可能性があり、最終的に配列インデックスが配列範囲を超える原因になります。
多くの場合、結果の詳細 (または Polyspace as You Code のソース コード ツールヒント) には欠陥につながる一連のイベントが表示されます。そのシーケンス内のどのイベントについても修正を実装できます。結果の詳細にイベント履歴が表示されない場合は、ソース コード内で右クリック オプションを使用して、欠陥に関連する変数のこれまでの参照を検索し、関連するイベントを検出できます。Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈またはPolyspace Access Web インターフェイスでの Bug Finder の結果の解釈 (Polyspace Access)も参照してください。
以下の修正例を参照してください。
問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。
Polyspace ユーザー インターフェイスでのバグ修正または正当化による結果への対処 (Polyspace ユーザー インターフェイスで結果をレビューする場合)。
Polyspace Access でのバグ修正または正当化による結果への対処 (Polyspace Access) (Web ブラウザーで結果をレビューする場合)。
コードへの注釈付けと既知の結果または許容可能な結果の非表示 (IDE で結果をレビューする場合)
入力値が不明であり、入力のサブセットのみがエラーの原因となっている場合、既定の Bug Finder 解析ではこの欠陥が報告されない可能性があります。特定のシステム入力値を原因とする欠陥の有無をチェックするには、より厳密な Bug Finder 解析を実行してください。特定のシステム入力値から欠陥を見つけるための Bug Finder チェッカーの拡張を参照してください。
#include <stdio.h>
void fibonacci(void)
{
int i;
int fib[10];
for (i = 0; i < 10; i++)
{
if (i < 2)
fib[i] = 1;
else
fib[i] = fib[i-1] + fib[i-2];
}
printf("The 10-th Fibonacci number is %i .\n", fib[i]); //Noncompliant
/* Defect: Value of i is greater than allowed value of 9 */
}
配列 fib
にはサイズ 10 が割り当てられています。fib
の配列インデックスに許可される値は [0,1,2,...,9]
です。変数 i
が for
ループから出るときの値は 10 です。したがって、printf
ステートメントは i
を用いて fib[10]
にアクセスしようと試みます。
1 つの修正方法として、for
ループの後で、fib[i]
ではなく fib[i-1]
を出力するとします。
#include <stdio.h>
void fibonacci(void)
{
int i;
int fib[10];
for (i = 0; i < 10; i++)
{
if (i < 2)
fib[i] = 1;
else
fib[i] = fib[i-1] + fib[i-2];
}
/* Fix: Print fib[9] instead of fib[10] */
printf("The 10-th Fibonacci number is %i .\n", fib[i-1]);
}
printf
ステートメントは、fib[10]
ではなく fib[9]
にアクセスします。
この問題は、calloc
や malloc
などのメモリ割り当て関数で、セキュリティで保護されていないソースからのサイズ引数が使用された場合に発生します。
メモリ割り当てが制御されていないと、プログラムによってシステム メモリが過剰に要求されることがあります。その結果、メモリ不足の状態やリソースの過剰割り当てによりクラッシュすることがあります。
メモリを割り当てる前に引数の値をチェックして、範囲を超えないことを確認します。
既定では、Polyspace® は外部ソースからのデータは汚染されていると仮定します。Polyspace 解析での汚染のソースを参照してください。Polyspace 解析の現在のスコープ以外から発生したすべてのデータを汚染されたものと見なすには、コマンド ライン オプション [-consider-analysis-perimeter-as-trust-boundary]
を使用します。
#include<stdio.h>
#include <stdlib.h>
int* bug_taintedmemoryallocsize(void) {
size_t size;
scanf("%zu", &size);
int* p = (int*)malloc(size);//Noncompliant
return p;
}
この例では、malloc
がポインター p
用のメモリを size
バイト割り当てます。変数 size
はプログラムのユーザーから取得されます。その値がチェックされないため、使用可能なメモリ量を超える可能性があります。size
が使用可能なバイト数を上回ると、プログラムがクラッシュする可能性があります。
1 つの修正方法として、malloc
操作を実行する前に、割り当てるメモリのサイズをチェックします。この例では、size
が正で、最大サイズより小さいかどうかを確認します。
#include<stdio.h>
#include <stdlib.h>
enum {
SIZE10 = 10,
SIZE100 = 100,
SIZE128 = 128
};
int* corrected_taintedmemoryallocsize(void) {
size_t size;
scanf("%zu", &size);
int* p = NULL;
if (size>0 && size<SIZE128) { /* Fix: Check entry range before use */
p = (int*)malloc((unsigned int)size);
}
return p;
}
この問題は、ポインターがその範囲外でデリファレンスされた場合に発生します。
ポインターにアドレスが割り当てられると、そのポインターにメモリのブロックが関連付けられます。そのポインターを使用してそのブロック外のメモリにアクセスすることはできません。
範囲外のポインターのデリファレンスは未定義の動作です。予測不能な値を読み取ったり、許可されていない位置へのアクセスを試みてセグメンテーション違反が発生したりする可能性があります。
修正方法は欠陥の根本原因によって異なります。たとえば、ループ内のポインターをデリファレンスする際、次のいずれかの状況が発生したとします。
ループの上限が大きすぎる。
ポインターをインクリメントするためにポインター演算を使用する際、不適切な値でポインターを進めている。
この問題を修正するには、ループの範囲またはポインターのインクリメント値を変更する必要があります。
多くの場合、結果の詳細 (または Polyspace as You Code のソース コード ツールヒント) には欠陥につながる一連のイベントが表示されます。そのシーケンス内のどのイベントについても修正を実装できます。結果の詳細にイベント履歴が表示されない場合は、ソース コード内で右クリック オプションを使用して、欠陥に関連する変数のこれまでの参照を検索し、関連するイベントを検出できます。Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈またはPolyspace Access Web インターフェイスでの Bug Finder の結果の解釈 (Polyspace Access)も参照してください。
以下の修正例を参照してください。
問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。
Polyspace ユーザー インターフェイスでのバグ修正または正当化による結果への対処 (Polyspace ユーザー インターフェイスで結果をレビューする場合)。
Polyspace Access でのバグ修正または正当化による結果への対処 (Polyspace Access) (Web ブラウザーで結果をレビューする場合)。
コードへの注釈付けと既知の結果または許容可能な結果の非表示 (IDE で結果をレビューする場合)
int* Initialize(void)
{
int arr[10];
int *ptr=arr;
for (int i=0; i<=9;i++)
{
ptr++;
*ptr=i; //Noncompliant
/* Defect: ptr out of bounds for i=9 */
}
return(arr);
}
ptr
には、サイズ 10*sizeof(int)
のメモリ ブロックを指すアドレス arr
が割り当てられます。for
ループで、ptr
は 10 回インクリメントされます。ループの最後の反復で、ptr
は割り当てられたメモリ ブロックの外を指します。したがって、デリファレンスはできません。
1 つの修正方法として、ptr
のインクリメントとデリファレンスの順序を逆にすることができます。
int* Initialize(void)
{
int arr[10];
int *ptr=arr;
for (int i=0; i<=9;i++)
{
/* Fix: Dereference pointer before increment */
*ptr=i;
ptr++;
}
return(arr);
}
最後のインクリメントの後で ptr
は割り当てられたメモリ ブロックの外を指しますが、もうデリファレンスされることはありません。
この問題は、セキュリティで保護されていないソースからの値が、符号付きの値から符号なしの値に暗黙的または明示的に変換された場合に発生します。
たとえば、size_t
を引数として使用する関数では、引数が暗黙的に符号なし整数に変換されます。size_t
を暗黙的に変換する関数のいくつかを、以下に挙げます。
bcmp
memcpy
memmove
strncmp
strncpy
calloc
malloc
memalign
小さい負の数値を符号なしに変換すると、その結果は大きい正の数値となります。大きい正の数値により、セキュリティが脆弱になる可能性があります。たとえば、符号なしの値を以下で使用した場合がこれに該当します。
メモリ サイズ ルーチン — メモリ割り当ての問題の原因となります。
文字列操作ルーチン — バッファー オーバーフローの原因となります。
ループ境界 — 無限ループの原因となります。
符号なしの負の値の変換を避けるため、変換対象の値が許容範囲内にあることを確認します。たとえば、値がサイズを表す場合は、その値が負ではなく値の最大サイズより小さいことを検証します。
既定では、Polyspace は外部ソースからのデータは汚染されていると仮定します。Polyspace 解析での汚染のソースを参照してください。Polyspace 解析の現在のスコープ以外から発生したすべてのデータを汚染されたものと見なすには、コマンド ライン オプション [-consider-analysis-perimeter-as-trust-boundary]
を使用します。
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
enum {
SIZE10 = 10,
SIZE100 = 100,
SIZE128 = 128
};
void bug_taintedsignchange(void) {
int size;
scanf("%d",&size);
char str[SIZE128] = "";
if (size<SIZE128) {
memset(str, 'c', size); //Noncompliant
}
}
この例では、バッファー char
が作成され、memset
を使用して埋められます。memset
のサイズ引数は、関数の入力引数です。
memset
を呼び出すことにより、size
が符号なし整数へと暗黙的に変換されます。size
が大きい負の数値である場合、その絶対値は整数で表現するには大きすぎる可能性があり、バッファー オーバーフローの原因となります。
size
の値をチェック1 つの修正方法として、size
が有効範囲内にあるかどうかをチェックします。この修正では、size
がゼロより大きくバッファー サイズより小さいかどうかを、memset
を呼び出す前にチェックします。
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
enum {
SIZE10 = 10,
SIZE100 = 100,
SIZE128 = 128
};
void corrected_taintedsignchange(void) {
int size;
scanf("%d",&size);
char str[SIZE128] = "";
if (size>0 && size<SIZE128) {
memset(str, 'c', size);
}
}
この問題は、可変長配列 (VLA) のサイズがセキュリティで保護されていないソースから取得された場合に発生します。
攻撃者が VLA のサイズを予期しない値に変更した場合、プログラムのクラッシュや予期しない動作の原因となることがあります。
サイズが正でない場合、VLA の動作は未定義となります。プログラムは想定どおりには実行されません。
サイズが無制限の場合、VLA はメモリ枯渇やスタック オーバーフローを引き起こすことがあります。
VLA のサイズを検証して、正であり最大値より小さいことを確認します。
既定では、Polyspace は外部ソースからのデータは汚染されていると仮定します。Polyspace 解析での汚染のソースを参照してください。Polyspace 解析の現在のスコープ以外から発生したすべてのデータを汚染されたものと見なすには、コマンド ライン オプション [-consider-analysis-perimeter-as-trust-boundary]
を使用します。
#include<stdio.h>
#inclule<stdlib.h>
#define LIM 40
long squaredSum(int size) {
int tabvla[size]; //Noncompliant
long res = 0;
for (int i=0 ; i<LIM-1 ; ++i) {
tabvla[i] = i*i;
res += tabvla[i];
}
return res;
}
int main(){
int size;
scanf("%d",&size);
//...
long result = squaredSum(size);
//...
return 0;
}
この例では、可変長配列のサイズが入力引数に基づいています。この入力引数の値はチェックされていないため、サイズが負になるか大きすぎる可能性があります。
1 つの修正方法として、可変長配列を作成する前にサイズ変数をチェックします。この例では、VLA を作成する前に、サイズが 0 より大きく 40 より小さいかどうかをチェックしています。
#include <stdio.h>
#include <stdlib.h>
#define LIM 40
long squaredSum(int size) {
long res = 0;
if (size>0 && size<LIM){
int tabvla[size];
for (int i=0 ; i<size || i<LIM-1 ; ++i) {
tabvla[i] = i*i;
res += tabvla[i];
}
}else{
res = -1;
}
return res;
}
int main(){
int size;
scanf("%d",&size);
//...
long result = squaredSum(size);
//...
return 0;
}
この問題は、以下の条件が両方当てはまる場合に発生します。
メモリ ブロックのアドレスをポインターに代入するか、2 つのメモリ ブロック間でデータを転送します。この代入またはコピーで、
sizeof
演算子を使用します。たとえば、
malloc(sizeof(
を使用してポインターを初期化するか、type
))memcpy(
を使用して 2 つのアドレス間でデータをコピーします。destination_ptr
,source_ptr
, sizeof(type
))sizeof
演算子の引数に間違った型を使用します。次に例を示します。ポインターが指す型ではなく、ポインター型を使用している可能性がある。たとえば、
ポインターを初期化する際に、type
*malloc(sizeof(
ではなく、type
))malloc(sizeof(
を使用している可能性があります。type
*))sizeof
引数としてまったく無関係な型を使用している可能性がある。たとえば、
ポインターを初期化する際に、type
*malloc(sizeof(
を使用している可能性があります。anotherType
))
type
が何型でも、式 sizeof(
では常に固定サイズが返されます。返されるサイズは、お使いのプラットフォームでのポインターのサイズ (バイト単位) です。type
*)sizeof(
の出現は、多くの場合、意図とは異なる使い方を示しています。このエラーにより、必要とするよりもかなり小さなメモリ ブロックの割り当てになり、バッファー オーバーフローなどの脆弱性などにつながる可能性があります。type*
)
たとえば、structType
が 10 個の int
変数を含む構造体だとします。32 ビット プラットフォームで malloc(sizeof(structType*))
を使用して structType*
ポインターを初期化すると、ポインターには 4 バイトのメモリ ブロックが割り当てられます。しかし、1 つの structType
変数全体を割り当てるには、structType*
ポインターは sizeof(structType) = 10 * sizeof(int)
バイトのメモリ ブロックを指さなければなりません。必要なサイズは、実際に割り当てられた 4 バイトのサイズよりもはるかに大きなサイズです。
ポインターを初期化するには、ポインターの初期化式の type
*sizeof(
を type
*)sizeof(
に置き換えます。type
)
#include <stdlib.h>
void test_case_1(void) {
char* str;
str = (char*)malloc(sizeof(char*) * 5); //Noncompliant
free(str);
}
この例では、5 つの文字ポインターの malloc
を使用して文字ポインター str
にメモリを割り当てています。しかし、str
は文字を指すポインターであり、文字ポインターを指すポインターではありません。したがって、sizeof
の引数 char*
は正しくありません。
sizeof
の引数と一致させる1 つの修正方法として、引数をポインターの型に一致させることができます。この例では、str
は文字ポインターなので引数も文字でなければなりません。
#include <stdlib.h>
void test_case_1(void) {
char* str;
str = (char*)malloc(sizeof(char) * 5);
free(str);
}
チェック情報
カテゴリ: Memory Buffer Errors |
バージョン履歴
R2023a で導入
MATLAB Command
You clicked a link that corresponds to this MATLAB command:
Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.
Web サイトの選択
Web サイトを選択すると、翻訳されたコンテンツにアクセスし、地域のイベントやサービスを確認できます。現在の位置情報に基づき、次のサイトの選択を推奨します:
また、以下のリストから Web サイトを選択することもできます。
最適なサイトパフォーマンスの取得方法
中国のサイト (中国語または英語) を選択することで、最適なサイトパフォーマンスが得られます。その他の国の MathWorks のサイトは、お客様の地域からのアクセスが最適化されていません。
南北アメリカ
- América Latina (Español)
- Canada (English)
- United States (English)
ヨーロッパ
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)