配列コピー時に犯しやすい誤りに注意する
――C/C++セキュアコーディング入門(6)
「動けばいいってもんじゃない」 脆弱性を作り込まないコーディング 第6回
コピー元のデータ量に基づきコピー先の記憶領域を動的に確保
コピー元のデータ量に基づいてコピー先の記憶領域を動的に確保する場合には、以下のようなコードになるでしょう。動的に確保するコピー先領域のサイズを計算する際、演算結果が整数オーバーフローを引き起こさないことをチェックする必要があります。
void func(const int *src, size_t num_elem) {
int *dest;
if (num_elem > SIZE_MAX/sizeof(int)) {
/* 整数オーバーフロー時の処理 */
}
dest = (int *)malloc(sizeof(int) * num_elem);
if (dest == NULL) {
/* 動的領域確保に失敗した場合の処理 */
}
memcpy(dest, src, sizeof(int) * num_elem);
/* ... */
free(dest);
}
サイズを示す変数は符号なし整数を用いて符号エラーを避ける
以下に、上記のコードを一部変更したコード例を示します。コピーする配列の要素数を示す値を符号付き整数(int num_elem)で受けており、渡された配列の要素数が上限値未満であることを確認しています。しかしこのコードでは、配列要素数として負の値が渡される可能性を考慮していません。もしも配列要素数として負の値が渡された場合、上限値検査をパスし、malloc()の引数として符号付き型から符号なし型への(暗黙の)変換が発生、その結果、巨大な正の値として取り扱われてしまいます。
void func(const int *src, int num_elem) {
int *dest;
if (num_elem < SIZE_MAX/sizeof(int)) { //負の値に対する下限チェックがない
dest = (int *)malloc(sizeof(int) * num_elem);
・・・
}else{
/* 整数オーバーフロー時の処理 */
}
・・・
この例では、負の値を取りうる配列要素数に対して下限検査が行われていないため、プログラマが意図していない非常に大きな記憶領域が確保されてしまう可能性があります。また、memcpy()などの引数として負の値が渡されるケースでは、コピー先領域を超えたサイズを指定することになり、バッファオーバーフローに繋がってしまうでしょう。
上記のようなコード例においては、下限チェックを加えることにより引数が正の値であることを確認する必要があります。そもそも、オブジェクトのサイズや配列のインデックスのような正の値を取るべき変数には、最初からsize_t型やunsigned int型などの符号なしの型を利用すべきでしょう。
文字列をはじめとする配列データの操作のために領域を確保したり、必要なサイズを計算することは多くあります。そのような場合に整数オーバーフローやバッファオーバーフローに繋がらないよう、コーディング時に注意を払いましょう。
今後の連載について
これまで6回にわたりセキュアなコーディングを行うために心がけるポイントや方法について解説してきたこの連載ですが、いったん、ここで終了させたいと思います。
しかし、まだまだカバーできていないトピックが「CERT C セキュアコーディングスタンダード」には残っています。これらについては、記事の形式をコードレビュー形式に変えた上で、近いうちに新しい連載として開始する予定です。
こうご期待。
参考資料
この記事は参考になりましたか?
既に会員の方はを行ってください。
- C/C++セキュアコーディング入門連載記事一覧
-
- 配列コピー時に犯しやすい誤りに注意する ――C/C++セキュアコーディング入門(6)
- sizeofオペレータを正しく使おう ――C/C++セキュアコーディング入門(5)
- 安全なシグナルハンドラを実装するには ――C/C++セキュアコーディング入門(4)
- この記事の著者
-
富樫 一哉(トガシ カズヤ)
システム開発マネージャJPCERTコーディネーションセンターカナダ British Columbia Institute of Technologyにて、Bachelor of Technology in Computer Systems修了。メーカー系、独立系システムインテグレーターにて、システム...
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
この記事は参考になりましたか?
この記事をシェア
