Android / Pixel 2026-05 CVE 検証サマリ

PC版

CVE-2026-0073: System / adbd RCE

  • Android Security Bulletin: May 2026、公開 2026-05-04、更新 2026-05-07
  • Security patch level: 2026-05-01
  • Component: System
  • Subcomponent: adbd / Google Play system updates
  • Android bug: A-469080888
  • Type: RCE、Severity: Critical
  • Updated AOSP versions: 14, 15, 16, 16-qpr2
  • Androidブリテン上の影響: 追加権限やユーザー操作なしで、近接/隣接から shell user としてリモートコード実行につながる可能性
  • Pixel Bulletin: May 2026には追加のPixel固有CVE行なし。GoogleデバイスはMay 2026 Android Security Bulletinの修正を含む扱い。

参照: Android Security Bulletin May 2026, Pixel Update Bulletin May 2026

判定した脆弱性

adbdのワイヤレスADB/TLSクライアント証明書検証で、未承認クライアントの証明書が承認済みADB鍵として扱われる認証バイパス。 成功するとADB接続が確立し、shell userとしてコード実行可能になる。

根本原因

EVP_PKEY_cmp() は一致時に 1、不一致時に 0、エラー時に負数を返す。 脆弱版は if (EVP_PKEY_cmp(...)) としていたため、鍵タイプ不一致などで返る -1 / -2 も真として扱い、verified = true に到達する。

特定根拠

  • AOSP修正コミット 842d331f9e5fb10770a09379e19240daea057dba の差分で、EVP_PKEY_cmp() の結果を cmp_result == 1 に限定する修正を確認。
  • daemon/auth.cppadbd_tls_verify_cert() で、登録済みADB公開鍵とTLS証明書公開鍵を比較している箇所を確認。
  • Android BoringSSLのヘッダ/実装で、EVP_PKEY_cmp() が鍵タイプ不一致時に -1、比較不能時に -2 を返すことを確認。
  • transport.cpp で、adbdサーバ側TLSハンドシェイクが adbd_tls_verify_cert() を証明書検証コールバックとして使うことを確認。
validated.md を表示
# CVE-2026-0073 System / adbd RCE 検証メモ

## 結論

特定できた。CVE-2026-0073 は adbd の TLS クライアント証明書検証で、`EVP_PKEY_cmp()` の戻り値を真偽値として扱ったため、比較エラーを「公開鍵一致」と誤認する認証バイパスである。

このバイパスにより、ワイヤレスADB/TLS接続で未承認クライアントが既存の承認済みADB公開鍵として扱われ、adbd の shell 権限でADB接続を確立できる。Android Security Bulletin の分類は System / RCE / Critical / remote proximal-adjacent code execution as shell user。

## 参照情報

- Android Security Bulletin May 2026: https://source.android.com/docs/security/bulletin/2026/2026-05-01
- Pixel Update Bulletin May 2026: https://source.android.com/docs/security/bulletin/pixel/2026/2026-05-01
- AOSP修正コミット: https://android.googlesource.com/platform/packages/modules/adb/+/842d331f9e5fb10770a09379e19240daea057dba
- 修正コミット: `842d331f9e5fb10770a09379e19240daea057dba`
- 親コミット: `1a4091e7b8d980ee3a7f7d9cdb00285a69d88639`
- Bug ID: `A-469080888`
- 変更ファイル: `daemon/auth.cpp`
- 付帯ファイル: `artifacts/`

## パッチ差分

変更は `adbd_tls_verify_cert()` 内の1箇所。

脆弱版:

```cpp
if (EVP_PKEY_cmp(known_evp.get(), evp_pkey.get())) {
    VLOG(AUTH) << "Matched auth_key=" << public_key;
    verified = true;
}
```

修正版:

```cpp
int cmp_result = EVP_PKEY_cmp(known_evp.get(), evp_pkey.get());
if (cmp_result == 1) {
    VLOG(AUTH) << "Matched auth_key=" << public_key;
    verified = true;
}
```

`artifacts/patch.diff` に公式Gitilesから取得した差分を保存した。

## 根本原因

根本原因は OpenSSL/BoringSSL API の戻り値契約の取り違え。

Android側BoringSSLヘッダでは `EVP_PKEY_cmp()` は次の契約になっている。

- `1`: 公開鍵が等しい
- `0`: 公開鍵が等しくない
- 負数: エラー

実装でも、鍵タイプが違う場合は `-1`、比較処理が存在しない場合は `-2` を返す。保存した証拠は `artifacts/boringssl_evp_pkey_cmp_header.txt` と `artifacts/boringssl_evp_pkey_cmp_impl.txt`。

