JPCERT コーディネーションセンター

INT06-C. 文字列トークンを整数に変換するには strtol() 系の関数を使う

文字列トークンを整数に変換するには strtol 系関数を使うこと。これらの関数は他の方法よりも堅牢なエラー処理を提供する。

strtol()strtoll()strtoul() および strtoull() 関数は、null 終端バイト文字列の最初の部分を、long intlong long intunsigned long int および unsigned long long int へそれぞれ変換する。

signed intsigned shortsinged char など、より小さな符号付き型に変換するには、strtol() 関数を使い、結果の値をその型の範囲に照らし合わせてテストすること。

unsigned intunsigned shortunsigned char などより小さな符号無し型に変換するには、strtoul() 関数を使い、結果の値をその型の範囲に照らし合わせてテストすること。

これらの範囲テストは、より小さな型がたまたま同じサイズと表現を持つような特定のコンパイラではなにもしない。

違反コード (atoi())

以下のコード例は、静的配列 buff に格納されている文字列トークンを、atoi() 関数を使用して符号付き整数値に変換している。

int si;

if (argc > 1) {
  si = atoi(argv[1]);
}

atoi()atol() および atoll() 関数は、文字列トークンをそれぞれ intlong intlong long int 表現に変換する。エラーが発生する場合を除き、以下と同じ結果になる。

atoi: (int)strtol(nptr, (char **)NULL, 10)
atol: strtol(nptr, (char **)NULL, 10)
atoll: strtoll(nptr, (char **)NULL, 10)

残念ながら atoi() 系の関数は無効な値に対してエラーを報告するメカニズムを持っていない。特に atoi()atol()atoll() の各関数は以下の特徴を持つ。

違反コード(sscanf())

以下のコード例では、sscanf() 関数を使って文字列トークンを整数に変換している。sscanf() 関数には atoi() と同じ制限がある。

int matches; 
int si;

if (argc > 1) {
  matches = sscanf(argv[1], "%d", &si);
  if (matches != 1) {
    /* エラー処理 */
  }
}

sscanf() 関数は、一致と代入が成功した入力要素の個数を返す。返される値は渡された変換の個数よりも少ないこともあり、最初に一致の失敗があった場合には 0 になることもある。しかし、sscanf() は、strtol() が報告するオーバーフローなどのような他のエラーについては報告しない。

適合コード (strtol())

strtol()strtoll()strtoul() および strtoull() 関数は、null終端バイト文字列をそれぞれ long intlong long intunsigned long int および unsigned long long int 表現にそれぞれ変換する。

この適合コードでは、strtol() を使って文字列トークンを整数に変換しており、結果の値が int の範囲にあることを保証している。

int main(int argc, char *argv[]) {

  if (argc < 2)
    return EXIT_SUCCESS;

  const char* const str = argv[1];
  char *end;
  int si;

  errno = 0;

  const long sl = strtol(str, &end, 10);

  if (end == str) {
    fprintf(stderr, "%s: not a decimal number\n", str);
  }
  else if ('\0' != *end) {
    fprintf(stderr, "%s: extra characters at end of input: %s\n", str, end);
  }
  else if ((LONG_MIN == sl || LONG_MAX == sl) && ERANGE == errno) {
    fprintf(stderr, "%s out of range of type long\n", str);
  }
  else if (sl > INT_MAX) {
    fprintf(stderr, "%ld greater than INT_MAX\n", sl);
  }
  else if (sl < INT_MIN) {
    fprintf(stderr, "%ld less thatn INT_MIN\n", sl);
  }
  else {
    si = (int)sl;

    /* si を使った処理 */

    return EXIT_SUCCESS;
  }
  return EXIT_FAILURE;
}
リスク評価

このレコメンデーションの違反がセキュリティ上の脆弱性につながることはまれだが、データの欠損や誤解釈には容易につながるおそれがある。

レコメンデーション

深刻度

可能性

修正コスト

優先度

レベル

INT06-C

P8

L2

自動検出

ツール

バージョン

チェッカー

説明

Compass/ROSE

 

 

以下に挙げる関数呼び出しを警告することで、このレコメンデーションの違反を検出できる。

    • atoi()
    • scanf(), fscanf(), sscanf()
    • others?

Fortify SCA

5.0

 

CERT C Rule Packを使ってこのレコメンデーションの違反を検出できる

LDRA tool suite

V. 8.5.4

44 S

実装済み

PRQA QA-C 8.1 Warncall -wc atoi, -wc atol 部分的に実装済み
関連するガイドライン
CERT C++ Secure Coding Standard INT06-CPP. Use strtol() or a related function to convert a string token to an integer
MITRE CWE CWE-676, Use of potentially dangerous function
CWE-20, Insufficient input validation
参考資料
[Klein 2002]
翻訳元

これは以下のページを翻訳したものです。

INT06-C. Use strtol() or a related function to convert a string token to an integer (revision 86)

Top へ

Topへ
最新情報(RSSメーリングリストTwitter