FlawOpen

flawopen.com/Teardowns/cve-2026-49878-android-wpa-supplicant-oob-write

● CVE-2026-49878 · CVSS 7.2 · 高
セキュリティ研究 · FlawOpen

CVE-2026-49878:Android Wi-Fi の範囲外書き込み

Android 2026年10月のセキュリティ情報は、このWi-Fiのリモートコード実行の脆弱性をHighと評価しています。AOSPはバイト数で確保していた2つのint配列を修正しました。記録上、システム権限が必要です。

💡 わかりやすい解説 (ELI5)

棚には品目ごとに箱を置く必要があるのに、担当者が箱1個につき1センチ分しか場所を確保しなければ、箱は棚からはみ出します。CVE-2026-49878では、wpa_supplicantが整数の個数をバイト数として確保し、その領域に整数を書き込みました。Googleの修正は各要素の実サイズを確保します。

主要な概念と専門用語

wpa_supplicant
無線認証と関連する802.11通信を管理するAndroidのWi-Fiコンポーネントです。
SCS応答
Stream Classification Serviceの応答アクションフレームです。要求が保留中でdialog tokenが一致する場合にのみ処理されます。
範囲外書き込み(CWE-787)
確保したメモリ領域を越えて書き込むことです。ここではバイト単位で確保しながらint配列としてアクセスします。
os_zalloc / os_calloc
wpa_supplicantのメモリ確保関数です。修正では要素数と要素サイズを渡し、配列全体を確保します。
Androidセキュリティパッチレベル(SPL)
インストール済み更新レベルを示す日付です。Googleによると2026-10-01以降で10月分の問題を修正します。配信は端末メーカーが管理します。

フレームワーク対応

  • このガイドで説明する弱点の CWE 参照: CWE-787

根本原因の分析 (Root Cause)

wpas_handle_robust_av_scs_recv_action の scs_resp[0] と [1] は int * 配列です。修正前の os_zalloc(num_active_scs) はその数だけのバイトしか確保しませんでした。コードは整数IDと状態を添字位置に書き込むため、num_active_scs * sizeof(int) バイトが必要です。保留中の要求、dialog tokenの一致、件数、フレーム長の検査は入力を制限しますが、確保単位は修正しません。AOSPは両方を os_calloc(num_active_scs, sizeof(int)) に変更します。この書き込みだけから攻撃者が制御するコード実行を推定してはいけません。

ステップ・バイ・ステップの攻撃フロー

ステップ 1

応答フレームが振り分けられる

Wi-Fi経路はRobust AV SCS Responseを対象ハンドラーへ渡します。ネットワーク経路ですが、未認証送信者が全条件を満たせるとは公開資料で確認されていません。

ステップ 2

要求状態と境界を検査

保留中の要求と一致tokenを要求し、件数も検証します。NVDのCISA-ADPベクトルはAV:N/AC:L/PR:H/UI:Nです。高い権限が必要という前提を維持します。

ステップ 3

整数がバイト確保量を超える

旧コードは項目あたり1バイトを確保し、int値を書き込みます。件数制限は確保バイト数を増やしません。

ステップ 4

10月の修正が確保量を直す

Googleの変更は両配列に num_active_scs 個の sizeof(int) 要素を確保します。payloadを作らず、diffから任意コード実行を主張しないでください。

ソースコード比較:脆弱 vs 堅牢化

このdiffはAOSPがコミット d131540379d631d7dcb09b0169e4462bc65abcca で公開した変更であり、再構成した疑似コードではありません。os_zalloc(n) は n をバイト数として扱い、os_calloc(count, size) は指定数の要素を確保してゼロ初期化します。修正は両配列を直し、確保失敗時の既存の後始末を維持します。

脆弱な実装
/* AOSP の修正前: num_active_scs は要素数だが、
 * os_zalloc にはバイト数として渡されている。 */
scs_resp[0] = (int *) os_zalloc(num_active_scs);
if (!scs_resp[0])
    return;

scs_resp[1] = (int *) os_zalloc(num_active_scs);
if (!scs_resp[1]) {
    os_free(scs_resp[0]);
    return;
}
堅牢化されたセキュアパッチ
/* AOSP の修正: 各エントリーに int 1 個分を割り当てる。 */
scs_resp[0] = os_calloc(num_active_scs, sizeof(int));
if (!scs_resp[0])
    return;

scs_resp[1] = os_calloc(num_active_scs, sizeof(int));
if (!scs_resp[1]) {
    os_free(scs_resp[0]);
    return;
}

エンジニアリング&システム堅牢化チェックリスト

参考資料