SizeofPtr -- ポインタ型に対する sizeof() の使用
C++ 検査 への移動
説明
SizeofPtr では、ポインタ式に対して意図せず sizeof() を使用している場合に警告を出力します。
malloc で割り当てられたポインタ型に対してコードで sizeof() を呼び出しています(必ず wordsize/8
が返されます)。 どれだけのメモリが割り当てられているかを判断するためにそのようなコードにしている場合には、予期しない結果が生じる可能性があります。
例 1
データ構造を指すポインタのサイズではなくデータ構造自体のサイズを sizeof が返すようにするには、注意が必要です。
次の例では sizeof(foo)
はポインタのサイズを返してしまいます。
double *foo;
...
foo = (double *)malloc(sizeof(foo));
次の例では、sizeof(*foo)
はポインタのサイズではなくデータ構造のサイズを返します。
double *foo;
...
foo = (double *)malloc(sizeof(*foo));
例 2
次の例では、固定されたユーザー名とパスワードが定義されています。 AuthenticateUser() 関数では、信頼できないユーザーからユーザー名とパスワードを受け取り、それが固定のユーザー名およびパスワードと一致するかを確認します。 ユーザー名とパスワードが一致すれば、AuthenticateUser() は認証が成功したことを示します。
char *username = "admin";
char *pass = "password";
int AuthenticateUser(char *inUser, char *inPass) {
printf("Sizeof username = %d\n", sizeof(username));
printf("Sizeof pass = %d\n", sizeof(pass));
if (strncmp(username, inUser, sizeof(username))) {
printf("Auth failure of username using sizeof\n");
return(AUTH_FAIL);
}
/* sizeof returns 4 on many platforms and architectures. */
if (! strncmp(pass, inPass, sizeof(pass))) {
printf("Auth success of password using sizeof\n");
return(AUTH_SUCCESS);
}
else {
printf("Auth fail of password using sizeof\n");
return(AUTH_FAIL);
}
}
int main (int argc, char **argv)
{
int authResult;
if (argc < 3) {
ExitError("Usage: Provide a username and password");
}
authResult = AuthenticateUser(argv[1], argv[2]);
if (authResult != AUTH_SUCCESS) {
ExitError("Authentication failed");
}
else {
DoAuthenticatedTask(argv[1]);
}
}
ところが、AuthenticateUser() では配列型のパラメータに対して sizeof() を適用しています。現在の多くのアーキテクチャでは sizeof() は 4 を返します。 その結果、strncmp() を呼び出したときには入力パスワードの最初の 4 文字しか確認されないことになり、一部しか比較されないため正しく認証が行われません。
一部しか比較されないため、"admin" ユーザーに対して次のどのパスワードを指定しても、認証は成功します。
pass5 passABCDEFGH passWORD
確認対象が最初の 4 文字だけなので、攻撃を受けたときの検索範囲が大幅に狭まり、総当たり攻撃を実行しやすくなってしまいます。
ユーザー名にも同じ問題が発生します。つまり、adminXYZ
や administrator
などの値をユーザー名に指定しても認証が成功します。