CWE Rule 805
説明
ルールの説明
The software uses a sequential operation to read or write a buffer, but it uses an incorrect length value that causes it to access memory that is outside of the bounds of the buffer.
Polyspace 実装
ルール チェッカーは以下の問題をチェックします。
不正確な文字列形式指定子によるバッファー オーバーフロー
文字列操作で格納先バッファーがオーバーフローしています
文字列操作で格納先バッファーがアンダーフローしています
標準ライブラリ メモリ ルーチンの無効な使用
標準ライブラリ ルーチンの無効な使用
標準ライブラリ文字列ルーチンの無効な使用
データの長さとサイズが一致していません
sizeof を誤って使用している可能性があります
例
この問題は、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);
}
この問題は、バッファー オーバーフローから保護するために、memcpy、memset、memmove などのメモリ コピー関数の長さ引数とデータ バッファー引数がチェックされていない場合に発生します。
データ バッファーや長さの引数を攻撃者が操作できる場合、その攻撃者は、実際のデータ サイズをその長さより小さくすることによってバッファー オーバーフローを引き起こすことができます。
長さのこうした不一致のため、攻撃者は、データ バッファーに収まらないメモリを新しい場所にコピーできます。余剰分のメモリに機密情報が含まれている場合、攻撃者はそのデータにアクセスできるようになります。
この欠陥は、SSL Heartbleed バグと類似しています。
メモリのコピーまたは操作を行う際、長さの引数をデータから直接計算して、サイズが一致するようにします。
#include <stdlib.h>
#include <string.h>
typedef struct buf_mem_st {
char *data;
size_t max; /* size of buffer */
} BUF_MEM;
extern BUF_MEM beta;
int cpy_data(BUF_MEM *alpha)
{
BUF_MEM *os = alpha;
int num, length;
if (alpha == 0x0) return 0;
num = 0;
length = *(unsigned short *)os->data;
memcpy(&(beta.data[num]), os->data + 2, length); //Noncompliant
return(1);
}この関数では、バッファー alpha をバッファー beta にコピーします。しかし、変数 length は data+2 とは関連していません。
1 つの修正方法として、バッファーの長さを、最大値から 2 を引いた値に対してチェックします。このチェックにより、構造体 beta にデータをコピーする十分なスペースが確保されます。
#include <stdlib.h>
#include <string.h>
typedef struct buf_mem_st {
char *data;
size_t max; /* size of buffer */
} BUF_MEM;
extern BUF_MEM beta;
int cpy_data(BUF_MEM *alpha)
{
BUF_MEM *os = alpha;
int num, length;
if (alpha == 0x0) return 0;
num = 0;
length = *(unsigned short *)os->data;
if (length<(os->max -2)) {
memcpy(&(beta.data[num]), os->data + 2, length);
}
return(1);
}この問題は、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;
}
}チェック情報
| カテゴリ: 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)