CWE Rule 170
説明
ルールの説明
The software does not terminate or incorrectly terminates a string or array with a null character or equivalent terminator.
Polyspace 実装
ルール チェッカーは以下の問題をチェックします。
標準ライブラリ文字列ルーチンの無効な使用
string 配列での null 値の欠落
readlink() の不適切な使用
汚染された NULL 文字列または非 NULL 終端文字列
例
この問題は、文字列ライブラリ関数が無効な引数で呼び出された場合に発生します。
リスクは無効な引数のタイプによって異なります。たとえば、コピー先引数より大きいコピー元引数を指定して関数 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";
}この問題は、バッファー内に NULL 終端用のスペースを残さない、readlink() へのバッファー サイズ引数を渡した場合に発生します。
次に例を示します。
ssize_t len = readlink("/usr/bin/perl", buf, sizeof(buf));readlink() を使用すると、NULL 終端を入れる領域が残りません。関数 readlink() は、シンボリック リンク (最初の引数) のコンテンツをバッファー (2 番目の引数) にコピーします。ただし、この関数はコピーしたコンテンツに NULL 終端を追加しません。readlink() を使用後、NULL 終端をバッファーに明示的に追加しなければなりません。
readlink の使用時にバッファー全体が占有されると、NULL 終端の領域が残りません。
関数 readlink() を使用するときは、3 番目の引数をバッファー サイズよりも 1 文字分短くします。
その後、NULL 終端をバッファーに追加します。NULL 終端の追加場所を決めるには、readlink() の戻り値をチェックします。戻り値が -1 の場合、エラーが発生しています。そうでない場合、戻り値はコピーされた文字数 (バイト) です。
#include <unistd.h>
#define SIZE1024 1024
extern void display_path(const char *);
void func() {
char buf[SIZE1024];
ssize_t len = readlink("/usr/bin/perl", buf, sizeof(buf)); //Noncompliant
if (len > 0) {
buf[len - 1] = '\0';
}
display_path(buf);
}この例では、readlink の 3 番目の引数がバッファー (2 番目の引数) のサイズとまったく同じです。最初の引数がバッファーを占有する場合、このように readlink を使用すると、NULL 終端の領域が残りません。
また、文字がコピーされないとき、readlink の戻り値は 0 です。以下のステートメントでは、len が 0 のときにバッファー アンダーフローになります。
buf[len - 1] = '\0';1 つの修正方法として、readlink の 3 番目の引数を 2 番目の引数のサイズよりも 1 文字分短くします。
修正した次のコードでは、readlink が 0 を返す場合も考慮します。
#include <stdlib.h>
#include <unistd.h>
#define fatal_error() abort()
#define SIZE1024 1024
extern void display_path(const char *);
void func() {
char buf[SIZE1024];
ssize_t len = readlink("/usr/bin/perl", buf, sizeof(buf) - 1);
if (len != -1) {
buf[len] = '\0';
display_path(buf);
}
else {
/* Handle error */
fatal_error();
}
}この問題は、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 //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 //Noncompliant
// - 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;
}チェック情報
| カテゴリ: Data Neutralization Issues |
バージョン履歴
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)