しかし脆弱版adbdは `if (EVP_PKEY_cmp(...))` と書いていたため、`-1` や `-2` もC/C++の真として扱い、`verified = true` に到達する。

## 攻撃が成立する状況

成立条件は次の通り。

1. デバイス側adbdでADB認証が必要である。
2. デバイスに少なくとも1つ承認済みADB公開鍵が保存されている。
3. 攻撃者がワイヤレスADB/TLS接続の到達範囲にいる。
4. 攻撃者が、保存済みADB公開鍵と同一ではないが、`EVP_PKEY_cmp()` が負数エラーを返す公開鍵を入れたクライアント証明書を提示する。

特に分かりやすいケースは、登録済みADB鍵がAndroidの通常形式どおりRSAで、攻撃者のTLSクライアント証明書がEC/Ed25519などRSA以外の公開鍵を持つ場合。`adbd_tls_verify_cert()` は登録済み公開鍵を `android_pubkey_decode()` でRSAとして読み、`EVP_PKEY_set1_RSA()` で `known_evp` を作る。一方、TLS証明書から得た `evp_pkey` が別タイプなら、BoringSSLの `EVP_PKEY_cmp()` は `a->type != b->type` で `-1` を返す。脆弱版ではこの `-1` が成功扱いになる。

`transport.cpp` ではサーバ側adbdが `SetCertVerifyCallback()` に `adbd_tls_verify_cert()` を登録し、TLSハンドシェイク成功時に接続を継続する。つまりこの誤判定は単なるログ上の問題ではなく、TLSクライアント認証の許可判定に直結する。

## 影響

未承認の近接/隣接ネットワーク攻撃者が、ユーザー承認済みADB鍵を持っていなくても、adbdにTLSクライアント証明書を承認済みと誤認させられる。成功するとADB接続が確立し、Androidブリテン記載どおり shell user としてコード実行可能になる。

この問題は旧来の `A_AUTH` トークン署名検証経路ではなく、ワイヤレスADBのTLS証明書検証経路にある。`adbd_auth_verify()` の `RSA_verify(...) == 1` は明示比較になっており、今回の直接原因ではない。

## 修正の意味

修正は `EVP_PKEY_cmp()` の戻り値を `cmp_result == 1` に限定し、負数エラーを失敗扱いにするもの。ログにも戻り値が出るようになったため、将来同種の比較不能ケースを追跡しやすくなっている。

## Pixelについて

Pixel Update Bulletin May 2026 には、このCVEに対応する追加のPixel固有行はなかった。Googleデバイスは May 2026 Android Security Bulletin の修正を含むため影響を受けるが、今回の原因はAOSP `platform/packages/modules/adb` の公開ソースで完全に説明できる。したがってPixelファームウェアのバイナリ取得や `../binaries` への保存は不要と判断した。

## 調査時のメモ

- コミットメッセージは `Fix EVP_PKEY_cmp usage.` で、`Bug: 469080888` と `CVE_FIX` を含む。ブリテンの `A-469080888` と対応する。
- 公開ドキュメントの一部では `EVP_PKEY_cmp()` を「一致なら1、不一致なら0」と簡略に説明しているものがあるが、Androidの実際のBoringSSLヘッダと実装では負数エラーが存在する。今回のバグはまさにその負数を見落としたもの。
- 登録済みADB公開鍵がない場合は `IteratePublicKeys()` のループが成立しないため、このバグだけでは承認済み鍵を捏造できない。
- RSA同士で単に別鍵を提示した場合は通常 `pub_cmp` が `0` を返すため、このパッチ差分から読める主な悪用形は「鍵タイプ不一致」または「比較不能鍵」による負数戻り値の成功扱いである。

## 保存した付帯ファイル

- `artifacts/patch.diff`: 公式修正コミットの差分
- `artifacts/auth_before.cpp`: 親コミットの `daemon/auth.cpp`
- `artifacts/auth_after.cpp`: 修正コミットの `daemon/auth.cpp`
- `artifacts/adbd_tls_verify_cert_before.txt`: 脆弱版の該当関数抜粋
- `artifacts/adbd_tls_verify_cert_after.txt`: 修正版の該当関数抜粋
- `artifacts/boringssl_evp_pkey_cmp_header.txt`: Android BoringSSLヘッダの戻り値契約
- `artifacts/boringssl_evp_pkey_cmp_impl.txt`: Android BoringSSL実装の `-1` / `-2` 戻り値
- `artifacts/transport_tls_callback_after.txt`: adbd TLSハンドシェイクで検証コールバックを登録する箇所
該当する項目がありません