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

FIO44-C. fsetpos() には fgetpos() が返す値を使用する

FIO44-C. fsetpos() には fgetpos() が返す値を使用する

C99 のセクション 7.19.9.3 は fsetpos() の動作を次のように定めている[ISO/IEC 9899:1999]。

fsetpos 関数は、pos が指すオブジェクトの値に従って、stream が指すストリームの mbstate_t オブジェクト(もしあれば)およびファイル位置表示子を設定する。pos が指すオブジェクトの値は、同じファイルに結び付いたストリームに対するそれ以前の成功した fgetpos 関数の呼び出しから得られた値でなければならない。

したがって、fgetpos() が返す値以外のいかなる値を pos に使用しても未定義の動作となるため、これは避けるべきである。

違反コード

以下のコードでは、ファイルから3つの値を読み取り、読み取り位置をファイルの先頭に設定し、呼び出し元に戻る。

enum { NO_FILE_POS_VALUES = 3 };

int opener(FILE* file, /* ... */ ) {
  int rc;
  fpos_t offset;

  /* ... */

  memset(&offset, 0, sizeof(offset));

  if (file == NULL) { return EINVAL; }

  /* ファイルからのデータ読込み */

  rc = fsetpos(file, &offset);
  if (rc != 0 ) { return rc; }

  /* ... */

  return 0;
}

しかし、fsetpos() への有効な引数は fgetpos() の返り値だけであるため、他の手段で作成された fpos_t を使用してはいけない。位置指定子はファイルの任意の位置に設定される可能性がある。

適合コード

以下の解決法では、fgetpos() を呼び出してファイル位置表示子の初期位置を格納し、後で fsetpos() を呼び出す際に読み込み位置を元に戻すために使用している。

enum { NO_FILE_POS_VALUES = 3 };

int opener(FILE* file, /* ... */) {
  int rc;
  fpos_t offset;

  /* ... */

  if (file == NULL) { return EINVAL; }

  rc = fgetpos(file, &offset);
  if (rc != 0 ) { return rc; }

  /* ファイルからのデータ読み込み */

  rc = fsetpos(file, &offset);
  if (rc != 0 ) { return rc; }

  /* ... */

  return 0;
}
リスク評価

fsetpos() を誤用すると、ファイルストリームの読み取りが意図しない位置で行われる可能性がある。この位置を指定する引数にユーザからの入力が使われている場合、ファイルから読み取られる変数をユーザが自由に操作できる可能性がある。

ルール 深刻度 可能性 修正コスト 優先度 レベル
FIO44-C P4 L3
自動検出

CERT C Rule Pack を適用した Fortify SCA バージョン 5.0 はこのルールの違反を検知することができる。

Compass/ROSE はこのルールの一般的な違反を検知することができる。しかし、fgetpos() の返り値が複数の変数にわたってコピーされてから fsetpos() に渡されるようなケースは正しく扱えない。

参考情報
翻訳元

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

FIO44-C. Only use values for fsetpos() that are returned from fgetpos()

Top へ

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