flawopen.com/インシデント/ANGLE汎用ゼロデイ:Chrome、iOS、Androidを同時に脅かした描画層の盲点

ANGLE汎用ゼロデイ:Chrome、iOS、Androidを同時に脅かした描画層の盲点

緊急 · CVSS 8.8 CWE-125 / CWE-787: 境界外メモリアクセス インシデント分析 · 2025年12月
ELI5 (5歳児でもわかる解説)

激しい競争関係にある2つのスマートフォンメーカー(GoogleとApple)を想像してください。両社は開発コストを削減するため、国際規格の電源(WebGL)を自社の端末規格(iPhoneのMetal、AndroidのVulkan)に変換する共通の電源アダプタ(ANGLE)を端末内部に採用していました。攻撃者はWebサイト経由で特定の異常な電流を送り込み、この共通アダプタを加熱・ショートさせ、全く同じ攻撃コードでiPhoneとAndroidの両方を同時にハッキングすることに成功しました。

このページの重要用語
ANGLE (Almost Native Graphics Layer Engine)
WebGLの命令を各OSネイティブのAPI(Metal、Direct3D、Vulkanなど)に変換するためにGoogleが開発し、Appleも採用している描画エンジン。
サプライチェーンの共通単一障害点
競合するプラットフォームが同一のオープンソースライブラリを共有しているために生じる脆弱性の連鎖。
Metalバックエンドの深度テクスチャ変換
WebGLの3D深度バッファをAppleのMetal固有のテクスチャ形式に変換する処理ブロック。
WebGL経由のメモリ破壊攻撃
権限のない通常のWebページ上のJavaScriptからGPU描画パイプラインのメモリ不整合を突く攻撃。

インシデントの概要

In December 2025, Google and Apple issued rare, synchronized emergency security advisories for a high-severity zero-day vulnerability tracked as CVE-2025-14174. The vulnerability was discovered by Google's Threat Analysis Group (TAG) and Apple's Security Engineering and Architecture (SEAR) team being actively exploited in targeted in-the-wild cyber espionage campaigns.

Unlike conventional browser zero-days that target V8 (Chrome) or JavaScriptCore (Safari), CVE-2025-14174 originated in ANGLE (Almost Native Graphics Layer Engine). Because Google maintains ANGLE for Chromium and Apple integrates ANGLE into WebKit for WebGL translation on iOS and iPadOS, this single memory corruption bug compromised both browser ecosystems simultaneously.

An attacker hosting a malicious web page could trigger an out-of-bounds memory write simply by rendering a WebGL canvas with specially crafted depth texture parameters, gaining arbitrary code execution within the browser's sandboxed renderer process on both Android/Chrome and iOS/Safari.

技術的根本原因の徹底解剖

1. Arithmetic Overflow in Depth Texture Slice Calculation

When uploading 3D or 2D depth textures via WebGL (texImage2D / texSubImage2D), ANGLE's Metal backend calculated the required staging buffer size based on width, height, and depth. Due to improper bounds validation during pixel format conversion (from WebGL depth formats like DEPTH_COMPONENT32F to Metal's MTLPixelFormatDepth32Float), the row pitch calculation under-allocated memory while the copy routine processed the full input buffer, writing past the heap boundary.

2. Shared Library Dependency Across Competing Vendors

Apple adopted Google's ANGLE to accelerate WebGL compliance without maintaining a separate translation layer from scratch. This created a shared software monoculture: an exploit payload weaponized against ANGLE on Chrome was instantly portable to Apple's WebKit WebContent process on iOS and iPadOS.

3. WebGL Direct Surface Exposure to Untrusted Web Pages

WebGL exposes direct GPU memory management primitives (buffers, textures, shaders) to arbitrary JavaScript execution. Because WebGL is enabled by default across all mobile browsers and requires zero user prompts, any visited web link can immediately interact with complex C++ graphics drivers.

脆弱な実装 vs 安全なバッファ計算

VULNERABLE: UNVALIDATED TEXTURE BUFFER ALLOCATION (ANGLE)
// Conceptual flaw in ANGLE's Metal backend (TextureMtl.mm)
angle::Result TextureMtl::uploadDepthData(const gl::Context *context,
                                         const gl::Extents &size,
                                         const uint8_t *clientData) {
  // Bug: Row pitch multiplication lacks overflow checks
  size_t rowPitch = size.width * getBytesPerPixel(mFormat);
  size_t allocationSize = rowPitch * size.height; // Can overflow!

  // Under-allocated heap buffer
  uint8_t *stagingBuffer = new uint8_t[allocationSize];

  // HEAP OUT-OF-BOUNDS WRITE:
  // Metal copy helper copies bytes calculated from internal format stride!
  CopyDepthSlices(clientData, stagingBuffer, size.width, size.height, size.depth);
  return angle::Result::Continue;
}
HARDENED: CHECKED ARITHMETIC & BOUNDS CLAMPING
// Fixed ANGLE implementation using base::CheckedNumeric
angle::Result TextureMtl::uploadDepthData(const gl::Context *context,
                                         const gl::Extents &size,
                                         const uint8_t *clientData) {
  // Fix 1: Safe integer multiplication preventing integer overflow
  base::CheckedNumeric<size_t> safeSize = size.width;
  safeSize *= getBytesPerPixel(mFormat);
  safeSize *= size.height;
  safeSize *= size.depth;

  if (!safeSize.IsValid()) {
    return angle::Result::Stop; // Reject invalid buffer geometry
  }

  size_t allocationSize = safeSize.ValueOrDie();
  std::vector<uint8_t> stagingBuffer(allocationSize);

  // Fix 2: Bounded copy strictly constrained to allocated buffer capacity
  SafeCopyDepthSlices(clientData, stagingBuffer.data(), stagingBuffer.size(), size);
  return angle::Result::Continue;
}

検知およびセキュリティ制御ルール

# Network IDS / Zeek: Flag suspicious WebGL depth texture exploit payloads event http_reply(c: connection, msg: http_message) { if (msg$body matches /texImage2D.*DEPTH_COMPONENT/) ... } # Safari / Chrome Enterprise Policy: Disable WebGL for high-security endpoints defaults write com.apple.Safari WebKitPreferences.webGLEnabled -bool false # Chrome Enterprise Policy: Enforce software fallback or block WebGL on untrusted origins {"Disable3DAPIs": true, "WebGLBlockedForOrigins": ["*"]}
In high-threat environments (journalists, government officials, defense personnel), enforce Apple's Lockdown Mode or Chrome's Disable3DAPIs policy to completely eliminate the WebGL/ANGLE attack surface.

サプライチェーンの教訓と再発防止チェックリスト

情報源および公式アドバイザリ