実例で学ぶ脆弱性対策コーディング 第6回

 本連載では、脆弱性を含むサンプルコードを題材に、修正方法の例を解説していきます。今回は以前にも取り上げたオープンソースの画像処理ライブラリであるlibtiffに最近見つかった脆弱性を、セキュリティコードレビューを行いながら見てみましょう。

1 2 3 →

 今回は、第2回でも取り上げたオープンソースの画像処理ライブラリであるlibtiffに最近見つかった脆弱性を、セキュリティコードレビューを行いながら見てみましょう。

サンプルコード

 以下のコードはlibtiff 3.9.2の/libtiff/tif_getimage.cから抜粋したものです。実際のコードでは、マクロを何段にも活用して関数定義を行っています。ここでは、YCbCrtoRGB以外のマクロはすべて展開した形で引用しました。それでは、このコードのどこに問題があるのかを考えてみましょう。

/*
 * YCbCr -> RGB conversion and packing routines.
 */
#define YCbCrtoRGB(dst, Y) { \
  uint32 r, g, b; \
  TIFFYCbCrtoRGB(img->ycbcr, (Y), Cb, Cr, &r, &g, &b); \
  dst = ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|(((uint32)0xffL)<<24)) \
}

/*
 * 8-bit packed YCbCr samples w/ 2,2 subsampling => RGB
 */
static void putcontig8bitYCbCr22tile(
      TIFFRGBAImage* img,
      uint32* cp,
      uint32 x, uint32 y,
      uint32 w, uint32 h,
      int32 fromskew, int32 toskew,
      unsigned char* pp
)
{
  uint32* cp2;
  (void) y;
  fromskew = (fromskew / 2) * 6;
  cp2 = cp+w+toskew;
  while (h>=2) {
    x = w;
    while (x>=2) {
      uint32 Cb = pp[4];
      uint32 Cr = pp[5];
      YCbCrtoRGB(cp[0], pp[0]);
      YCbCrtoRGB(cp[1], pp[1]);
      YCbCrtoRGB(cp2[0], pp[2]);
      YCbCrtoRGB(cp2[1], pp[3]);
      cp += 2;
      cp2 += 2;
      pp += 6;
      x -= 2;
    }
    if (x==1) {
      uint32 Cb = pp[4];
      uint32 Cr = pp[5];
      YCbCrtoRGB(cp[0], pp[0]);
      YCbCrtoRGB(cp2[0], pp[2]);
      cp ++ ;
      cp2 ++ ;
      pp += 6;
    }
    cp += toskew*2+w;
    cp2 += toskew*2+w;
    pp += fromskew;
    h-=2;
  }
  (中略)
}

 putcontig8bitYCbCr22tile()関数は画像データの変換に使われる関数のひとつです。libtiffライブラリ内部では、画像データを1ピクセルRGBA各8ビット合計32ビットで表現しています。入出力においてさまざまな形式の画像データに対応するため、このような変換関数が多数用意されているのです。

 元データは引数に渡されるimgの先にあり、変換したデータを格納するための十分な大きさを持ったバッファはあらかじめ用意され、引数のcpで渡されます。fromskewやtoskewは画像の反転などのような変形操作のパラメータです。whileループのなかでは、各ピクセルデータを指すポインタを動かしながら、各ピクセルの色情報をTIFFYCbCrtoRGB()を使ってYCbCr形式からRGB形式に変換してバッファに書き込んでいくという処理を行っています。

脆弱性の解説:64ビット環境で問題になる整数変換

 このコードで注目すべき箇所は、ポインタを移動させる

cp += toskew*2 + w;

 という演算です。ここで使われている各変数の型を確認してみてください。

ポインタ値 += 2 * int32値 + uint32値

 このコードが64ビット環境でコンパイル・実行されると、int32型の変数値が負の値をとるときに問題が発生します。それでは順を追って見ていきましょう。

 代入式の右辺をみると、(int32型 * 定数) + uint32型となっており、これはint32型 + uint32型の演算式として評価されます。int32型は符号付き整数型、uint32型は符号無し整数型なので、これら2つのオペランドは異なる型を持ちます。このように異なる型が混在する加算演算を行う場合にはどちらか一方の型に合わせるような型変換が行われます。さて、どちらの型に合わせるか分かりますか? Cでは「通常の算術型変換」(usual arithmetic conversion)と呼ばれるルールに従い、型変換が行われます。


1 2 3
→
INDEX
TIFFライブラリに潜む脆弱性をつぶすパッチ(その2)
Page1
サンプルコード
脆弱性の解説:64ビット環境で問題になる整数変換
「通常の算術型変換」
プログラムのクラッシュは脅威
参考情報
プロフィール
久保 正樹(JPCERT コーディネーションセンター) クボ マサキ(JPCERT コーディネーションセンター)

脆弱性アナリスト

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

慶応義塾大学環境情報学部卒。ソニーでデスクトップPCのソフトウェア開発に携わったのち、米国ダートマス大学にてオーディオ信号処理、電子音響音楽の研究を行い、電子音響音楽修士を取得。2005年4月よりJPCERTコーディネーションセンターにて、脆弱性ハンドリング業務に従事。2007年よりセキュアコーディングプロジェクトリードとして、教育マテリアルの開発や講義・講演活動などをこなす。GSSP-Cプログラマ。


記事へのコメント・トラックバック機能は2011年6月に廃止させていただきました。記事に対する反響はTwitterやFacebook、ソーシャルブックマークサービスのコメントなどでぜひお寄せください。

スポンサーサイト