CWE Rule 188
説明
ルールの説明
The software makes invalid assumptions about how protocol data or memory is organized at a lower level, resulting in unintended program behavior.
Polyspace 実装
ルール チェッカーは以下の問題をチェックします。
メモリ編成の前提条件が無効です
パディング データのメモリ比較
データ転送時の欠落しているバイトの並べ替え
例
この問題は、スタック内の変数のアドレスが、別の非配列変数のアドレスに対して加算または減算することによって計算された場合に発生します。
スタック内の変数のアドレスが、別の変数のアドレスに対し加算または減算を行うことによって計算される場合は、特定のメモリ編成が仮定されています。仮定に誤りがある場合、計算されたアドレスへのアクセスが無効になることがあります。
メモリ編成についての仮定に依存したアクセスは実行しないようにします。
void func(void) {
int var1 = 0x00000011, var2;
*(&var1 + 1) = 0; //Noncompliant
}この例で、プログラマは、&var1 + 1 が var2 のアドレスを提供するという仮定に依存しています。したがって、[メモリ編成の前提条件が無効です] が + 演算に表示されます。さらに、[範囲外にアクセスするポインター] エラーもデリファレンスに表示されます。
1 つの修正方法として、別々に宣言された変数にアクセスする目的で、アドレスについて直接計算を実行しないようにします。
この問題は、memcmp 関数を使用して、2 つの構造体全体が比較された場合に発生します。この処理では、構造体のパディングで格納された無意味なデータが比較されます。
次に例を示します。
struct structType {
char member1;
int member2;
.
.
};
structType var1;
structType var2;
.
.
if(memcmp(&var1,&var2,sizeof(var1)))
{...}
構造体のメンバーが異なるデータ型を持っている場合、コンパイラはメモリ内のデータ アライメントのために追加のパディングを導入します。パディングの例については、ローカル変数サイズのより高い推定値 (Polyspace Code Prover)を参照してください。
これらの追加のパディング バイトの内容に意味はありません。C 標準では、さまざまなコンパイラが独自のパディングを自由に実装できるように、それらのバイトのコンテンツが不確定になることを許容しています。memcmp で構造体のバイト単位の比較を実行する場合、パディングに格納された意味のないデータも比較されます。対応するメンバーが同じ値であっても、2 つのデータ構造体が等しくないという誤った結論になる可能性があります。
2 つの構造体を 1 回の試行で比較するのではなく、構造体のメンバーごとに比較します。
効率的なコードにするには、メンバーごとに比較を行う関数を作成します。2 つの構造体を比較するには、この関数を使用します。
構造体がパディングを含まないことがわかっている場合のみ、構造体のバイト単位の比較に memcmp を使用します。通常、パディングが行われないようにするには、特定の属性または #pragma pack などのプラグマを使用します。ただし、このような属性やプラグマは、必ずしもすべてのコンパイラでサポートされているとは限らず、コードの実装はそれぞれ異なります。構造体にビット フィールドが含まれる場合、このような属性やプラグマを使用しても、パディングを防ぐことはできません。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define fatal_error() abort()
typedef struct s_padding
{
char c;
int i;
unsigned int bf1:1;
unsigned int bf2:2;
unsigned char buffer[20];
} S_Padding ;
/* Function that guarantees safe access to the input memory */
extern int trusted_memory_zone(void *ptr, size_t sz);
int func(const S_Padding *left, const S_Padding *right)
{
if (!trusted_memory_zone((void *)left, sizeof(S_Padding)) ||
!trusted_memory_zone((void *)right, sizeof(S_Padding))) {
fatal_error();
}
if (0 == memcmp(left, right, sizeof(S_Padding))) //Noncompliant
{
return 1;
}
else
return 0;
}この例では、memcmp を使用して left および right が指す 2 つの構造体をバイト単位で比較しています。構造体の各メンバーに格納された値が同じでも、パディング バイトに使われる意味のない値が同じでなければ、この比較によって等しくないという結果になる可能性があります。
1 つの修正方法として、構造体のメンバーを個別に比較します。
メモ
memcmp を使用して、配列全体を比較できます。配列のメンバーはすべてデータ型が同じです。配列の格納にはパディング バイトは必要ありません。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define fatal_error() abort()
typedef struct s_padding
{
char c;
int i;
unsigned int bf1:1;
unsigned int bf2:2;
unsigned char buffer[20];
} S_Padding ;
/* Function that guarantees safe access to the input memory */
extern int trusted_memory_zone(void *ptr, size_t sz);
int func(const S_Padding *left, const S_Padding *right)
{
if (!trusted_memory_zone((void *)left, sizeof(S_Padding)) ||
!trusted_memory_zone((void *)right, sizeof(S_Padding))) {
fatal_error();
}
return ((left->c == right->c) &&
(left->i == right->i) &&
(left->bf1 == right->bf1) &&
(left->bf2 == right->bf2) &&
(memcmp(left->buffer, right->buffer, 20) == 0));
}この問題は、以下のタイミングでバイト順関数が使用されなかった場合に発生します。
ネットワーク ソケットにデータを送信する前。
ネットワーク ソケットからデータを受信した後。
リトル エンディアン バイト順 (最下位バイトが先) を実装しているシステム アーキテクチャもあれば、ビッグ エンディアン バイト順 (最上位バイトが先) を実装しているシステム アーキテクチャもあります。送信データのエンディアンが受信システムのエンディアンと一致しない場合、データ読み取り時に返される値は正しくありません。
ソケットからデータを受信した後に、ntohl() などのバイト順関数を使用します。ソケットにデータを送信する前に、htonl() などのバイト順関数を使用します。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <byteswap.h>
#include <unistd.h>
#include <string.h>
unsigned int func(int sock, int server)
{
unsigned int num; /* assume int is 32-bits */
if (server)
{
/* Server side */
num = 0x17;
/* Endianness of server host may not match endianness of network. */
if (send(sock, (void *)&num, sizeof(num), 0) < (int)sizeof(num)) //Noncompliant
{
/* Handle error */
}
return 0;
}
else {
/* Endianness of client host may not match endianness of network. */
if (recv (sock, (void *)&num, sizeof(num), 0) < (int) sizeof(num))
{
/* Handle error */
}
/* Comparison may be inaccurate */
if (num> 255) //Noncompliant
{
return 255;
}
else
{
return num;
}
}
}
この例では、変数 num は 16 進数値 0x17 が代入され、ネットワークを経由してサーバーからクライアントに送信されます。サーバー ホストがリトル エンディアンで、ネットワークがビッグ エンディアンの場合、num は 0x17000000 として転送されます。その後、クライアントでは num の誤った値を読み取って、ローカルの数値と比較します。
サーバー ホストから num を送信する前に、htonl() を使用してホストからネットワークへのバイト順を変換します。同様に、クライアント ホストで num を読み取る前に、ntohl() を使用して、ネットワークからホストへのバイト順を変換します。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <byteswap.h>
#include <unistd.h>
#include <string.h>
unsigned int func(int sock, int server)
{
unsigned int num; /* assume int is 32-bits */
if (server)
{
/* Server side */
num = 0x17;
/* Convert to network byte order. */
num = htonl(num);
if (send(sock, (void *)&num, sizeof(num), 0) < (int)sizeof(num))
{
/* Handle error */
}
return 0;
}
else {
if (recv (sock, (void *)&num, sizeof(num), 0) < (int) sizeof(num))
{
/* Handle error */
}
/* Convert to host byte order. */
num = ntohl(num);
if (num > 255)
{
return 255;
}
else
{
return num;
}
}
} チェック情報
| カテゴリ: 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)