メインコンテンツ

CERT C: Rec.PRE09-C

セキュリティ保護された関数を非推奨または使用されなくなった関数と置き換えない

説明

ルール定義

セキュリティ保護された関数を非推奨または使用されなくなった関数と置き換えないようにします。1

Polyspace 実装

ルール チェッカーは以下の問題をチェックします。

  • 危険な標準関数を使用しています

  • 格納先バッファー サイズが不十分

すべて展開する

問題

危険な標準関数を使用していますチェックでは、特定の環境において本質的に危険か潜在的に危険な関数の使用が強調表示されます。次の表に、潜在的に危険な関数、各関数を使用する場合のリスクおよび代用する関数をリストします。

危険な関数リスク レベルより安全な関数
gets本質的に危険 — コンソールからは入力の長さを制御できない。fgets
cin本質的に危険 — コンソールからは入力の長さを制御できない。使用を避けるか、cin の呼び出しの前に cin.width を追加する。
strcpy潜在的に危険 — ソースの長さがコピー先より大きいと、バッファー オーバーフローが発生する可能性がある。strncpy
stpcpy潜在的に危険 — ソースの長さがコピー先より大きいと、バッファー オーバーフローが発生する可能性がある。stpncpy
lstrcpy または StrCpy潜在的に危険 — ソースの長さがコピー先より大きいと、バッファー オーバーフローが発生する可能性がある。StringCbCopyStringCchCopystrncpystrcpy_s または strlcpy
strcat潜在的に危険 — 連結された結果が作成先より大きいと、バッファー オーバーフローが発生する可能性がある。strncatstrlcat または strcat_s
lstrcat または StrCat潜在的に危険 — 連結された結果が作成先より大きいと、バッファー オーバーフローが発生する可能性がある。StringCbCatStringCchCatstrncaystrcat_s または strlcat
wcpcpy潜在的に危険 — ソースの長さがコピー先より大きいと、バッファー オーバーフローが発生する可能性がある。wcpncpy
wcscat潜在的に危険 — 連結された結果が作成先より大きいと、バッファー オーバーフローが発生する可能性がある。wcsncatwcslcat または wcncat_s
wcscpy潜在的に危険 — ソースの長さがコピー先より大きいと、バッファー オーバーフローが発生する可能性がある。wcsncpy
sprintf潜在的に危険 — 出力の長さが不明な長さや値に依存していると、バッファー オーバーフローが発生する可能性がある。snprintf
vsprintf潜在的に危険 — 出力の長さが不明な長さや値に依存していると、バッファー オーバーフローが発生する可能性がある。vsnprintf
リスク

これらの関数はバッファー オーバーフローの原因となることがあり、攻撃者はこれを利用してプログラムに侵入できます。

修正方法

修正方法は欠陥の根本原因によって異なります。多くの場合、結果の詳細には欠陥につながる一連のイベントが表示されます。そのシーケンス内のどのイベントについても修正を実装できます。結果の詳細にイベント履歴が表示されない場合は、ソース コード内で右クリック オプションを使用して逆のトレースを行い、これまでの関連するイベントを確認できます。Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈も参照してください。

以下の修正例を参照してください。

問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。

例 - sprintf の使用
#include <stdio.h>
#include <string.h>
#include <iostream>

#define BUFF_SIZE 128


int dangerous_func(char *str)
{
    char dst[BUFF_SIZE];
    int r = 0;

    if (sprintf(dst, "%s", str) == 1) //Noncompliant
    {
        r += 1;
        dst[BUFF_SIZE-1] = '\0';
    }
    
    return r;
}

この関数例では、sprintf を使用して文字列 strdst にコピーしています。しかし、str がバッファーより大きいと、sprintf がバッファー オーバーフローの原因となる場合があります。

修正 — バッファー サイズを指定して snprintf を使用

1 つの修正方法として、snprintf を代わりに使用し、バッファー サイズを指定します。

#include <stdio.h>
#include <string.h>
#include <iostream>

#define BUFF_SIZE 128


int dangerous_func(char *str)
{
    char dst[BUFF_SIZE];
    int r = 0;

    if (snprintf(dst, sizeof(dst), "%s", str) == 1)
    {
        r += 1;
        dst[BUFF_SIZE-1] = '\0';
    }
    
    return r;
}
問題

"格納先バッファー サイズが不十分" は、strcpy 演算内の格納先バッファーにソース バッファーと null 終端が収まらない場合に発生します。この問題は、ソース バッファーのサイズが不明な場合に報告されます。次のコードについて考えます。

int main (int argc, char *argv[])
{
  const char *const input = ((argc && argv[0]) ? argv[0] : "");
  char str[100];
  strcpy(input, str); // Noncompliant
}
このケースでは、ソース バッファー input のサイズが不明です。格納先バッファー str のサイズが、値 (strlen(input)+1) より小さい可能性があります。Polyspace® は、strcpy 演算に対する違反を報告します。

リスク

サイズが不十分な格納先バッファーを使用すると、攻撃者がバッファー オーバーフローを引き起こすことができるようになる可能性があります。前のコード例では、argv[0] に 100 個以上の文字が含まれている場合に、strcpy 演算でバッファー オーバーフローが発生します。

修正方法

関数 strcpy() を呼び出す前に、十分なメモリを動的に割り当てます。たとえば、関数 strlen() を使用してソース バッファーのサイズを決定してから、格納先バッファーを、そのサイズが値 strlen(source) + 1 を上回るように割り当てます。

例 — 格納先バッファーが小さすぎる

この例では、source バッファーのサイズは不明ですが、destination バッファーのサイズは 128 で固定されます。この destination バッファーのサイズは、source バッファーからの文字を収め、そのバッファーを null で終了するには不十分な可能性があります。Polyspace は、ルールの違反を報告します。

#include <string.h>
  
int main(int argc, char *argv[]) {
  const char *const source = (argc && argv[0]) ? argv[0] : "";
  char destination[128];
  strcpy(source, destination);//Noncompliant
  
  return 0;
}
修正 — 格納先バッファーに十分なメモリを割り当てる

この違反は、destination バッファーに十分なメモリを割り当てることによって解決されます。たとえば、関数 strlen() を使用して source バッファーのサイズを計算し、source バッファーからのすべての文字と null 終端 ('\0') を収めるのに十分なメモリを destination バッファーに割り当てます。

#include <string.h>
  
int main(int argc, char *argv[]) {
  const char *const source = (argc && argv[0]) ? argv[0] : "";
  char* destination = (char *)malloc(strlen(source)+ 1);
  if(destination!=NULL){
      strcpy(source, destination);//Compliant
  }else{
      /*Handle Error*/
  }
  //...
  free(destination);
  return 0;
}

チェック情報

グループ: Rec.01.プリプロセッサ (PRE)

バージョン履歴

R2019a で導入

すべて展開する


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.