SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

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

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

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


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

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

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

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

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

 典型的な誤りとしては、文字列コピーにおける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);
  /* ... */
}

会員登録無料すると、続きをお読みいただけます

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

次のページ
コピー元のデータ量に基づきコピー先の記憶領域を動的に確保

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
C/C++セキュアコーディング入門連載記事一覧

もっと読む

この記事の著者

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

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

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/4831 2010/04/26 14:19

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング