CWE Rule 125
説明
ルールの説明
The software reads data past the end, or before the beginning, of the intended buffer.
Polyspace 実装
ルール チェッカーは以下の問題をチェックします。
配列が範囲外にアクセス
汚染されたインデックスによる配列へのアクセス
不正確な文字列形式指定子によるバッファー オーバーフロー
文字列操作で格納先バッファーがオーバーフローしています
文字列操作で格納先バッファーがアンダーフローしています
標準ライブラリ メモリ ルーチンの無効な使用
標準ライブラリ文字列ルーチンの無効な使用
string 配列での null 値の欠落
範囲外にアクセスするポインター
汚染されたオフセットによるポインターのデリファレンス
sizeof を誤って使用している可能性があります
汚染された NULL 文字列または非 NULL 終端文字列
例
この問題は、配列へのアクセス中に配列のインデックスが範囲 [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] にアクセスします。
この問題は、セキュリティで保護されていないソースから取得され、検証されていないインデックスを使用して配列にアクセスした場合に発生します。
インデックスは有効な配列範囲を外れている可能性があります。汚染されたインデックスが配列範囲を外れていると、以下の原因となることがあります。
バッファー アンダーフローまたはアンダーライト — バッファーの先頭より前のメモリへの書き込み。
バッファー オーバーフロー — バッファーの末尾より後のメモリへの書き込み。
バッファーのオーバーリード — 対象バッファーの末尾より後のメモリへのアクセス。
バッファーのアンダーリード、すなわち、対象バッファーの先頭より前のメモリへのアクセス。
攻撃者は無効な読み取りや書き込みの操作を利用して、プログラムに問題を生じさせることができます。
インデックスを使用して配列にアクセスする前に、インデックス値を検証して、それが配列範囲内にあることを確認します。
既定では、Polyspace® は外部ソースからのデータは汚染されていると仮定します。Polyspace 解析での汚染のソースを参照してください。Polyspace 解析の現在のスコープ以外から発生したすべてのデータを汚染されたものと見なすには、コマンド ライン オプション [-consider-analysis-perimeter-as-trust-boundary] を使用します。
#include <stdlib.h>
#include <stdio.h>
#define SIZE100 100
extern int tab[SIZE100];
static int tainted_int_source(void) {
return strtol(getenv("INDEX"),NULL,10);
}
int taintedarrayindex(void) {
int num = tainted_int_source();
return tab[num];//Noncompliant
}この例では、インデックス num により配列 tab にアクセスします。インデックス num は保護されないソースから取得され、関数 taintedarrayindex は num が tab の範囲内にあるかどうかをチェックしません。
1 つの修正方法として、num が範囲内にあることを使用前にチェックします。
#include <stdlib.h>
#include <stdio.h>
#define SIZE100 100
extern int tab[SIZE100];
static int tainted_int_source(void) {
return strtol(getenv("INDEX"),NULL,10);
}
int taintedarrayindex(void) {
int num = tainted_int_source();
if (num >= 0 && num < SIZE100) {
return tab[num];
} else {
return -1;
}
}
この問題は、sscanf などの関数の書式指定子引数が、メモリ バッファー引数でのオーバーフローまたはアンダーフローにつながる場合に発生します。
形式指定子で指定した精度がメモリ バッファー サイズより大きいと、オーバーフローが発生します。オーバーフローは、メモリ破損のような予期しない動作を引き起こす可能性があります。
メモリ バッファー サイズに適合する形式指定子を使用します。
#include <stdio.h>
void func (char *str[]) {
char buf[32];
sscanf(str[1], "%33c", buf); //Noncompliant
}この例では、buf に char 要素を 32 個格納できます。したがって、形式指定子 %33c はバッファー オーバーフローの原因となります。
考えられる修正の 1 つは、バッファーに読み込む要素の数を減らすことです。
#include <stdio.h>
void func (char *str[]) {
char buf[32];
sscanf(str[1], "%32c", buf);
}この問題は、特定の文字列操作関数によって、その格納先バッファー引数にバッファー サイズを超えるオフセットで書き込まれた場合に発生します。
たとえば、関数 sprintf(char* buffer, const char* format) を呼び出す際に、buffer より大きいサイズの定数文字列 format を使用する場合などです。
バッファー オーバーフローにより、メモリ破損やシステム停止といった予期しない動作を引き起こす可能性があります。また、バッファー オーバーフローは、コード インジェクションのリスクにもつながります。
1 つの解決策として、代替となる関数を使用して、書き込まれる文字の数を制限します。次に例を示します。
書式設定されたデータを文字列に書き込むのに
sprintfを使用している場合は、代わりにsnprintf、_snprintfまたはsprintf_sを使用して長さを制御します。あるいは、asprintfを使用して、格納先バッファーに必要なメモリを自動で割り当てます。書式設定されたデータを可変引数リストから文字列に書き込むのに
vsprintfを使用している場合は、代わりにvsnprintfまたはvsprintf_sを使用して長さを制御します。ワイド文字列をコピーするのに
wcscpyを使用している場合は、代わりにwcsncpy、wcslcpyまたはwcscpy_sを使用して長さを制御します。
別の解決策として、バッファー サイズを増やします。
#include <stdio.h>
void func(void) {
char buffer[20];
char *fmt_string = "This is a very long string, it does not fit in the buffer";
sprintf(buffer, fmt_string); //Noncompliant
}この例では、buffer は char 要素を 20 個格納できますが、fmt_string はより大きいサイズとなっています。
snprintf を sprintf の代わりに使用1 つの修正方法として、関数 snprintf を使用して長さを制御します。
#include <stdio.h>
void func(void) {
char buffer[20];
char *fmt_string = "This is a very long string, it does not fit in the buffer";
snprintf(buffer, 20, fmt_string);
}この問題は、特定の文字列操作関数によって、その格納先バッファー引数にバッファーの先頭から負のオフセットで書き込まれた場合に発生します。
たとえば、関数 sprintf(char* buffer, const char* format) では buffer を演算 buffer = (char*)arr; ... buffer += offset; から取得します。arr は配列で、offset は負の値です。
バッファー アンダーフローにより、メモリ破損やシステム停止のような予期しない動作を引き起こす可能性があります。また、バッファー アンダーフローは、コード インジェクションのリスクにもつながります。
格納先バッファーの引数がポインター演算の結果得られたものである場合は、ポインターをデクリメントしているかどうかを確認します。デクリメント前の元の値かデクリメント値を変更することで、ポインターのデクリメントを修正します。
#include <stdio.h>
#define offset -2
void func(void) {
char buffer[20];
char *fmt_string ="Text";
sprintf(&buffer[offset], fmt_string); //Noncompliant
}この例では、&buffer[offset] は buffer に割り当てられているメモリから負のオフセットの位置にあります。
1 つの修正方法として、offset の値を変更します。
#include <stdio.h>
#define offset 2
void func(void) {
char buffer[20];
char *fmt_string ="Text";
sprintf(&buffer[offset], fmt_string);
}この問題は、メモリ ライブラリ関数が無効な引数で呼び出された場合に発生します。たとえば、関数 memcpy でコピー先の配列に格納できないバイト数をコピーする場合が該当します。
無効な引数でメモリ ライブラリ関数を使用すると、バッファー オーバーフローなどの問題が発生する可能性があります。
修正方法は欠陥の根本原因によって異なります。多くの場合、結果の詳細 (または Polyspace as You Code のソース コード ツールヒント) には欠陥につながる一連のイベントが表示されます。そのシーケンス内のどのイベントについても修正を実装できます。結果の詳細にイベント履歴が表示されない場合は、ソース コード内で右クリック オプションを使用して、欠陥に関連する変数のこれまでの参照を検索し、関連するイベントを検出できます。Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈またはPolyspace Access Web インターフェイスでの Bug Finder の結果の解釈 (Polyspace Access)も参照してください。
以下の修正例を参照してください。
問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。
Polyspace ユーザー インターフェイスでのバグ修正または正当化による結果への対処 (Polyspace ユーザー インターフェイスで結果をレビューする場合)。
Polyspace Access でのバグ修正または正当化による結果への対処 (Polyspace Access) (Web ブラウザーで結果をレビューする場合)。
コードへの注釈付けと既知の結果または許容可能な結果の非表示 (IDE で結果をレビューする場合)
#include <string.h>
#include <stdio.h>
char* Copy_First_Six_Letters(void)
{
char str1[10],str2[5];
printf("Enter string:\n");
scanf("%9s",str1);
memcpy(str2,str1,6); //Noncompliant
/* Defect: Arguments of memcpy invalid: str2 has size < 6 */
return str2;
}文字列 str2 のサイズは 5 ですが、関数 memcpy を使用して 6 文字の文字列 str1 が str2 にコピーされています。
1 つの修正方法として、関数 memcpy でコピーされる文字が収まるように、str2 のサイズを調整するとします。
#include <string.h>
#include <stdio.h>
char* Copy_First_Six_Letters(void)
{
/* Fix: Declare str2 with size 6 */
char str1[10],str2[6];
printf("Enter string:\n");
scanf("%9s",str1);
memcpy(str2,str1,6);
return str2;
}この問題は、文字列ライブラリ関数が無効な引数で呼び出された場合に発生します。
リスクは無効な引数のタイプによって異なります。たとえば、コピー先引数より大きいコピー元引数を指定して関数 strcpy を使用すると、バッファー オーバーフローが発生する可能性があります。
修正方法は欠陥に関連する標準ライブラリ関数に依存します。場合によっては、関数呼び出しの前に関数の引数を制約することができます。たとえば、次の関数 strcpy を考えます。
char * strcpy(char * destination, const char* source)strcpy を呼び出す前にコピー元引数を制約します。場合によっては、代替となる関数を使用してエラーを回避できます。たとえば、strcpy の代わりに strncpy を使用するとコピーされるバイト数を制御できます。以下の修正例を参照してください。
問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。
Polyspace ユーザー インターフェイスでのバグ修正または正当化による結果への対処 (Polyspace ユーザー インターフェイスで結果をレビューする場合)。
Polyspace Access でのバグ修正または正当化による結果への対処 (Polyspace Access) (Web ブラウザーで結果をレビューする場合)。
コードへの注釈付けと既知の結果または許容可能な結果の非表示 (IDE で結果をレビューする場合)
#include <string.h>
#include <stdio.h>
char* Copy_String(void)
{
char *res;
char gbuffer[5],text[20]="ABCDEFGHIJKL";
res=strcpy(gbuffer,text); //Noncompliant
/* Error: Size of text is less than gbuffer */
return(res);
}
文字列 text はサイズが gbuffer より大きくなっています。したがって、関数 strcpy は text を gbuffer にコピーできません。
1 つの修正方法として、コピー先の文字列 gbuffer をソース文字列 text 以上のサイズで宣言するとします。
#include <string.h>
#include <stdio.h>
char* Copy_String(void)
{
char *res;
/*Fix: gbuffer has equal or larger size than text */
char gbuffer[20],text[20]="ABCDEFGHIJKL";
res=strcpy(gbuffer,text);
return(res);
}
この問題は、null 文字 '\0' で終了するだけの十分なスペースが文字列にない場合に発生します。
この欠陥は C のプロジェクトのみに当てはまります。
暗黙的な NULL 終端を仮定せずに文字列を配列にコピーすると、バッファー オーバーフローが発生する可能性があります。
文字配列をリテラルで初期化する場合、配列範囲の指定を避けます。
char three[] = "THREE";初期化後に問題が発生した場合、NULL 終端を考慮するために配列のサイズを 1 だけ増やさなければならない場合があります。
特定の状況では、文字列の代わりに文字のシーケンスを使用して文字配列を初期化することが必要な場合があります。この場合、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。
Polyspace ユーザー インターフェイスでのバグ修正または正当化による結果への対処 (Polyspace ユーザー インターフェイスで結果をレビューする場合)。
Polyspace Access でのバグ修正または正当化による結果への対処 (Polyspace Access) (Web ブラウザーで結果をレビューする場合)。
コードへの注釈付けと既知の結果または許容可能な結果の非表示 (IDE で結果をレビューする場合)
void countdown(int i)
{
static char one[5] = "ONE";
static char two[5] = "TWO";
static char three[5] = "THREE"; //Noncompliant
}文字配列 three のサイズは 5 で、この配列には 'T'、'H'、'R'、'E' および 'E' の 5 つの文字があります。three の大きさは 5 バイトしかないため、最後に null 文字を入れる余地がありません。
1 つの修正方法として、配列のサイズを変更して 5 つの文字と null 文字が入るようにできます。
void countdown(int i)
{
static char one[5] = "ONE";
static char two[5] = "TWO";
static char three[6] = "THREE";
}1 つの修正方法として、配列のサイズを空白にしたままで文字列を初期化することができます。この初期化方法では、5 つの文字と終端の null 文字のために十分なメモリが割り当てられます。
void countdown(int i)
{
static char one[5] = "ONE";
static char two[5] = "TWO";
static char three[] = "THREE";
}この問題は、ポインターがその範囲外でデリファレンスされた場合に発生します。
ポインターにアドレスが割り当てられると、そのポインターにメモリのブロックが関連付けられます。そのポインターを使用してそのブロック外のメモリにアクセスすることはできません。
範囲外のポインターのデリファレンスは未定義の動作です。予測不能な値を読み取ったり、許可されていない位置へのアクセスを試みてセグメンテーション違反が発生したりする可能性があります。
修正方法は欠陥の根本原因によって異なります。たとえば、ループ内のポインターをデリファレンスする際、次のいずれかの状況が発生したとします。
ループの上限が大きすぎる。
ポインターをインクリメントするためにポインター演算を使用する際、不適切な値でポインターを進めている。
この問題を修正するには、ループの範囲またはポインターのインクリメント値を変更する必要があります。
多くの場合、結果の詳細 (または 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 は割り当てられたメモリ ブロックの外を指しますが、もうデリファレンスされることはありません。
この問題は、ポインターのデリファレンスで、不明なソースまたはセキュリティで保護されていないソースからのオフセット変数が使用された場合に発生します。
このチェックでは、動的に割り当てられたバッファーに注目します。静的バッファーのオフセットについては、汚染されたインデックスによる配列へのアクセスを参照してください。
インデックスは有効な配列範囲を外れている可能性があります。汚染されたインデックスが配列範囲を外れていると、以下の原因となることがあります。
バッファー アンダーフローまたはアンダーライト、すなわち、バッファーの先頭より前でのメモリへの書き込み。
バッファー オーバーフロー、すなわち、バッファーの末尾より後でのメモリへの書き込み。
バッファー オーバーリード、すなわち、対象バッファーの末尾より後でのメモリへのアクセス。
バッファーのアンダーリード、すなわち、対象バッファーの先頭より前のメモリへのアクセス。
攻撃者は、無効な読み取りや書き込みを使用してプログラムを侵害できます。
変数を使用してポインターにアクセスする前に、インデックスを検証します。変数が有効範囲内にありオーバーフローしないことを確認します。
既定では、Polyspace は外部ソースからのデータは汚染されていると仮定します。Polyspace 解析での汚染のソースを参照してください。Polyspace 解析の現在のスコープ以外から発生したすべてのデータを汚染されたものと見なすには、コマンド ライン オプション [-consider-analysis-perimeter-as-trust-boundary] を使用します。
#include <stdio.h>
#include <stdlib.h>
enum {
SIZE10 = 10,
SIZE100 = 100,
SIZE128 = 128
};
extern void read_pint(int*);
int taintedptroffset(void) {
int offset;
scanf("%d",&offset);
int* pint = (int*)calloc(SIZE10, sizeof(int));
int c = 0;
if(pint) {
/* Filling array */
read_pint(pint);
c = pint[offset];//Noncompliant
free(pint);
}
return c;
}
この例では、関数が整数ポインター pint を初期化しています。ポインターは、入力インデックス offset を使用してデリファレンスされています。offset の値はポインター範囲外である可能性があり、値域外エラーの原因となります。
1 つの修正方法として、offset の値を検証します。offset が有効範囲内にある場合のみ、ポインターのデリファレンスを続行します。
#include <stdlib.h>
#include <stdio.h>
enum {
SIZE10 = 10,
SIZE100 = 100,
SIZE128 = 128
};
extern void read_pint(int*);
int taintedptroffset(void) {
int offset;
scanf("%d",&offset);
int* pint = (int*)calloc(SIZE10, sizeof(int));
int c = 0;
if (pint) {
/* Filling array */
read_pint(pint);
if (offset>0 && offset<SIZE10) {
c = pint[offset];
}
free(pint);
}
return c;
}この問題は、Polyspace Bug Finder™ が sizeof 演算子の使用が原因の、おそらく想定外である結果を検出した場合に発生します。次に例を示します。
配列のサイズを求めるため、
sizeof演算子が配列パラメーター名で使用されている。しかし、配列パラメーター名それ自体がポインターである。sizeof演算子からは、そのポインターのサイズが返される。配列のサイズを求めるため、
sizeof演算子が配列要素で使用されている。しかし、演算子はその配列要素のサイズを返す。正しくない想定のもとに
sizeof演算子を先に使用したため、特定の関数 (strncmpやwcsncpyなど) の size 引数が不適切になっている。次に例を示します。関数呼び出し
strncmp(string1, string2, num)で、numが、ポインターでのsizeof演算子の誤使用により取得されている。関数呼び出し
wcsncpy(destination, source, num)で、numがワイド文字の数ではなく、sizeof演算子を使用して取得されたバイト単位のサイズとなっている。たとえば、wcsncpy(destination, source, (sizeof(desintation)/sizeof(wchar_t)) - 1)ではなくwcsncpy(destination, source, sizeof(destination) - 1)を使用した場合などです。
sizeof 演算子の不適切な使用は、次の問題の原因となることがあります。
sizeof演算子により配列サイズが返され、その戻り値がループの制限に使用されることを想定している場合に、ループの実行回数が想定より少なくなる。sizeof演算子の戻り値がバッファーの割り当てに使用される場合に、バッファー サイズが必要なサイズより小さくなる。バッファーが不十分だと、結果としてバッファー オーバーフローなどの脆弱性などにつながることがあります。sizeof演算子の戻り値が関数呼び出しで不適切に使用される場合に、関数が想定どおりに動作しない。
考えられる修正方法は次のとおりです。
sizeof演算子を、配列サイズを決定するために配列パラメーター名や配列要素で使用しない。ベスト プラクティスは、配列サイズを別の関数パラメーターとして渡し、そのパラメーターを関数本体で使用することです。
sizeof演算子を慎重に使用して、strncmpやwcsncpyのような関数の数値引数を決定する。たとえば、wcsncpyなどのワイド文字列関数で、バイト数ではなくワイド文字の数を引数として使用します。
#define MAX_SIZE 1024
void func(int a[MAX_SIZE]) {
int i;
for (i = 0; i < sizeof(a)/sizeof(int); i++) //Noncompliant
{
a[i] = i + 1;
}
}この例では、sizeof(a) は配列サイズではなくポインター a のサイズを返します。
1 つの修正方法として、別の方法を使用して配列サイズを決定します
#define MAX_SIZE 1024
void func(int a[MAX_SIZE]) {
int i;
for (i = 0; i < MAX_SIZE; i++) {
a[i] = i + 1;
}
}この問題は、strcpy や sprintf などの文字列バッファーを暗黙的にデリファレンスする文字列操作ルーチンで、セキュリティで保護されていないソースからの文字列が使用された場合に発生します。
汚染された NULL 文字列または非 NULL 終端文字列では、scanf ファミリの可変個引数関数の呼び出しから返された文字列に関する欠陥が報告されません。同様に、文字列と一緒に %s 指定子を printf ファミリの可変個引数関数に渡した場合も欠陥は報告されません。
文字列がセキュリティで保護されないソースに由来している場合、攻撃者により文字列が操作されている可能性や、文字列ポインターが異なるメモリ位置に向けられている可能性があります。
文字列が NULL である場合、文字列ルーチンは文字列をデリファレンスできず、プログラムがクラッシュする原因となります。文字列が null で終了しない場合、文字列ルーチンでは文字列がいつ終了するかわからない可能性があります。このエラーは範囲外への書き込みの原因となり、バッファー オーバーフローを引き起こします。
文字列は、使用する前に検証します。以下についてチェックします。
文字列が NULL でない。
文字列が null で終了している。
文字列のサイズが、必要なサイズと一致している。
既定では、Polyspace は外部ソースからのデータは汚染されていると仮定します。Polyspace 解析での汚染のソースを参照してください。Polyspace 解析の現在のスコープ以外から発生したすべてのデータを汚染されたものと見なすには、コマンド ライン オプション [-consider-analysis-perimeter-as-trust-boundary] を使用します。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define SIZE128 128
#define MAX 40
extern void print_str(const char*);
void warningMsg(void)
{
char userstr[MAX];
read(0,userstr,MAX);
char str[SIZE128] = "Warning: ";
strncat(str, userstr, SIZE128-(strlen(str)+1));//Noncompliant
print_str(str);
}
この例では、文字列 str は引数 userstr と連結しています。userstr の値は不明です。userstr のサイズが使用可能なスペースより大きい場合、この連結はオーバーフローします。
1 つの修正方法として、strncat で使用する前に、userstr のサイズをチェックして、文字列が必ず null で終了するようにします。この例では、補助関数 sansitize_str を使用して文字列を検証しています。欠陥はこの関数に集中しています。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define SIZE128 128
#define MAX 40
extern void print_str(const char*);
int sanitize_str(char* s) {
int res = 0;
if (s && (strlen(s) > 0)) { // Noncompliant-TAINTED_STRING only flagged here
// - string is not null
// - string has a positive and limited size
// - TAINTED_STRING on strlen used as a firewall
res = 1;
}
return res;
}
void warningMsg(void)
{
char userstr[MAX];
read(0,userstr,MAX);
char str[SIZE128] = "Warning: ";
if (sanitize_str(userstr))
strncat(str, userstr, SIZE128-(strlen(str)+1));
print_str(str);
}別の修正方法として、特定の文字列を含む関数 errorMsg および warningMsg を呼び出します。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SIZE128 128
extern void print_str(const char*);
void warningMsg(char* userstr)
{
char str[SIZE128] = "Warning: ";
strncat(str, userstr, SIZE128-(strlen(str)+1));
print_str(str);
}
void errorMsg(char* userstr)
{
char str[SIZE128] = "Error: ";
strncat(str, userstr, SIZE128-(strlen(str)+1));
print_str(str);
}
int manageSensorValue(int sensorValue) {
int ret = sensorValue;
if ( sensorValue < 0 ) {
errorMsg("sensor value should be positive");
exit(1);
} else if ( sensorValue > 50 ) {
warningMsg("sensor value greater than 50 (applying threshold)...");
sensorValue = 50;
}
return sensorValue;
}チェック情報
| カテゴリ: 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)