Lenovo製PC及びその他多数に影響すると見られるIntelのコードの脆弱性


Cr4sh氏がLenovo ThinkPadに存在する新たな脆弱性を公表した. 前回とは異なり, 日本のメディアでも伝えられるなど, 注目を集めたようである. 私はちょうど手持ちのThinkPad X220のBIOSを調査していており, ある程度詳細な情報を得ているので, ちょっとした解説記事を書こうと思う. 間違い等があったらメールなりTwitterなりで報告して欲しい.

要点

影響

この脆弱性により, コンピュータでカーネル権限 (OS上の全権限) がある状態において, SMM (System Management Mode) への侵入を許し, BIOSの改変による除去不能なマルウェアの侵入, 安全に関わるハードウェア操作などを可能にする.

これらは通常ハードウェアへのアクセスが必要だが, これの場合ソフトウェアでのアクセスで十分なため, OSにある脆弱性などと組み合わせることでリモートからの攻撃が可能である. これがこのSMMへの攻撃の意義である.

一方で, この攻撃には欠点もある. まず問題なのが, この攻撃を行う前に強力な, そしておそらく厳重に保護されているカーネル権限を得る必要があるということだ. 次に問題なのは, 仮にSMMに侵入できたとしても, Boot Guardによってマルウェアの混入したBIOSの実行を阻まれたり, あるいはカーネル権限で既に多くのことができてしまうため, SMMに侵入しても更なる利を得ることができないということである.

まとめると, この脆弱性は価値の高い攻撃対象 (例えば大統領のコンピュータとか) においてもっとも危険なものである. 一方で, 一般の利用者については特に影響はないかもしれない. しかしこれは実際に攻撃があってから分かるもので, 安全とは言い切れない.

影響を受けるPC/マザーボード

実のところ, Lenovo製であるかは関係なく, 単にCr4sh氏がLenovo製のラップトップで発見しただけである.

既に脆弱性があることが確認されているPC/マザーボードを以下に挙げる. また, 括弧付きで確認した人を付記しておく.

T440, T440p, T440s, T440u, T450, T450s, T540, T540p, T550, W540, W541, W550s, X1 Carbon (20Ax and 20Bx), X240, X240s, X250 and Yoga 15 / S5 Yoga (Cr4sh氏)
HP dv7 4087cl, GIGABYTE Z77X-UD5H, Z68-UD3H, Z87MX-D3H, Z97-D3Hとその他GIGABYTEの多数のボード] (Alex James氏)
Fujitsu LIFEBOOK A574/H (173210)

Lenovoはセキュリティアドバイザリを出している. (私はむしろLenovoのこの素早い対応と, X220という古い型でも脆弱性への対策を公開してきたこれまでの対応を評価している. これはステルスマーケティングではない. ファンマーケティングである.)

その他多数のPCが影響を受けると思われる. その理由については後述.

原因となったコード

ここから先は専門用語などは解説なし. テキトーにググること.

この脆弱性はCr4sh氏が以前見つけた脆弱性を用いてダンプしたSMRAMからSMIハンドラを解析して見つかった. しかし, そのコードは実はオープンソースになっていたことがAlex James氏によって示された. 当該コードはIntelにより, かの有名なIntel Galileoに使われたSoC, Intel Quark X1000用のサポートパッケージに同梱されて提供された.

Download Intel® Quark™ SoC X1000 Board Support Package (BSP) Release Archive

ここに公開されているもののうち, 2014年1月20日に初めてソースと共に公開されたv0.9.0から, 2014年5月22日に公開されたv1.0.1まで脆弱なコードを含んでおり, 2015年2月に公開されたv1.1.0からは当該コードは削除されている. (なお, オープンソース化前にはリバースエンジニアリングを禁止する忌々しいライセンスがふせられている. そのままではバックドアと見られても仕方なかっただろうが, その危機は免れた.) 著作権表示にCopyright (c) 2013 Intel Corporation.とあり, 実際にはベンダには2年間脆弱なコードが提供されていた可能性がある.

