CodeZine(コードジン)

特集ページ一覧

配列コピー時に犯しやすい誤りに注意する
――C/C++セキュアコーディング入門(6)

「動けばいいってもんじゃない」 脆弱性を作り込まないコーディング 第6回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2010/02/15 14:00

 配列をコピーする際、記憶領域の扱いを適切に行わないとバッファオーバーフローにつながります。コピー元のデータ量またはコピー先の記憶領域のサイズをチェックするのが基本的な対策になりますが、誤って脆弱性を引き起こすことも多々あります。今回は、こういった配列コピー時に犯しやすい誤りについて解説します。

目次

配列コピー時に犯しやすい誤り

 データをコピーする先の記憶領域として十分なサイズが確保されていないと、バッファオーバーフローに繋がります。例えば、コピー先の領域として確保するサイズが不十分だったり、コピー先の領域は意図どおり確保していても、コピーするデータのサイズを誤って指定してしまう場合などです。

 典型的な誤りとしては、文字列コピーにおけるNULL終端バイト分のサイズの配慮し忘れがあります(関連ルール「STR31-C. 文字データとNULL終端文字を格納するために十分なサイズの領域を確保する」を参照)。

 また、コピーサイズを計算する際に整数オーバーフローが発生したり、正の値を処理することを想定しているロジックに負の値を持った符号付き整数を渡すことで、暗黙の変換により大きな正の値として扱われて問題を起こすケースもあります(関連ルール「STR31-C. 文字データとNULL終端文字を格納するために十分なサイズの領域を確保する」「INT32-C. 符号付き整数演算がオーバーフローを引き起こさないことを保証する」を参照)。

 こういったコーディング上の誤りが脆弱性に繋がるケースも少なくありません。例えば、オープンソースのネットワーク侵入検知システムであるSourcefire Snortの旧バージョンには、改ざんされたパケットを送りつけることでサービス停止妨害や任意のコード実行が可能になる脆弱性(CVE-2006-5276)が存在しました。

 コーディング時における基本的な対策として、(1)コピー先のサイズに応じてコピーするデータ量を制限する、あるいは(2)コピー先に十分なサイズの領域を確保する、ということを確実に行う必要があるのです。

 今回はこういった配列コピー時に犯しやすい誤りについて解説します。

コピーサイズとして誤った値を指定

 次に示すコード例は、memcpy()を用いて配列のコピーを行います。memcpy()のサイズ引数としてコピー元の記憶領域サイズを指定していますが、これはコピー先の記憶領域サイズよりも大きいため、バッファオーバーフローが発生します。

コード例1(コピー先の領域に基づいた制限を行っていない)
enum { WORKSPACE_BOUND = 256 };

void func(const int *src, size_t num_elem) {
  int dest[WORKSPACE_BOUND];
  memcpy(dest, src, num_elem * sizeof(int)); //コピー先の領域に基づいた制限を行っていない
  /* ... */
}

 文字列操作関数strncpy()の使用においても同じような誤りを犯しがちです。

 また、配列コピーの際、配列要素型のサイズを考慮し忘れるとコピーデータの欠損に繋がります。

コード例2(配列要素型のサイズを考慮していない)
enum { WORKSPACE_BOUND = 256 };

void func(const int *src, size_t num_elem) {
  int dest[WORKSPACE_BOUND];
  memcpy(dest, src, WORKSPACE_BOUND); //配列要素型のサイズを考慮していない
  /* ... */
}

 これらのコーディングエラーは、単体テストレベルで明らかになる部類のものですが、コーディング段階で十分注意しておきたいものです。

コピーするデータ量をコピー先の記憶領域に基づき制限

 コピーするデータ量をコピー先の記憶領域に基づいて制限する場合、コピー元のデータがコピー先の領域に収まることをあらかじめ確認する必要があります。

コード例3(コピー元のデータがコピー先に収まることを確認)
enum { WORKSPACE_BOUND = 256 };

void func(const int *src, size_t num_elem) {
  int dest[WORKSPACE_BOUND];
  if (num_elem > WORKSPACE_BOUND) {
    /* コピー先の記憶領域が不足するためエラー処理などの対応 */
  }
  memcpy(dest, src, sizeof(int) * num_elem);
  /* ... */
}

  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:C/C++セキュアコーディング入門

著者プロフィール

  • 富樫 一哉(トガシ カズヤ)

    システム開発マネージャ JPCERTコーディネーションセンター カナダ British Columbia Institute of Technologyにて、Bachelor of Technology in Computer Systems修了。メーカー系、独立系システムインテグレーターにて、...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5