SHOEISHA iD

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

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

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

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

画像処理ソフトウェア「ImageMagick」の脆弱性

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


ImageMagickの脆弱性:その2

 同じくImageMagicの別の脆弱性について考えてみましょう。以下のコードは、ImageMagick バージョン 6.3.4、coders/dib.cからの抜粋です。解説の便宜上、余分なコードは省略しています。

static Image *ReadDIBImage(const ImageInfo *image_info,ExceptionInfo *exception)
{
...
  /* 
     Microsoft Windows 3.X DIB image file. 
   */
  dib_info.width=(short) ReadBlobLSBLong(image);
...
  image->columns=(unsigned long) dib_info.width;
...
 /*
    Read image data.
  */
...
  bytes_per_line=4*((image->columns*dib_info.bits_per_pixel+31)/32);
  length=bytes_per_line*image->rows;
  pixels=(unsigned char *) AcquireMagickMemory((size_t) MagickMax(
    bytes_per_line,image->columns+256)*image->rows*sizeof(*pixels));
  if (pixels == (unsigned char *) NULL)
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
  if ((dib_info.compression == BI_RGB) ||
      (dib_info.compression == BI_BITFIELDS))
    {
      count=ReadBlob(image,length,pixels);
...

 ReadDIBImage()はマイクロソフトウィンドウズのビットマップ画像を読み込み、それを返す関数です。また、ReadBlobLSBLong()はunsigned long型の値を返します。どのような問題があるか分かりましたか?

脆弱性の解説:符号拡張の問題

 LP64データモデルを前提に解説します。ReadBlobSBLong()関数の返り値は、short型に明示的にキャストされたのち、long型のdib_info.widthに代入されます。この代入式を変数の型名だけで示すと

long = (short) unsigned long

 のようになります。問題はshort型にキャストされた値がlong型変数に代入されるときに発生します。例えば、

long = (short) 0x0...00008000

 のような代入が行われると、longの値は0xf...fff8000という負の値になってしまいます。なぜこのようなことが起こるのかというと、longの幅にshortの値を入れる際、足りない上位ビットは「符号拡張」によって充足されるからです。符号拡張とは「符号付の数値を表現するビット列が格納領域のビット幅より短い場合に、隙間を適切に埋めることによって数値としての同一性を維持する手法」です(wikipedia)。つまり、上位ビットを符号ビットの'1'を使って埋めるため、dib_info.widthの値が0xf...ffff8000になってしまうのです。

 その結果、非常に大きな値がimage->columnsに代入され、AcquireMagickMemory()の引数の式、

MagickMax(bytes_per_line,image->columns+256)*image->rows*sizeof(*pixels)

 はsize_tで表現しきれない大きな値になることから、ラップアラウンドが発生してしまう可能性があるのです。符号付きの型と符号無しの型との間の型変換は、ここで問題になったような符号エラーにつながることが多く、注意が必要です。

 この問題の修正は次のように行われました。

- image->columns=(unsigned long) dib_info.width;
+ image->columns=(unsigned long) MagickAbsoluteValue(dib_info.width);

 MagickAbsoluteValue(a)は、aの値が0より小さい場合に‐aを返し、それ以外の場合は、aを返す関数です。この関数を途中に挟むことにより、符号拡張の問題の発生を防ぐように修正されています。

CERT C セキュアコーディングスタンダード

 今回紹介した脆弱性を作り込まないコーディングについては、以下のルールに詳しく解説しています。こちらも併せて参照ください。

参考資料

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

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
実例で学ぶ脆弱性対策コーディング連載記事一覧

もっと読む

この記事の著者

久保 正樹(JPCERT コーディネーションセンター)(クボ マサキ(JPCERT コーディネーションセンター))

脆弱性アナリストJPCERTコーディネーションセンター慶応義塾大学環境情報学部卒。ソニーでデスクトップPCのソフトウェア開発に携わったのち、米国ダートマス大学にてオーディオ信号処理、電子音響音楽の研究を行い、電子音響音楽修士を取得。2005年4月よりJPCERTコーディネーションセンターにて、脆弱性...

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

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

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/5171 2013/11/06 13:22

イベント

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

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

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

メールバックナンバー