なお, 脆弱なコードが削除されたv1.1.0のリリースノートにはこの脆弱性について記されておらず, Intelはこの脆弱性を認識していなかった可能性がある. 同様にベンダがこれを知ることもできなかったかもしれない.

脆弱性

さて, 脆弱なコードはQuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmRuntime/SmmRuntime.c内に存在する.

EFI_STATUS
EFIAPI
SmmRuntimeManagementCallback (
  IN EFI_HANDLE             SmmImageHandle,
  IN CONST VOID             *Context         OPTIONAL,
  IN OUT VOID               *CommunicationBuffer,
  IN OUT UINTN              *SourceSize
  )
/*++
  
  Routine Description:
    This Function executes the Callback Function. This function is called at every SMI occurance.
    At the SMI occurance, it investigates if somebody asked for the Runtime Service. On a valid
    RT Service request, it executes the callback function.

  Arguments:
    SmmImageHandle      - Handle for the smm image of this driver
    Smst                - Pointer to the SMM System Table
    CommunicationBuffer - Pointer to the buffer that contains the communication Message
    Source Size         - Size of the memory image to be used for handler.

  Returns:
    EFI_SUCCESS         - Callback Function Executed
--*/
// GC_TODO:    SourceSize - add argument and description to function comment
{
  SMM_RUNTIME_COMMUNICATION_STRUCTURE *SmmRtStruct;
  EFI_SMM_RT_CALLBACK_SERVICES        *RtServices;

  RtServices  = NULL;

  SmmRtStruct = (SMM_RUNTIME_COMMUNICATION_STRUCTURE *) CommunicationBuffer;
  RtServices  = (EFI_SMM_RT_CALLBACK_SERVICES *) SmmRtStruct->PrivateData.SmmRuntimeCallHandle;

  if (RtServices != NULL) {
    RtServices->CallbackFunction (RtServices->Context, gSmst, (VOID *) &SmmRtStruct->PrivateData);
    SmmRtStruct->PrivateData.SmmRuntimeCallHandle = NULL;
  }

  return EFI_SUCCESS;
}

このCommunicationBufferはSMM外から提供される. この中の関数ポインタを読んでしまっているため, 任意のコードが実行可能という, 極めて単純なものである. バックドアではないかと疑ってしまう程だ.

このプログラムは他にも非常に信頼性のないコードが見られる. 例えば, 次のコードである.

    Status = gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof (EFI_SMM_RT_GLOBAL), &SmmRtGlobal);
/****************************************************
**                                                 **
** EST override - begins here                      **
**                                                 **
****************************************************/
    ASSERT_EFI_ERROR (Status);    
/*+++++++++++++++++++++++++++++++++++++++++++++++++++
++                                                 ++
++ EST override - ends here                        ++
++                                                 ++
+++++++++++++++++++++++++++++++++++++++++++++++++++*/
    if (Status == EFI_SUCCESS) {
      ZeroMem (SmmRtGlobal, sizeof (EFI_SMM_RT_GLOBAL));
    }

    Status = gBS->AllocatePool (
                    EfiReservedMemoryType,
                    sizeof (SMM_RUNTIME_COMMUNICATION_STRUCTURE),
                    &SmmRtGlobal->SmmRtServices.ChildRuntimeBuffer
                    );

なぜかASSERT_EFI_ERRORとその次のif文の2つのエラーチェックがある. 更にif文でのエラーチェックはどう見ても不完全である. その後にSmmRtGlobalへの参照がある. ASSERT_EFI_ERRORはデバッグ用にコンパイルしたときのみ有効らしく, リリース版ではこれはクラッシュを引き起こしかねない.

単純に品質が低いために作り込まれた脆弱性か, それとも木は森に隠すということか. いずれにせよIntelへの信用を落としかねないものである.

[top]