| # | 判定 | 内容 |
|---|---|---|
| 1 | OK | CVE-2026-0047 - Framework EoP Critical |
001
ok
CVE-2026-0047 - Framework EoP Critical001-ok-dumpbitmaps-permission-bypass cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP Critical vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(何が起きる脆弱性だったか) `ActivityManagerService.dumpBitmapsProto()` に権限チェックが無く、通常アプリから他プロセスのメモリ内 Bitmap 情報を dump できる問題だった。 この API は `IActivityManager` の Binder メソッドとして存在し、呼び出し元が渡した `ParcelFileDescriptor` に dump 結果を書き出す。修正前は、呼び出し権限も、対象プロセスが debuggable かどうかも確認していなかった。そのため、攻撃アプリは対象プロセス名や pid、または未指定による全プロセス対象で `dumpBitmapsProto` を呼び、他アプリが保持している Bitmap を protobuf として取得できる。 `Bitmap.dumpAll(proto, dumpFormat)` は Bitmap の id、幅、高さ、サイズ、config などのメタデータを書くだけでなく、`dumpFormat` が `png` / `jpg` / `webp` などなら Bitmap を圧縮して `CONTENT` に格納する。つまり、条件次第では他アプリの UI 画像、表示中の写真、QR コード、認証画面、サムネイルなどの画素データそのものが漏れる。 原因(根本原因) デバッグ・診断用の強力な dump 機能を `IActivityManager` 経由で公開したにもかかわらず、サーバ側実装に認可境界が無かったことが根本原因。 具体的には、修正前の `dumpBitmapsProto()` は次の制御だけで動いていた。 1. 呼び出し元提供の fd を受け取る。 2. `collectProcesses(null, 0, allPkgs, processes)` で対象プロセスを集める。 3. 対象プロセスの `IApplicationThread.dumpBitmapsProto()` を呼ぶ。 4. 対象アプリ内で `Bitmap.dumpAll()` を実行し、結果を fd に書く。 ここに `SET_ACTIVITY_WATCHER` などの権限チェックが無く、production build で非 debuggable アプリを除外する処理も無かった。 同じ `ActivityManagerService` の `dumpHeap()` は既に `SET_ACTIVITY_WATCHER` と `enforceDebuggable(proc)` を使っており、今回の修正もそれに合わせている。つまり、本来 heap dump 相当の機密性を持つ操作なのに、`dumpBitmapsProto()` だけが認可を抜いていた。 どこから特定したか validated.md の「対象」「パッチ内容」 / Android bug参照 A-465136263 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://storage.googleapis.com/android-osv/ASB-A-465136263.json, https://android.googlesource.com/platform/frameworks/base/+/93b72e5a84815c09d5eac89fe8f974a44002c629 validated.md を表示# CVE-2026-0047 検証結果
## 判定
OK。AOSP の修正コミットと前後ソースから、脆弱性の発生条件、影響、根本原因をソースコードベースで特定できた。
## 対象
- CVE: CVE-2026-0047
- Android bug: A-465136263
- コンポーネント: Framework / `platform/frameworks/base`
- 影響: 16-qpr2 / 16-qpr2-next
- 種別: EoP
- 深刻度: Critical
- 公開ブリテン: https://source.android.com/docs/security/bulletin/2026/2026-03-01
- OSV: https://storage.googleapis.com/android-osv/ASB-A-465136263.json
- 解析した修正コミット: https://android.googlesource.com/platform/frameworks/base/+/93b72e5a84815c09d5eac89fe8f974a44002c629
## 何が起きる脆弱性だったか
`ActivityManagerService.dumpBitmapsProto()` に権限チェックが無く、通常アプリから他プロセスのメモリ内 Bitmap 情報を dump できる問題だった。
この API は `IActivityManager` の Binder メソッドとして存在し、呼び出し元が渡した `ParcelFileDescriptor` に dump 結果を書き出す。修正前は、呼び出し権限も、対象プロセスが debuggable かどうかも確認していなかった。そのため、攻撃アプリは対象プロセス名や pid、または未指定による全プロセス対象で `dumpBitmapsProto` を呼び、他アプリが保持している Bitmap を protobuf として取得できる。
`Bitmap.dumpAll(proto, dumpFormat)` は Bitmap の id、幅、高さ、サイズ、config などのメタデータを書くだけでなく、`dumpFormat` が `png` / `jpg` / `webp` などなら Bitmap を圧縮して `CONTENT` に格納する。つまり、条件次第では他アプリの UI 画像、表示中の写真、QR コード、認証画面、サムネイルなどの画素データそのものが漏れる。
## 根本原因
デバッグ・診断用の強力な dump 機能を `IActivityManager` 経由で公開したにもかかわらず、サーバ側実装に認可境界が無かったことが根本原因。
具体的には、修正前の `dumpBitmapsProto()` は次の制御だけで動いていた。
1. 呼び出し元提供の fd を受け取る。
2. `collectProcesses(null, 0, allPkgs, processes)` で対象プロセスを集める。
3. 対象プロセスの `IApplicationThread.dumpBitmapsProto()` を呼ぶ。
4. 対象アプリ内で `Bitmap.dumpAll()` を実行し、結果を fd に書く。
ここに `SET_ACTIVITY_WATCHER` などの権限チェックが無く、production build で非 debuggable アプリを除外する処理も無かった。
同じ `ActivityManagerService` の `dumpHeap()` は既に `SET_ACTIVITY_WATCHER` と `enforceDebuggable(proc)` を使っており、今回の修正もそれに合わせている。つまり、本来 heap dump 相当の機密性を持つ操作なのに、`dumpBitmapsProto()` だけが認可を抜いていた。
## パッチ内容
修正ファイルは `services/core/java/com/android/server/am/ActivityManagerService.java` のみ。
`dumpBitmapsProto()` の先頭に以下が追加された。
```java
enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
"dumpBitmapsProto()");
```
さらに各対象プロセスについて、user build では debuggable アプリ以外を skip する処理が追加された。
```java
if (!Build.IS_DEBUGGABLE && !r.isDebuggable()) {
Slog.w(TAG, "Process not debuggable: " + r.info.packageName);
continue;
}
```
この 2 つにより、未権限の通常アプリは Binder 呼び出し時点で拒否され、権限を持つ診断主体であっても production build では非 debuggable アプリの Bitmap を dump できなくなる。
## 攻撃シナリオ
修正前の端末で、攻撃アプリが hidden API / Binder transaction などで ActivityManager の `dumpBitmapsProto` を呼ぶ。
- fd: 攻撃アプリが読める pipe や file descriptor
- processes: victim の processName / pid、または空配列
- dumpFormat: `png` など
サーバ側は呼び出し元 uid の権限を確認せず、対象プロセスへ `IApplicationThread.dumpBitmapsProto()` を依頼する。victim プロセス側は自身の live Bitmap を列挙し、指定形式で圧縮した画像データを system_server 経由で攻撃側 fd に書き出す。
プロセス未指定の場合、`ProcessList.collectProcessesLOSP()` は LRU プロセス一覧全体を返すため、全実行中アプリを対象にできる点も危険だった。また `dumpBitmapsProto` の `userId` 引数は対象収集に使われていない。
## 調査中に分かった面白い点
- Android ブリテン上では `A-465136263` にリンクが無く、詳細は OSV と修正コミットから復元する必要があった。
- OSV の details には「missing permission check」と書かれているが、実パッチでは permission check だけでなく debuggability check も追加されている。
- `am dumpbitmaps` は単なる shell command front-end であり、実際の境界は `ActivityManagerService.dumpBitmapsProto()` の Binder サーバ側にある。
- `dumpBitmapsProto()` は `userId` を受け取るが、修正前後とも対象プロセス収集では使っていない。今回の直接の修正対象ではないが、API 設計上は気になる点。
- OSV は `16-qpr2` の fix として `70d95430379ece974722a1044cb693371412b636` も列挙していたが、この実行時点では Gitiles から直接取得すると 404 だった。取得可能な `16-qpr2-next` の `93b72e5a...` と OSV の Vanir signature が同一関数を指しているため、こちらで解析した。
## 保存した付帯ファイル
- `ASB-A-465136263.json`: OSV レコード
- `commit_93b72e5a.txt`: 修正コミット本文
- `patch_93b72e5a.diff`: 修正差分
- `ActivityManagerService_before.java`: 修正前ソース
- `ActivityManagerService_after.java`: 修正後ソース
- `ActivityManagerShellCommand_after.java`: `am dumpbitmaps` 呼び出し経路確認用
- `IActivityManager_after.aidl`: Binder API 確認用
- `ProcessList_after.java`: 対象プロセス収集ロジック確認用
- `ActivityThread_after.java`: victim プロセス側 dump 呼び出し確認用
- `Bitmap_after.java`: Bitmap 内容が圧縮され protobuf に入ることの確認用
- `patch_analysis.md`: 解析メモ
## 検証限界
実機・エミュレータでの PoC 実行はしていない。ただし、公開 OSV、AOSP 修正コミット、前後ソース、呼び出し経路、dump されるデータ内容が一致しており、脆弱性の種類と根本原因はソースコードから十分に特定できる。
cve.md を表示# CVE-2026-0047 - Framework EoP Critical ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0047 - Component: Framework - Reference: A-465136263 - Type: EoP - Severity: Critical - Updated AOSP versions: 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP Critical vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 2 | OK | CVE-2025-32313 - Framework EoP High |
002
ok
CVE-2025-32313 - Framework EoP High002-ok-NotificationHistory-Parcel-position-validation-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の正体) `NotificationHistory` は通知履歴を一度に全部 Java オブジェクトへ展開せず、内部に通知リスト用の `Parcel mParcel` を保持して、`getNextNotification()` で順番に読む遅延イテレータになっている。 この内部形式では、外側の blob に次のような値が入る。 1. `mHistoryCount` 2. `mIndex` 3. string pool 4. `listByteLength` 5. `positionInParcel` 6. 通知リスト本体の bytes 問題は、修正前のコンストラクタが `positionInParcel` を信頼していたこと。攻撃者が `listByteLength` より大きい `positionInParcel` を入れた malformed Parcel を作ると、`NotificationHistory` は実際にコピーした通知リストの末尾より先へ `mParcel` の読み取り位置を移動できた。 Android native `Parcel::setDataPosition()` は位置を代入するだけで、実データサイズ以下かを強制しない。さらに `Parcel::dataSize()` は `max(mDataSize, mDataPos)` を返すため、不正な `mDataPos` によって Java 側の `dataSize()` も攻撃者の値まで膨らむ。このため、存在しない通知レコード領域を正規の内部状態のように扱える。 原因(根本原因) 根本原因は、Parcelable の内部カーソル値を信頼境界越しの入力として扱っているのに、復元時に「カーソルがコピー済み通知リストの範囲内である」という不変条件を検証していなかったこと。 `NotificationHistory.writeToParcel()` は未展開の履歴を再送する場合、`mParcel.dataSize()` と `mParcel.dataPosition()` をそのまま書き戻す。したがって、修正前は一度壊れた `positionInParcel` が入ると、読み取り位置や論理サイズが後続の IPC / 再 Parcel 化にも影響する。これは Android で過去にも問題になっている self-modifying Parcelable 系のバグに近い。 どこから特定したか validated.md の「何が修正されたか」 / Android bug参照 A-399155883 validated.md を表示# CVE-2025-32313 検証結果
## 判定
OK。AOSP の修正コミットと該当ソースを確認し、脆弱性の根本原因を特定できた。
- 対象: CVE-2025-32313 / A-399155883
- Bulletin: Android Security Bulletin - March 2026
- Component: Framework
- 種別: EoP
- 重要度: High
- 修正コミット: `platform/frameworks/base` `59c15187e7ee299592c22a166528fb27b3a03867`
- 修正ファイル: `core/java/android/app/NotificationHistory.java`
- パッチ題名: `NotificationHistory validate position value`
## 何が修正されたか
修正は `NotificationHistory(Parcel in)` の 1 箇所で、Parcel 内から読んだ
`positionInParcel` を `mParcel.setDataPosition(positionInParcel)` に渡す前に、
`mParcel.dataSize()` を越えていないか確認するものだった。
修正前:
```java
mParcel.appendFrom(data, data.dataPosition(), listByteLength);
mParcel.setDataSize(mParcel.dataPosition());
mParcel.setDataPosition(positionInParcel);
```
修正後:
```java
mParcel.appendFrom(data, data.dataPosition(), listByteLength);
mParcel.setDataSize(mParcel.dataPosition());
if (positionInParcel > mParcel.dataSize()) {
throw new IllegalStateException(
"Obtained an invalid position value(" + positionInParcel + " from Parcel.");
}
mParcel.setDataPosition(positionInParcel);
```
## 脆弱性の正体
`NotificationHistory` は通知履歴を一度に全部 Java オブジェクトへ展開せず、内部に通知リスト用の `Parcel mParcel` を保持して、`getNextNotification()` で順番に読む遅延イテレータになっている。
この内部形式では、外側の blob に次のような値が入る。
1. `mHistoryCount`
2. `mIndex`
3. string pool
4. `listByteLength`
5. `positionInParcel`
6. 通知リスト本体の bytes
問題は、修正前のコンストラクタが `positionInParcel` を信頼していたこと。攻撃者が `listByteLength` より大きい `positionInParcel` を入れた malformed Parcel を作ると、`NotificationHistory` は実際にコピーした通知リストの末尾より先へ `mParcel` の読み取り位置を移動できた。
Android native `Parcel::setDataPosition()` は位置を代入するだけで、実データサイズ以下かを強制しない。さらに `Parcel::dataSize()` は `max(mDataSize, mDataPos)` を返すため、不正な `mDataPos` によって Java 側の `dataSize()` も攻撃者の値まで膨らむ。このため、存在しない通知レコード領域を正規の内部状態のように扱える。
## 根本原因
根本原因は、Parcelable の内部カーソル値を信頼境界越しの入力として扱っているのに、復元時に「カーソルがコピー済み通知リストの範囲内である」という不変条件を検証していなかったこと。
`NotificationHistory.writeToParcel()` は未展開の履歴を再送する場合、`mParcel.dataSize()` と `mParcel.dataPosition()` をそのまま書き戻す。したがって、修正前は一度壊れた `positionInParcel` が入ると、読み取り位置や論理サイズが後続の IPC / 再 Parcel 化にも影響する。これは Android で過去にも問題になっている self-modifying Parcelable 系のバグに近い。
## EoP につながる条件
`INotificationManager.aidl` には次の API がある。
```aidl
@EnforcePermission("ACCESS_NOTIFICATIONS")
NotificationHistory getNotificationHistory(String callingPkg, String callingAttributionTag);
```
`NotificationManagerService.getNotificationHistory()` は `ACCESS_NOTIFICATIONS` と `OP_ACCESS_NOTIFICATIONS` を確認してから `NotificationHistoryManager.readNotificationHistory()` の結果を返す。つまり通常の通知履歴取得自体は権限付き API。
この CVE の危険点は、`NotificationHistory` が Framework の Parcelable 型として Binder 境界を越え、受信側が「復元できたなら妥当な履歴」と扱いやすいことにある。修正前は、攻撃者が細工した blob から `NotificationHistory` を復元させるだけで、内部 `mParcel` の読み取り位置を実データ外へ動かせた。特権側コードがこのオブジェクトを読み取る、または再度 Binder へ転送すると、権限チェック済みデータの内容・境界・論理サイズが攻撃者制御のカーソルに引きずられる。
## 面白い点・調査メモ
- パッチは `positionInParcel > mParcel.dataSize()` だけを追加しており、`listByteLength` 自体の検証ではない。問題の本丸は「通知リストの長さ」ではなく「そのリスト内の現在位置」だった。
- `Parcel.java` のコメントでは `setDataPosition()` の引数は `dataSize()` 以下であるべきと書かれているが、native 実装は通常範囲を強制しない。呼び出し側 Parcelable が不変条件を守る必要がある。
- `Parcel::dataSize()` が `mDataPos` を含めた最大値を返すため、範囲外 seek は単なる読み取り失敗ではなく、後続の `dataSize()` 利用箇所にも波及する。
- `NotificationHistory` は `readBlob()` / `unmarshall()` で内側 Parcel を作る。大きい履歴を Binder transaction に載せるための設計だが、内側 Parcel のメタデータも攻撃面になる。
- `writeToParcel()` には「system_server to a process」と「process to process」の 2 分岐があり、後者は `mParcel` をそのまま再利用する。この再利用設計が、カーソル値検証漏れの影響を増幅している。
## 保存した付帯ファイル
- `patch.diff`: Gitiles から取得した修正差分。
- `local_source.diff`: 取得した修正前後ソースのローカル diff。
- `NotificationHistory_before.java` / `NotificationHistory_after.java`: 修正前後の対象ファイル。
- `INotificationManager.aidl`: Binder API 確認用。
- `NotificationManagerService.java`: 権限チェックと履歴取得経路確認用。
- `NotificationHistoryManager.java`, `NotificationHistoryDatabase.java`, `NotificationHistoryProtoHelper.java`: 履歴生成・永続化経路確認用。
- `Parcel.java`, `Parcel.cpp`, `android_os_Parcel.cpp`: Java/native Parcel 挙動確認用。
- `commit_59c15187.json`: 修正コミット metadata。
- `artifact_hashes.sha256`: 取得ファイルの SHA-256。
- `analysis_notes.md`: 解析メモ。
## 検証限界
このジョブでは AOSP 全体のビルドや実機 PoC 実行はしていない。ただし、公開 bulletin が指す修正コミット、修正前後のソース差分、`NotificationHistory` の Parcelable 実装、`INotificationManager` の Binder 露出、native `Parcel` の `setDataPosition()` / `dataSize()` 挙動をソースで確認できたため、脆弱性の原因は特定済みと判断する。
cve.md を表示# CVE-2025-32313 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-32313 - Component: Framework - Reference: A-399155883 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 3 | OK | CVE-2025-48544 - Framework EoP High |
003
ok
CVE-2025-48544 - Framework EoP High003-ok-MediaProvider-included-default-directories-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) これは SQL injection ではなく、内部用 capability の混同によるアクセス制御不備である。 `INCLUDED_DEFAULT_DIRECTORIES` は本来、MediaProvider 内部の FUSE directory rename 処理で、System Gallery 向けの例外として `DCIM` / `Pictures` / `Movies` などのデフォルトディレクトリ配下をまとめて扱うための内部情報だった。しかし古い設計では、この内部情報が一般的な `Bundle extras` と同じ経路で `AccessChecker` まで届き、`AccessChecker` 自身もその値を信用して SQL の許可条件に追加していた。 攻撃者アプリが何らかの MediaProvider 操作で次の Bundle 値を保持したまま `Files` 系 URI のアクセスチェックに到達できると、通常なら所有者不一致で拒否される行に対して、デフォルトディレクトリ一致の条件が追加される。 [コードブロック省略] 結果として、攻撃者は自分の所有物ではない `DCIM/`、`Pictures/`、`Movies/` 配下のメディア行に対する read/write 判定を通せる。write 系の経路では、データベース行の更新、削除、置換、または backing file の write/open に繋がり得るため、Scoped Storage の境界を越える EoP になる。 原因(根本原因) 根本原因は、内部専用の権限拡張情報を、外部入力にも使われる `Bundle` の文字列キーで表現し、その `Bundle` を権限判定層に直接渡していたこと。 特に問題だった点: - `android:included-default-directories` は package-private 定数だが、実体は単なる文字列なので外部アプリでも同じキーを作れる。 - 権限判定の中心である `AccessChecker` が、値の出所を検証せず `extras.getStringArrayList()` の結果を信用していた。 - 2020 年に Binder 入口でこのキーを削除する対策が入っていたが、入口サニタイズに依存する設計のままだった。 - 2025 年の修正は、入口で削除するのではなく、`AccessChecker` の API から `Bundle` 依存を外して内部呼び出しだけが明示的に `Optional<List<String>>` を渡す形にしている。 どこから特定したか validated.md の「参照した情報」 / Android bug参照 A-415783046 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://android.googlesource.com/platform/packages/providers/MediaProvider/+/a5f1f182733953ef5919311d3d8d2087d9451f1f validated.md を表示# CVE-2025-48544 検証結果
## 判定
`ok`
ソースコード差分から、CVE-2025-48544 / A-415783046 は MediaProvider の
`INCLUDED_DEFAULT_DIRECTORIES` 内部用 Bundle キーを外部入力で悪用できる権限昇格問題だと特定できた。
## 参照した情報
- Android Security Bulletin 2026-03-01
- `https://source.android.com/docs/security/bulletin/2026/2026-03-01`
- Google Play system updates の MediaProvider に `CVE-2025-48544` が掲載されている。
- AOSP / Gitiles
- `https://android.googlesource.com/platform/packages/providers/MediaProvider/+/a5f1f182733953ef5919311d3d8d2087d9451f1f`
- コミット: `a5f1f182733953ef5919311d3d8d2087d9451f1f`
- 件名: `Fix misuse of MediaProvider#INCLUDED_DEFAULT_DIRECTORIES`
- Bug: `415783046`
- 比較用の先行対策
- `710787bcae97b3db6190edea0469b58a8a08ff6d`
- 件名: `Delete INCLUDED_DEFAULT_DIRECTORIES from extras received over binder`
- Bug: `156201613`
付帯ファイル:
- `artifacts/a5f1f182733953ef5919311d3d8d2087d9451f1f.patch`
- `artifacts/710787bcae97b3db6190edea0469b58a8a08ff6d-2020-sanitizer.patch`
- `artifacts/key-snippets.txt`
- `artifacts/analysis-notes.md`
## パッチで変わったこと
脆弱な実装では、`AccessChecker.getWhereForConstrainedAccess()` が汎用の `Bundle extras` を受け取り、`MediaProvider.INCLUDED_DEFAULT_DIRECTORIES` という内部用キーを直接読んでいた。
該当キーの文字列は次の通り。
```text
android:included-default-directories
```
古い `AccessChecker` は `FILES` / `FILES_ID` のアクセス制約を作るとき、このキーに入っているディレクトリ名を次の SQL 条件に変換し、通常の「所有者一致」「メディア権限」「legacy write」などの条件に OR していた。
```sql
relative_path LIKE '<defaultDir>/%'
```
つまり、`["DCIM", "Pictures", "Movies"]` のような値が入ると、呼び出し元がそのファイルを所有していなくても、該当ディレクトリ配下の `files` 行がアクセス可能として扱われる。
パッチ後は以下の設計に変わっている。
- `MediaProvider.INCLUDED_DEFAULT_DIRECTORIES` 定数を削除。
- `AccessChecker.getWhereForConstrainedAccess()` の引数を `Bundle extras` から `Optional<List<String>> includedDefaultDirectoriesOptional` に変更。
- ほぼすべての `getQueryBuilder()` 呼び出しは `Optional.empty()` を渡す。
- 例外的に、内部の FUSE directory rename 経路だけが `Optional.of(getIncludedDefaultDirectories())` を渡す。
この変更により、Binder 経由で渡される `Bundle` の文字列キーが権限付与の capability として使われなくなった。
## 脆弱性の内容
これは SQL injection ではなく、内部用 capability の混同によるアクセス制御不備である。
`INCLUDED_DEFAULT_DIRECTORIES` は本来、MediaProvider 内部の FUSE directory rename 処理で、System Gallery 向けの例外として `DCIM` / `Pictures` / `Movies` などのデフォルトディレクトリ配下をまとめて扱うための内部情報だった。しかし古い設計では、この内部情報が一般的な `Bundle extras` と同じ経路で `AccessChecker` まで届き、`AccessChecker` 自身もその値を信用して SQL の許可条件に追加していた。
攻撃者アプリが何らかの MediaProvider 操作で次の Bundle 値を保持したまま `Files` 系 URI のアクセスチェックに到達できると、通常なら所有者不一致で拒否される行に対して、デフォルトディレクトリ一致の条件が追加される。
```java
extras.putStringArrayList(
"android:included-default-directories",
new ArrayList<>(List.of("DCIM", "Pictures", "Movies")));
```
結果として、攻撃者は自分の所有物ではない `DCIM/`、`Pictures/`、`Movies/` 配下のメディア行に対する read/write 判定を通せる。write 系の経路では、データベース行の更新、削除、置換、または backing file の write/open に繋がり得るため、Scoped Storage の境界を越える EoP になる。
## 根本原因
根本原因は、内部専用の権限拡張情報を、外部入力にも使われる `Bundle` の文字列キーで表現し、その `Bundle` を権限判定層に直接渡していたこと。
特に問題だった点:
- `android:included-default-directories` は package-private 定数だが、実体は単なる文字列なので外部アプリでも同じキーを作れる。
- 権限判定の中心である `AccessChecker` が、値の出所を検証せず `extras.getStringArrayList()` の結果を信用していた。
- 2020 年に Binder 入口でこのキーを削除する対策が入っていたが、入口サニタイズに依存する設計のままだった。
- 2025 年の修正は、入口で削除するのではなく、`AccessChecker` の API から `Bundle` 依存を外して内部呼び出しだけが明示的に `Optional<List<String>>` を渡す形にしている。
## 面白い点・調査メモ
- 2020 年の `710787b...` で既に「`INCLUDED_DEFAULT_DIRECTORIES` は内部だけがセットすべきなので Binder 経由 extras から消す」と書かれていた。今回の CVE は、その場当たり的な入口サニタイズではなく、権限判定 API の型を変えて capability を分離した修正になっている。
- パッチでは外部入口の `extras.remove(INCLUDED_DEFAULT_DIRECTORIES)` が消えている箇所がある。これは防御を弱めたのではなく、定数自体を消して `AccessChecker` が Bundle を見なくなったため、削除処理が不要になったという意味。
- `AccessCheckerTest` では、`Optional.empty()` の場合はデフォルトディレクトリ条件が追加されず、`Optional.of(List.of(DCIM, Pictures, Movies))` の場合だけ SQL に `relative_path LIKE 'DCIM/%' ...` が追加されることが明示的に検証されている。
- ディレクトリ名の SQL 組み立ては文字列連結だが、CVE の本質は SQL injection ではない。通常のディレクトリ名だけで権限条件が広がるため、攻撃に SQL メタ文字は不要。
## 再現条件の要約
完全な端末上 PoC は実行していないが、ソース上の脆弱プリミティブは次の条件で説明できる。
1. 対象はパッチ前の MediaProvider。
2. 呼び出し元は対象ファイルの owner ではなく、対象 `Files` 行への通常の broad write/read 権限も持たない。
3. `Files` / `Files_ID` 型のアクセスチェックに到達する。
4. `Bundle extras` に `android:included-default-directories` としてデフォルトディレクトリ名リストが残っている。
5. `AccessChecker.getWhereForConstrainedAccess()` が `relative_path LIKE '<dir>/%'` を OR 条件に追加し、対象行がそのディレクトリ配下ならアクセスが許可される。
パッチ後は 4 の値が存在しても `AccessChecker` が `Bundle` を参照しないため、この条件では許可条件が広がらない。
## 結論
CVE-2025-48544 は MediaProvider の内部用 `INCLUDED_DEFAULT_DIRECTORIES` 例外を、外部入力可能な `Bundle` を通じて権限判定に混入できる EoP だった。修正は、内部例外を `Bundle` 文字列キーから切り離し、FUSE directory rename の内部経路だけが型付き引数で明示的にデフォルトディレクトリリストを渡せるようにするものだった。
cve.md を表示# CVE-2025-48544 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48544 - Component: Framework - Subcomponent: MediaProvider - Reference: A-415783046 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 4 | OK | CVE-2025-48567 - Framework EoP High |
004
ok
CVE-2025-48567 - Framework EoP High004-ok-MediaProvider-ZWS-path-sanitization-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱だった処理) 修正前の `FileUtils` には次のような正規表現があり、これをもとに private directory 判定をしていた。 - `PATTERN_OWNED_PATH`: `^/storage/.../Android/(?:data|media|obb)/([^/]+)...` - `PATTERN_OWNED_RELATIVE_PATH`: `^Android/(?:data|media|obb)/([^/]+)...` - `PATTERN_DATA_OR_OBB_PATH`: `^/storage/.../Android/(?:data|obb)/?$` - `PATTERN_DATA_OR_OBB_RELATIVE_PATH`: `^Android/(?:data|obb)(?:/.*)?$` 修正前は、`An\u200Bdroid/data/com.victim/files` が文字列としては `Android/data/...` と一致しないため、次の判定が失敗する。 - `extractPathOwnerPackageName(path)` が owner package を抽出できない。 - `isDataOrObbPath(path)` が `Android/data` / `Android/obb` と認識できない。 - `extractOwnerPackageNameFromRelativePath(relativePath)` が package owner を認識できない。 一方、コミットメッセージには lower file system がこれらの文字を保存時に無視すると明記されている。そのため、MediaProvider のポリシー判定層と lower filesystem の実体解釈に不一致が生じる。 原因(根本原因) 根本原因は、セキュリティ境界であるパス分類を、ファイルシステム実装と同じ canonical form に揃えないまま正規表現で行っていたこと。 より具体的には、MediaProvider の保護ロジックは Java 文字列上の `Android/data` / `Android/obb` というリテラル一致に依存していた。しかし lower filesystem は Default Ignorable Code Point を無視するため、MediaProvider と filesystem の間で「同じパスかどうか」の解釈がずれていた。この種のチェックでは、判定前に正規化・不可視文字除去・canonicalization を行い、その canonical form だけでアクセス制御を判断する必要がある。 どこから特定したか validated.md の「参照情報」「パッチ解析」 / Android bug参照 A-377888957 validated.md を表示# CVE-2025-48567 検証結果 ## 判定 ok: 脆弱性の原因と修正点をソースコード差分から特定できた。 この問題は、MediaProvider が `Android/data` / `Android/obb` などのアプリ private 外部ストレージディレクトリを正規表現で判定する前に、lower filesystem が無視する Unicode Default Ignorable Code Point を正規化・除去していなかったことによる EoP である。攻撃アプリは `An\u200Bdroid/data/...` のようにゼロ幅スペースなどの不可視文字をパスへ混ぜ、MediaProvider 側の `Android/data` 判定を外しつつ、lower filesystem 側では実質的に `Android/data/...` として扱わせることで、private app directory 保護を迂回できた。 ## 参照情報 - Android Security Bulletin 2026-03-01: `CVE-2025-48567`, `A-377888957`, Framework / MediaProvider, EoP, High, updated AOSP versions 14, 15, 16 - 公開修正コミット: `237fb89f532504aeef0c3ee2038aad89a8a66180` - コミットタイトル: `[security-aosp-25Q2-staging] Remove default ignoreable characters before regex checks` - 親コミット: `68cd09759ae7a40787a5dfd9d9443cc8dc692b77` - 共有キャッシュ: `../binaries/platform_packages_providers_MediaProvider.git` ## パッチ解析 主修正は `FileUtils.normalizeAndFilterDefaultIgnorableCodepoints()` の追加と、private path 判定前の呼び出し追加である。 `src/com/android/providers/media/util/FileUtils.java`: - `Normalizer.normalize(path, Normalizer.Form.NFD)` でパスを NFD 正規化する。 - `UCharacter.hasBinaryProperty(codePoint, UProperty.DEFAULT_IGNORABLE_CODE_POINT)` で default ignorable code point を検出する。 - 該当 code point を除去したパスを返す。 - `enable_path_sanitization` フラグでガードされる。後続履歴では `27d5b689b` でこのフラグが削除され、常時有効化されている。 `src/com/android/providers/media/MediaProvider.java`: - `isPrivatePackagePathNotAccessibleByCaller(String path)` の先頭でパスを正規化・フィルタするようになった。 - FUSE 経由の `isUidAllowedAccessToDataOrObbPathForFuse(int uid, String path)` は、公開 `@Keep` メソッドとして残しつつ、内部判定へ渡す前にパスを正規化するようになった。 - `shouldBypassFuseRestrictions()` からは、既に正規化済みの内部 `isUidAllowedAccessToDataOrObbPath()` を呼ぶ形へ分離された。 `tests/src/com/android/providers/media/util/FileUtilsTest.java`: - `"/storage/emulated/0/An\u200Bdroid/data/com.google.example/files"` が `"/storage/emulated/0/Android/data/com.google.example/files"` に変換されることをテストしている。 - `4\uFE0F⃣` から VS16 が除去されるケースもあり、対象は U+200B だけではなく Unicode Default Ignorable Code Point 全般である。 ## 脆弱だった処理 修正前の `FileUtils` には次のような正規表現があり、これをもとに private directory 判定をしていた。 - `PATTERN_OWNED_PATH`: `^/storage/.../Android/(?:data|media|obb)/([^/]+)...` - `PATTERN_OWNED_RELATIVE_PATH`: `^Android/(?:data|media|obb)/([^/]+)...` - `PATTERN_DATA_OR_OBB_PATH`: `^/storage/.../Android/(?:data|obb)/?$` - `PATTERN_DATA_OR_OBB_RELATIVE_PATH`: `^Android/(?:data|obb)(?:/.*)?$` 修正前は、`An\u200Bdroid/data/com.victim/files` が文字列としては `Android/data/...` と一致しないため、次の判定が失敗する。 - `extractPathOwnerPackageName(path)` が owner package を抽出できない。 - `isDataOrObbPath(path)` が `Android/data` / `Android/obb` と認識できない。 - `extractOwnerPackageNameFromRelativePath(relativePath)` が package owner を認識できない。 一方、コミットメッセージには lower file system がこれらの文字を保存時に無視すると明記されている。そのため、MediaProvider のポリシー判定層と lower filesystem の実体解釈に不一致が生じる。 ## 想定される悪用条件 攻撃アプリが FUSE / MediaProvider 経由で、他アプリの private 外部ディレクトリに相当するパスへ不可視文字を混ぜる。 例: - 見た目: `/storage/emulated/0/Android/data/com.victim/files` - 実際に渡す文字列: `/storage/emulated/0/An\u200Bdroid/data/com.victim/files` 修正前の MediaProvider はこのパスを private package path と認識しないため、`isPrivatePackagePathNotAccessibleByCaller()` や `isDataOrObbPath()` による拒否に到達しない可能性がある。lower filesystem が U+200B などを無視すると、実際のアクセス先は `Android/data/com.victim/...` になり、他アプリ private directory へのアクセス制御迂回になる。 ## 根本原因 根本原因は、セキュリティ境界であるパス分類を、ファイルシステム実装と同じ canonical form に揃えないまま正規表現で行っていたこと。 より具体的には、MediaProvider の保護ロジックは Java 文字列上の `Android/data` / `Android/obb` というリテラル一致に依存していた。しかし lower filesystem は Default Ignorable Code Point を無視するため、MediaProvider と filesystem の間で「同じパスかどうか」の解釈がずれていた。この種のチェックでは、判定前に正規化・不可視文字除去・canonicalization を行い、その canonical form だけでアクセス制御を判断する必要がある。 ## 関連履歴から分かったこと 同じ Bug ID `377888957` には、最初に `5dc5ccb4d` の「FUSE操作で default ignorable 文字を含むパスを拒否する」修正があった。この案は `onFileLookupForFuse`, `getFilesInDirectoryForFuse`, `renameForFuse`, `onFileOpenForFuse`, `insertFileIfNecessaryForFuse`, `deleteFileForFuse`, `isDirAccessAllowedForFuse`, `isUidAllowedAccessToDataOrObbPathForFuse` などで `assertNoDefaultIgnorableCharactersInPath()` を呼び、該当文字を含むパスを `IllegalArgumentException` にしていた。 その後 `bf7e03f67` でこの修正は revert され、最終的には「拒否」ではなく「判定前に除去して同一視する」方針へ変わった。これは、不可視文字を含む既存ファイル名や一般的なUnicode入力を一律拒否するより、保護対象ディレクトリ判定だけを lower filesystem と同じ見方に寄せる方が互換性面で安全だったためと推測できる。 また、mainline 側の `ac3a6dc8d` では `FileUtils` の複数ヘルパー、特に `isDataOrObbRelativePath()` 自体にも正規化が入っている。一方、今回の公開 advisory が指す `237fb89f...` の security branch 用 cherry-pick では、`MediaProvider` の呼び出し側で正規化する形も含まれている。ブランチごとに適用形は異なるが、セキュリティ上の要点は同じである。 ## ローカル検証 Android 実機・atest はこの環境では実行していない。代わりに、対象フォルダ内の `regex_bypass_demo.py` で問題の本質を確認した。 実行結果: ```text raw: /storage/emulated/0/An\u200bdroid/data/com.victim/files visible: /storage/emulated/0/Android/data/com.victim/files owned? False rel data? False filtered: /storage/emulated/0/Android/data/com.victim/files owned? True rel data? False raw: An\u200bdroid/data/com.victim/files visible: Android/data/com.victim/files owned? False rel data? False filtered: Android/data/com.victim/files owned? False rel data? True ``` これは、不可視文字入りの `Android` が正規表現には一致せず、除去後は一致することを示す。Android 固有の lower filesystem 挙動までは再現していないが、公開コミットメッセージとテストがその前提を明示しているため、脆弱性条件は十分に説明できる。 ## 保存した付帯ファイル - `android-security-bulletin-2026-03-01.html`: bulletin のローカル保存 - `commit_237fb89f532504aeef0c3ee2038aad89a8a66180.json`: Gitiles commit JSON - `patch_237fb89f532504aeef0c3ee2038aad89a8a66180.diff`: 公開修正の生diff - `patch_237fb89f532504aeef0c3ee2038aad89a8a66180_full_git_show.txt`: `git show` 形式の修正 - `related_5dc5ccb4d_restrict_zws_for_fuse.*`: 初期の拒否型修正 - `related_bf7e03f67_revert_restrict_zws.*`: 初期修正の revert - `related_ac3a6dc8d_main_fix.*`: mainline 側の最終修正 - `regex_bypass_demo.py`: 最小再現デモ - `regex_bypass_demo_output.txt`: デモ実行結果 cve.md を表示# CVE-2025-48567 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48567 - Component: Framework - Subcomponent: MediaProvider - Reference: A-377888957 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 5 | OK | CVE-2025-48568 - Framework EoP High |
005
ok
CVE-2025-48568 - Framework EoP High005-ok-lockscreen-bypass-user-switch-race cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性が起きる状況) パッチに追加されたテストが、脆弱な状況をかなり直接表している。 1. 旧ユーザーでKeyguardが表示されている。 2. 旧ユーザー側でKeyguard解除が進み、`keyguardGoingAway` が要求される。 3. WindowManagerがKeyguard exit animationを開始する前に、セキュアな別ユーザーへ切り替わる。 4. 修正前は、その後に届いた旧ユーザー由来のexit animation/dismissが拒否されず、新ユーザー側のKeyguardを隠す方向に働き得る。 5. 修正後は、要求時ユーザーIDと現在ユーザーIDが異なる場合、`handleStartKeyguardExitAnimation` が処理を拒否し、secure userなら `doKeyguardLocked()` で再表示する。 別のケースとして、Keyguardが見えていない状態でセキュアなユーザーへ切り替わった場合も、修正後は `setCurrentUser()` が `setPendingLock(true)`、`setLockScreenShown(true, ...)`、`doKeyguardLocked(null)` を即時実行する。追加テスト `testUserSwitchToSecureUserWhileKeyguardNotVisibleShowsKeyguard` がこの条件を確認している。 原因(脆弱性の根本原因) 根本原因は、ユーザー切替とKeyguard状態遷移の間に、単一の同期ポイントとユーザーID検証がなかったこと。 具体的には、修正前は次の非同期処理が別々に進行していた。 - ユーザー切替により `KeyguardUpdateMonitor` / `UserController` のcurrent userが更新される。 - 旧ユーザーで開始された `keyguardGoingAway` やremote unlock animationが、WindowManagerから後でコールバックされる。 - `dismiss()` / `HIDE` / delayed dismissがHandler上に残り得る。 - `completeUserSwitch()` が、切替先ユーザーのKeyguard表示完了を厳密には待たずに、`ACTION_USER_SWITCHED` / `onUserSwitchComplete` へ進む。 このため、旧ユーザーの「Keyguardを消す」処理が、新しいセキュアユーザーへ切り替わった後に実行されるレースが成立する。あるいは、Keyguardが一時的に非表示の状態でセキュアユーザーへ切り替わった場合、切替先ユーザーのロックスクリーンを強制表示する処理が不足していた。 どこから特定したか validated.md の「参照した一次情報」「修正内容の要約」 / Android bug参照 A-322157041 validated.md を表示# CVE-2025-48568 パッチ解析結果 ## 判定 ok。ソースコード差分から脆弱性の種類、競合が起きる場所、修正方針を特定できた。 このCVEは、ユーザー切替とKeyguardの非表示/解除アニメーションが競合したときに、セキュアな切替先ユーザーのロックスクリーンが表示されない、または古いユーザーのKeyguard解除処理が新しいユーザーに対して後から効いてしまうロックスクリーンバイパスである。結果として、認証が必要なユーザーへ切り替わった直後に、PIN/Pattern/Password入力なしでロック後ろの画面へ到達し得る。 ## 参照した一次情報 - Android Security Bulletin 2026-03-01: `CVE-2025-48568 / A-322157041 / Framework / EoP / High / Android 14, 15` - OSV: `ASB-A-322157041.json` - Android 14 fix: `platform/frameworks/base` commit `b00cff0ff1afbcad8b9dc7d8f893f2d6aad9d204` - Android 15/16系の関連fix: - `d8c3d450f77f77232a89ac37c9b9b266e28c0202` - `f7efa779da5c59085b38cb73da61ef0d83b672b6` の公開cherry-pick相当 `c059123b8e9c0920a30f896513116a8b88bfc4e1` - `66a279ee4cc34c0fbbf7d19ae09bf7c2f4816493` の公開cherry-pick相当 `8c290a4d87c27a4ad65757e97ff9e634d9fe865e` - `175dd00420c6727793b724ecbb9fe90e54f8b688` の公開cherry-pick相当 `5f59ac63cb7042d58dae196e890ec52424ebe8b5` 付帯ファイルとして、OSV JSONと取得できたGitiles差分を同じフォルダに保存した。 ## 修正内容の要約 修正の中心は `UserController` と `SystemUI` の `KeyguardViewMediator` である。 `UserController` 側では、ユーザー切替中にセキュアなユーザーへ移る場合、WindowManager/SystemUIへ `lockNow(Bundle)` を送り、`LOCK_ON_USER_SWITCH_CALLBACK` という `IRemoteCallback` が返るまで待つようになった。旧実装では、ユーザー切替完了通知やユーザー切替ダイアログの処理が、Keyguardの表示完了と十分に同期していなかった。 `SystemUI` 側では、`KeyguardViewMediator` がユーザー切替を明示的に扱うようになった。切替先ユーザーがsecureなら、保留中の `DISMISS` / `HIDE` と遅延dismissを消し、`keyguardGoingAway` 状態を解除し、`setLockScreenShown(true, ...)` と `doKeyguardLocked()` で即座にKeyguardを表示する。また、表示できた、または表示不要と判断した時点で `notifyLockNowCallback()` を呼び、`UserController` を進める。 もう一つ重要なのは、Keyguard解除アニメーションの所有ユーザーを検証するようになった点である。`mGoingAwayRequestedForUserId` に `keyguardGoingAway` 要求時のユーザーIDを保存し、後でWindowManagerから `startKeyguardExitAnimation` が来たときに現在ユーザーと一致しなければ、古い解除アニメーションを拒否してKeyguardを再表示する。 ## 脆弱性の根本原因 根本原因は、ユーザー切替とKeyguard状態遷移の間に、単一の同期ポイントとユーザーID検証がなかったこと。 具体的には、修正前は次の非同期処理が別々に進行していた。 - ユーザー切替により `KeyguardUpdateMonitor` / `UserController` のcurrent userが更新される。 - 旧ユーザーで開始された `keyguardGoingAway` やremote unlock animationが、WindowManagerから後でコールバックされる。 - `dismiss()` / `HIDE` / delayed dismissがHandler上に残り得る。 - `completeUserSwitch()` が、切替先ユーザーのKeyguard表示完了を厳密には待たずに、`ACTION_USER_SWITCHED` / `onUserSwitchComplete` へ進む。 このため、旧ユーザーの「Keyguardを消す」処理が、新しいセキュアユーザーへ切り替わった後に実行されるレースが成立する。あるいは、Keyguardが一時的に非表示の状態でセキュアユーザーへ切り替わった場合、切替先ユーザーのロックスクリーンを強制表示する処理が不足していた。 ## 脆弱性が起きる状況 パッチに追加されたテストが、脆弱な状況をかなり直接表している。 1. 旧ユーザーでKeyguardが表示されている。 2. 旧ユーザー側でKeyguard解除が進み、`keyguardGoingAway` が要求される。 3. WindowManagerがKeyguard exit animationを開始する前に、セキュアな別ユーザーへ切り替わる。 4. 修正前は、その後に届いた旧ユーザー由来のexit animation/dismissが拒否されず、新ユーザー側のKeyguardを隠す方向に働き得る。 5. 修正後は、要求時ユーザーIDと現在ユーザーIDが異なる場合、`handleStartKeyguardExitAnimation` が処理を拒否し、secure userなら `doKeyguardLocked()` で再表示する。 別のケースとして、Keyguardが見えていない状態でセキュアなユーザーへ切り替わった場合も、修正後は `setCurrentUser()` が `setPendingLock(true)`、`setLockScreenShown(true, ...)`、`doKeyguardLocked(null)` を即時実行する。追加テスト `testUserSwitchToSecureUserWhileKeyguardNotVisibleShowsKeyguard` がこの条件を確認している。 ## 面白い点・調査メモ - ブリテン上の `A-322157041` には直接のAOSPリンクが付いていなかったが、OSVの `ASB-A-322157041.json` には修正コミットとVanir signatureが含まれていた。 - Android 14は1つの大きなbackport commitにまとまっており、Android 15/16系ではUserSwitchObserverのcallback化、UserControllerの処理分割、SystemUI Keyguard対応などが複数commitに分かれている。 - 修正コミットメッセージに「If the user is secure, initiate a call to SystemUI to lockNow(), and wait for the callback」「If the callback does not arrive, crash the system after some time」とあり、Keyguard表示完了をセキュリティ境界として扱う意図が明確。 - `LOCK_ON_USER_SWITCH_CALLBACK` は、単なる通知ではなく「UserControllerが先へ進んでよい」という同期バリアとして追加されている。 - `dismiss()` が `isKeyguardGoingAway()` 中なら無視されるようになった点も重要。古いdismissを消すだけでなく、進行中の解除状態そのものを危険状態として扱っている。 - `mGoingAwayRequestedForUserId` によるユーザーID一致確認は、このCVEの本質に近い。Keyguard exit animationは非同期で戻るため、要求時と実行時で保護対象ユーザーが変わっていないことを確認しないと、古い解除イベントが新しいユーザーのロック状態を破壊する。 ## 付帯ファイル - `ASB-A-322157041.json`: OSVの脆弱性レコード。 - `aosp14_b00cff0_commit.txt`: Android 14修正コミットのメタデータ。 - `aosp14_b00cff0_diff.txt`: Android 14修正差分。 - `d8c3d450_commit.txt`: 16-qpr2-next修正コミットのメタデータ。 - `d8c3d450_diff.txt`: 16-qpr2-next修正差分。 - `aosp15_public_c059123b_diff.txt`: Android 15系 `f7efa779...` の公開cherry-pick相当差分。 - `aosp15_public_8c290a4d_diff.txt`: Android 15系 `66a279ee...` の公開cherry-pick相当差分。 - `aosp15_public_5f59ac63_diff.txt`: Android 15系 `175dd004...` の公開cherry-pick相当差分。 ## 結論 CVE-2025-48568は、ユーザー切替とKeyguard解除/表示処理の競合によるロックスクリーンバイパスである。修正は、セキュアユーザーへの切替時にSystemUIがKeyguardを表示したことをUserControllerがcallbackで待つ同期バリアを追加し、さらに古いユーザーのKeyguard exit animationやdismissが新ユーザーへ作用しないよう、保留メッセージの削除、`keyguardGoingAway` の解除、ユーザーID一致検証、exit animationキャンセル処理を追加している。 cve.md を表示# CVE-2025-48568 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48568 - Component: Framework - Reference: A-322157041 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 6 | OK | CVE-2025-48574 - Framework EoP High |
006
ok
CVE-2025-48574 - Framework EoP High006-ok-global-drag-intercept-permission-bypass cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性が起きる状況) 攻撃側が WindowManager にウィンドウを追加する際、`WindowManager.LayoutParams.privateFlags` に `PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP` を立てる。 本来この private flag は `@RequiresPermission(permission.MANAGE_ACTIVITY_TASKS)` で、システム権限を持つコンポーネントに限定されるべきである。ところが修正前は window add の検査が実呼び出し元 UID ではなく clear 後 identity に対して行われるため、`MANAGE_ACTIVITY_TASKS` を持たない呼び出し元でも検査を通過し得る。 この flag を持つウィンドウは global drag/drop の特権的な受信者になる。ソース上のコメントと `DragState` の実装から、次の能力が確認できる。 - 非表示ウィンドウでも drag event の対象になり得る。 - 全 active user の drag を受けられる。 - `ACTION_DRAG_STARTED` で `ClipData` を受け取る経路がある。 - `ACTION_DROP` で drag surface と drag flags を受け取る経路がある。 - 通常の同一ユーザー・同一アプリ制限を `interceptsGlobalDrag` として迂回する分岐がある。 したがって影響は、単なるクラッシュではなく、本来 `MANAGE_ACTIVITY_TASKS` 保有者だけが使える global drag interception 権限の獲得であり、Framework EoP High と整合する。 原因(根本原因) 根本原因は、権限チェック API の選択ミスである。 `WindowManagerService.addWindow()` は、ウィンドウ追加リクエストの入口で次の順序を取る。 1. `Binder.getCallingUid()` と `Binder.getCallingPid()` を `callingUid/callingPid` に保存する。 2. `Binder.clearCallingIdentity()` を呼ぶ。 3. その後、`displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid)` を呼ぶ。 この設計では、`validateAddingWindowLw()` 内の権限チェックは保存済み `callingPid/callingUid` を使わなければならない。実際、`PRIVATE_FLAG_TRUSTED_OVERLAY` や status bar 系 window type の検査は `mContext.enforcePermission(..., callingPid, callingUid, ...)` を使っている。 しかし修正前の `PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP` だけは `ActivityTaskManagerService.enforceTaskPermission()` を使っていた。この helper は現在の Binder caller を見るため、`clearCallingIdentity()` 後の system_server 側 identity で `MANAGE_ACTIVITY_TASKS` を満たしてしまう。結果として、実際のアプリ UID に対する検査になっていなかった。 どこから特定したか validated.md の「対象情報」「パッチ内容」 / Android bug参照 A-428700812 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://android.googlesource.com/platform/frameworks/base/+/1cfd8237b5a8e9fa64367e3d0dfff525d63821e1 validated.md を表示# CVE-2025-48574 検証結果
## 判定
`ok`: ソースコード差分から脆弱性の根本原因と成立条件を特定できた。
脆弱性は、WindowManager のウィンドウ追加処理で `PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP` に必要な `MANAGE_ACTIVITY_TASKS` 権限を、実際の呼び出し元 UID/PID ではなく `Binder.clearCallingIdentity()` 後の Binder identity で検査していたことによる権限昇格である。
## 対象情報
- CVE: `CVE-2025-48574`
- Android bug: `A-428700812`
- Bulletin: Android Security Bulletin - March 2026, `2026-03-01`
- Component: Framework
- Type: EoP
- Severity: High
- Updated AOSP versions: 14, 15, 16
- 修正コミット: `1cfd8237b5a8e9fa64367e3d0dfff525d63821e1`
- 親コミット: `e707f6600330691f9c67dc023c09f4cd2fc59192`
## パッチ内容
修正前の `DisplayPolicy.validateAddingWindowLw()` は、`PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP` が指定された場合に次を呼んでいた。
```java
ActivityTaskManagerService.enforceTaskPermission("DisplayPolicy");
```
修正後は、同じメソッドの引数として渡されている保存済みの実呼び出し元 PID/UID を使う検査に変わった。
```java
mContext.enforcePermission(
android.Manifest.permission.MANAGE_ACTIVITY_TASKS, callingPid, callingUid,
"DisplayPolicy");
```
差分は小さいが意味は大きい。`ActivityTaskManagerService.enforceTaskPermission()` は `checkCallingPermission()` を使い、エラーメッセージも `Binder.getCallingPid()` / `Binder.getCallingUid()` を参照する。つまり、引数で渡された `callingPid/callingUid` ではなく、その時点の Binder calling identity に依存する。
## 根本原因
根本原因は、権限チェック API の選択ミスである。
`WindowManagerService.addWindow()` は、ウィンドウ追加リクエストの入口で次の順序を取る。
1. `Binder.getCallingUid()` と `Binder.getCallingPid()` を `callingUid/callingPid` に保存する。
2. `Binder.clearCallingIdentity()` を呼ぶ。
3. その後、`displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid)` を呼ぶ。
この設計では、`validateAddingWindowLw()` 内の権限チェックは保存済み `callingPid/callingUid` を使わなければならない。実際、`PRIVATE_FLAG_TRUSTED_OVERLAY` や status bar 系 window type の検査は `mContext.enforcePermission(..., callingPid, callingUid, ...)` を使っている。
しかし修正前の `PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP` だけは `ActivityTaskManagerService.enforceTaskPermission()` を使っていた。この helper は現在の Binder caller を見るため、`clearCallingIdentity()` 後の system_server 側 identity で `MANAGE_ACTIVITY_TASKS` を満たしてしまう。結果として、実際のアプリ UID に対する検査になっていなかった。
## 脆弱性が起きる状況
攻撃側が WindowManager にウィンドウを追加する際、`WindowManager.LayoutParams.privateFlags` に `PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP` を立てる。
本来この private flag は `@RequiresPermission(permission.MANAGE_ACTIVITY_TASKS)` で、システム権限を持つコンポーネントに限定されるべきである。ところが修正前は window add の検査が実呼び出し元 UID ではなく clear 後 identity に対して行われるため、`MANAGE_ACTIVITY_TASKS` を持たない呼び出し元でも検査を通過し得る。
この flag を持つウィンドウは global drag/drop の特権的な受信者になる。ソース上のコメントと `DragState` の実装から、次の能力が確認できる。
- 非表示ウィンドウでも drag event の対象になり得る。
- 全 active user の drag を受けられる。
- `ACTION_DRAG_STARTED` で `ClipData` を受け取る経路がある。
- `ACTION_DROP` で drag surface と drag flags を受け取る経路がある。
- 通常の同一ユーザー・同一アプリ制限を `interceptsGlobalDrag` として迂回する分岐がある。
したがって影響は、単なるクラッシュではなく、本来 `MANAGE_ACTIVITY_TASKS` 保有者だけが使える global drag interception 権限の獲得であり、Framework EoP High と整合する。
## 検証した証跡
- `patch_1cfd8237.diff`: `DisplayPolicy.java` の権限チェックが `enforceTaskPermission()` から `mContext.enforcePermission(... callingPid, callingUid ...)` に変更されている。
- `commit_1cfd8237.txt`: コミットメッセージに「Binder calling uid/pid が clear された後なので `ActivityTaskManagerService.enforceTaskPermission()` に依存できない」と明記されている。
- `WindowManagerService_after.java`: `addWindow()` が `callingUid/callingPid` 保存直後に `Binder.clearCallingIdentity()` し、その後 `validateAddingWindowLw(attrs, callingPid, callingUid)` を呼ぶ。
- `ActivityTaskManagerService_after.java`: `enforceTaskPermission()` が `checkCallingPermission(MANAGE_ACTIVITY_TASKS)` と Binder の current caller に依存する。
- `WindowManager_after.java`: `PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP` が `MANAGE_ACTIVITY_TASKS` 要求の hidden private flag であり、全ユーザー global drag/drop を扱うことがコメントされている。
- `DragState_after.java`: `interceptsGlobalDrag` の場合に `ClipData` をコピーして dispatch し、drop target 検証でも特別扱いしている。
- `DragDropControllerTests_after.java`: テストの期待値が ATM helper 呼び出しから `mContext.enforcePermission(MANAGE_ACTIVITY_TASKS, pid, uid, ...)` に変更されている。
## 行単位の確認
- `WindowManagerService_after.java:1550-1552`: `callingUid` / `callingPid` を保存し、直後に `Binder.clearCallingIdentity()` を実行する。
- `WindowManagerService_after.java:1760`: clear 済み identity のまま `displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid)` を呼ぶ。
- `DisplayPolicy_before.java:1073-1074`: vulnerable 版は `PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP` に対して `ActivityTaskManagerService.enforceTaskPermission("DisplayPolicy")` を呼ぶ。
- `ActivityTaskManagerService_after.java:3400-3412`: `enforceTaskPermission()` は `checkCallingPermission()` と `Binder.getCallingPid()` / `Binder.getCallingUid()` に依存する。引数で保存された caller PID/UID は受け取らない。
- `DisplayPolicy_after.java:1073-1076`: patched 版は `mContext.enforcePermission(MANAGE_ACTIVITY_TASKS, callingPid, callingUid, ...)` に変更され、保存済み実 caller を検査する。
- `WindowManager_after.java:3628-3641`: 対象 private flag は全 user の global drag/drop 受信、不可視 window の drag event 対象化、`ClipData` / drag surface の提供を伴い、`MANAGE_ACTIVITY_TASKS` が必要と定義されている。
- `DragState_after.java:533-572`: flag を持つ window には `ACTION_DRAG_STARTED` が dispatch され、`interceptsGlobalDrag` の場合は `ClipData` がコピーされる。
- `DragState_after.java:600-635`: drop target 判定で `interceptsGlobalDrag` は app extras、same-app、user 境界の通常制限を迂回する例外条件になる。
## 攻撃成立モデル
1. 攻撃アプリが `WindowManager.LayoutParams.privateFlags` に `PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP` を設定して window 追加を要求する。
2. `WindowManagerService.addWindow()` は実 caller の UID/PID を保存するが、policy 検証前に `Binder.clearCallingIdentity()` を実行する。
3. 修正前 `DisplayPolicy.validateAddingWindowLw()` は保存済み UID/PID を使わず `ActivityTaskManagerService.enforceTaskPermission()` を呼ぶ。
4. `enforceTaskPermission()` は current Binder caller を検査するため、clear 後の system_server identity で `MANAGE_ACTIVITY_TASKS` 検査が成功し得る。
5. その結果、権限を持たない caller が global drag interception 用 private flag 付き window を登録できる。
6. 以後、その window は `DragState` の `interceptsGlobalDrag` 経路で drag start/drop event の特権的な受信者として扱われる。
このモデルは、ソース差分だけで caller identity の取り違えと権限境界の破綻を説明できるため、`ok` 判定に足る。
## 面白い点・調査メモ
- パッチは実質 1 箇所の API 差し替えだが、`Binder.clearCallingIdentity()` の位置によってセキュリティ境界が反転している。
- 同じ `validateAddingWindowLw()` 内の他の権限チェックはすでに保存済み PID/UID を使っており、この flag だけが例外的に危険な helper を呼んでいた。
- 追加テストは「例外が投げられる」ことまでは直接検証しておらず、正しい permission API が呼ばれることを mock で確認している。今回のバグはロジック差分そのものが本質なので、このテスト変更は regressions の検出に向いている。
- CVE 名は Framework EoP だが、実際の権限昇格先は task 管理 API そのものではなく、drag/drop の global interception private flag である。
- `PRIVATE_FLAG_TRUSTED_OVERLAY` など周辺の検査は以前から `mContext.enforcePermission(..., callingPid, callingUid, ...)` 形式で、今回の修正はこの局所的な例外を周辺コードの設計に戻すものだった。
## 参考 URL
- Android Security Bulletin March 2026: https://source.android.com/docs/security/bulletin/2026/2026-03-01
- 修正コミット: https://android.googlesource.com/platform/frameworks/base/+/1cfd8237b5a8e9fa64367e3d0dfff525d63821e1
cve.md を表示# CVE-2025-48574 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48574 - Component: Framework - Reference: A-428700812 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 7 | OK | CVE-2025-48578 - Framework EoP High |
007
ok
CVE-2025-48578 - Framework EoP High007-ok-getMediaUri-calling-identity-restore-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) これは MediaProvider の Binder/local calling identity 復元漏れである。 `MediaStore.getMediaUri(Context, Uri)` は公開 API で、内部的には MediaProvider に `GET_MEDIA_URI_CALL` を送る。MediaProvider 側の `getResultForGetMediaUri()` は、渡された `documentUri` について read URI permission を確認したあと、外部の DocumentsProvider へ 問い合わせるために `clearCallingIdentity()` を呼ぶ。 問題は、`clearCallingIdentity()` の直後に `documentUri.getAuthority()` を検証し、 authority が次のどちらでもない場合に `IllegalArgumentException` を投げていた点である。 - `MediaDocumentsProvider.AUTHORITY` - `DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY` この authority 検証は `try/finally` の前に置かれていたため、例外パスでは `restoreCallingIdentity(token)` が実行されなかった。 MediaProvider の calling identity は単なる Binder identity だけではない。 `mCallingIdentity` という `ThreadLocal<LocalCallingIdentity>` も使われており、 `clearCallingIdentity()` / `clearLocalCallingIdentity()` により、そのスレッドの `mCallingIden... 原因(根本原因) 根本原因は、特権 identity に切り替える処理を、例外を投げ得る外部入力検証より前に実行し、 その直後から `try/finally` で保護していなかったこと。 具体的には、`clearCallingIdentity()` 後の最初の外部入力依存処理である `documentUri.getAuthority()` / authority allowlist 検証が `try` ブロック外にあり、 unsupported authority という攻撃者が制御できるエラー条件で復元処理をバイパスできた。 どこから特定したか validated.md の「参照した情報」 / Android bug参照 A-418225717 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://android.googlesource.com/platform/packages/providers/MediaProvider/+/7ea0a039ec32fcd6477355431b953f4689a2fa61 validated.md を表示# CVE-2025-48578 検証結果
## 判定
`ok`
ソースコード差分から、CVE-2025-48578 / A-418225717 は MediaProvider の
`getResultForGetMediaUri()` で `clearCallingIdentity()` 後に例外が投げられると
calling identity が復元されない EoP だと特定できた。
## 参照した情報
- Android Security Bulletin 2026-03-01
- `https://source.android.com/docs/security/bulletin/2026/2026-03-01`
- Framework / MediaProvider に `CVE-2025-48578`、参照 `A-418225717`、EoP High、対象 Android 14/15/16 として掲載。
- AOSP / Gitiles
- `https://android.googlesource.com/platform/packages/providers/MediaProvider/+/7ea0a039ec32fcd6477355431b953f4689a2fa61`
- コミット: `7ea0a039ec32fcd6477355431b953f4689a2fa61`
- 件名: `Restore calling identity when exception is thrown`
- Bug: `417195606`, `418225717`
付帯ファイル:
- `artifacts/7ea0a039ec32fcd6477355431b953f4689a2fa61.patch`
- `artifacts/prepatch-getResultForGetMediaUri.txt`
- `artifacts/postpatch-getResultForGetMediaUri.txt`
- `artifacts/calling-identity-helpers.txt`
- `artifacts/public-api-getMediaUri.txt`
- `artifacts/analysis-notes.md`
## パッチで変わったこと
該当コミットは `MediaProvider.java` だけを変更している。CVE-2025-48578 に対応する変更は
`getResultForGetMediaUri()` の unsupported authority 分岐で、例外を投げる前に
`restoreCallingIdentity(token)` を呼ぶ 1 行の追加である。
パッチ前:
```java
final CallingIdentity token = clearCallingIdentity();
final String authority = documentUri.getAuthority();
if (!authority.equals(MediaDocumentsProvider.AUTHORITY)
&& !authority.equals(DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY)) {
throw new IllegalArgumentException("Provider for this Uri is not supported.");
}
try (...) {
...
} finally {
restoreCallingIdentity(token);
}
```
パッチ後:
```java
if (!authority.equals(MediaDocumentsProvider.AUTHORITY)
&& !authority.equals(DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY)) {
restoreCallingIdentity(token);
throw new IllegalArgumentException("Provider for this Uri is not supported.");
}
```
同じコミットには `updateInternal()` の `ContentUris.parseId(uri)` が
`NumberFormatException` を投げる経路の修正も含まれるが、Android bulletin の対応関係では
`A-417195606` が CVE-2025-48579、`A-418225717` が CVE-2025-48578 である。
したがって、このフォルダの対象は `getResultForGetMediaUri()` 側と判断した。
## 脆弱性の内容
これは MediaProvider の Binder/local calling identity 復元漏れである。
`MediaStore.getMediaUri(Context, Uri)` は公開 API で、内部的には MediaProvider に
`GET_MEDIA_URI_CALL` を送る。MediaProvider 側の `getResultForGetMediaUri()` は、渡された
`documentUri` について read URI permission を確認したあと、外部の DocumentsProvider へ
問い合わせるために `clearCallingIdentity()` を呼ぶ。
問題は、`clearCallingIdentity()` の直後に `documentUri.getAuthority()` を検証し、
authority が次のどちらでもない場合に `IllegalArgumentException` を投げていた点である。
- `MediaDocumentsProvider.AUTHORITY`
- `DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY`
この authority 検証は `try/finally` の前に置かれていたため、例外パスでは
`restoreCallingIdentity(token)` が実行されなかった。
MediaProvider の calling identity は単なる Binder identity だけではない。
`mCallingIdentity` という `ThreadLocal<LocalCallingIdentity>` も使われており、
`clearCallingIdentity()` / `clearLocalCallingIdentity()` により、そのスレッドの
`mCallingIdentity` は MediaProvider 自身の identity に置き換わる。MediaProvider 自身の
identity は `PERMISSION_IS_SELF` を持つため、`isCallingPackageSelf()` が true になる。
その状態が復元されずに残ると、同じ Binder スレッドで後続の MediaProvider 処理が実行された際に、
通常アプリの呼び出しが MediaProvider 自身の呼び出しとして扱われ得る。MediaProvider では
`isCallingPackageSelf()` や `mCallingIdentity.get()` を使って、隠し行、所有者、配置変更、
内部用更新、メタデータ列などの扱いを分岐しているため、これは権限昇格になる。
## 発火条件
ソース上の発火条件は次の通り。
1. パッチ前の MediaProvider である。
2. 攻撃者が `MediaStore.getMediaUri(context, documentUri)` を呼べる。
3. `documentUri` について `Intent.FLAG_GRANT_READ_URI_PERMISSION` の確認を通過する。
攻撃者自身の provider 由来 URI、または攻撃者に read grant がある URI で満たせる。
4. `documentUri.getAuthority()` が MediaProvider の DocumentsProvider authority でも
ExternalStorageProvider authority でもない。
5. `getResultForGetMediaUri()` が `clearCallingIdentity()` 後、`try/finally` に入る前に
`IllegalArgumentException` を投げる。
6. `restoreCallingIdentity(token)` が呼ばれず、その Binder スレッドの identity が
MediaProvider 自身のまま残る。
パッチ後は 5 の例外を投げる直前に復元するため、この poison 状態が残らない。
## 根本原因
根本原因は、特権 identity に切り替える処理を、例外を投げ得る外部入力検証より前に実行し、
その直後から `try/finally` で保護していなかったこと。
具体的には、`clearCallingIdentity()` 後の最初の外部入力依存処理である
`documentUri.getAuthority()` / authority allowlist 検証が `try` ブロック外にあり、
unsupported authority という攻撃者が制御できるエラー条件で復元処理をバイパスできた。
## 面白い点・調査メモ
- このコミットは 2 つの CVE を同時に直している。どちらも「`clearCallingIdentity()` 後、`finally` に入る前に例外を投げる」同型のバグだが、CVE-2025-48578 は `getResultForGetMediaUri()` の unsupported authority、CVE-2025-48579 は `updateInternal()` の `ContentUris.parseId(uri)` 失敗である。
- 修正は非常に小さいが影響は広い。MediaProvider 内では `isCallingPackageSelf()` が多数のアクセス制御分岐に使われ、self identity は通常アプリより強い内部権限を持つ。
- パッチは構造的には `try/finally` の範囲を広げるほうが自然にも見えるが、実際の修正は該当 throw の直前で復元する最小変更になっている。
- `MediaStore.getMediaUri()` 自体は正規には MediaDocumentsProvider / ExternalStorageProvider の document URI を MediaStore URI に変換する API であり、脆弱性の本質は変換ロジックではなく、エラー処理時の identity 管理にある。
## 結論
CVE-2025-48578 は、MediaProvider の `getResultForGetMediaUri()` が unsupported authority の
`documentUri` を処理したとき、`clearCallingIdentity()` 後に `restoreCallingIdentity()` なしで
例外終了する calling identity 復元漏れだった。攻撃者は read URI permission を満たすサポート外
authority の URI を `MediaStore.getMediaUri()` に渡すことで MediaProvider の Binder スレッドを
MediaProvider 自身の identity に汚染でき、その後の MediaProvider 操作が self 権限として評価され得る。
cve.md を表示# CVE-2025-48578 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48578 - Component: Framework - Subcomponent: MediaProvider - Reference: A-418225717 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 8 | OK | CVE-2025-48579 - Framework EoP High |
008
ok
CVE-2025-48579 - Framework EoP High008-ok-MediaProvider-updateInternal-parseId-identity-restore-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) MediaProvider は Binder の calling identity とは別に、`ThreadLocal<LocalCallingIdentity>` の `mCallingIdentity` を使って呼び出し元を判断している。`clearLocalCallingIdentity()` は現在の identity を token として保存し、そのスレッドの `mCallingIdentity` を `LocalCallingIdentity.fromSelfAsUser(...)`、つまり MediaProvider 自身の identity に置き換える。 この self identity は `PERMISSION_IS_SELF` を持つため、`isCallingPackageSelf()` が true になる。 MediaProvider 内ではこの値により、内部呼び出し、MediaScanner 相当、隠し行、配置変更、所有者列、 生成番号、位置情報、raw filesystem path などの扱いを分岐している。 問題の箇所は `updateInternal()` の「配置変更列を更新する場合、既存値を読み込んでパスを再計算する」 `MP.movement` ブロックである。`DISPLAY_NAME`, `RELATIVE_PATH`, `MIME_TYPE`, `IS_PENDING`, `IS_TRASHED`, `DATE_EXPIRES` など `sPlacementColumns` に含まれる列を更新し、かつ `DATA` を直接指定していない場合、このブロックに入る。 修正前はこのブロックで `clearLocalCallingIdentity()` した直後に、 対象 URI の ID を `ContentUris.parseId(uri)` で取り出して `Files` の generic URI を作っていた。 しかし、... 原因(根本原因) 根本原因は、MediaProvider の local calling identity を self に切り替えた後、 攻撃者制御の URI ID をパースする処理を `try/finally` の外に置いたこと。 `clearLocalCallingIdentity()` は強い identity への切り替えであり、直後の処理は例外を含めて必ず 復元されなければならない。しかし修正前は、`ContentUris.parseId(uri)` という外部入力依存で 例外を投げ得る処理が、復元を保証する `finally` より前にあった。これにより例外パスだけが identity 復元をバイパスできた。 どこから特定したか validated.md の「参照情報」 / Android bug参照 A-417195606 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://osv.dev/vulnerability/ASB-A-417195606, https://android.googlesource.com/platform/packages/providers/MediaProvider/+/7ea0a039ec32fcd6477355431b953f4689a2fa61 validated.md を表示# CVE-2025-48579 検証結果
## 判定
`ok`
ソースコード差分から、CVE-2025-48579 / A-417195606 は MediaProvider の
`updateInternal()` で `clearLocalCallingIdentity()` 後に `ContentUris.parseId(uri)` が
`NumberFormatException` を投げると、`restoreLocalCallingIdentity()` が実行されず、
同じ Binder スレッドの MediaProvider local calling identity が self のまま残る EoP だと特定できた。
## 参照情報
- Android Security Bulletin 2026-03-01
- `https://source.android.com/docs/security/bulletin/2026/2026-03-01`
- Framework / MediaProvider に `CVE-2025-48579`, `A-417195606`, EoP High, Android 14/15/16 として掲載。
- OSV / Android Security Bulletin record
- `https://osv.dev/vulnerability/ASB-A-417195606`
- 説明: MediaProvider.java の複数関数で confused deputy により external storage write permission bypass が起き得る。
- AOSP / Gitiles
- `https://android.googlesource.com/platform/packages/providers/MediaProvider/+/7ea0a039ec32fcd6477355431b953f4689a2fa61`
- コミット: `7ea0a039ec32fcd6477355431b953f4689a2fa61`
- 件名: `Restore calling identity when exception is thrown`
- Bug: `417195606`, `418225717`
## 付帯ファイル
- `artifacts/7ea0a039ec32fcd6477355431b953f4689a2fa61.patch`: 修正コミット差分。
- `artifacts/prepatch-updateInternal.txt`: 修正前 `updateInternal()` 抜粋。
- `artifacts/postpatch-updateInternal.txt`: 修正後 `updateInternal()` 抜粋。
- `artifacts/identity-permission-uri-snippets.txt`: identity 復元、権限確認、配置列などの関連抜粋。
- `artifacts/local-uri-matcher-snippets.txt`: ID URI matcher の関連抜粋。
- `artifacts/ASB-A-417195606.json`: OSV record。
- `artifacts/analysis-notes.md`: 調査メモ。
- `artifacts/identity_poison_model.py`: identity 汚染の最小モデル。
- `artifacts/identity_poison_model_output.txt`: モデル実行結果。
## パッチで変わったこと
該当コミットは `MediaProvider.java` だけを変更している。`A-417195606` に対応する変更は、
`updateInternal()` の配置変更処理で `ContentUris.parseId(uri)` を `try/catch` に入れ、
`NumberFormatException` を再 throw する前に `restoreLocalCallingIdentity(token)` を呼ぶもの。
修正前:
```java
final LocalCallingIdentity token = clearLocalCallingIdentity();
final Uri genericUri = MediaStore.Files.getContentUri(volumeName,
ContentUris.parseId(uri));
try (Cursor c = queryForSingleItem(genericUri,
sPlacementColumns.toArray(new String[0]), userWhere, userWhereArgs, null)) {
...
} finally {
restoreLocalCallingIdentity(token);
}
```
修正後:
```java
final LocalCallingIdentity token = clearLocalCallingIdentity();
final Uri genericUri;
try {
genericUri = MediaStore.Files.getContentUri(volumeName, ContentUris.parseId(uri));
} catch (NumberFormatException e) {
restoreLocalCallingIdentity(token);
throw e;
}
```
同じコミットには `getResultForGetMediaUri()` の unsupported authority 例外経路修正も含まれる。
Android bulletin / OSV の対応関係では `A-417195606` が CVE-2025-48579、
`A-418225717` が CVE-2025-48578 なので、このフォルダでは `updateInternal()` 側を対象にした。
## 脆弱性の内容
MediaProvider は Binder の calling identity とは別に、`ThreadLocal<LocalCallingIdentity>` の
`mCallingIdentity` を使って呼び出し元を判断している。`clearLocalCallingIdentity()` は現在の
identity を token として保存し、そのスレッドの `mCallingIdentity` を
`LocalCallingIdentity.fromSelfAsUser(...)`、つまり MediaProvider 自身の identity に置き換える。
この self identity は `PERMISSION_IS_SELF` を持つため、`isCallingPackageSelf()` が true になる。
MediaProvider 内ではこの値により、内部呼び出し、MediaScanner 相当、隠し行、配置変更、所有者列、
生成番号、位置情報、raw filesystem path などの扱いを分岐している。
問題の箇所は `updateInternal()` の「配置変更列を更新する場合、既存値を読み込んでパスを再計算する」
`MP.movement` ブロックである。`DISPLAY_NAME`, `RELATIVE_PATH`, `MIME_TYPE`, `IS_PENDING`,
`IS_TRASHED`, `DATE_EXPIRES` など `sPlacementColumns` に含まれる列を更新し、かつ
`DATA` を直接指定していない場合、このブロックに入る。
修正前はこのブロックで `clearLocalCallingIdentity()` した直後に、
対象 URI の ID を `ContentUris.parseId(uri)` で取り出して `Files` の generic URI を作っていた。
しかし、この `parseId()` は `try/finally` の前にあったため、`NumberFormatException` が起きると
`finally { restoreLocalCallingIdentity(token); }` に到達しない。
その結果、例外を返した後も同じ Binder スレッドの `mCallingIdentity` が MediaProvider 自身のまま残る。
後続の別リクエストが同じスレッドで処理されると、通常アプリ由来の処理でも
`isCallingPackageSelf()` が true と評価され、外部ストレージ書き込み制御を含む
MediaProvider 内部権限チェックをバイパスし得る。
## 発火条件
ソース上、発火条件は次のように整理できる。
1. 修正前の MediaProvider である。
2. 呼び出し元が `ContentResolver.update()` 経由で `updateInternal()` に到達する。
3. URI が `AUDIO_MEDIA_ID`, `AUDIO_PLAYLISTS_ID`, `VIDEO_MEDIA_ID`, `IMAGES_MEDIA_ID`,
`DOWNLOADS_ID`, `FILES_ID` のいずれかとして `matchUri()` される。
4. `initialValues` に `sPlacementColumns` のいずれかが含まれ、`DATA` は含まれず、thumbnail ではなく、
`allowMovement` が true である。
5. `enforceCallingPermission(uri, extras, true)` を通過する。
6. URI の最後のセグメントが `UriMatcher` の `#` にマッチする数字文字列だが、`Long` に収まらない。
例: `content://media/external/images/media/999999999999999999999999999999999999`
7. `clearLocalCallingIdentity()` 後、`ContentUris.parseId(uri)` が `NumberFormatException` を投げる。
8. 修正前は `restoreLocalCallingIdentity(token)` が呼ばれず、スレッドの local identity が self のまま残る。
重要な制約として、通常の `images/video/files/downloads` の ID URI では、先行する
`enforceCallingPermission()` 内の `checkCallingPermissionGlobal()` でも `ContentUris.parseId(uri)` が
呼ばれる。したがって、完全に無権限の通常アプリが常に上記 7 まで到達できる、とは断定しない。
確実な説明としては、`MANAGE_EXTERNAL_STORAGE` 相当で `isCallingPackageManager()` が true になるなど、
グローバル権限チェックを先に通過できる呼び出し元、または同等に `enforceCallingPermission()` を通過する
権限状態が必要である。
## 根本原因
根本原因は、MediaProvider の local calling identity を self に切り替えた後、
攻撃者制御の URI ID をパースする処理を `try/finally` の外に置いたこと。
`clearLocalCallingIdentity()` は強い identity への切り替えであり、直後の処理は例外を含めて必ず
復元されなければならない。しかし修正前は、`ContentUris.parseId(uri)` という外部入力依存で
例外を投げ得る処理が、復元を保証する `finally` より前にあった。これにより例外パスだけが
identity 復元をバイパスできた。
## 簡易モデルによる確認
`identity_poison_model.py` は、`clearLocalCallingIdentity()` 後に例外が起きた場合の状態だけを
モデル化している。
```text
vulnerable: exception=NumberFormatException before restoreLocalCallingIdentity(token); identity_after_exception=media_provider_self; scanner_only_write=True
fixed: exception=NumberFormatException; identity_after_exception=attacker; scanner_only_write=False
```
このモデルは Android 実装そのものではないが、パッチの意味を最小化して示している。
修正前は例外後のスレッド identity が self のまま残り、修正後は例外再 throw 前に元の identity に戻る。
## 面白い点・調査メモ
- 修正は `try/finally` の範囲を広げるのではなく、`parseId()` だけを `try/catch` で包んで
catch 側で復元する最小変更になっている。
- `UriMatcher` の `#` にマッチさせるため、ID セグメントは非数字ではなく「巨大な数字」にする必要がある。
非数字だと ID URI として match せず、対象ブロックに到達しない。
- OSV の Vanir 署名は `updateInternal` と `getResultForGetMediaUri` の両方を含む。同じコミットが
2つの復元漏れを同時に直しているため、CVE と Bug ID の対応を取り違えやすい。
- `checkCallingPermissionGlobal()` にも `ContentUris.parseId(uri)` があり、発火入力の説明には
「先行チェックをどう通るか」の制約が必要だった。
- Pixel 固有のバイナリ解析は不要だった。AOSP の MediaProvider 差分から脆弱性、根本原因、修正内容を説明できる。
## 結論
CVE-2025-48579 は、MediaProvider の `updateInternal()` における local calling identity 復元漏れだった。
配置変更列を含む update 処理で MediaProvider self identity に切り替えた直後、
`ContentUris.parseId(uri)` が `NumberFormatException` を投げると、修正前は
`restoreLocalCallingIdentity()` が実行されなかった。
このため、同じ Binder スレッド上の後続 MediaProvider 処理が self identity として評価され、
外部ストレージ書き込み許可や内部専用列の制御をバイパスし得る。修正は例外再 throw 前に必ず
local identity を復元することで、この confused deputy 状態を塞いでいる。
cve.md を表示# CVE-2025-48579 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48579 - Component: Framework - Subcomponent: MediaProvider - Reference: A-417195606 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 9 | OK | CVE-2025-48582 - Framework EoP High |
009
ok
CVE-2025-48582 - Framework EoP High009-ok-MediaProvider-bulk-request-intent-redirect-delete-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱だった処理) 公開 API の `MediaStore#createDeleteRequest()` は、対象 URI 群を `Bundle` に詰めて `ContentResolver.call(MediaStore.AUTHORITY, "create_delete_request", ...)` を呼ぶ。 MediaProvider 側では URI が具体的な media item ID を指すことを検証し、 `PermissionActivity` を起動する `PendingIntent` を返す。 設計上、この API は本来「ユーザーに削除確認を出し、承認後に削除する」ためのものだが、 `PermissionActivity#shouldShowActionDialog()` には、呼び出し元がすでに `MANAGE_EXTERNAL_STORAGE` などの十分な権限を持つ場合にダイアログを出さない fast path がある。 修正前の問題は、`PermissionActivity` がこの判定の対象 package を `Activity#getCallingPackage()` から取得していたこと。`PendingIntent` が intent redirect 経路で 別アプリから送信されると、ここで見える package は bulk request を作った攻撃アプリではなく、 `PendingIntent` を送信して Activity を起動したアプリになり得る。 その結果、次の流れが成立する。 1. 攻撃アプリ A は `MANAGE_EXTERNAL_STORAGE` を持たない。 2. A が削除したい media URI に対して `MediaStore.createDeleteRequest()` を呼び、 `PermissionActivity` 宛ての `PendingIntent` を得る。 3. A が intent redirec... 原因(根本原因) 根本原因は、権限付き `PendingIntent` の作成時点で request creator identity を束縛せず、 実行時に Activity 起動者 identity を使って権限判定していたこと。 `FLAG_IMMUTABLE` により `PendingIntent` の内容改変は防げていたが、このバグの本質は extras の改変ではない。 「どのアプリの権限でダイアログ省略や grant 先を決めるか」を実行時の `getCallingPackage()` に依存したことで、リダイレクト送信者が confused deputy になった。 修正は、`MediaProvider#createRequest()` 時点の Binder caller UID を `EXTRA_CALLING_PACKAGE_UID` として保存し、後段の `PermissionActivity` が常にその UID 由来の package / user を使うようにするもの。これにより、`PendingIntent` を誰が送信しても、 権限判定対象はリクエスト作成者 A のままになる。 どこから特定したか validated.md の「参照情報」 / Android bug参照 A-369105011 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://osv.dev/vulnerability/ASB-A-369105011, https://android.googlesource.com/platform/packages/providers/MediaProvider/+/1b7d4ce446d149a34d8b317d41127379f017165d validated.md を表示# CVE-2025-48582 検証結果
## 判定
`ok`
ソースコード差分から、CVE-2025-48582 / A-369105011 は MediaProvider の
`MediaStore.createDeleteRequest()` などの bulk request 用 `PendingIntent` で、
リクエスト作成者ではなく `PermissionActivity` を起動した相手の package / uid を
権限判定に使っていた intent redirect 型の EoP だと特定できた。
攻撃者は `MANAGE_EXTERNAL_STORAGE` を持たなくても、攻撃者が作成した削除リクエストの
`PendingIntent` を、同権限を持つアプリ・コンポーネントに送信させるリダイレクト経路へ渡せると、
ユーザー確認なしで対象メディア削除に到達し得る。
## 参照情報
- Android Security Bulletin 2026-03-01
- `https://source.android.com/docs/security/bulletin/2026/2026-03-01`
- Framework / MediaProvider に `CVE-2025-48582`, `A-369105011`, EoP, High, Android 14/15/16 が掲載。
- OSV / Android Security Bulletin record
- `https://osv.dev/vulnerability/ASB-A-369105011`
- 説明: intent redirect により `MANAGE_EXTERNAL_STORAGE` なしでメディア削除できる可能性。
- AOSP / Gitiles
- `https://android.googlesource.com/platform/packages/providers/MediaProvider/+/1b7d4ce446d149a34d8b317d41127379f017165d`
- コミット: `1b7d4ce446d149a34d8b317d41127379f017165d`
- 件名: `Store calling package uid of create bulk requests for permission checks`
- Bug: `369105011`
- mainline 側コミット
- `96bb34d4348019b7521530b81a5c565a3aacc884`
## 付帯ファイル
- `ASB-A-369105011.json`: OSV Android record の保存。
- `android-security-bulletin-2026-03-01.html`: Android Security Bulletin の保存。
- `patch_1b7d4ce44.diff`: Android 16 security release 側の修正差分。
- `patch_96bb34d43_main.diff`: mainline 側の修正差分。
- `vulnerable_snippets.txt`: 修正前の重要箇所抜粋。
- `patched_snippets.txt`: 修正後の重要箇所抜粋。
- `analysis-notes.md`: 調査メモ。
- `intent_redirect_model.py`: identity 混同を表す最小モデル。
- `intent_redirect_model_output.txt`: モデル実行結果。
- `related_f18d63605_skip_dialog_if_relevant_permissions.diff`: 関連するダイアログ省略ロジックの参考差分。
## パッチで変わったこと
修正前の `MediaProvider#createRequest()` は、`MediaStore.createWriteRequest()`、
`createTrashRequest()`、`createFavoriteRequest()`、`createDeleteRequest()` のために
`PermissionActivity` 宛ての one-shot / immutable `PendingIntent` を作るが、
その `PendingIntent` に「この bulk request を作った呼び出し元 UID」を保存していなかった。
修正後は `MediaProvider#createRequest()` で次の値を extras に入れる。
```java
extras.putInt(EXTRA_CALLING_PACKAGE_UID, getCallingUidOrSelf());
```
そして `PermissionActivity#resolveCallingAppInfo()` は、extras に
`MediaStore.EXTRA_CALLING_PACKAGE_UID` がある場合、その UID から package と user を解決する。
```java
int callingUid = extras.getInt(EXTRA_CALLING_PACKAGE_UID);
callingPackage = Objects.requireNonNull(
getPackageManager().getPackagesForUid(callingUid))[0];
userHandle = getUserHandleForUid(callingUid);
return getPackageManager().getApplicationInfoAsUser(callingPackage, 0, userHandle);
```
さらに `PermissionActivity` 内の複数箇所で `getCallingPackage()` を使うのをやめ、
解決済みの `appInfo.packageName` を使うようになった。
- `shouldShowActionDialog(...)` に渡す package。
- write request 許可時の `grantUriPermission(...)` 先 package。
- allow / deny の metrics に記録する package。
## 脆弱だった処理
公開 API の `MediaStore#createDeleteRequest()` は、対象 URI 群を `Bundle` に詰めて
`ContentResolver.call(MediaStore.AUTHORITY, "create_delete_request", ...)` を呼ぶ。
MediaProvider 側では URI が具体的な media item ID を指すことを検証し、
`PermissionActivity` を起動する `PendingIntent` を返す。
設計上、この API は本来「ユーザーに削除確認を出し、承認後に削除する」ためのものだが、
`PermissionActivity#shouldShowActionDialog()` には、呼び出し元がすでに
`MANAGE_EXTERNAL_STORAGE` などの十分な権限を持つ場合にダイアログを出さない fast path がある。
修正前の問題は、`PermissionActivity` がこの判定の対象 package を
`Activity#getCallingPackage()` から取得していたこと。`PendingIntent` が intent redirect 経路で
別アプリから送信されると、ここで見える package は bulk request を作った攻撃アプリではなく、
`PendingIntent` を送信して Activity を起動したアプリになり得る。
その結果、次の流れが成立する。
1. 攻撃アプリ A は `MANAGE_EXTERNAL_STORAGE` を持たない。
2. A が削除したい media URI に対して `MediaStore.createDeleteRequest()` を呼び、
`PermissionActivity` 宛ての `PendingIntent` を得る。
3. A が intent redirect 可能な経路を使い、`MANAGE_EXTERNAL_STORAGE` を持つアプリ B に
その `PendingIntent` を送信させる。
4. 修正前の `PermissionActivity` は `getCallingPackage()` により B を呼び出し元として扱う。
5. B の権限で `shouldShowActionDialog()` が評価され、ダイアログ不要と判断される。
6. `PermissionActivity#onPositiveAction()` が即時に `ContentProviderOperation.newDelete(uri)` を
`applyBatch(MediaStore.AUTHORITY, ops)` で実行する。
このとき削除処理は MediaProvider / PermissionActivity 側で実行されるため、A 自身が
対象 URI の write/delete 権限や `MANAGE_EXTERNAL_STORAGE` を持つ必要がない。
## 根本原因
根本原因は、権限付き `PendingIntent` の作成時点で request creator identity を束縛せず、
実行時に Activity 起動者 identity を使って権限判定していたこと。
`FLAG_IMMUTABLE` により `PendingIntent` の内容改変は防げていたが、このバグの本質は extras の改変ではない。
「どのアプリの権限でダイアログ省略や grant 先を決めるか」を実行時の
`getCallingPackage()` に依存したことで、リダイレクト送信者が confused deputy になった。
修正は、`MediaProvider#createRequest()` 時点の Binder caller UID を
`EXTRA_CALLING_PACKAGE_UID` として保存し、後段の `PermissionActivity` が常にその UID 由来の
package / user を使うようにするもの。これにより、`PendingIntent` を誰が送信しても、
権限判定対象はリクエスト作成者 A のままになる。
## 簡易モデルによる確認
`intent_redirect_model.py` で identity 選択だけをモデル化した。
```text
vulnerable: checked=com.privileged.redirector, show_dialog=False
fixed: checked=com.attacker, show_dialog=True
```
これは、修正前はリダイレクト送信者 B の `MANAGE_EXTERNAL_STORAGE` により確認ダイアログが省略され、
修正後は request creator A の権限で評価されるため確認が必要になることを示している。
## 面白い点・調査メモ
- CVE 説明の "multiple locations" は、`PermissionActivity` 内の複数の `getCallingPackage()` 使用箇所を指すと見られる。最も危険なのは削除時のダイアログ省略だが、write request の URI permission grant 先も同じ混同の影響を受けていた。
- `createDeleteRequest()` は公開 API として「prompt を作るだけ」と説明されているが、実際には `PermissionActivity` が承認後に `ContentResolver#delete` 相当の処理を最後まで実行する。したがってダイアログ要否判定を誤ると、ユーザー操作なしの削除プリミティブになる。
- `PendingIntent` は `FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE` で作られていた。immutable でも、実行時 identity の取り方を間違えると防げない好例。
- 修正では UID から `getPackagesForUid(callingUid)[0]` を使って package を選んでいる。同一 UID の sharedUserId 的なケースでは代表 package になるが、少なくともリダイレクト送信者 B ではなく request creator UID に固定される点がセキュリティ上の本質。
- Pixel 固有のバイナリ解析は不要だった。CVE は AOSP の `platform/packages/providers/MediaProvider` 差分だけで、脆弱条件と修正意図を説明できる。
## 再現条件の要約
完全な実機 PoC はこの環境では実行していないが、ソースコード上の脆弱性条件は次のように説明できる。
1. 対象端末の MediaProvider が `1b7d4ce44` 相当の修正前である。
2. 攻撃アプリは対象 media item ID を含む URI を用意し、`MediaStore.createDeleteRequest()` で `PendingIntent` を作成する。
3. 攻撃アプリは、その `PendingIntent` を権限の強いアプリに送信させる intent redirect 経路を持つ。
4. その送信者アプリが `MANAGE_EXTERNAL_STORAGE` を持つ、または当該ブランチの fast path 条件を満たす。
5. 修正前の `PermissionActivity` は送信者アプリを呼び出し元として扱い、確認ダイアログを省略する。
6. delete request の場合、`PermissionActivity` が `applyBatch()` で対象 URI を削除する。
修正後は 5 の権限判定対象が request creator UID に固定されるため、攻撃アプリ自身が権限を持たない限り同じリダイレクトではダイアログ省略に到達しない。
## 結論
CVE-2025-48582 は MediaProvider の bulk media operation request における request creator と
PendingIntent sender の identity 混同だった。根本原因は、権限判定に必要な元の呼び出し元 UID を
PendingIntent 作成時に保存しておらず、`PermissionActivity` 実行時の `getCallingPackage()` に依存したこと。
パッチは元の呼び出し元 UID を `EXTRA_CALLING_PACKAGE_UID` として保存し、`PermissionActivity` の
ダイアログ要否判定、URI permission grant、metrics の package をその UID から解決した
`appInfo.packageName` に統一している。このため、intent redirect によって権限の強い送信者を挟んでも、
攻撃アプリが `MANAGE_EXTERNAL_STORAGE` なしにメディア削除を実行する経路は塞がれる。
cve.md を表示# CVE-2025-48582 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48582 - Component: Framework - Subcomponent: MediaProvider - Reference: A-369105011 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 10 | OK | CVE-2025-48619 - Framework EoP High |
010
ok
CVE-2025-48619 - Framework EoP High010-ok-ContentProvider-read-only-truncate-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱な到達経路) 攻撃者が read-only の `content://` URI を持っている状態で、次のように呼ぶ。 [コードブロック省略] 修正前の Framework 側では、`enforceFilePermission()` が `mode.indexOf('w') != -1` だけを見て write 権限チェックに進むかを決める。`"rt"` には `w` がないため read 権限チェックだけになる。 しかし、その後 provider 側へ渡される `mode` は `"rt"` のままだった。provider が標準的な `ContentProvider.openFileHelper()` を使う場合、内部で `_data` カラムから実パスを取り出し、`ParcelFileDescriptor.parseMode(mode)` と `ParcelFileDescriptor.open(new File(path), modeBits)` を呼ぶ。 `ParcelFileDescriptor.parseMode()` は `FileUtils.translateModeStringToPosix()` を経由する。この変換では、`mode` に `t` が含まれていれば `O_TRUNC` を立て、`a` が含まれていれば `O_APPEND` を立てる。つまり `"rt"` は read-only の権限判定を通った後、実ファイルを truncate する open flag を provider 側へ到達させられる。 原因(根本原因) - `mode` 文字列の意味を `w` の有無だけで単純化して権限判定していた。 - `t` / `a` は `w` がなくても destructive / modifying な意味を持つのに、Framework の境界で正規化されていなかった。 - 権限チェックに使った mode と provider へ渡す mode が同じ未検証文字列であり、provider 側の `ParcelFileDescriptor.parseMode()` が `t` / `a` を有効なファイルフラグとして解釈できた。 どこから特定したか validated.md の「対象」「参照した公開情報」「パッチ解析」 / Android bug参照 A-414387646 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://android.googlesource.com/platform/frameworks/base/+/31e77d73c5e6439bc942a92676c4076ebd8295ff, https://android.googlesource.com/platform/frameworks/base/+/31e77d73c5e6439bc942a92676c4076ebd8295ff%5E%21/, https://www.cve.org/CVERecord?id=CVE-2025-48619 validated.md を表示# CVE-2025-48619 検証結果
## 結論
このCVEは特定できた。Android Framework の `ContentProvider.Transport` におけるファイルオープンモード検証の不備により、読み取り権限しか持たないアプリが `ContentResolver.openFileDescriptor(uri, "rt")` などを使って、対象 `ContentProvider` の実ファイルを truncate できる可能性があった。
根本原因は、Framework の権限判定が `mode` 文字列に `w` が含まれるかだけで read/write を切り替えていた一方で、`w` を含まないが破壊的な `t` / `a` ビットを持つ mode を provider 実装へそのまま渡していたこと。`rt` は `w` を含まないため読み取り権限チェックだけを通過するが、provider 側で `ParcelFileDescriptor.parseMode("rt")` が呼ばれると `O_TRUNC` / `MODE_TRUNCATE` へ変換され得る。
## 対象
- CVE: CVE-2025-48619
- Android bug: A-414387646
- Component: Framework
- Severity: High
- Type: EoP
- Bulletin: Android Security Bulletin - March 2026
- Affected AOSP versions: 14, 15, 16
- 修正コミット: `31e77d73c5e6439bc942a92676c4076ebd8295ff`
- 修正対象: `platform/frameworks/base/core/java/android/content/ContentProvider.java`
## 参照した公開情報
- Android Security Bulletin 2026-03-01: https://source.android.com/docs/security/bulletin/2026/2026-03-01
- AOSP commit: https://android.googlesource.com/platform/frameworks/base/+/31e77d73c5e6439bc942a92676c4076ebd8295ff
- AOSP diff: https://android.googlesource.com/platform/frameworks/base/+/31e77d73c5e6439bc942a92676c4076ebd8295ff%5E%21/
- CVE Record / public description: https://www.cve.org/CVERecord?id=CVE-2025-48619
## パッチ解析
修正前の `ContentProvider.Transport.openFile()` / `openAssetFile()` は、受け取った `mode` をそのまま `enforceFilePermission()` に渡し、その後も同じ `mode` を `mInterface.openFile()` / `mInterface.openAssetFile()` へ渡していた。
修正後は次の流れに変わった。
1. `validateFileMode(mode)` を呼ぶ。
2. `mode` に `w` が含まれない場合、`t` と `a` を削除する。
3. 書き換え後の `updatedMode` を権限チェックと provider 呼び出しの両方に使う。
追加された `validateFileMode()` は、互換性のため例外を投げず、無効な破壊的ビットだけを黙って落とす設計になっている。コメント上も、現在サポートされる mode は `r`, `w`, `wt`, `wa`, `rw`, `rwt` であり、理想的には不正 mode を `SecurityException` にするがアプリ互換性のためビット削除にしている、と説明されている。
## 脆弱な到達経路
攻撃者が read-only の `content://` URI を持っている状態で、次のように呼ぶ。
```java
context.getContentResolver().openFileDescriptor(uri, "rt");
```
修正前の Framework 側では、`enforceFilePermission()` が `mode.indexOf('w') != -1` だけを見て write 権限チェックに進むかを決める。`"rt"` には `w` がないため read 権限チェックだけになる。
しかし、その後 provider 側へ渡される `mode` は `"rt"` のままだった。provider が標準的な `ContentProvider.openFileHelper()` を使う場合、内部で `_data` カラムから実パスを取り出し、`ParcelFileDescriptor.parseMode(mode)` と `ParcelFileDescriptor.open(new File(path), modeBits)` を呼ぶ。
`ParcelFileDescriptor.parseMode()` は `FileUtils.translateModeStringToPosix()` を経由する。この変換では、`mode` に `t` が含まれていれば `O_TRUNC` を立て、`a` が含まれていれば `O_APPEND` を立てる。つまり `"rt"` は read-only の権限判定を通った後、実ファイルを truncate する open flag を provider 側へ到達させられる。
## 影響
直接的な影響は「read-only として共有・許可された URI に対して、書き込み権限なしでファイル内容を0バイトへ破壊できる」こと。公開CVE説明も「read-only access を持つアプリが truncate できる可能性」としている。
EoP と評価される理由は、ContentProvider の権限モデルでは read grant と write grant が分離されているため、read-only grant のはずの呼び出しが provider 所有ファイルの状態変更に変わるから。対象が上位権限アプリやシステムアプリの provider で、provider 実装が標準的な mode 変換に依存している場合、攻撃アプリは自分の権限を超えて他プロセス所有データを破壊できる。
## 根本原因
- `mode` 文字列の意味を `w` の有無だけで単純化して権限判定していた。
- `t` / `a` は `w` がなくても destructive / modifying な意味を持つのに、Framework の境界で正規化されていなかった。
- 権限チェックに使った mode と provider へ渡す mode が同じ未検証文字列であり、provider 側の `ParcelFileDescriptor.parseMode()` が `t` / `a` を有効なファイルフラグとして解釈できた。
## 修正の妥当性
修正は Framework の binder 境界に近い `ContentProvider.Transport` で行われているため、個別 provider が `openFile()` / `openAssetFile()` をどう実装していても、`w` なしの `t` / `a` は provider へ届かなくなる。
`wt`, `wa`, `rwt` のように `w` を含む mode は従来通り write 権限チェックへ進み、破壊的ビットも維持される。したがって、正当な書き込み操作は壊さず、read-only 経路からの truncate / append だけを潰している。
## 付帯ファイル
- `artifacts/commit.json`: 公開AOSP修正コミットのGitiles JSON
- `artifacts/original-commit-f8099b069.json`: cherry-pick 元コミットのGitiles JSON
- `artifacts/31e77d73.diff`: 修正コミットの生diff
- `artifacts/ContentProvider-db86972777c84a386d8a6d2d34879923bdbccdf6.java`: 修正前 `ContentProvider.java`
- `artifacts/ContentProvider-31e77d73c5e6439bc942a92676c4076ebd8295ff.java`: 修正後 `ContentProvider.java`
- `artifacts/ContentProvider-vulnerable-transport-snippet.java`: 修正前の重要箇所
- `artifacts/ContentProvider-fixed-transport-snippet.java`: 修正後の重要箇所
- `artifacts/ContentProvider-enforceFilePermission-snippet.java`: 権限チェックロジック
- `artifacts/ParcelFileDescriptor.java`: mode parse の呼び出し元
- `artifacts/FileUtils.java`: mode 文字列からPOSIX/PFDフラグへの変換
- `artifacts/FileUtils-mode-translation-snippet.java`: mode 変換の重要箇所
- `artifacts/mode-behavior-table.md`: 修正前後の mode 挙動表
- `artifacts/poc-sketch.md`: read-only URI に `"rt"` を指定するPoCスケッチ
## 調査メモ
- `.patch` エンドポイントは認証/NOT_FOUND HTMLを返したため、Gitiles の `^!/?format=TEXT` を base64 decode して `31e77d73.diff` として保存した。
- Bulletin の表では `CVE-2025-48619` が `A-414387646` として `frameworks/base` の単一コミットにリンクされていた。
- コミットメッセージは「read に truncation / append bits があり write bit がない場合、不意の変更を防ぐため無効ビットを落とす」と説明しており、CVE公開説明と一致する。
- `openAssetFile()` も同様に修正されているため、通常の `openFileDescriptor()` 経路だけでなく asset file descriptor 経路も対象だった。
cve.md を表示# CVE-2025-48619 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48619 - Component: Framework - Reference: A-414387646 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 11 | OK | CVE-2025-48634 - Framework EoP High |
011
ok
CVE-2025-48634 - Framework EoP High011-ok-WindowManager-privateFlags-permission-bypass cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(何が脆弱だったか) `WindowManagerService.relayoutWindow()` の既存ウィンドウ再レイアウト経路で、呼び出し元から渡された `LayoutParams.privateFlags` が権限検査なしに反映され得る問題だった。 修正前の `relayoutWindow()` は `attrs.flags` に対して `sanitizeFlagSlippery()`、`attrs.inputFeatures` に対して `sanitizeInputFeatures()` を呼んでいたが、`attrs.privateFlags` には同等の sanitizer がなかった。 そのため、攻撃者が自分のウィンドウに対して再レイアウトを行い、`LayoutParams.privateFlags` に特権 bit を追加できる場合、以下のような本来システム権限が必要な private flag を WindowManagerService 側で受け入れさせられる。 - `PRIVATE_FLAG_TRUSTED_OVERLAY` - `PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY` - `PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP` 特に `PRIVATE_FLAG_TRUSTED_OVERLAY` は `WindowManager.java` 上で「trusted system overlay」とされ、input dispatch の obscured-window 判定で無視される旨と `INTERNAL_SYSTEM_WINDOW` が必要な旨が明記されている。権限なしアプリがこれを自分のウィンドウへ付与できると、通常の untrusted overlay として扱われるべきウィンドウを trusted overlay として扱わせ、タップジャック防止の前提を崩せる。 原因(根本原因) `LayoutParams.privateFlags` は hidden/internal 用のフィールドだが、`LayoutParams` の parcel 化対象であり、`relayoutWindow()` の Binder 入力としてサーバ側へ届く。WindowManagerService は window type 変更や一部 flags/inputFeatures は検証していた一方、既存ウィンドウの `privateFlags` 差分には権限境界を置いていなかった。 つまり根本原因は、「再レイアウト時にクライアント制御の `privateFlags` を信頼し、特権 private flag の追加を `INTERNAL_SYSTEM_WINDOW` / `MANAGE_ACTIVITY_TASKS` で gate していなかったこと」。 どこから特定したか validated.md の「参照情報」「パッチ解析」 / Android bug参照 A-406243581 validated.md を表示# CVE-2025-48634 検証結果
## 判定
ok: 脆弱性をソースコード差分から特定できた。
タイトル: `WindowManager privateFlags permission bypass`
## 参照情報
- Android Security Bulletin 2026-03-01: `CVE-2025-48634`, `A-406243581`, Framework, EoP, High, affected/updated versions 14/15/16。
- CVE record: `relayoutWindow` の missing permission check により tapjack attack が可能。
- AOSP commit: `d550a457e65ccbbf252ec2e60d93e8bcd111de0e`
- Commit subject: `Sanitize window private flags based on caller permissions.`
- 親 commit: `9489a5dcd3cdd426d5b39d9caf6bb78142af2399`
## 何が脆弱だったか
`WindowManagerService.relayoutWindow()` の既存ウィンドウ再レイアウト経路で、呼び出し元から渡された `LayoutParams.privateFlags` が権限検査なしに反映され得る問題だった。
修正前の `relayoutWindow()` は `attrs.flags` に対して `sanitizeFlagSlippery()`、`attrs.inputFeatures` に対して `sanitizeInputFeatures()` を呼んでいたが、`attrs.privateFlags` には同等の sanitizer がなかった。
そのため、攻撃者が自分のウィンドウに対して再レイアウトを行い、`LayoutParams.privateFlags` に特権 bit を追加できる場合、以下のような本来システム権限が必要な private flag を WindowManagerService 側で受け入れさせられる。
- `PRIVATE_FLAG_TRUSTED_OVERLAY`
- `PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY`
- `PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP`
特に `PRIVATE_FLAG_TRUSTED_OVERLAY` は `WindowManager.java` 上で「trusted system overlay」とされ、input dispatch の obscured-window 判定で無視される旨と `INTERNAL_SYSTEM_WINDOW` が必要な旨が明記されている。権限なしアプリがこれを自分のウィンドウへ付与できると、通常の untrusted overlay として扱われるべきウィンドウを trusted overlay として扱わせ、タップジャック防止の前提を崩せる。
## 根本原因
`LayoutParams.privateFlags` は hidden/internal 用のフィールドだが、`LayoutParams` の parcel 化対象であり、`relayoutWindow()` の Binder 入力としてサーバ側へ届く。WindowManagerService は window type 変更や一部 flags/inputFeatures は検証していた一方、既存ウィンドウの `privateFlags` 差分には権限境界を置いていなかった。
つまり根本原因は、「再レイアウト時にクライアント制御の `privateFlags` を信頼し、特権 private flag の追加を `INTERNAL_SYSTEM_WINDOW` / `MANAGE_ACTIVITY_TASKS` で gate していなかったこと」。
## パッチ解析
修正コミット `d550a457e65c...` は `WindowManagerService.relayoutWindow()` に以下を追加した。
```java
attrs.privateFlags = sanitizePrivateFlags(attrs.privateFlags,
win.mAttrs.privateFlags, win.getName(), uid, pid);
```
追加された `sanitizePrivateFlags()` は、`addedPrivateFlags = ~oldPrivateFlags & newPrivateFlags` で新たに追加された bit だけを対象にして、権限がなければ対象 bit を落とす。
- `PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY | PRIVATE_FLAG_TRUSTED_OVERLAY`: `INTERNAL_SYSTEM_WINDOW` が必要。
- `PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP`: `MANAGE_ACTIVITY_TASKS` が必要。
追加テストでは、再レイアウトで各 private flag を追加するケースについて、permission denied では `expectedChangedPrivateFlags = 0`、permission granted では対象 bit が残ることを確認している。これにより「初期値ではなく、再レイアウトで新規追加された private flag が問題だった」ことが分かる。
## 攻撃シナリオ
1. 攻撃アプリが自分のウィンドウを追加する。
2. そのウィンドウの `LayoutParams.privateFlags` に `PRIVATE_FLAG_TRUSTED_OVERLAY` などの特権 bit を追加した状態で再レイアウトする。
3. 修正前の `WindowManagerService.relayoutWindow()` は `privateFlags` を権限検査せずに受け入れる。
4. 攻撃ウィンドウが trusted overlay として扱われ、入力ディスパッチの obscured 判定を回避し得る。
5. 結果として、ユーザーが見ている UI と実際にタップされる対象をずらす tapjacking による権限昇格が成立する。
## 調査中に分かったこと
- `addWindow()` 側にも `sanitizeFlagSlippery()` と `sanitizeInputFeatures()` はあるが、今回の公開修正が `relayoutWindow()` に入っていること、CVE record が `relayoutWindow` と明記していること、追加テストが `firstRelayout = false` を使っていることから、主な問題経路は既存ウィンドウ更新時の private flag 追加である。
- `WindowManager.LayoutParams.privateFlags` は `writeToParcel()` / `LayoutParams(Parcel in)` で送受信されるため、hidden field であっても WindowManagerService の信頼境界ではクライアント入力として扱う必要がある。
- 修正コミットには気になる点がある。`hasPermission(String permission, int callingPid, int callingUid)` に対して `sanitizePrivateFlags(... int callingUid, int callingPid)` から `hasPermission(..., callingUid, callingPid)` と渡しており、名前上は pid/uid の順序が逆に見える。既存 `sanitizeFlagSlippery()` は `checkPermission(permission, callingPid, callingUid)` としているため、修正コミットの回帰リスクとして注意が必要。追加テストは `anyInt()` で mock しているため、この種の引数順ミスは検出できない。
## 付帯ファイル
- `artifacts/patch_d550a457e65c.diff`
- `artifacts/commit_d550a457e65c.json`
- `artifacts/WindowManagerService_before.java`
- `artifacts/WindowManagerService_after.java`
- `artifacts/WindowManager_before.java`
- `artifacts/WindowManager_after.java`
- `artifacts/key_snippets.txt`
- `artifacts/analysis_notes.md`
- `artifacts/SHA256SUMS`
## 結論
CVE-2025-48634 は、Framework の WindowManagerService における `relayoutWindow()` の権限検査漏れであり、権限なし caller が特権 `LayoutParams.privateFlags`、特に `PRIVATE_FLAG_TRUSTED_OVERLAY` を既存ウィンドウへ追加できることによる tapjacking 型 EoP だった。
cve.md を表示# CVE-2025-48634 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48634 - Component: Framework - Reference: A-406243581 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 12 | OK | CVE-2025-48635 - Framework EoP High |
012
ok
CVE-2025-48635 - Framework EoP High012-ok-TaskFragmentOrganizer-activity-token-leak cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) `TaskFragmentOrganizerController` は、Activity embedding / TaskFragment 関連イベントを organizer アプリへ通知する。`prepareActivityReparentedToTask()` は Activity が Task に reparent されたことを通知する `TaskFragmentTransaction.Change` を作る際、Activity tokenを organizer へ渡す。 Activity token は ActivityRecord を指す強い capability として扱われるため、別プロセス/別UIDの実tokenを未権限アプリへ渡してはいけない。そのため修正前コードにもコメント上の意図はあり、別プロセスの場合は実tokenではなく一時token `TemporaryActivityToken` を渡す設計だった。 しかし修正前の判定は「同一プロセス」を `PID` だけで判定していた。 [コードブロック省略] この `mOrganizerPid` は `registerOrganizerInternal()` で `Binder.getCallingPid()` から保存される。コミットメッセージによると、悪意あるアプリは one-way Binder call 経由で organizer を登録し、呼び出し元PIDを `0` として見せかけることができた。`ITaskFragmentOrganizer` 自体も `oneway interface` であることを `artifacts/ITaskFragmentOrganizer.aidl` で確認した。 結果として、`mOrganizerPid == 0` の organizer 状態が作られる。後続で Activity 側の `getPid()` も `0` になる場面、例えばまだプロセスにattac... 原因(根本原因) 根本原因は、Activity tokenを渡してよい「同一プロセス/同一所有者」の検証に、信頼できない、または不正値になり得る `Binder.getCallingPid()` 由来のPIDだけを使っていたこと。 PID `0` は通常のアプリプロセスPIDではなく、one-way Binder call のような経路で呼び出し元PIDとして観測され得る特殊値である。修正前コードはこの値を organizer 登録時に拒否せず、後段の token disclosure 判定にも使っていた。さらにPID一致だけではUID境界を確認していないため、Activity tokenという権限境界上のcapabilityを渡す条件として不十分だった。 どこから特定したか validated.md の「参照情報」「パッチ差分の要約」 / Android bug参照 A-446678690 validated.md を表示# CVE-2025-48635 検証結果
## 判定
`ok`
脆弱性は `frameworks/base` の `TaskFragmentOrganizerController.java` における Activity token の漏えいで、修正差分と公開OSV情報から根本原因を特定できた。未権限アプリが `TaskFragmentOrganizer` 登録時の呼び出し元PIDを不正な `0` として記録させると、後続の TaskFragment transaction 生成時に「同一プロセスのActivity」と誤判定され、別UID/別プロセスの実Activity tokenが organizer 側へ渡され得る。
## 参照情報
- CVE: `CVE-2025-48635`
- Android bug: `A-446678690`
- Bulletin: Android Security Bulletin 2026-03-01
- Component: Framework
- Severity: High
- Type: EoP
- Affected: Android 14, 15
- OSV: `ASB-A-446678690`
- 修正対象: `platform/frameworks/base/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java`
OSVの説明では、`TaskFragmentOrganizerController.java` の複数関数にロジックエラーがあり、Activity token leak により user interaction なしで local EoP につながるとされている。OSVが示す修正コミットは以下。
- Android 14: `a0d83002325f7d7ab4216d0533884f461a3c900e`
- Android 15: `6ab778a0dd3d09c6e3e2b6176245d3c99b5170ce`
- 16-qpr2-next: `61ab2b65caf855c48fdb4166f94e02bf79c90e7b`
公開Gitiles上では、同じ修正内容を含む公開cherry-pick `9515a9448c528d45c9b673e2e9b61971bc7e58c1` も確認した。このコミットメッセージは攻撃条件を明確に説明している。
> Prevent activity token leaked to another process
>
> Malicious app could register the organizer via one-way binder call
> to disguise as running on pid 0.
## パッチ差分の要約
保存済み差分: `artifacts/TaskFragmentOrganizerController.diff`
修正は主に3点。
1. `prepareActivityReparentedToTask()` で実Activity tokenを organizer に渡す条件が、修正前は `activity.getPid() == mOrganizerPid` のPID一致のみだった。修正後は `activity.getUid() == mOrganizerUid` も要求する。
2. `prepareActivityReparentedToTask()` の PiP restore / overlay 向け `setOtherActivityToken()` でも、修正前は `nextFillTaskActivity.getPid() == mOrganizerPid` のみだった。修正後はUID一致も要求する。
3. `registerOrganizerInternal()` で `Binder.getCallingPid()` の結果が `0` 以下の場合に登録を拒否するチェックが追加された。
該当差分:
```diff
- if (activity.getPid() == mOrganizerPid) {
+ if (activity.getPid() == mOrganizerPid && activity.getUid() == mOrganizerUid) {
...
- && nextFillTaskActivity.getPid() == mOrganizerPid) {
+ && nextFillTaskActivity.getPid() == mOrganizerPid
+ && nextFillTaskActivity.getUid() == mOrganizerUid) {
...
+ if (pid <= 0) {
+ throw new IllegalStateException("Cannot register from invalid pid: " + pid);
+ }
```
## 脆弱性の内容
`TaskFragmentOrganizerController` は、Activity embedding / TaskFragment 関連イベントを organizer アプリへ通知する。`prepareActivityReparentedToTask()` は Activity が Task に reparent されたことを通知する `TaskFragmentTransaction.Change` を作る際、Activity tokenを organizer へ渡す。
Activity token は ActivityRecord を指す強い capability として扱われるため、別プロセス/別UIDの実tokenを未権限アプリへ渡してはいけない。そのため修正前コードにもコメント上の意図はあり、別プロセスの場合は実tokenではなく一時token `TemporaryActivityToken` を渡す設計だった。
しかし修正前の判定は「同一プロセス」を `PID` だけで判定していた。
```java
if (activity.getPid() == mOrganizerPid) {
activityToken = activity.token;
} else {
activityToken = new Binder("TemporaryActivityToken");
}
```
この `mOrganizerPid` は `registerOrganizerInternal()` で `Binder.getCallingPid()` から保存される。コミットメッセージによると、悪意あるアプリは one-way Binder call 経由で organizer を登録し、呼び出し元PIDを `0` として見せかけることができた。`ITaskFragmentOrganizer` 自体も `oneway interface` であることを `artifacts/ITaskFragmentOrganizer.aidl` で確認した。
結果として、`mOrganizerPid == 0` の organizer 状態が作られる。後続で Activity 側の `getPid()` も `0` になる場面、例えばまだプロセスにattachされていない/プロセス情報が有効でないActivityを扱う場面では、修正前ロジックが「同一プロセス」と誤判定し、別UIDの実Activity tokenを organizer に渡し得る。
修正後は二重に防いでいる。
- `pid <= 0` の organizer 登録を拒否するため、`mOrganizerPid == 0` の状態を作れない。
- Activity tokenを渡す条件にUID一致を追加したため、仮にPIDが一致しても別UIDなら実tokenは渡されない。
## 根本原因
根本原因は、Activity tokenを渡してよい「同一プロセス/同一所有者」の検証に、信頼できない、または不正値になり得る `Binder.getCallingPid()` 由来のPIDだけを使っていたこと。
PID `0` は通常のアプリプロセスPIDではなく、one-way Binder call のような経路で呼び出し元PIDとして観測され得る特殊値である。修正前コードはこの値を organizer 登録時に拒否せず、後段の token disclosure 判定にも使っていた。さらにPID一致だけではUID境界を確認していないため、Activity tokenという権限境界上のcapabilityを渡す条件として不十分だった。
## 影響
未権限ローカルアプリが user interaction なしで、TaskFragment organizer 経由のtransactionから本来受け取るべきでないActivity tokenを取得できる。Activity tokenは WindowContainerTransaction 等のActivity操作で参照されるため、別Activityへの操作能力を得る形で権限昇格につながる。
CVEの分類はOSV/CVEでは `CWE-200`, `CWE-532`, `CWE-693` が併記されているが、今回のパッチ上の本質は `CWE-693 Protection Mechanism Failure` と `CWE-200 Exposure of Sensitive Information to an Unauthorized Actor` に近い。公開CVE説明の「activity token leak」とパッチ内容が一致する。
## 調査時メモ
- Android Security BulletinのCVE表では `CVE-2025-48635 / A-446678690 / EoP / High / 14, 15` と記載されているが、表上は修正コミットへの直接リンクがなかった。
- OSV JSONには修正コミットとVanir signatureが含まれており、対象関数として `prepareActivityReparentedToTask`, `registerOrganizerInternal`, Android 14では `registerOrganizer` が列挙されていた。
- `registerOrganizer()` 自体のAIDLは `oneway` ではない。一方、organizer callback 側の `ITaskFragmentOrganizer` は `oneway interface` で、公開コミットメッセージの「one-way binder call」と整合する。
- AOSP git fetchでコミット単体取得を試したが、ローカルの浅い/空キャッシュ状態とHTTP RPC失敗により完走しなかった。そのためGitiles/OSVからソースと差分を直接取得して証跡化した。
- Pixel固有バイナリ解析は不要。対象はFramework/AOSPで、公開ソース差分から根本原因まで説明できる。
## 保存した付帯ファイル
- `artifacts/ASB-A-446678690.json`: OSVの脆弱性情報
- `artifacts/9515a944_public_commit.json`: 公開cherry-pickコミットのGitiles JSON
- `artifacts/9515a944_public_diff.html`: 公開cherry-pickコミット差分HTML
- `artifacts/TaskFragmentOrganizerController.before.java`: 修正前ソース
- `artifacts/TaskFragmentOrganizerController.after.java`: 修正後ソース
- `artifacts/TaskFragmentOrganizerController.diff`: 修正前後のunified diff
- `artifacts/ITaskFragmentOrganizer.aidl`: organizer callback AIDL。`oneway interface` を確認
- `artifacts/ITaskFragmentOrganizerController.aidl`: controller AIDL
- `artifacts/evidence_grep.txt`: 重要語句のgrep結果
cve.md を表示# CVE-2025-48635 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48635 - Component: Framework - Reference: A-446678690 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 13 | OK | CVE-2025-48645 - Framework EoP High |
013
ok
CVE-2025-48645 - Framework EoP High013-ok-DeviceAdminInfo-loadDescription-OOM-persistent-admin-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) 悪意あるアプリが Device Admin Receiver の説明リソースに極端に大きい文字列を設定し、そのアプリが active device admin になると、ユーザーが Settings の device admin 管理画面を開いて無効化/削除しようとした時に `DeviceAdminAdd.updateInterface()` が次を実行する。 [コードブロック省略] 修正前は `OutOfMemoryError` がここで捕捉されないため、Settings の当該画面がクラッシュし、ユーザーが削除/無効化 UI に到達できない。結果として、通常ならユーザー操作で解除されるべき active device admin 状態が残留する。 OSV の “possible persistent package” はこの挙動を指している。コミットメッセージは「巨大文字列による DoS」と説明しているが、ASB が EoP としている理由は、単なる UI DoS ではなく device admin 権限の保持・永続化につながるため。 原因(根本原因) 根本原因は、アプリ制御下の device admin 説明リソースを信頼し、リソース展開時のメモリ枯渇を API 境界で安全な失敗に正規化していなかったこと。 `loadDescription()` は公開 API 的には説明文を返すか `NotFoundException` を投げるメソッドとして使われており、Settings 側もその契約に沿って `NotFoundException` のみを捕捉していた。しかし実際には `PackageManager.getText()` が APK 内リソースから大きな `CharSequence` を構築する過程で `OutOfMemoryError` を投げ得る。未信頼リソースを扱う Framework API でこの unchecked error を外へ漏らしたため、権限解除 UI のクラッシュに直結した。 どこから特定したか validated.md の「参照情報」「パッチ解析」 / Android bug参照 A-443062265 validated.md を表示# CVE-2025-48645 検証結果
## 判定
OK。ソースコード差分と呼び出し元から、脆弱性の発生条件と修正意図を特定できた。
タイトル: `DeviceAdminInfo loadDescription OOM による active device admin 永続化`
## 参照情報
- Android Security Bulletin: March 2026, `CVE-2025-48645`, `A-443062265`, Framework, EoP, High, affected AOSP versions 14/15/16/16-qpr2
- OSV: `ASB-A-443062265`
- 修正コミット: `platform/frameworks/base` `cee45869c491d4e39877918ee881eb60dec7d6e5`
- 主要変更ファイル: `core/java/android/app/admin/DeviceAdminInfo.java`
## パッチ解析
修正前の `DeviceAdminInfo.loadDescription(PackageManager pm)` は、device admin アプリが manifest/meta-data で指定した `mActivityInfo.descriptionRes` をそのまま `PackageManager.getText()` で読み込んでいた。
```java
if (mActivityInfo.descriptionRes != 0) {
return pm.getText(mActivityInfo.packageName,
mActivityInfo.descriptionRes, mActivityInfo.applicationInfo);
}
throw new NotFoundException();
```
修正後は `pm.getText()` を `try` で囲み、`OutOfMemoryError` を `NotFoundException` に変換する。
```java
try {
return pm.getText(mActivityInfo.packageName,
mActivityInfo.descriptionRes, mActivityInfo.applicationInfo);
} catch (OutOfMemoryError e) {
throw new NotFoundException();
}
```
差分は非常に小さいが、例外境界の意味が重要。`loadDescription()` の利用側は説明リソースが存在しない/読めない場合を `Resources.NotFoundException` として扱う設計になっている。一方で、巨大または病的な説明リソースが原因で `OutOfMemoryError` が出ると、修正前は unchecked error として Settings プロセスまで伝播していた。
## 脆弱性の内容
悪意あるアプリが Device Admin Receiver の説明リソースに極端に大きい文字列を設定し、そのアプリが active device admin になると、ユーザーが Settings の device admin 管理画面を開いて無効化/削除しようとした時に `DeviceAdminAdd.updateInterface()` が次を実行する。
```java
try {
mAdminDescription.setText(
mDeviceAdmin.loadDescription(getPackageManager()));
mAdminDescription.setVisibility(View.VISIBLE);
} catch (Resources.NotFoundException e) {
mAdminDescription.setVisibility(View.GONE);
}
```
修正前は `OutOfMemoryError` がここで捕捉されないため、Settings の当該画面がクラッシュし、ユーザーが削除/無効化 UI に到達できない。結果として、通常ならユーザー操作で解除されるべき active device admin 状態が残留する。
OSV の “possible persistent package” はこの挙動を指している。コミットメッセージは「巨大文字列による DoS」と説明しているが、ASB が EoP としている理由は、単なる UI DoS ではなく device admin 権限の保持・永続化につながるため。
## 根本原因
根本原因は、アプリ制御下の device admin 説明リソースを信頼し、リソース展開時のメモリ枯渇を API 境界で安全な失敗に正規化していなかったこと。
`loadDescription()` は公開 API 的には説明文を返すか `NotFoundException` を投げるメソッドとして使われており、Settings 側もその契約に沿って `NotFoundException` のみを捕捉していた。しかし実際には `PackageManager.getText()` が APK 内リソースから大きな `CharSequence` を構築する過程で `OutOfMemoryError` を投げ得る。未信頼リソースを扱う Framework API でこの unchecked error を外へ漏らしたため、権限解除 UI のクラッシュに直結した。
## 悪用条件
- 攻撃アプリが device admin receiver を持つ。
- 攻撃アプリが active device admin として有効化済みである。
- 攻撃アプリの `android:description` / `mActivityInfo.descriptionRes` が、読み込み時に Settings 側ヒープを圧迫する巨大または病的な文字列リソースを指す。
- ユーザーが Settings から当該 admin を確認、無効化、削除しようとする。
この条件で、修正前は Settings の device-admin 管理画面が説明文ロード時に落ち、無効化操作を妨害できる。
## 修正の効果
修正後は `OutOfMemoryError` が `NotFoundException` に変換される。Settings 側は既存の `catch (Resources.NotFoundException e)` で説明欄を非表示にして処理を継続するため、削除/無効化 UI は表示される。悪意ある説明文字列は無視され、active device admin の永続化には使えなくなる。
## 調査時メモ
- 実際の修正対象は `loadDescription()` の `descriptionRes` だが、コミットメッセージには “Receiver's label” とある。`loadLabel()` への変更はないため、メッセージ上の label は厳密には説明リソースのことを指している可能性が高い。
- `Framework EoP High` だが、パッチの直接 primitive は Settings UI のクラッシュであり、分類上は DoS に見える。active device admin はアンインストール/無効化を通常 UI 経由で制御する特権状態なので、UI クラッシュによる解除妨害が package persistence になり、EoP として扱われている。
- 修正は長さ制限や install-time validation ではない。既存互換性を壊さないため、危険な失敗だけを `NotFoundException` に落として説明欄を非表示にする設計。
## 保存した付帯ファイル
- `artifacts/ASB-A-443062265.json`: OSV/ASB の機械可読情報
- `artifacts/cee45869c491d4e39877918ee881eb60dec7d6e5.patch`: 代表修正コミットの差分
- `artifacts/06a5b2327caa3aa8843496458e98b9bb070df6e5.patch`: qpr2-next 側の同一修正差分
- `artifacts/8402416df645b196d38e8279a02c8efa4f12ba7d.patch`: Android 14 側の同一修正差分
- `artifacts/DeviceAdminInfo_before.java`: 修正前 `DeviceAdminInfo.java`
- `artifacts/DeviceAdminInfo_after.java`: 修正後 `DeviceAdminInfo.java`
- `artifacts/DeviceAdminAdd_main.java`: Settings 側の呼び出し元
- `artifacts/DeviceAdminAdd_loadDescription_call.txt`: 呼び出し元の重要部分抜粋
- `artifacts/analysis-notes.md`: 解析メモ
- `artifacts/artifact_hashes.sha256`: 付帯ファイルの SHA-256
cve.md を表示# CVE-2025-48645 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48645 - Component: Framework - Reference: A-443062265 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 14 | OK | CVE-2025-48646 - Framework EoP High |
014
ok
CVE-2025-48646 - Framework EoP High014-ok-launchedFromPackage-forward-result-spoof cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の再構成) 追加された `ActivityStarterTests.testLaunchedFromPackage_nextMatchingActivity_forwardResult()` が攻撃シナリオを明示している。 1. 特権アプリ P が攻撃アプリ M の Activity M1 を起動する。 2. M1 が `startNextMatchingActivity()` を使って、同じ攻撃アプリ内の M2 に遷移する。 3. この時点で M2 の `launchedFromPackage` は P になり得る。 4. M2 が `FLAG_ACTIVITY_FORWARD_RESULT` を付けて P の Activity P2 を起動する。 5. 修正前の `ActivityStarter` は `sourceRecord.launchedFromUid == callingUid` だけを見て、M2 に残っていた `launchedFromPackage == P` を P2 にコピーする。 6. 結果として P2 は、実際には M から起動されているのに、`launchedFromPackage` が P であるかのように見える。 修正後テストは、P2 の `launchedFromPackage` が特権パッケージ P ではなく、直前の呼び出し元である攻撃パッケージ M になることを検証している。 原因(根本原因) 根本原因は、Activity 起動元 identity の整合性検証不足である。 `launchedFromUid` は数値 UID なので比較対象として比較的信頼できる。一方、`launchedFromPackage` はパッケージ名文字列であり、ActivityRecord の遷移によって古い値や別 UID の値を保持し得る。修正前コードは、`sourceRecord.launchedFromUid == callingUid` だけを根拠に、`sourceRecord.launchedFromPackage` も同じ UID に属すると仮定していた。 しかし `startNextMatchingActivity()` は「現在の Activity を次にマッチする Activity に置き換える」特殊な API で、元の起動元 identity を引き継いで次の Activity を開始する。そのため、攻撃アプリ M の ActivityRecord に、特権アプリ P の `launchedFromPackage` 文字列が残る状況を作れる。この状態で `FLAG_ACTIVITY_FORWARD_RESULT` の転送処理に入ると、修正前は stale/spoofed なパッケージ名が次の Activity に伝播していた。 どこから特定したか validated.md の「参照情報」「パッチ解析」 / Android bug参照 A-457742426 validated.md を表示# CVE-2025-48646 検証結果
## 判定
OK: 脆弱性を特定できた。
この CVE は Android Framework の Activity 起動処理における `launchedFromPackage` 偽装の問題だった。公開修正コミット、修正前後の `ActivityStarter.java`、追加された回帰テスト、関連する `startNextMatchingActivity()` の実装を確認した結果、攻撃条件と根本原因をソースコード上で説明できる。
## 参照情報
- Android Security Bulletin - March 2026: `CVE-2025-48646`, `A-457742426`, Framework, EoP, High, affected/fixed versions 14/15/16/16-qpr2
- AOSP 修正コミット: `c148b4fae6347652231d1c4a633f5cc9a8f057f8`
- コミットタイトル: `Prevent launchedFromPackage spoofing via FLAG_ACTIVITY_FORWARD_RESULT.`
- 修正ファイル:
- `services/core/java/com/android/server/wm/ActivityStarter.java`
- `services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java`
## 保存した付帯ファイル
- `c148b4fa.diff`: AOSP Gitiles から取得した修正差分
- `ActivityStarter.before.java`: 修正前 `ActivityStarter`
- `ActivityStarter.after.java`: 修正後 `ActivityStarter`
- `ActivityStarterTests.before.java`: 修正前テスト
- `ActivityStarterTests.after.java`: 修正後テスト
- `ActivityTaskManagerService.java`: `startNextMatchingActivity()` の確認用
- `Activity.java`: `startNextMatchingActivity()` と `getLaunchedFromPackage()` API の確認用
- `ActivityClientController.java`: `launchedFromPackage` が公開 API に返る経路の確認用
- `analysis_notes.md`: 調査メモ
## パッチ解析
問題箇所は `ActivityStarter` が `Intent.FLAG_ACTIVITY_FORWARD_RESULT` を処理する分岐にある。
修正前は、起動元 ActivityRecord の `sourceRecord.launchedFromUid` が現在の `callingUid` と一致すると、次に作られる ActivityRecord の起動元として `sourceRecord.launchedFromPackage` と `sourceRecord.launchedFromFeatureId` を無条件にコピーしていた。
```java
if (sourceRecord.launchedFromUid == callingUid) {
callingPackage = sourceRecord.launchedFromPackage;
callingFeatureId = sourceRecord.launchedFromFeatureId;
}
```
修正後は、`sourceRecord.launchedFromPackage` を `PackageManagerInternal.getPackageUid()` で UID に解決し、その UID が `callingUid` と同じアプリかどうかを `UserHandle.isSameApp()` で確認してからコピーする。
```java
final int packageUid = pmInternal.getPackageUid(
launchedFromPackage, 0 /* flags */,
UserHandle.getUserId(callingUid));
if (UserHandle.isSameApp(packageUid, callingUid)) {
callingPackage = launchedFromPackage;
callingFeatureId = sourceRecord.launchedFromFeatureId;
}
```
つまり修正は「UID が一致する」だけでなく、「コピーしようとしているパッケージ名が本当にその UID に属する」ことを検証するものだった。
## 脆弱性の再構成
追加された `ActivityStarterTests.testLaunchedFromPackage_nextMatchingActivity_forwardResult()` が攻撃シナリオを明示している。
1. 特権アプリ P が攻撃アプリ M の Activity M1 を起動する。
2. M1 が `startNextMatchingActivity()` を使って、同じ攻撃アプリ内の M2 に遷移する。
3. この時点で M2 の `launchedFromPackage` は P になり得る。
4. M2 が `FLAG_ACTIVITY_FORWARD_RESULT` を付けて P の Activity P2 を起動する。
5. 修正前の `ActivityStarter` は `sourceRecord.launchedFromUid == callingUid` だけを見て、M2 に残っていた `launchedFromPackage == P` を P2 にコピーする。
6. 結果として P2 は、実際には M から起動されているのに、`launchedFromPackage` が P であるかのように見える。
修正後テストは、P2 の `launchedFromPackage` が特権パッケージ P ではなく、直前の呼び出し元である攻撃パッケージ M になることを検証している。
## 根本原因
根本原因は、Activity 起動元 identity の整合性検証不足である。
`launchedFromUid` は数値 UID なので比較対象として比較的信頼できる。一方、`launchedFromPackage` はパッケージ名文字列であり、ActivityRecord の遷移によって古い値や別 UID の値を保持し得る。修正前コードは、`sourceRecord.launchedFromUid == callingUid` だけを根拠に、`sourceRecord.launchedFromPackage` も同じ UID に属すると仮定していた。
しかし `startNextMatchingActivity()` は「現在の Activity を次にマッチする Activity に置き換える」特殊な API で、元の起動元 identity を引き継いで次の Activity を開始する。そのため、攻撃アプリ M の ActivityRecord に、特権アプリ P の `launchedFromPackage` 文字列が残る状況を作れる。この状態で `FLAG_ACTIVITY_FORWARD_RESULT` の転送処理に入ると、修正前は stale/spoofed なパッケージ名が次の Activity に伝播していた。
## セキュリティ影響
攻撃者が特権 UID そのものを得る脆弱性ではない。影響は、起動先 Activity が「どのパッケージから起動されたか」を信頼判断に使う場合に、攻撃者主導の起動を特権パッケージ由来に見せられる点にある。
`Activity.getLaunchedFromPackage()` と `Activity.getLaunchedFromUid()` は、同一 UID、identity sharing、有効な内部/プラットフォーム呼び出しなどの条件下で参照できる。特に platform-signed/system/privileged 側の Activity や内部サービスがこの値を信頼して挙動を変える場合、攻撃アプリが privileged app P 由来の launch と誤認させ、保護された処理に到達できる可能性があるため EoP と評価されている。
## 面白い点・調査メモ
- 修正前コメントは「同じ UID なので安全」と説明していたが、実際にはパッケージ名文字列がその UID に属するかを確認していなかった。このコメント自体が誤ったセキュリティ前提を示している。
- パッチは互換性のために `FLAG_ACTIVITY_FORWARD_RESULT` の trampoline 的な挙動を残し、パッケージ名の UID 解決だけを追加している。かなり狭い修正で、原因箇所に直接対応している。
- 追加テストは攻撃の payload ではなく、ActivityRecord に保存される identity の誤りを検証している。つまりこの CVE の本質はコード実行プリミティブではなく、Framework 内の caller identity 偽装プリミティブである。
- `startNextMatchingActivity()` は通常の `startActivity()` より特殊で、元の起動元情報を引き継ぐため、stale な `launchedFromPackage` を作る入口になっていた。
## 結論
CVE-2025-48646 は、`startNextMatchingActivity()` と `FLAG_ACTIVITY_FORWARD_RESULT` を組み合わせることで、Activity 起動元の `launchedFromPackage` を別パッケージに偽装できる Framework EoP だった。
根本原因は、`ActivityStarter` が `sourceRecord.launchedFromUid == callingUid` のみを検証し、`sourceRecord.launchedFromPackage` が本当にその UID に属するかを検証せずに次の ActivityRecord へ伝播していたこと。修正は `PackageManagerInternal.getPackageUid()` と `UserHandle.isSameApp()` によって package string と caller UID の対応を確認するもので、脆弱性の原因に直接対応している。
cve.md を表示# CVE-2025-48646 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48646 - Component: Framework - Reference: A-457742426 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 15 | OK | CVE-2025-48654 - Framework EoP High |
015
ok
CVE-2025-48654 - Framework EoP High015-ok-CompanionDeviceManager-revoked-association-reboot-role-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の仕組み) Companion Device association の削除は常に即時完了するわけではない。`DisassociationProcessor.disassociate()` は、対象 package が foreground で、かつその device profile role を他の active association が使っていない場合、すぐに role holder を剥奪せず、association を `revoked=true` に更新して戻る。 この delayed cleanup は、foreground 中のアプリから role holder を外す処理を後回しにし、UID importance が下がったときに `OnUidImportanceListener` から再度 `disassociate(..., REASON_REVOKED)` する設計になっている。 しかし listener はメモリ上の状態なので reboot で失われる。一方、`revoked=true` の association は association store に書き戻される。修正前 `onStart()` はこの永続化された revoked association を拾わなかったため、再起動後は cleanup が再開されない。 原因(根本原因) 状態機械の永続化境界の設計漏れ。 - `AssociationInfo` は `revoked` を「削除済みだが final cleanup のため保持する record」として定義している。 - `isActive()` は `!mRevoked && !mPending` なので、revoked association は通常の active association API からは消える。 - ただし final cleanup は `OnUidImportanceListener` に依存しており、この listener は reboot を跨がない。 - 起動時 recovery がなかったため、`revoked` という一時状態が永続状態になってしまう。 どこから特定したか validated.md の「対象」「パッチ差分」 / Android bug参照 A-442392902 validated.md を表示# CVE-2025-48654 解析結果
## 結論
脆弱性を特定できた。CVE-2025-48654 は Android Framework の Companion Device Manager における、削除済み association の再起動後 cleanup 漏れによる EoP だった。
根本原因は、`revoked=true` にした association をディスクへ永続化する設計なのに、`CompanionDeviceManagerService.onStart()` が再起動時にその中間状態を回収して最終削除する処理を持っていなかったこと。これにより、association 削除時に companion app が foreground だった場合、削除の後半処理である RoleManager の role holder 剥奪が reboot によって失われ、アプリが CDM device profile の特権状態を保持し続ける。
## 対象
- CVE: CVE-2025-48654
- Android bug: A-442392902
- Component: Framework
- 種別: EoP
- Severity: High
- 影響バージョン: Android 16, 16-qpr2
- 公開修正コミット: `924df83d73d9f938fde025c2e793ca12646207e0`
- 変更ファイル: `services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java`
## パッチ差分
修正コミットの差分は小さく、`onStart()` の association store 初期化直後に次の処理を追加している。
```java
for (AssociationInfo ai : mAssociationStore.getRevokedAssociations()) {
mDisassociationProcessor.disassociate(ai.getId(), REASON_REVOKED);
}
```
ローカル保存差分: `artifacts/924df83d73d9.patch`
修正前は `mAssociationStore.refreshCache()` の後、revoked association を処理せずに UUID store 初期化と binder service 公開へ進んでいた。修正後は binder service 公開前に revoked association を disassociate へ戻す。
## 脆弱性の仕組み
Companion Device association の削除は常に即時完了するわけではない。`DisassociationProcessor.disassociate()` は、対象 package が foreground で、かつその device profile role を他の active association が使っていない場合、すぐに role holder を剥奪せず、association を `revoked=true` に更新して戻る。
この delayed cleanup は、foreground 中のアプリから role holder を外す処理を後回しにし、UID importance が下がったときに `OnUidImportanceListener` から再度 `disassociate(..., REASON_REVOKED)` する設計になっている。
しかし listener はメモリ上の状態なので reboot で失われる。一方、`revoked=true` の association は association store に書き戻される。修正前 `onStart()` はこの永続化された revoked association を拾わなかったため、再起動後は cleanup が再開されない。
## 根本原因
状態機械の永続化境界の設計漏れ。
- `AssociationInfo` は `revoked` を「削除済みだが final cleanup のため保持する record」として定義している。
- `isActive()` は `!mRevoked && !mPending` なので、revoked association は通常の active association API からは消える。
- ただし final cleanup は `OnUidImportanceListener` に依存しており、この listener は reboot を跨がない。
- 起動時 recovery がなかったため、`revoked` という一時状態が永続状態になってしまう。
## 影響
CDM の device profile は RoleManager role と結びつく。`RolesUtils.addRoleHolderForAssociation()` は association 作成時に `RoleManager.addRoleHolderAsUser()` を呼び、削除完了時には `removeRoleHolderForAssociation()` が `RoleManager.removeRoleHolderAsUser()` を呼ぶ。
修正前は、association 削除後に reboot を挟むことでこの role 剥奪が走らない。結果として、ユーザーが companion device の関連付けを削除した後も、攻撃アプリが watch/glasses/app streaming/computer などの CDM profile に紐づく role holder として残る。これは CDM が RoleManager に対して「削除済み association」を根拠に権限状態を残してしまう confused deputy であり、CVE Record の説明と一致する。
## 攻撃成立条件
1. 攻撃アプリが正規に Companion Device association を作成し、role 付き device profile を得る。
2. association が削除される。
3. 削除時に攻撃アプリが foreground/visible で、同一 package に同 profile の別 active association がない。
4. `disassociate()` が `setRevoked(true)` を書いた後、UID importance が下がる前に端末が再起動する。
5. 修正前では起動時に revoked association の cleanup が走らず、role holder が残る。
## 面白い点・調査メモ
- パッチはわずか 6 行程度だが、実際の問題は「foreground app を kill しないために cleanup を遅延する」という UX/安定性配慮と、reboot recovery の不足の組み合わせだった。
- `revoked` association は active 一覧からは消えるため、UI や通常 API では削除済みに見えやすい。その一方で RoleManager 側の holder は別状態として残るので、見かけ上の削除と権限状態がズレる。
- `AssociationStore.getAssociationWithCallerChecks()` は association ID の存在と package 管理権限を確認するが、`isActive()` は見ない。今回の直接修正は role cleanup だが、revoked record を長期残存させる設計は ID 指定 API との相性も悪い。
- role なし profile、または同一 package に同じ profile の別 active association がある場合は、role が残ること自体が正当化されるので、この CVE の再現条件から外れる。
## 保存した付帯ファイル
- `artifacts/924df83d73d9.patch`: 公開修正差分。
- `artifacts/CompanionDeviceManagerService_before.java`: 修正前ソース。
- `artifacts/CompanionDeviceManagerService_after.java`: 修正後ソース。
- `artifacts/AssociationInfo.java`: `revoked` / `isActive()` 定義。
- `artifacts/AssociationStore.java`: association store と caller check。
- `artifacts/DisassociationProcessor.java`: delayed cleanup の本体。
- `artifacts/RolesUtils.java`: RoleManager role の付与・削除。
- `artifacts/SystemDataTransferProcessor.java`: ID 指定 API の補足確認。
- `artifacts/analysis_notes.md`: 解析メモ。
- `artifacts/repro_scenario.md`: 再現シナリオモデル。
- `artifacts/source_manifest.md`: 取得元一覧。
## 判定
ok。公開ソースコードとパッチ差分から、脆弱性の種類、再現条件、根本原因、修正が効く理由を説明できる。
cve.md を表示# CVE-2025-48654 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48654 - Component: Framework - Reference: A-442392902 - Type: EoP - Severity: High - Updated AOSP versions: 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 16 | OK | CVE-2026-0010 - Framework EoP High |
016
ok
CVE-2026-0010 - Framework EoP High016-ok-drmserver-fd-format-stack-overflow-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性が起きる状況) 攻撃入力は `drmserver` の Binder サービスに対する `ACQUIRE_DRM_INFO` トランザクション。Parcel の中に `FileDescriptorKey` というキーを入れ、その直後に有効な fd オブジェクトを置かない、または fd ではない Binder オブジェクト/不正な fd 参照を置くと、サーバ側の `data.readFileDescriptor()` は fd ではなく負のエラー値を返す。 `Parcel::readFileDescriptor()` は、カレント位置に fd オブジェクトがない場合 `BAD_TYPE` を返す。AOSP の `Errors.h` では `BAD_TYPE = UNKNOWN_ERROR + 1`、つまり `-2147483647`。この値を修正前コードが `(unsigned long)` にキャストすると、64-bit 環境では `18446744071562067969` という 20 桁の文字列になる。NUL 終端込みで 21 バイト必要なので、`char buffer[16]` を 5 バイト以上オーバーフローする。 付帯ファイル `artifacts/fd_format_overflow_model_output.txt` で確認した結果: [コードブロック省略] 通常の小さい正の fd 値では 16 バイトを超えないため、問題の本質は「大きい fd」ではなく「失敗時の負の戻り値を unsigned long で 64-bit 十進表記したこと」。 原因(根本原因) 根本原因は以下の組み合わせ。 - `readFileDescriptor()` が返す `int` を、fd とエラーコードの区別なく扱っていた。 - `fd < 0` の検証がなかった。 - 負の `int` を `(unsigned long)` にキャストしていた。 - `sprintf` を固定長 16 バイトのスタックバッファに対して使っていた。 本来は `readFileDescriptor()` の戻り値を検証してエラーとして処理するべきだが、今回のパッチは互換性を保つためか、不正 fd も文字列として `DrmInfoRequest` に入れる挙動は残しつつ、`String8::format("%d", fd)` にしてスタック破壊だけを潰している。 どこから特定したか validated.md の「公開情報」「パッチ解析」 / Android bug参照 A-379695596 validated.md を表示# CVE-2026-0010 検証結果
## 判定
`ok`。ソースコード差分から脆弱性の場所、入力条件、根本原因を特定できた。
CVE-2026-0010 は `drmserver` の Binder ハンドラにあるスタックバッファオーバーフローだった。`IDrmManagerService::ACQUIRE_DRM_INFO` トランザクションで、キーが `FileDescriptorKey` の場合に `Parcel::readFileDescriptor()` の戻り値を文字列化する処理があり、失敗時の負の `status_t` を `unsigned long` として `sprintf` していたため、16 バイトの固定長スタックバッファを超えて書き込める。
## 公開情報
- Bulletin: Android Security Bulletin - March 2026
- CVE: CVE-2026-0010
- Reference: A-379695596
- Component: Framework
- Type: EoP
- Severity: High
- Updated AOSP versions: 14, 15, 16
- 公開パッチ: `platform/frameworks/av` commit `ebdbf918dd87127eaeca15336c33e1d3c1ae7dd6`
- コミットメッセージ: `Fix vulnerability in drmserver`
- コミット内テスト記載: `atest StsHostTestCases:android.security.sts.Bug_379695596`
## パッチ解析
修正対象は `drm/common/IDrmManagerService.cpp` の `ACQUIRE_DRM_INFO` 処理だけだった。
修正前:
```cpp
if (key == String8("FileDescriptorKey")) {
char buffer[16];
int fd = data.readFileDescriptor();
sprintf(buffer, "%lu", (unsigned long)fd);
drmInfoRequest->put(key, String8(buffer));
}
```
修正後:
```cpp
if (key == String8("FileDescriptorKey")) {
int fd = data.readFileDescriptor();
drmInfoRequest->put(key, String8::format("%d", fd));
}
```
この変更で、固定長 `char buffer[16]` と無制限 `sprintf` が消え、さらに負値を unsigned 64-bit 表現に変換しなくなった。
## 脆弱性が起きる状況
攻撃入力は `drmserver` の Binder サービスに対する `ACQUIRE_DRM_INFO` トランザクション。Parcel の中に `FileDescriptorKey` というキーを入れ、その直後に有効な fd オブジェクトを置かない、または fd ではない Binder オブジェクト/不正な fd 参照を置くと、サーバ側の `data.readFileDescriptor()` は fd ではなく負のエラー値を返す。
`Parcel::readFileDescriptor()` は、カレント位置に fd オブジェクトがない場合 `BAD_TYPE` を返す。AOSP の `Errors.h` では `BAD_TYPE = UNKNOWN_ERROR + 1`、つまり `-2147483647`。この値を修正前コードが `(unsigned long)` にキャストすると、64-bit 環境では `18446744071562067969` という 20 桁の文字列になる。NUL 終端込みで 21 バイト必要なので、`char buffer[16]` を 5 バイト以上オーバーフローする。
付帯ファイル `artifacts/fd_format_overflow_model_output.txt` で確認した結果:
```text
fd=-1 unsigned_long=18446744073709551615 digits=20 bytes_with_nul=21
fd=-2147483647 unsigned_long=18446744071562067969 digits=20 bytes_with_nul=21
fd=-2147483648 unsigned_long=18446744071562067968 digits=20 bytes_with_nul=21
```
通常の小さい正の fd 値では 16 バイトを超えないため、問題の本質は「大きい fd」ではなく「失敗時の負の戻り値を unsigned long で 64-bit 十進表記したこと」。
## 根本原因
根本原因は以下の組み合わせ。
- `readFileDescriptor()` が返す `int` を、fd とエラーコードの区別なく扱っていた。
- `fd < 0` の検証がなかった。
- 負の `int` を `(unsigned long)` にキャストしていた。
- `sprintf` を固定長 16 バイトのスタックバッファに対して使っていた。
本来は `readFileDescriptor()` の戻り値を検証してエラーとして処理するべきだが、今回のパッチは互換性を保つためか、不正 fd も文字列として `DrmInfoRequest` に入れる挙動は残しつつ、`String8::format("%d", fd)` にしてスタック破壊だけを潰している。
## 影響
破壊されるのは `/system/bin/drmserver` プロセスのスタック。`drmserver.rc` では `user drm`、`group drm system inet drmrpc readproc` で起動される。SELinux policy でも Binder サービスとして公開され、DRM/メディア/一部 app data 系ファイルへのアクセス許可を持つ。
そのため、未権限アプリ等が Binder 経由で到達できる場合、`drmserver` 権限でのコード実行または制御フロー破壊につながるメモリ破壊になり得る。Android bulletin の EoP High という分類と整合する。
## 調査中に分かったこと
- Advisory 上は Framework だが、実修正は `frameworks/av` にある。legacy DRM framework の Binder 実装がこのリポジトリにあるため。
- コミットに STS テスト名 `Bug_379695596` が記載されているが、テスト本体は公開検索では見つからなかった。
- `data.dataAvail()` はループ継続の確認には使われているが、`FileDescriptorKey` の後に本当に fd オブジェクトがあることは保証しない。
- 修正は入力拒否ではなく安全な文字列化なので、既存の DRM plugin 側の挙動変化を抑えたパッチに見える。
## 保存した付帯ファイル
- `artifacts/patch_ebdbf918dd87127eaeca15336c33e1d3c1ae7dd6.decoded.diff`: 公開パッチ差分
- `artifacts/commit_ebdbf918dd87127eaeca15336c33e1d3c1ae7dd6.clean.json`: コミットメタデータ
- `artifacts/IDrmManagerService_before.cpp`: 修正前ソース
- `artifacts/IDrmManagerService_after.cpp`: 修正後ソース
- `artifacts/IDrmManagerService.h`: トランザクション enum と interface 定義
- `artifacts/Parcel_main.cpp`: `readFileDescriptor()` 確認用
- `artifacts/Errors.h`: `status_t` / `BAD_TYPE` 定義確認用
- `artifacts/drmserver.rc`: `drmserver` 起動ユーザ/グループ確認用
- `artifacts/drmserver.te`: SELinux policy 確認用
- `artifacts/fd_format_overflow_model.c`: 負値 fd の unsigned long 文字列長モデル
- `artifacts/fd_format_overflow_model_output.txt`: モデル実行結果
- `artifacts/analysis-notes.md`: 解析メモ
cve.md を表示# CVE-2026-0010 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0010 - Component: Framework - Reference: A-379695596 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 17 | OK | CVE-2026-0011 - Framework EoP High |
017
ok
CVE-2026-0011 - Framework EoP High017-ok-uid-migration-sharedUserMaxSdkVersion cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) Android 13 以降の `sharedUserMaxSdkVersion` は、shared UID からの移行を支援する属性である。公開ドキュメント上の仕様は次の通り: - 新規インストールでは、端末 SDK が `sharedUserMaxSdkVersion` を超えていると `sharedUserId` がなかったものとして扱われる。 - ただし、既にインストール済みで更新されるアプリは、既存の shared UID を維持する。 この CVE は、その「更新済みアプリは既存 shared UID を維持する」という不変条件が、system app update のアンインストール経路で崩れる問題だった。 典型的な発生条件: 1. プリロード system app が `android:sharedUserId` を持つ。 2. 同じ manifest または更新版 manifest が `android:sharedUserMaxSdkVersion` を持つ。 3. その system app の update がインストールされ、元のプリロード版 `PackageSetting` は disabled system package として `mDisabledSysPackages` 側に退避される。 4. update がアンインストールされ、`Settings.enableSystemPackageLPw()` がプリロード版を再有効化する。 5. 修正前は、退避されていた `PackageSetting` が shared UID 所属であっても、通常 package と同じ `addPackageLPw()` 経路で再追加された。 6. `addPackageLPw()` は `mAppIds.registerExistingAppId(uid, p, name)` を呼ぶが、shared UID の appId は既に `SharedUser... 原因(根本原因) 根本原因は、`enableSystemPackageLPw()` の復元処理が「shared UID の appId は `PackageSetting` 個別ではなく `SharedUserSetting` が所有する」というデータモデルを考慮していなかったこと。 修正前の `addPackageLPw()` は、新しい `PackageSetting` を作った後、次の条件でのみ `mPackages` に登録していた。 - SDK library 例外、または - `mAppIds.registerExistingAppId(uid, p, name)` が成功する しかし `AppIdSettingMap.registerExistingAppId()` は、対象 appId が既に存在する場合 false を返す。shared UID の場合、その appId は shared user 用の `SharedUserSetting` として既に登録されているため、この false は異常ではなく期待される状態だった。 修正はこのモデル不一致を埋めている。`hasSharedUser` を別引数で渡し、shared UID package の復元では appId の重複登録失敗を理由に `PackageSetting` 登録を拒否しない。また、`sharedUserAppId` 自体も復元先へコピーして、`hasSharedUser()` と shared user 参照が失われないようにしている。 どこから特定したか validated.md の「根拠」 / Android bug参照 A-454062218 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://android.googlesource.com/platform/frameworks/base/+/51368785bd09cd652ed9851727b16545cb92c4e5, https://android.googlesource.com/platform/frameworks/base/+/51368785bd09cd652ed9851727b16545cb92c4e5%5E%21/, https://developer.android.com/about/versions/13/behavior-changes-all#migrate-away-from-shared-user-id validated.md を表示# CVE-2026-0011 検証結果 ## 判定 ok: 脆弱性を特定できた。 対象は AOSP `platform/frameworks/base` の PackageManager 設定処理で、system app update をアンインストールしてプリロード版を再有効化する際、`sharedUserMaxSdkVersion` 付き shared UID アプリの既存 `PackageSetting` を再利用できず、プリロード APK が新規アプリとして再スキャンされ得る不具合だった。 ## 根拠 - Android Security Bulletin March 2026 の Framework セクションで、CVE-2026-0011 / A-454062218 / EoP High / AOSP 14, 15, 16, 16-qpr2 更新対象として掲載されている。 - 公開参照 commit は `platform/frameworks/base` の `51368785bd09cd652ed9851727b16545cb92c4e5`。 - commit message は `[UidMigration] fix update uninstallation with sharedUserMaxSdkVersion` で、system app update のアンインストール後に shared UID 付き system app を再有効化するケースを明示している。 - 取得したパッチ、commit JSON、前後版ソース、diff は同フォルダに保存済み。 ## 解析したパッチ 対象 commit: `51368785bd09cd652ed9851727b16545cb92c4e5` 親 commit: `73ad07fe2736c8a34fc7f5788b849a558045d07b` 変更ファイル: - `services/core/java/com/android/server/pm/Settings.java` - `services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt` 主な変更: - `Settings.enableSystemPackageLPw()` が `addPackageLPw()` に `p.hasSharedUser()` を渡すようになった。 - `addPackageLPw()` が `hasSharedUser == true` の場合、`mAppIds.registerExistingAppId(uid, p, name)` が false でも `mPackages.put(name, p)` して `PackageSetting` を戻すようになった。 - `enableSystemPackageLPw()` が復元先 `PackageSetting` に `ret.setSharedUserAppId(p.getSharedUserAppId())` をコピーするようになった。 ## 脆弱性の内容 Android 13 以降の `sharedUserMaxSdkVersion` は、shared UID からの移行を支援する属性である。公開ドキュメント上の仕様は次の通り: - 新規インストールでは、端末 SDK が `sharedUserMaxSdkVersion` を超えていると `sharedUserId` がなかったものとして扱われる。 - ただし、既にインストール済みで更新されるアプリは、既存の shared UID を維持する。 この CVE は、その「更新済みアプリは既存 shared UID を維持する」という不変条件が、system app update のアンインストール経路で崩れる問題だった。 典型的な発生条件: 1. プリロード system app が `android:sharedUserId` を持つ。 2. 同じ manifest または更新版 manifest が `android:sharedUserMaxSdkVersion` を持つ。 3. その system app の update がインストールされ、元のプリロード版 `PackageSetting` は disabled system package として `mDisabledSysPackages` 側に退避される。 4. update がアンインストールされ、`Settings.enableSystemPackageLPw()` がプリロード版を再有効化する。 5. 修正前は、退避されていた `PackageSetting` が shared UID 所属であっても、通常 package と同じ `addPackageLPw()` 経路で再追加された。 6. `addPackageLPw()` は `mAppIds.registerExistingAppId(uid, p, name)` を呼ぶが、shared UID の appId は既に `SharedUserSetting` によって登録済みなので duplicate として false になる。 7. その結果 `addPackageLPw()` は null を返し、disabled package setting を直接再利用できない。 8. PackageManager はプリロード版を改めてスキャンする。このとき `sharedUserMaxSdkVersion` の「新規インストールでは sharedUserId を無視する」側の挙動に落ち、以前の shared UID ではなく別 UID / 非 shared UID として扱われ得る。 ## 根本原因 根本原因は、`enableSystemPackageLPw()` の復元処理が「shared UID の appId は `PackageSetting` 個別ではなく `SharedUserSetting` が所有する」というデータモデルを考慮していなかったこと。 修正前の `addPackageLPw()` は、新しい `PackageSetting` を作った後、次の条件でのみ `mPackages` に登録していた。 - SDK library 例外、または - `mAppIds.registerExistingAppId(uid, p, name)` が成功する しかし `AppIdSettingMap.registerExistingAppId()` は、対象 appId が既に存在する場合 false を返す。shared UID の場合、その appId は shared user 用の `SharedUserSetting` として既に登録されているため、この false は異常ではなく期待される状態だった。 修正はこのモデル不一致を埋めている。`hasSharedUser` を別引数で渡し、shared UID package の復元では appId の重複登録失敗を理由に `PackageSetting` 登録を拒否しない。また、`sharedUserAppId` 自体も復元先へコピーして、`hasSharedUser()` と shared user 参照が失われないようにしている。 ## EoP としての影響 この問題は任意コード実行ではなく、PackageManager の UID / identity migration バグである。 Android の permission、app data、signature/system app 扱い、privileged permission、shared UID membership は package name だけでなく UID と `PackageSetting` に強く依存する。system app の update uninstall 後に UID が変わると、次のような不整合が起き得る。 - 本来 shared UID の一員として動くべき system app が、shared UID から外れて別 UID になる。 - 既存 data directory の所有 UID、permission grant、package setting 上の identity が実 APK の再スキャン結果と食い違う。 - privileged / system app の復元時に、PackageManager が「更新アプリの継続」ではなく「新規インストール相当」として扱う。 - 攻撃者が system app update の導入とアンインストールを誘導・実行できる状況では、パッケージ identity の不整合を利用して、本来許されない状態遷移を作れる。 公開 commit の説明は「changed UIDs can bring breaking behavior」と控えめだが、Android bulletin では EoP High として扱われている。理由は、対象が通常アプリではなく system app / shared UID / PackageManager の identity 管理であり、UID 変更が permission boundary の破壊に直結し得るためと判断できる。 ## 面白い点・調査メモ - パッチの実コード変更は小さいが、根本は shared UID 移行 (`sharedUserMaxSdkVersion`) と system app update rollback という特殊なライフサイクルの交差にある。 - `sharedUserMaxSdkVersion` の仕様自体が「新規インストール」と「更新」で挙動を変えるため、PackageManager が update uninstall を誤って新規インストール相当にしてしまうと、そのまま UID migration バグになる。 - `registerExistingAppId()` の duplicate 失敗は、通常 package では異常だが shared UID では正常な既存状態である。修正はこの区別を `hasSharedUser` で外から渡している。 - `ret.setSharedUserAppId(p.getSharedUserAppId())` の追加が重要。`mPackages` に戻すだけでは、復元後の `PackageSetting.hasSharedUser()` が false になり得る。 - バイナリ解析は不要だった。CVE 参照が AOSP `frameworks/base` の公開 commit に直接紐付いており、差分から原因と影響条件を説明できる。 ## 保存した付帯ファイル - `51368785bd09_CVE-2026-0011.patch`: Gitiles から取得した対象 commit のパッチ。 - `51368785bd09_commit.json`: Gitiles commit JSON。 - `Settings_before.java`: 修正前 `Settings.java`。 - `Settings_after.java`: 修正後 `Settings.java`。 - `Settings_before_after.diff`: 前後版 diff。 - `PackageSetting_before.java`: `hasSharedUser()` / `sharedUserAppId` 確認用。 - `AppIdSettingMap_before.java`: `registerExistingAppId()` の duplicate 判定確認用。 - `FrameworkParsingPackageUtils_before.java`: 関連 parser 周辺確認用。 - `analysis_notes.md`: 作業中の要点メモ。 - `gitiles_search_454062218.json`: Gitiles 検索結果メモ。検索 API としてはノイズが多かったが、探索ログとして保存。 ## 参照 - Android Security Bulletin - March 2026: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - AOSP commit: https://android.googlesource.com/platform/frameworks/base/+/51368785bd09cd652ed9851727b16545cb92c4e5 - AOSP patch: https://android.googlesource.com/platform/frameworks/base/+/51368785bd09cd652ed9851727b16545cb92c4e5%5E%21/ - Android Developers: Behavior changes, migrate away from shared user ID: https://developer.android.com/about/versions/13/behavior-changes-all#migrate-away-from-shared-user-id cve.md を表示# CVE-2026-0011 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0011 - Component: Framework - Reference: A-454062218 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 18 | OK | CVE-2026-0013 - Framework EoP High |
018
ok
CVE-2026-0013 - Framework EoP High018-ok-DocumentsUI-selector-confused-deputy-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(判定) 判定: **ok** 脆弱性は DocumentsUI の `PickActivity.setupLayout()` における Intent selector のサニタイズ漏れによる confused deputy だった。AOSP の公開パッチと周辺ソースから、攻撃者が DocumentsUI に渡した `Intent` の `selector` が「他のアプリで開く」候補解決に残り、DocumentsUI が任意 Activity を DocumentsUI の権限文脈で起動し得ることを確認した。 フォルダ名候補: `018-ok-DocumentsUI-selector-confused-deputy-EoP` 原因(根本原因) `PickActivity.setupLayout()` は、DocumentsUIのピッカーを起動した元Intentを `new Intent(intent)` でコピーし、`moreApps` として「このリクエストを処理できる他アプリ」一覧に渡す。 修正前はこのコピーに対して `setComponent(null)` と `setPackage(null)` だけを実行していた。つまり、明示コンポーネントやパッケージ指定は消して「暗黙Intent化」しているつもりだったが、Intent解決に影響する `selector` は残っていた。 Android framework側では、resolver処理中に base Intent の component が null かつ selector が存在する場合、解決対象を `intent.getSelector()` に差し替える。保存した `framework_resolver_selector_snippets.txt` では `ComputerEngine` 内で `intent = intent.getSelector()` となる箇所を確認した。 このため、攻撃者は DocumentsUI に渡す picker Intent に悪意ある selector を入れ、DocumentsUI が候補アプリを問い合わせる時だけ攻撃者指定のActivityを解決させることができた。修正は `moreApps.setSelector(null)` でこの解決経路を遮断している。 どこから特定したか validated.md の「参照情報」「パッチ差分」 / Android bug参照 A-447135012 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://android.googlesource.com/platform/packages/apps/DocumentsUI/+/9f2d3f09f8fdc099d5a2d4c8bf3e8ec460bb9233, https://github.com/advisories/GHSA-v2w2-grhg-jf52 validated.md を表示# CVE-2026-0013 検証結果
## 判定
判定: **ok**
脆弱性は DocumentsUI の `PickActivity.setupLayout()` における Intent selector のサニタイズ漏れによる confused deputy だった。AOSP の公開パッチと周辺ソースから、攻撃者が DocumentsUI に渡した `Intent` の `selector` が「他のアプリで開く」候補解決に残り、DocumentsUI が任意 Activity を DocumentsUI の権限文脈で起動し得ることを確認した。
フォルダ名候補: `018-ok-DocumentsUI-selector-confused-deputy-EoP`
## 参照情報
- Android Security Bulletin March 2026: `https://source.android.com/docs/security/bulletin/2026/2026-03-01`
- ASB上の記載: `CVE-2026-0013 / A-447135012 / EoP / High / Android 14, 15, 16`
- Google Play system updates の対象サブコンポーネント: `Documents UI`
- 公開修正コミット: `https://android.googlesource.com/platform/packages/apps/DocumentsUI/+/9f2d3f09f8fdc099d5a2d4c8bf3e8ec460bb9233`
- GitHub Advisory: `https://github.com/advisories/GHSA-v2w2-grhg-jf52`
## パッチ差分
修正コミット `9f2d3f09f8fdc099d5a2d4c8bf3e8ec460bb9233` は `src/com/android/documentsui/picker/PickActivity.java` に2行を追加している。
```diff
final Intent moreApps = new Intent(intent);
moreApps.setComponent(null);
moreApps.setPackage(null);
+// Clear the selector to prevent a malicious selector from launching an arbitrary activity.
+moreApps.setSelector(null);
```
コミットメッセージ自体も、`PickActivity` が呼び出し元Intentを再利用してリクエストを処理できるアプリ一覧を表示しており、元Intentに selector があると DocumentsUI の権限で任意 Activity を起動できる、と説明している。
## 根本原因
`PickActivity.setupLayout()` は、DocumentsUIのピッカーを起動した元Intentを `new Intent(intent)` でコピーし、`moreApps` として「このリクエストを処理できる他アプリ」一覧に渡す。
修正前はこのコピーに対して `setComponent(null)` と `setPackage(null)` だけを実行していた。つまり、明示コンポーネントやパッケージ指定は消して「暗黙Intent化」しているつもりだったが、Intent解決に影響する `selector` は残っていた。
Android framework側では、resolver処理中に base Intent の component が null かつ selector が存在する場合、解決対象を `intent.getSelector()` に差し替える。保存した `framework_resolver_selector_snippets.txt` では `ComputerEngine` 内で `intent = intent.getSelector()` となる箇所を確認した。
このため、攻撃者は DocumentsUI に渡す picker Intent に悪意ある selector を入れ、DocumentsUI が候補アプリを問い合わせる時だけ攻撃者指定のActivityを解決させることができた。修正は `moreApps.setSelector(null)` でこの解決経路を遮断している。
## 脆弱なコード経路
確認した主な経路は以下。
1. `PickActivity.setupLayout()` が元Intentを `moreApps` にコピーする。
2. 修正前は `component` と `package` だけを消し、`selector` を残す。
3. `RootsFragment.show(..., includeApps, moreApps)` に渡す。`ACTION_GET_CONTENT` では `includeApps` が true。
4. `RootsFragment.includeHandlerApps()` が `pm.queryIntentActivities(handlerAppIntent, MATCH_DEFAULT_ONLY)` を実行する。
5. framework resolver が selector を使って `ResolveInfo` を返す。
6. `AppItem` または apps row の `AppData` が、その `ResolveInfo` から表示項目を作る。
7. 項目が開かれると `picker.ActionHandler.openRoot(ResolveInfo, UserId)` が `setComponent(info.activityInfo...)` したIntentを `startActivity()` / `startActivityAsUser()` で起動する。
DocumentsUI の manifest では `PickActivity` は exported で、DocumentsUI 自体は `MANAGE_DOCUMENTS`, `INTERACT_ACROSS_USERS`, `QUERY_ALL_PACKAGES` などの強い権限を持つ。したがって、これは呼び出し元アプリが DocumentsUI を代理人として使う confused deputy 型のEoPになる。
## 攻撃条件のモデル
最小モデルは `artifacts/exploit_intent_model.md` に保存した。要点は次の通り。
```java
Intent base = new Intent(Intent.ACTION_GET_CONTENT);
base.setType("*/*");
base.setComponent(new ComponentName(
"com.android.documentsui",
"com.android.documentsui.picker.PickActivity"));
Intent selector = new Intent();
selector.setComponent(new ComponentName("target.package", "target.package.TargetActivity"));
base.setSelector(selector);
startActivityForResult(base, 100);
```
この形で DocumentsUI 側に渡された selector が、修正前は `moreApps` に残る。`moreApps` は候補アプリ列挙用に component/package を消されるため、resolver側で selector が効く。
## 調査中に分かった注意点
- 公開アドバイザリやNVD系の転載では「user interaction not needed」とされているが、今回のソース確認で直接追えた実起動点は `AppItem.open()` / apps row click から `openRoot(ResolveInfo)` に入る経路だった。activity作成時に selector の `ResolveInfo` を自動起動する経路は、このリポジトリ上では見つけていない。
- ただし、根本原因と修正内容は完全に一致しており、selectorが候補解決を汚染し、DocumentsUIがその結果を用いて起動する confused deputy であることはソースコードで確認できる。
- パッチは1ファイル2行のみで、テスト追加は公開コミットには含まれていなかった。コミット上の `Test: manual` も、脆弱性がUI/Intent解決の組み合わせで再現されることを示唆している。
- DocumentsUI は Mainline/Google Play system update 対象のため、ASBのFramework表に載りつつ、Google Play system updates欄では `Documents UI` として再掲されている。
## 保存した付帯ファイル
- `artifacts/commit_9f2d3f09.txt`: 修正コミットのメタ情報
- `artifacts/patch_9f2d3f09.diff`: 公開パッチ差分
- `artifacts/PickActivity_before.java`: 修正前 `PickActivity.java`
- `artifacts/PickActivity_after.java`: 修正後 `PickActivity.java`
- `artifacts/RootsFragment_after.java`: 候補アプリ列挙経路
- `artifacts/AppItem_after.java`: 候補アプリ項目のopen経路
- `artifacts/AppsRowItemData_after.java`: apps row click経路
- `artifacts/PickerActionHandler_after.java`: DocumentsUIによる実起動経路
- `artifacts/AndroidManifest_after.xml`: DocumentsUIのexported activityと権限
- `artifacts/framework_Intent_selector_snippets.txt`: `Intent#setSelector` 関連framework抜粋
- `artifacts/framework_resolver_selector_snippets.txt`: selectorがresolverで使われる箇所
- `artifacts/exploit_intent_model.md`: 攻撃Intentモデル
- `artifacts/analysis-notes.md`: 調査メモ
- `artifacts/evidence_grep.txt`: 主要シンボルgrep
- `artifacts/SHA256SUMS`: 付帯ファイルのハッシュ
cve.md を表示# CVE-2026-0013 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0013 - Component: Framework - Subcomponent: Documents UI - Reference: A-447135012 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 19 | OK | CVE-2026-0020 - Framework EoP High |
019
ok
CVE-2026-0020 - Framework EoP High019-ok-permission-name-trim-consent-bypass cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性が起きる状況) 最小条件は次の通り。 1. 攻撃アプリまたは共謀アプリが、末尾空白付きの dangerous permission を宣言する。例: `android.permission.CAMERA `。 2. その permission の `android:permissionGroup` を、既に許可済みのプラットフォーム権限グループに入れる。例: `android.permission-group.CAMERA`。 3. 対象アプリが既に同じグループの正規プラットフォーム権限を持っている。例: 正規 `android.permission.CAMERA` が許可済み。 4. 対象アプリが空白付き permission を runtime request する。 PermissionController の処理: - `PackagePermissionsLiveData` は request された permission 名がプラットフォーム表に無ければ `PackageManager.getPermissionInfo()` を呼ぶ。 - 空白付き permission は未修正 Framework では存在するため `PermissionInfo` が返る。 - `PermissionMapping.getGroupOfPermission()` は、プラットフォーム permission 名に完全一致しない場合 `PermissionInfo.group` を採用する。 - `GrantPermissionsViewModel.getGroupState()` は `behavior.isGroupFullyGranted()` が true の場合、未許可 permission に `grantForegroundRuntimePermissions()` / `grantBackgroundRuntimePermissions()` を呼ぶ。 - `LightApp... 原因(根本原因) `ParsedComponentUtils.parseComponent()` は manifest の `android:name` を `array.getNonConfigurationString()` で読み、`ParsingUtils.buildClassName()` でパッケージ名補完するだけで、前後空白を落としていなかった。 関連証跡: - `artifacts/ParsedComponentUtils.java` - `artifacts/InternalParsingUtils.java` - `artifacts/ParsedPermissionUtils_before.java` - `artifacts/ParsedPermissionUtils_after.java` `ParsingUtils.buildClassName()` は、名前が `.` で始まる場合は package prefix を足し、`.` を含まない場合も package prefix を足し、それ以外は入力文字列をそのまま返す。したがって `android.permission.CAMERA ` のような末尾空白付き完全修飾名は、そのまま permission 名になる。 Framework 側では、その名前が registry key として使われる。 - `PermissionManagerServiceImpl.addAllPermissionsInternal()` は `mRegistry.getPermission(p.getName())` / `mRegistry.addPermission(permission)` を使う。 - `addAllPermissionGroupsInternal()` も `mRegistry.getPermissionGroup(pg.getName())` / `mRegistry.addPermissionGrou... どこから特定したか validated.md の「公開情報」「パッチ差分」 / Android bug参照 A-453649815 validated.md を表示# CVE-2026-0020 検証結果 ## 判定 特定できたため `ok` と判断する。 タイトル案: `permission-name-trim-consent-bypass` この脆弱性は、Framework の manifest parser が `<permission>` / `<permission-tree>` / `<permission-group>` の `android:name` を前後空白付きのまま登録していたため、プラットフォーム権限・権限グループに見える別名の runtime permission / permission group を作れてしまう問題だった。PermissionController 側には「同じ権限グループが既に許可済みなら、同グループ内の未許可 runtime permission を同意 UI なしで自動付与する」挙動があるため、空白付き permission 名を使うと consent dialog を迂回して dangerous permission を取得できる。 ## 公開情報 - CVE: CVE-2026-0020 - Android bug: A-453649815 - Component: Framework - Type / Severity: EoP / High - Bulletin: Android Security Bulletin 2026-03-01 - OSV details: `artifacts/ASB-A-453649815.json` - 代表 fix commit: `e770e9f0234158f4631c7147b64a1d70e0843d0b` - mainline 元 commit: `595cf99ecd42927eebf804638a4623313f3f14db` OSV/NVD の説明は「`ParsedPermissionUtils.java` の `parsePermissionGroup` で、権限取得の consent dialog を迂回できる」となっている。OSV は `platform/frameworks/base` の修正として 14/15/16/16-qpr2/16-qpr2-next の各 commit を列挙していた。 ## パッチ差分 保存した差分: - `artifacts/patch_e770e9f0234158f4631c7147b64a1d70e0843d0b.decoded.diff` - `artifacts/patch_595cf99ecd42927eebf804638a4623313f3f14db.decoded.diff` 修正内容は小さい。 ```diff + permission.setName(permission.getName().trim()); ... + permission.setName(permission.getName().trim()); ... - .setFlags(...) + .setFlags(...) + .setName(permissionGroup.getName().trim()); ``` つまり、`ParsedPermissionUtils.parsePermission()`、`parsePermissionTree()`、`parsePermissionGroup()` で、パース済み component 名を registry に入れる前に `trim()` するようになった。 ## 根本原因 `ParsedComponentUtils.parseComponent()` は manifest の `android:name` を `array.getNonConfigurationString()` で読み、`ParsingUtils.buildClassName()` でパッケージ名補完するだけで、前後空白を落としていなかった。 関連証跡: - `artifacts/ParsedComponentUtils.java` - `artifacts/InternalParsingUtils.java` - `artifacts/ParsedPermissionUtils_before.java` - `artifacts/ParsedPermissionUtils_after.java` `ParsingUtils.buildClassName()` は、名前が `.` で始まる場合は package prefix を足し、`.` を含まない場合も package prefix を足し、それ以外は入力文字列をそのまま返す。したがって `android.permission.CAMERA ` のような末尾空白付き完全修飾名は、そのまま permission 名になる。 Framework 側では、その名前が registry key として使われる。 - `PermissionManagerServiceImpl.addAllPermissionsInternal()` は `mRegistry.getPermission(p.getName())` / `mRegistry.addPermission(permission)` を使う。 - `addAllPermissionGroupsInternal()` も `mRegistry.getPermissionGroup(pg.getName())` / `mRegistry.addPermissionGroup(pg)` を使う。 このため、未修正では `android.permission.CAMERA` と `android.permission.CAMERA `、`android.permission-group.CAMERA` と `android.permission-group.CAMERA ` が別物として登録され得る。 ## 脆弱性が起きる状況 最小条件は次の通り。 1. 攻撃アプリまたは共謀アプリが、末尾空白付きの dangerous permission を宣言する。例: `android.permission.CAMERA `。 2. その permission の `android:permissionGroup` を、既に許可済みのプラットフォーム権限グループに入れる。例: `android.permission-group.CAMERA`。 3. 対象アプリが既に同じグループの正規プラットフォーム権限を持っている。例: 正規 `android.permission.CAMERA` が許可済み。 4. 対象アプリが空白付き permission を runtime request する。 PermissionController の処理: - `PackagePermissionsLiveData` は request された permission 名がプラットフォーム表に無ければ `PackageManager.getPermissionInfo()` を呼ぶ。 - 空白付き permission は未修正 Framework では存在するため `PermissionInfo` が返る。 - `PermissionMapping.getGroupOfPermission()` は、プラットフォーム permission 名に完全一致しない場合 `PermissionInfo.group` を採用する。 - `GrantPermissionsViewModel.getGroupState()` は `behavior.isGroupFullyGranted()` が true の場合、未許可 permission に `grantForegroundRuntimePermissions()` / `grantBackgroundRuntimePermissions()` を呼ぶ。 - `LightAppPermGroup.AppPermSubGroup.allowFullGroupGrant` は、同じ platform group 内に許可済み platform/system permission があると true になる。 結果として、同じグループが既に許可済みなら、空白付き dangerous permission のための consent dialog は出ず、自動付与される。 重要な点として、この問題は「空白付き `android.permission.CAMERA ` が正規 Camera API の permission check を直接満たす」という話ではない。`AppOpsManager.permissionToOp()` は permission 名を完全一致で引くため、空白付き名は正規 camera app-op にはならない。問題は、Framework が dangerous permission として登録した別名 permission を、PermissionController が既存グループ許可状態に引きずられて同意なしに grant してしまう点にある。app-defined dangerous permission が他アプリの exported component / provider / service のアクセス制御に使われる場合、同意 UI を経ずにその権限を得られる。 ## 修正後の挙動 パッチ後は permission / permission-tree / permission-group の宣言名が `trim()` される。 - `android.permission.CAMERA ` は `android.permission.CAMERA` として扱われる。 - 既存の platform permission と衝突し、第三者アプリが空白付き別名 permission を新規登録する経路が潰れる。 - `android.permission-group.CAMERA ` も `android.permission-group.CAMERA` として扱われ、platform group の空白付き別名を作れなくなる。 これにより、PermissionController が「別名だが同じグループに見える permission」を request 対象として扱う状況が成立しなくなる。 ## 最小モデル検証 保存したモデル: - `artifacts/permission_trim_consent_bypass_model.py` - `artifacts/permission_trim_consent_bypass_model_output.txt` 実行結果: ```text patched=False: granted=True: auto-granted via already granted group 'android.permission-group.CAMERA' patched=True: granted=False: requested permission is not registered ``` このモデルは Android 全体を再実装していないが、今回の根本原因と grant 判定に必要な次の箇所を反映している。 - Framework parser が未修正では `android:name` を trim しない。 - Permission registry が permission 名を key として扱う。 - PermissionController が既に許可済みの同一グループにある未許可 permission を自動 grant する。 - 修正後は空白付き permission 名が trim され、別名 permission として登録されない。 ## 調査中に分かったこと - パッチは `parsePermissionGroup` だけでなく、`parsePermission` と `parsePermissionTree` も直している。CVE 説明は `parsePermissionGroup` に寄っているが、実際の修正は permission namespace 全体の正規化不足への対処。 - `PermissionInfo.group` 自体は `parsePermission()` 内で trim されていない。今回の修正ポイントは「定義される permission/group の名前」であり、参照先 group 文字列の正規化ではない。 - `PermissionController` 側は `PermissionMapping` という静的な platform permission map を持つ。ここは完全一致であり、空白付き permission は platform permission ではなく app-defined permission として流れる。 - `LightAppPermGroup` は platform group では platform/system permission だけを「既に許可済みグループ」の根拠に数える。この防御はあるが、空白付き app-defined permission の自動付与そのものは止めない。 - `AppOpsManager.permissionToOp()` も完全一致なので、空白付き `android.permission.CAMERA ` が正規 camera app-op に変換されるわけではない。過大評価しないこと。 ## 付帯ファイル - `artifacts/ASB-A-453649815.json`: OSV の CVE/ASB 情報 - `artifacts/commit_e770e9f0234158f4631c7147b64a1d70e0843d0b.json`: 代表 cherry-pick commit - `artifacts/commit_595cf99ecd42927eebf804638a4623313f3f14db.json`: mainline 元 commit - `artifacts/patch_e770e9f0234158f4631c7147b64a1d70e0843d0b.decoded.diff`: 代表パッチ差分 - `artifacts/patch_595cf99ecd42927eebf804638a4623313f3f14db.decoded.diff`: mainline パッチ差分 - `artifacts/ParsedPermissionUtils_before.java`: 修正前 - `artifacts/ParsedPermissionUtils_after.java`: 修正後 - `artifacts/PermissionManagerServiceImpl.java`: registry 登録・検索経路 - `artifacts/PackageInfoUtils.java`: `PermissionInfo` / `PermissionGroupInfo` 生成経路 - `artifacts/Permission.java`: permission 登録・更新モデル - `artifacts/ParsedComponentUtils.java`: manifest `android:name` 読み取り経路 - `artifacts/InternalParsingUtils.java`: `buildClassName()` 実装 - `artifacts/PermissionMapping.kt`: PermissionController の platform permission map - `artifacts/PackagePermissionsLiveData.kt`: request permission から UI group を作る経路 - `artifacts/GrantPermissionsViewModel.kt`: 自動 grant 判定 - `artifacts/LightAppPermGroup.kt`, `artifacts/LightPermission.kt`: group granted 判定 - `artifacts/AppOpsManager.java`: app-op 変換が完全一致である確認 - `artifacts/permission_trim_consent_bypass_model.py`: 最小モデル - `artifacts/permission_trim_consent_bypass_model_output.txt`: モデル出力 - `artifacts/SHA256SUMS`: 付帯ファイルのハッシュ cve.md を表示# CVE-2026-0020 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0020 - Component: Framework - Reference: A-453649815 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 20 | OK | CVE-2026-0023 - Framework EoP High |
020
ok
CVE-2026-0023 - Framework EoP High020-ok-PackageInstaller-managed-user-flag-update-ownership-bypass cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の再構成) `INSTALL_FROM_MANAGED_USER_OR_PROFILE` は `PackageInstallerSession.computeUserActionRequirement()` で使われる。update ownership enforcement が有効で、既存の update owner と今回の installer が違う場合、通常は `USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER` になり、ユーザー確認が必要になる。 ただし、この判定には例外がある。 [コードブロック省略] managed user/profile では update ownership enforcement を強制しないため、`isFromManagedUserOrProfile` が true なら reminder が出ない。修正前は攻撃側が `SessionParams.installFlags` に `INSTALL_FROM_MANAGED_USER_OR_PROFILE` を仕込むことで、通常ユーザーの session でもこの例外を成立させられた。 結果として、update owner ではない installer が、update ownership enforcement の確認を受けずに対象 package の更新フローへ進める。`InstallPackageHelper` 側では installer が既存 update owner と違う場合に update owner を clear し得るため、保護されていた update ownership を崩せる。 原因(根本原因) 根本原因は、サーバ側で計算すべき internal authorization state を、外部入力である `SessionParams.installFlags` と同じ bit field で受け取り、その internal bit を trust boundary で正規化しなかったこと。 `INSTALL_REQUEST_UPDATE_OWNERSHIP` については、`createSessionInternal()` が `ENFORCE_UPDATE_OWNERSHIP` permission を確認し、権限がない caller では flag を clear している。一方、`INSTALL_FROM_MANAGED_USER_OR_PROFILE` は「実際に対象 user が organization managed か」という Framework 側の事実であり、caller が指定してよい値ではない。それにもかかわらず修正前は caller-provided bit を消していなかった。 どこから特定したか validated.md の「参照情報」「パッチ解析」 / Android bug参照 A-459461121 validated.md を表示# CVE-2026-0023 検証結果
## 判定
OK: 脆弱性を特定できた。
この CVE は Android Framework の PackageInstaller における `INSTALL_FROM_MANAGED_USER_OR_PROFILE` フラグの信頼境界ミスだった。修正前の `PackageInstallerService.createSessionInternal()` は、外部アプリから渡された `SessionParams.installFlags` 内の internal-only flag を消さずに使っていた。その結果、通常ユーザーからの install session を「managed user/profile 由来」と偽装でき、update ownership enforcement の確認を迂回できる。
## 参照情報
- Android Security Bulletin - March 2026: `CVE-2026-0023`, `A-459461121`, Framework, EoP, High, affected/fixed versions 14/15/16/16-qpr2
- Android OSV: `ASB-A-459461121`
- AOSP 修正コミット: `09055276288a68cf35b0f84ba32e28822f74ecf9`
- コミットタイトル: `Explicitly unset INSTALL_FROM_MANAGED_USER_OR_PROFILE flag`
- 修正ファイル: `services/core/java/com/android/server/pm/PackageInstallerService.java`
## 保存した付帯ファイル
- `09055276288a.diff`: AOSP Gitiles から取得した修正差分
- `09055276288a.commit.json`: commit metadata
- `ASB-A-459461121.json`: Android OSV advisory
- `PackageInstallerService.before.java`: 修正前 `PackageInstallerService`
- `PackageInstallerService.after.java`: 修正後 `PackageInstallerService`
- `PackageInstaller.after.java`: `SessionParams` と update ownership API 確認用
- `PackageInstallerSession.after.java`: user action 判定確認用
- `InstallPackageHelper.after.java`: update owner 保存/clear ロジック確認用
- `InstallSource.after.java`: `mUpdateOwnerPackageName` 確認用
- `PackageManager.after.java`: internal flag 定義確認用
- `analysis_notes.md`: 調査メモ
## パッチ解析
修正前の `createSessionInternal()` は、管理対象ユーザー/プロファイルかどうかを調べ、該当する場合に `INSTALL_FROM_MANAGED_USER_OR_PROFILE` を OR していた。
```java
final var dpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
if (dpmi != null && dpmi.isUserOrganizationManaged(userId)) {
params.installFlags |= PackageManager.INSTALL_FROM_MANAGED_USER_OR_PROFILE;
}
```
問題は、該当しない場合にこの flag を clear していなかったこと。`SessionParams` は Binder 経由で外部 caller から渡される Parcelable で、`installFlags` は Parcel から復元される。そのため caller が hidden/internal bit を混入させた場合、修正前サーバはそれをそのまま信頼した。
修正後は、実際の user state を反映する前に必ず internal flag を消す。
```java
final var dpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
params.installFlags &= ~PackageManager.INSTALL_FROM_MANAGED_USER_OR_PROFILE;
if (dpmi != null && dpmi.isUserOrganizationManaged(userId)) {
params.installFlags |= PackageManager.INSTALL_FROM_MANAGED_USER_OR_PROFILE;
}
```
## 脆弱性の再構成
`INSTALL_FROM_MANAGED_USER_OR_PROFILE` は `PackageInstallerSession.computeUserActionRequirement()` で使われる。update ownership enforcement が有効で、既存の update owner と今回の installer が違う場合、通常は `USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER` になり、ユーザー確認が必要になる。
ただし、この判定には例外がある。
```java
if (isUpdateOwnershipEnforcementEnabled
&& !isApexSession()
&& !isUpdateOwner
&& !isInstallerShell
&& !isFromManagedUserOrProfile) {
return USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER;
}
```
managed user/profile では update ownership enforcement を強制しないため、`isFromManagedUserOrProfile` が true なら reminder が出ない。修正前は攻撃側が `SessionParams.installFlags` に `INSTALL_FROM_MANAGED_USER_OR_PROFILE` を仕込むことで、通常ユーザーの session でもこの例外を成立させられた。
結果として、update owner ではない installer が、update ownership enforcement の確認を受けずに対象 package の更新フローへ進める。`InstallPackageHelper` 側では installer が既存 update owner と違う場合に update owner を clear し得るため、保護されていた update ownership を崩せる。
## 根本原因
根本原因は、サーバ側で計算すべき internal authorization state を、外部入力である `SessionParams.installFlags` と同じ bit field で受け取り、その internal bit を trust boundary で正規化しなかったこと。
`INSTALL_REQUEST_UPDATE_OWNERSHIP` については、`createSessionInternal()` が `ENFORCE_UPDATE_OWNERSHIP` permission を確認し、権限がない caller では flag を clear している。一方、`INSTALL_FROM_MANAGED_USER_OR_PROFILE` は「実際に対象 user が organization managed か」という Framework 側の事実であり、caller が指定してよい値ではない。それにもかかわらず修正前は caller-provided bit を消していなかった。
## セキュリティ影響
攻撃者が system UID や device owner 権限を直接得る脆弱性ではない。影響は PackageInstaller の update ownership enforcement を迂回し、update owner ではない installer が管理対象ユーザー/プロファイル例外を偽装して、通常なら確認が必要な app update ownership の変更/解除に到達できる点にある。
Android OSV は「`createSessionInternal` で missing permission check により app が ownership を更新できる可能性があり、local EoP、追加実行権限不要、ユーザー操作不要」と説明している。ソース上の実体は、`INSTALL_FROM_MANAGED_USER_OR_PROFILE` という internal-only flag の注入による update ownership enforcement bypass と判断できる。
## 面白い点・調査メモ
- 修正は 1 行の bit clear だが、脆弱性の本質は Parcelable に載った internal flag をサーバ境界で信用していたこと。
- `SessionParams.setRequestUpdateOwnership()` には `@RequiresPermission(ENFORCE_UPDATE_OWNERSHIP)` が付いているが、annotation は enforcement ではない。実際の enforcement は `createSessionInternal()` の flag clear で行われる。
- 今回のパッチは `INSTALL_REQUEST_UPDATE_OWNERSHIP` ではなく、別の例外制御 flag である `INSTALL_FROM_MANAGED_USER_OR_PROFILE` を正規化している。つまり「ownership を要求する権限」ではなく「ownership enforcement の例外条件」を偽装できた問題。
- commit message の `Only the system should be able to set this flag` というコメントが、修正意図をほぼそのまま表している。
- Pixel 固有のバイナリ解析は不要だった。対象は AOSP `platform/frameworks/base` の Java ソースで、修正前後差分から原因と到達条件を説明できる。
## 結論
CVE-2026-0023 は、PackageInstaller の install session 作成時に `INSTALL_FROM_MANAGED_USER_OR_PROFILE` を caller-controlled な `SessionParams.installFlags` から受け入れてしまう Framework EoP だった。
修正前は、攻撃アプリが通常ユーザーの session に managed user/profile 由来を示す internal flag を混入でき、`computeUserActionRequirement()` の update ownership enforcement reminder を迂回できた。根本原因は、Framework 内部だけが設定すべき flag を `createSessionInternal()` の入口で clear せず、外部入力を信頼したこと。修正はこの flag を必ず unset してから、`DevicePolicyManagerInternal.isUserOrganizationManaged(userId)` の結果で再設定するもので、原因に直接対応している。
cve.md を表示# CVE-2026-0023 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0023 - Component: Framework - Reference: A-459461121 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 21 | OK | CVE-2026-0026 - Framework EoP High |
021
ok
CVE-2026-0026 - Framework EoP High021-ok-PermissionManager-removePermission-system-permission-override cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) `PermissionManager.removePermission()` は「以前 `addPermission()` で追加した dynamic permission を削除する」ためのAPIで、サービス側ではまず対象 permission 名が呼び出し元の所有する permission tree 配下にあるかを確認する。 Android 14 の修正前コードでは、対象 permission が非 dynamic の場合に `Slog.wtf()` で「Not allowed to modify non-dynamic permission」と記録していたが、そのまま `mRegistry.removePermission(permName)` へ進んでいた。つまり、禁止条件を検出していたが enforcement になっていなかった。 修正は単純で、非 dynamic permission の分岐内に `return;` を追加している。 [コードブロック省略] 原因(根本原因) 根本原因は、`removePermission()` の認可粒度が「permission tree 所有者ならOK」だけに寄っており、削除対象が dynamic permission かどうかの検査がログ出力だけで処理停止になっていなかったこと。 `addPermission()` 側は既存 permission が非 dynamic の場合に `SecurityException` を投げて更新を拒否している。一方 `removePermission()` 側は同じ制約を意図していたものの、`Slog.wtf()` 後に `return` していなかった。この非対称性により、permission tree 所有者が system/manifest permission を registry から消せた。 どこから特定したか validated.md の「パッチ解析で分かったこと」 / Android bug参照 A-321711213 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://osv.dev/vulnerability/ASB-A-321711213, https://android.googlesource.com/platform/frameworks/base/+/528a87e90ff9354581d54fd37fbe9f95cccbcdb1, https://android.googlesource.com/platform/frameworks/base/+/f02c71c2bad4c29eaf4ce20ef89b3c4f9f46dfe8, https://android.googlesource.com/platform/frameworks/base/+/0ead58f69f5de82b00406316b333366d556239f1 validated.md を表示# CVE-2026-0026 検証結果
## 判定
OK。ソースコード差分から脆弱性と根本原因を特定できた。
- 対象: `platform/frameworks/base`
- CVE: `CVE-2026-0026`
- Android bug: `A-321711213`
- 対象メソッド: `services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java` の `removePermission`
- 影響: permission tree の所有者が、本来削除できない非 dynamic の manifest/system permission を削除でき、後続の権限定義で system permission を上書きできる可能性がある。
## 脆弱性の内容
`PermissionManager.removePermission()` は「以前 `addPermission()` で追加した dynamic permission を削除する」ためのAPIで、サービス側ではまず対象 permission 名が呼び出し元の所有する permission tree 配下にあるかを確認する。
Android 14 の修正前コードでは、対象 permission が非 dynamic の場合に `Slog.wtf()` で「Not allowed to modify non-dynamic permission」と記録していたが、そのまま `mRegistry.removePermission(permName)` へ進んでいた。つまり、禁止条件を検出していたが enforcement になっていなかった。
修正は単純で、非 dynamic permission の分岐内に `return;` を追加している。
```diff
if (!bp.isDynamic()) {
Slog.wtf(TAG, "Not allowed to modify non-dynamic permission " + permName);
+ return;
}
mRegistry.removePermission(permName);
```
## 根本原因
根本原因は、`removePermission()` の認可粒度が「permission tree 所有者ならOK」だけに寄っており、削除対象が dynamic permission かどうかの検査がログ出力だけで処理停止になっていなかったこと。
`addPermission()` 側は既存 permission が非 dynamic の場合に `SecurityException` を投げて更新を拒否している。一方 `removePermission()` 側は同じ制約を意図していたものの、`Slog.wtf()` 後に `return` していなかった。この非対称性により、permission tree 所有者が system/manifest permission を registry から消せた。
## 攻撃条件と影響
攻撃者は、自分のアプリが所有する `<permission-tree>` 配下の permission 名に対して `removePermission()` を呼ぶ。`Permission.enforcePermissionTree()` は、対象名が tree 名 + `.` で始まり、tree 所有者の appId が呼び出し元と一致すれば成功する。
脆弱版ではこの後、対象が非 dynamic の system permission でも削除される。削除後に別パッケージが同名 permission を宣言できる状況を作ると、元の system permission 定義を上書きできる。OSV の説明にある「override any system permission」はこの状態を指すと判断した。
「User interaction is needed」とされているのは、攻撃者の permission tree 所有パッケージや同名 permission 宣言パッケージの導入にインストール等のユーザー操作が必要になるためと考えられる。追加の実行時権限は不要で、サービス側の主なチェックは permission tree 所有権である。
## パッチ解析で分かったこと
- OSV は Android 14 向け修正として `528a87e90ff9354581d54fd37fbe9f95cccbcdb1` を示している。
- Android 14 の公開ブランチでは、この修正の cherrypick `f02c71c2bad4c29eaf4ce20ef89b3c4f9f46dfe8` が確認できる。
- `16-qpr2-next` では `528a87e...` に加えて `0ead58f69f5de82b00406316b333366d556239f1` も修正として列挙されている。これは一部ブランチで条件が `if (bp.isDynamic())` になってしまい、dynamic permission 削除が拒否され、非 dynamic permission 削除が通る逆条件バグを直すものだった。
- つまり、このCVEの本質は「非 dynamic permission を削除してはいけない」という不変条件で、ブランチによって `return` 欠落と条件反転ミスの両方が関係していた。
## 保存した主な証拠ファイル
- `ASB-A-321711213.json`: Android OSV のCVE詳細。
- `patch_528a87e90ff9.diff`: upstream の `return` 追加差分。
- `patch_f02c71c.diff`: Android 14 側の cherrypick 差分。
- `patch_0ead58f69f5d.diff`: 条件反転ミスを直す follow-up 差分。
- `PermissionManagerServiceImpl_before.java` / `PermissionManagerServiceImpl_after.java`: `528a87e...` 前後の実装。
- `PermissionManagerServiceImpl_android14_r75.java`: Android 14 修正後の実装。
- `Permission_android14_r75.java`: permission tree 所有権チェックと system permission override 判定の根拠。
- `analysis_notes.md`, `repro_model.md`: 解析メモと最小再現モデル。
## 参照URL
- Android Security Bulletin 2026-03-01: https://source.android.com/docs/security/bulletin/2026/2026-03-01
- OSV ASB-A-321711213: https://osv.dev/vulnerability/ASB-A-321711213
- Fix commit: https://android.googlesource.com/platform/frameworks/base/+/528a87e90ff9354581d54fd37fbe9f95cccbcdb1
- Android 14 cherrypick: https://android.googlesource.com/platform/frameworks/base/+/f02c71c2bad4c29eaf4ce20ef89b3c4f9f46dfe8
- Follow-up commit: https://android.googlesource.com/platform/frameworks/base/+/0ead58f69f5de82b00406316b333366d556239f1
cve.md を表示# CVE-2026-0026 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0026 - Component: Framework - Reference: A-321711213 - Type: EoP - Severity: High - Updated AOSP versions: 14 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 22 | OK | CVE-2026-0034 - Framework EoP High |
022
ok
CVE-2026-0034 - Framework EoP High022-ok-managed-services-notification-policy-desync cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の実体) 通知ポリシー/DND 関連APIは `enforcePolicyAccess()` で保護される。修正前コードでは、この判定が `mConditionProviders.isPackageOrComponentAllowed()` と通知リスナーの有効状態を見ていた。 該当箇所: - `NotificationManagerService_before.java:6472-6489` - `NotificationManagerService_before.java:6503-6545` つまり `mConditionProviders` に誤って package/component が残る、または過剰に入ると、本来制限されるべき notification policy / Zen Mode / DND 操作の権限判定が通る。これは通常アプリに許される通知投稿などより強い権限であり、Framework EoP として扱われる。 根本原因は次の2点。 1. `ManagedServices` が外部入力由来の package/component 承認エントリを無制限に保持できた。 2. `setPackageOrComponentEnabled()` が成功可否を返さなかったため、通知リスナー承認と通知ポリシー承認のような複数リスト更新で、片側の状態遷移を検証してからもう片側へ反映する設計になっていなかった。 原因(根本原因を含む段落) 根本原因は次の2点。 どこから特定したか validated.md の「根拠」「パッチ解析」 / Android bug参照 A-428701593 validated.md を表示# CVE-2026-0034 検証結果 ## 結論 脆弱性を特定できたため `ok` 判定とする。 CVE-2026-0034 は、Framework の通知管理基盤 `ManagedServices.setPackageOrComponentEnabled()` における入力・状態遷移検証不足である。通知リスナー、通知アシスタント、DND/通知ポリシーアクセス用 Condition Provider は同じ `ManagedServices` 基盤で承認状態を管理しているが、修正前は per-user の承認リストに登録できる package/component 数に上限がなく、かつ状態変更の成否を呼び出し側へ返していなかった。 その結果、攻撃者が制御する package/component 名で managed service の承認状態を過剰に増やせ、通知リスナー承認と通知ポリシー承認の同期処理が失敗を検出できない設計になっていた。CVE公式説明の "notification policy desync" はこの状態不整合を指す。 ## 根拠 - Android Security Bulletin 2026-03-01: `CVE-2026-0034` / `A-428701593` / Framework / EoP / High / Android 14, 15, 16, 16-qpr2 - CVE Record: `ManagedServices.java` の `setPackageOrComponentEnabled` における improper input validation により notification policy desync が起き、ローカル権限昇格につながると説明されている。 - AOSP commit: `e363f82104566378b4b9936d6caf27c3ee631d80` - commit title: `Limit the number of services (NLSes, etc) that can be approved per user` - `Bug: 428701593` - `Flag: com.android.server.notification.limit_managed_services_count` ## パッチ解析 主な修正点は `ManagedServices.java` と `NotificationManagerService.java` の2ファイル。 `ManagedServices.java` の修正: - `MAX_SERVICE_ENTRIES = 100` を追加。 - `mApproved` と `mUserSetServices` に入る per-user entry 数を制限。 - `setPackageOrComponentEnabled()` の戻り値を `void` から `boolean` に変更。 - allow-list へ追加できなかった場合は `false` を返し、`rebindServices()` も呼ばない。 - 状態が変わった場合だけ `mUserSetServices` を更新する。 修正前の問題箇所: - `ManagedServices_before.java:923-961` - `approved.add(approvedItem)` が無制限。 - `userSetServices.add(pkgOrComponent)` も無制限。 - 呼び出し側は成功・失敗を判定できない。 修正後: - `ManagedServices_after.java:935-991` - `approved.size() < MAX_SERVICE_ENTRIES` の場合のみ追加。 - 失敗時は `false`。 - `changed == true` の場合だけ user-set metadata と rebind を更新。 `NotificationManagerService.java` の修正: - `setNotificationPolicyAccessGrantedForUser()` は `mConditionProviders.setPackageOrComponentEnabled()` が `false` の場合、broadcast と policy file 保存をしない。 - `setNotificationListenerAccessGrantedForUser()` は先に `mListeners.setPackageOrComponentEnabled()` を実行し、失敗したら `mConditionProviders` への mirror update をしない。 - `NotificationListeners.setPackageOrComponentEnabled()` も `super` が失敗したら trusted listener UID 更新や `ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED` broadcast をしない。 修正前の重要な同期処理: - `NotificationManagerService_before.java:6964-6969` - 通知リスナー承認時に `mConditionProviders` を先に更新し、その後 `mListeners` を更新していた。 修正後: - `NotificationManagerService_after.java:6967-6977` - `mListeners` の変更が成功した場合だけ `mConditionProviders` を更新する。 ## 脆弱性の実体 通知ポリシー/DND 関連APIは `enforcePolicyAccess()` で保護される。修正前コードでは、この判定が `mConditionProviders.isPackageOrComponentAllowed()` と通知リスナーの有効状態を見ていた。 該当箇所: - `NotificationManagerService_before.java:6472-6489` - `NotificationManagerService_before.java:6503-6545` つまり `mConditionProviders` に誤って package/component が残る、または過剰に入ると、本来制限されるべき notification policy / Zen Mode / DND 操作の権限判定が通る。これは通常アプリに許される通知投稿などより強い権限であり、Framework EoP として扱われる。 根本原因は次の2点。 1. `ManagedServices` が外部入力由来の package/component 承認エントリを無制限に保持できた。 2. `setPackageOrComponentEnabled()` が成功可否を返さなかったため、通知リスナー承認と通知ポリシー承認のような複数リスト更新で、片側の状態遷移を検証してからもう片側へ反映する設計になっていなかった。 ## 攻撃条件と影響 CVE Record は「追加の実行権限不要、ユーザー操作不要」としている。公開パッチから復元できる実害は、攻撃者が管理する多数の managed service package/component entry により、system_server 内の通知関連承認状態を上限なしに増やし、通知リスナー状態と通知ポリシー状態の同期を崩すこと。 影響は DND/Zen Mode/notification policy API への不正アクセスである。具体的には、`setInterruptionFilter()`、automatic zen rule 操作、notification policy 変更などが `enforcePolicyAccess()` を通過する可能性がある。 ## 付帯検証 保存した主な付帯ファイル: - `artifacts/patch_e363f8210456.diff`: AOSP公開パッチ - `artifacts/commit_e363f8210456.json`: commit metadata - `artifacts/ManagedServices_before.java` - `artifacts/ManagedServices_after.java` - `artifacts/NotificationManagerService_before.java` - `artifacts/NotificationManagerService_after.java` - `artifacts/ConditionProviders_before.java` - `artifacts/ConditionProviders_after.java` - `artifacts/CVE-2026-0034.cveawg.json` - `artifacts/android-security-bulletin-2026-03-01.html` - `artifacts/analysis_notes.md` - `artifacts/managed_services_desync_model.py` - `artifacts/managed_services_desync_model.out` `ConditionProviders.java` は前後で差分なしだった。これは、権限判定側ではなく、共通承認リストの更新ロジックと呼び出し側の同期制御が修正対象であることを示す。 簡易モデル `managed_services_desync_model.py` の出力: ```text pre_patch_listener_allowed True pre_patch_policy_allowed True post_patch_listener_allowed False post_patch_policy_allowed False ``` このモデルは実機PoCではないが、100件を超えた entry を修正後は listener 側で拒否し、policy 側にも反映しないというパッチの状態遷移を再現している。 ## 調査時メモ - 追加されたテスト `setPackageOrComponentEnabled_tooManyPackages_stopsAdding` は、101件目の package/component が承認されないことを検証している。 - 追加されたテスト `setPackageOrComponentEnabled_tooManyChanges_stopsAddingToUserSet` は、無効化済み entry で `mUserSetServices` が膨らむケースも問題視している。許可中のサービスだけでなく「ユーザーが明示的に触った」履歴も攻撃面だった。 - 追加されたテスト `testSetListenerAccessForUser_tooManyListeners_skipsFollowups` は、listener 側が失敗したときに condition provider 側の更新と broadcast をしないことを直接検証している。このテストが notification policy desync の修正意図を最も強く示している。 - commit message の "Trying to activate additional packages/components will be silently rejected." から、例外で呼び出し側を落とすのではなく、承認操作だけを静かに拒否する互換性重視の修正であると分かる。 ## 判定 `ok`: ソースコード差分とテストから、脆弱性の根本原因、影響する権限境界、修正方針を説明できる。 cve.md を表示# CVE-2026-0034 - Framework EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0034 - Component: Framework - Reference: A-428701593 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 23 | OK | CVE-2025-48630 - Framework ID High |
023
ok
CVE-2025-48630 - Framework ID High023-ok-blur-region-bounds-escape cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) SurfaceFlinger の Skia RenderEngine が、クライアント指定の `BlurRegion` を layer bounds に必ずしも clip せずに描画していた。通常の矩形 layer で rounded-corner crop が不要な場合、`getBoundsAndClip()` は `bounds` を返す一方で `roundRectClip` を空にする。この状態では pre-patch の blur 描画経路が canvas clip を張らない。 その後、`layer.blurRegions` 由来の矩形が `getBlurRRect(region)` で `SkRRect` に変換され、`BlurFilter::drawBlurRegion()` が `canvas->drawRect()` または `canvas->drawRRect()` で描画する。ここで `BlurRegion` の `left/top/right/bottom` は `SurfaceComposerClient::Transaction::setBlurRegions()` から入り、`LayerState` の parcel、`LayerSnapshotBuilder`、`LayerFE` を経由して RenderEngine へ渡る。 結果として、攻撃者が小さい layer bounds と大きい blur region を組み合わせると、blur 出力が本来の layer 領域外へ広がる。公開アドバイザリはこれを `drawLayersInternal` における GPU cache side-channel information disclosure と説明している。 原因(根本原因) 根本原因は、blur region の描画範囲と layer の所有範囲を別物として扱っていたこと。`blurRect` は blur 入力画像生成用に layer bounds から計算され display clip と交差させられているが、実際に描画される `effectRegion` はクライアント指定の `BlurRegion` であり、pre-patch では通常矩形 layer のとき layer bounds による canvas clip がなかった。 つまり「blur の計算元」は layer bounds で制限されていたが、「blur の描画先」は常に layer bounds で制限されていなかった。 どこから特定したか validated.md の「参照した公開情報」「何が修正されたか」 / Android bug参照 A-455563813 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://android.googlesource.com/platform/frameworks/native/+/c81cf361489e3a3cd764c0a0c85c84958e25d63c, https://github.com/advisories/GHSA-2p8v-r473-9vxr, https://www.originhq.com/research/patch-diffing-pipeline validated.md を表示# CVE-2025-48630 検証結果 ## 判定 ok。AOSP の修正コミットと該当ソースから、脆弱性の原因と発火条件を説明できる。 - CVE: CVE-2025-48630 - Android Bulletin: March 2026、Framework、ID、High、A-455563813 - 修正コミット: `c81cf361489e3a3cd764c0a0c85c84958e25d63c` - リポジトリ: `platform/frameworks/native` - 修正ファイル: `libs/renderengine/skia/SkiaRenderEngine.cpp` - 付帯ファイル: - `analysis/c81cf361_patch.diff` - `analysis/commit_metadata.txt` - `analysis/source_context.txt` - `analysis/repro_model.md` ## 何が修正されたか 修正は 1 ファイル 4 行追加のみ。`SkiaRenderEngine::drawLayersInternal()` の blur 描画処理で、従来は `roundRectClip` が空でない場合だけ `canvas->clipRRect(roundRectClip, true)` を適用していた。 パッチ後は `roundRectClip` が空の場合にも `canvas->clipRRect(bounds, true)` を実行する。コミットメッセージにも、blur が layer bounds から「escape」でき、1-2 pixel の小さい layer でも crafted blur region によって画面全体を埋められる、と説明されている。 ## 脆弱性の内容 SurfaceFlinger の Skia RenderEngine が、クライアント指定の `BlurRegion` を layer bounds に必ずしも clip せずに描画していた。通常の矩形 layer で rounded-corner crop が不要な場合、`getBoundsAndClip()` は `bounds` を返す一方で `roundRectClip` を空にする。この状態では pre-patch の blur 描画経路が canvas clip を張らない。 その後、`layer.blurRegions` 由来の矩形が `getBlurRRect(region)` で `SkRRect` に変換され、`BlurFilter::drawBlurRegion()` が `canvas->drawRect()` または `canvas->drawRRect()` で描画する。ここで `BlurRegion` の `left/top/right/bottom` は `SurfaceComposerClient::Transaction::setBlurRegions()` から入り、`LayerState` の parcel、`LayerSnapshotBuilder`、`LayerFE` を経由して RenderEngine へ渡る。 結果として、攻撃者が小さい layer bounds と大きい blur region を組み合わせると、blur 出力が本来の layer 領域外へ広がる。公開アドバイザリはこれを `drawLayersInternal` における GPU cache side-channel information disclosure と説明している。 ## 根本原因 根本原因は、blur region の描画範囲と layer の所有範囲を別物として扱っていたこと。`blurRect` は blur 入力画像生成用に layer bounds から計算され display clip と交差させられているが、実際に描画される `effectRegion` はクライアント指定の `BlurRegion` であり、pre-patch では通常矩形 layer のとき layer bounds による canvas clip がなかった。 つまり「blur の計算元」は layer bounds で制限されていたが、「blur の描画先」は常に layer bounds で制限されていなかった。 ## 発火条件 ソースから導ける最小条件は次の通り。 1. デバイス/構成が blur composition をサポートしている。 2. クライアントが `setBlurRegions()` で `eBlurRegionsChanged` を送る。 3. layer geometry の bounds は 1x1 や 2x2 のように小さい。 4. `BlurRegion.left/top/right/bottom` は layer bounds より大きく、画面の広い範囲を覆う。 5. layer が通常矩形で、`roundRectClip` が空になる。 6. pre-patch の `drawLayersInternal()` が `BlurFilter::drawBlurRegion()` を呼び、canvas clip なしで大きい blur region を描く。 修正後は 5 の場合でも `canvas->clipRRect(bounds, true)` が必ず入るため、6 の描画は layer bounds 内に閉じ込められる。 ## 面白い点・調査メモ - Android Bulletin では種別が ID だが、GitHub Advisory/NVD 系の説明では「local escalation of privilege」と CVSS `AV:L/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H` が付いている。公開情報だけ見ると表現にずれがある。今回のパッチ自体は layer 外描画を止める情報漏えい対策として読むのが自然。 - コミットの `Test: PoC app` から、Google 内部では実際に小さい layer と crafted blur region を使う PoC app が存在したと見られる。 - 修正は非常に小さいが、描画パイプライン上は SurfaceFlinger/RenderEngine の境界で効く。入力 validation ではなく、最終描画前の強制 clip で直しているため、既存 API 互換性を壊しにくい修正になっている。 - `BlurRegion` は `uint32_t blurRadius`、`float alpha`、`int left/top/right/bottom` などを持つだけで、構造体自体には layer bounds との整合性チェックがない。 - private bug `A-455563813` と内部 cherrypick 元は非公開だが、公開 AOSP コミットだけで原因箇所は十分に特定できた。 ## 参照した公開情報 - Android Security Bulletin March 2026: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - AOSP commit: https://android.googlesource.com/platform/frameworks/native/+/c81cf361489e3a3cd764c0a0c85c84958e25d63c - GitHub Advisory mirror: https://github.com/advisories/GHSA-2p8v-r473-9vxr - 参考にした patch-diffing pipeline 記事: https://www.originhq.com/research/patch-diffing-pipeline ## 検証限界 実機またはエミュレータでの PoC 実行はしていない。理由は private PoC が公開されておらず、このジョブではソース差分解析が主目的だったため。ただし、修正コミット、描画処理、入力経路、発火条件は AOSP ソース上で確認済みであり、脆弱性の特定としては ok と判断する。 cve.md を表示# CVE-2025-48630 - Framework ID High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48630 - Component: Framework - Reference: A-455563813 - Type: ID - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 24 | OK | CVE-2026-0012 - Framework ID High |
024
ok
CVE-2026-0012 - Framework ID High024-ok-ExpandableNotificationRow-hideSensitive-contact-name-leak cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(結論) CVE-2026-0012 は Android Framework/SystemUI の通知行表示処理における情報漏えいで、`ExpandableNotificationRow.setHideSensitive()` の公開/非公開レイアウト切替アニメーションをスキップする条件が広すぎたことが根本原因である。 公開情報では「`ExpandableNotificationRow.java` の `setHideSensitive` におけるロジックエラーにより contact name leak が起きる」と説明されている。AOSP の修正コミット `ef2a8e20316405ce6b704e800b1808c3aaf5ee43` はこの説明と一致し、`shouldSkipHideSensitiveAnimation` の条件を次のように修正している。 [コードブロック省略] このため、修正前は feature flag `skipHideSensitiveNotifAnimation` が有効で、かつ `mShowingPublic` が変化しない場合、公開表示中でなくても hide-sensitive アニメーションがスキップされていた。修正後は「すでに公開レイアウトを表示しており、表示レイアウトも変わらない」場合だけスキップする。 原因(根本原因) 根本原因は、security-sensitive な public/private content 切替を、単純な「`mShowingPublic` が変わったかどうか」だけで最適化したことにある。 `setHideSensitive()` の状態は少なくとも次の三つに分かれている。 - 実際に public layout を表示すべきか: `mShowingPublic` - レイアウト計算上 public layout を使うべきか: `mHideSensitiveForIntrinsicHeight` - 現在の view alpha/visibility が前回アニメーションから正しく復帰しているか 修正前コードはこの三つを区別せず、`skipHideSensitiveNotifAnimation` が有効なら `isShowingLayoutNotChanged` だけでスキップできると仮定していた。この仮定が誤りで、特に `mShowingPublic == false` の private 表示側では alpha を 1 に戻す処理が必要になる。 修正コミットのメッセージにも「表示レイアウトが変わらず `mShowingPublic` が true のときだけ hide sensitive animation を再生したくない。現行コードは aggressive すぎて content alpha が 0 になり得る」とある。つまり修正意図は、最適化の適用範囲を public 表示中の安全なケースに限定することである。 どこから特定したか Android bug参照 A-392614656 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://android.googlesource.com/platform/frameworks/base/+/ef2a8e20316405ce6b704e800b1808c3aaf5ee43%5E%21/, https://nvd.nist.gov/vuln/detail/CVE-2026-0012 validated.md を表示# CVE-2026-0012 検証結果
## 結論
CVE-2026-0012 は Android Framework/SystemUI の通知行表示処理における情報漏えいで、`ExpandableNotificationRow.setHideSensitive()` の公開/非公開レイアウト切替アニメーションをスキップする条件が広すぎたことが根本原因である。
公開情報では「`ExpandableNotificationRow.java` の `setHideSensitive` におけるロジックエラーにより contact name leak が起きる」と説明されている。AOSP の修正コミット `ef2a8e20316405ce6b704e800b1808c3aaf5ee43` はこの説明と一致し、`shouldSkipHideSensitiveAnimation` の条件を次のように修正している。
```diff
- Flags.skipHideSensitiveNotifAnimation() && isShowingLayoutNotChanged;
+ mShowingPublic && isShowingLayoutNotChanged;
```
このため、修正前は feature flag `skipHideSensitiveNotifAnimation` が有効で、かつ `mShowingPublic` が変化しない場合、公開表示中でなくても hide-sensitive アニメーションがスキップされていた。修正後は「すでに公開レイアウトを表示しており、表示レイアウトも変わらない」場合だけスキップする。
## パッチ情報
- Bulletin: Android Security Bulletin - March 2026
- CVE: CVE-2026-0012
- Android bug: A-392614656
- Component: Framework
- Type: ID
- Severity: High
- Updated AOSP versions: 14, 15, 16
- 修正コミット: `ef2a8e20316405ce6b704e800b1808c3aaf5ee43`
- 親コミット: `bc34b284c508cc5ffaa27b153acdeb896c3eb9ca`
- 対象ファイル: `packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java`
保存した付帯ファイル:
- `artifacts/ef2a8e20316405ce6b704e800b1808c3aaf5ee43.diff`
- `artifacts/ef2a8e20316405ce6b704e800b1808c3aaf5ee43.json`
- `artifacts/ExpandableNotificationRow.before.java`
- `artifacts/ExpandableNotificationRow.after.java`
## 重要なコード構造
`ExpandableNotificationRow` は通知内容を private layout と public layout に分けて持つ。
- `mPrivateLayout`: 通知の通常内容。メッセージ通知では連絡先名や本文など、ロック画面で隠すべき情報を含む。
- `mPublicLayout`: sensitive notification 用の公開/伏せ字表示。
- `mShowingPublic`: `setHideSensitive()` 内で更新される実表示用の状態。
- `mHideSensitiveForIntrinsicHeight`: `setHideSensitiveForIntrinsicHeight()` で先に渡される、レイアウト計算用の hide-sensitive 状態。
`setHideSensitiveForIntrinsicHeight()` は stack scroller 更新のかなり早い段階で呼ばれ、public/private のどちらの高さを使うかを先に反映するための API である。一方、`setHideSensitive()` は後段で実際の visibility と alpha animation を更新する。
修正前後の中心部分は以下である。
```java
boolean oldShowingPublic = mShowingPublic;
mShowingPublic = mSensitive && hideSensitive;
boolean isShowingLayoutNotChanged = mShowingPublic == oldShowingPublic;
final boolean shouldSkipHideSensitiveAnimation =
Flags.skipHideSensitiveNotifAnimation() && isShowingLayoutNotChanged; // 修正前
```
この後、`!animated || shouldSkipHideSensitiveAnimation` の分岐に入ると、`NotificationContentAlphaOptimization.isEnabled()` が有効で、かつ `mShowingPublic != oldShowingPublic` が false の場合は `resetAllContentAlphas()` を呼ばない。つまり、前回の表示遷移やキャンセル済みアニメーションで private/public layout の alpha が 0 のまま残っている場合でも、その alpha を 1 に戻さずに visibility だけを更新できてしまう。
修正後は以下になる。
```java
final boolean shouldSkipHideSensitiveAnimation =
mShowingPublic && isShowingLayoutNotChanged;
```
これにより、private layout を表示すべき状態、つまり `mShowingPublic == false` のときは、表示レイアウトが「変化なし」に見えてもスキップしない。`animateShowingPublic(..., false)` に入り、private layout を `VISIBLE` にして alpha 0 から 1 へ戻す経路が実行される。
## 脆弱性条件
ソースコードから再構成できる条件は次の通り。
1. sensitive notification が存在する。メッセージ通知など、private layout に連絡先名が含まれる通知が対象になる。
2. lockscreen / notification shade の hide-sensitive 状態が変化する、または通知行が再利用・再初期化される。
3. `NotificationContentAlphaOptimization` と `skipHideSensitiveNotifAnimation` 系の最適化が有効である。
4. `setHideSensitive()` 呼び出し時に `mShowingPublic == oldShowingPublic` となり、修正前コードが「表示レイアウトは変化していない」と判断する。
5. しかし実際には private/public layout の alpha が以前のアニメーション状態を引きずっており、alpha をリセットまたは再アニメーションしなければならない。
修正前は 4 の条件だけでアニメーションをスキップしていたため、公開表示でない場合にも必要な alpha 復帰処理が省略された。結果として、hide-sensitive の視覚状態と実際に見える notification content の状態がずれ、ロック画面や通知表示の遷移中に、本来隠すべき連絡先名が表示される可能性がある。
## 根本原因
根本原因は、security-sensitive な public/private content 切替を、単純な「`mShowingPublic` が変わったかどうか」だけで最適化したことにある。
`setHideSensitive()` の状態は少なくとも次の三つに分かれている。
- 実際に public layout を表示すべきか: `mShowingPublic`
- レイアウト計算上 public layout を使うべきか: `mHideSensitiveForIntrinsicHeight`
- 現在の view alpha/visibility が前回アニメーションから正しく復帰しているか
修正前コードはこの三つを区別せず、`skipHideSensitiveNotifAnimation` が有効なら `isShowingLayoutNotChanged` だけでスキップできると仮定していた。この仮定が誤りで、特に `mShowingPublic == false` の private 表示側では alpha を 1 に戻す処理が必要になる。
修正コミットのメッセージにも「表示レイアウトが変わらず `mShowingPublic` が true のときだけ hide sensitive animation を再生したくない。現行コードは aggressive すぎて content alpha が 0 になり得る」とある。つまり修正意図は、最適化の適用範囲を public 表示中の安全なケースに限定することである。
## なぜ情報漏えいになるか
notification の public/private layout は、ロック画面で通知内容を隠すための境界である。private layout には連絡先名などの個人情報が含まれ、public layout はそれを伏せるために使われる。
今回のバグはメモリ破壊ではなく UI state の整合性バグである。visibility と alpha animation の状態がずれると、hide-sensitive の状態遷移中に「本来 public layout だけが見えるべきタイミング」で private layout 由来の表示が残る、または再表示される。CVE の説明が contact name leak としているのはこのためで、攻撃者は追加権限なし・ユーザー操作なしに、端末画面上の通知から連絡先名を観測できる可能性がある。
## 検証メモ
- `setHideSensitiveForIntrinsicHeight()` は visibility を変える関数ではなく、先に intrinsic height を計算するための通知である。この事前状態と実表示状態を混同すると、表示中レイアウトの判定が直感とずれる。
- 修正は 1 行だけだが、`resetAllContentAlphas()` を呼ぶか、`animateShowingPublic()` で alpha を戻すかに影響するため、実際のセキュリティ境界に直結している。
- `mShowingPublicInitialized && isShowingLayoutNotChanged` の早期 return があるため、問題になるのは単純な通常更新だけではなく、行の reset/reinflate 後など `mShowingPublicInitialized` が false になる初期化経路が重要と考えられる。
- AOSP ソースと公開 CVE 説明が一致し、修正コミットにも A-392614656 が明記されているため、これは source-level に特定できた脆弱性として `ok` 判定にできる。
## 参考
- Android Security Bulletin - March 2026: https://source.android.com/docs/security/bulletin/2026/2026-03-01
- AOSP 修正差分: https://android.googlesource.com/platform/frameworks/base/+/ef2a8e20316405ce6b704e800b1808c3aaf5ee43%5E%21/
- NVD CVE-2026-0012: https://nvd.nist.gov/vuln/detail/CVE-2026-0012
cve.md を表示# CVE-2026-0012 - Framework ID High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0012 - Component: Framework - Reference: A-392614656 - Type: ID - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 25 | OK | CVE-2026-0025 - Framework ID High |
025
ok
CVE-2026-0025 - Framework ID High025-ok-Notification-MessagingStyle-message-array-uri-grant-ID cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(何が脆弱だったか) `NotificationRecord.calculateGrantableUris()` は通知内に含まれる `content://` URI を集めるため、`notification.visitUris()` を呼ぶ。集められた URI は `NotificationManagerService.updateUriPermissions()` により、通知を受け取る listener / renderer 側パッケージへ read grant される。 修正前の `Notification.visitUris()` は、MessagingStyle 用 extras を読む際に `EXTRA_MESSAGES` を `Parcelable[]` として取得していた。その後の `MessagingStyle.Message.getMessagesFromBundleArray()` は、配列中の `Bundle` だけを message として復元し、`Bundle` ではない要素は無視する。 この組み合わせにより、攻撃者は `EXTRA_MESSAGES` に次の2種類を混在させられた。 - 正規の message `Bundle`: sender `Person` の icon に `content://com.android.contacts/display_photo/1` のような URI を含める。 - 非 `Bundle` の Parcelable: 配列の schema を壊し、typed get の前提を崩す。 修正前は非 `Bundle` 要素が無視される一方、正規 message `Bundle` は処理されるため、message sender icon URI が `visitGrantableUri()` まで到達する。投稿アプリがその URI を grant できる権限を持っていれば、通知リスナーなど別パッケージに read grant が付... 原因(根本原因) 根本原因は、通知 extras という Binder 境界越しの非信頼入力に対して、Framework が `MessagingStyle` message 配列の要素型を厳密に検証していなかったこと。 `EXTRA_MESSAGES` / `EXTRA_HISTORIC_MESSAGES` は実質的に `Bundle[]` であり、`Notification.MessagingStyle.Message.toBundle()` / `getMessageFromBundle()` を前提にしている。しかし URI grant 計算、画像有無判定、style 復元では `Parcelable[]` として受けていた。さらに `getMessagesFromBundleArray()` は非 `Bundle` をエラーにせず無視するため、「壊れた Parcelable 配列の中にある有効な message Bundle」だけが処理される状態になっていた。 パッチは message 配列を `Bundle.class` で取得することで、schema 違反の配列を早期に失敗させる。これは URI grant の前提になる `visitUris()` だけでなく、`hasImage()` と `restoreFromExtras()` にも同じ型制約を入れて、MessagingStyle 全体の解釈を揃えている。 どこから特定したか validated.md の「参照情報」「パッチ差分」 / Android bug参照 A-433746973 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://android.googlesource.com/platform/frameworks/base/+/014dea279c49d532bc4fbbdebbc024133967b6a8 validated.md を表示# CVE-2026-0025 検証結果
## 判定
判定: **ok**
脆弱性は Framework の `Notification` / `MessagingStyle` extras 処理における message 配列の型検証不足だった。`EXTRA_MESSAGES` / `EXTRA_HISTORIC_MESSAGES` は実際には `Bundle[]` として扱うべき schema だが、修正前は `Parcelable[]` として読まれており、攻撃者が非 `Bundle` Parcelable を混ぜた message 配列を system_server に渡せた。これにより、message 内の `Person` icon URI が通知の URI grant 計算に到達し、通知リスナー等へ本来持たない `content://` URI read grant が渡る情報漏えいが成立し得た。
フォルダ名候補: `025-ok-Notification-MessagingStyle-message-array-uri-grant-ID`
## 参照情報
- Android Security Bulletin March 2026: `https://source.android.com/docs/security/bulletin/2026/2026-03-01`
- ASB上の記載: `CVE-2026-0025 / A-433746973 / Framework / ID / High / Android 14, 15, 16, 16-qpr2`
- 公開修正コミット: `https://android.googlesource.com/platform/frameworks/base/+/014dea279c49d532bc4fbbdebbc024133967b6a8`
- Commit subject: `Be more strict about content types for message array`
- 親コミット: `1e6af3296d50e3786f33afbbdcc80aa115a18172`
## パッチ差分
修正コミット `014dea279c49d532bc4fbbdebbc024133967b6a8` は `core/java/android/app/Notification.java` の message 配列取得を `Parcelable.class` から `Bundle.class` に変更した。対象は主に次の3箇所。
- `Notification.visitUris()`
- `Notification.hasImage()`
- `Notification.MessagingStyle.restoreFromExtras()`
修正前:
```java
final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES,
Parcelable.class);
```
修正後:
```java
final Bundle[] messages =
getParcelableArrayFromBundle(extras, EXTRA_MESSAGES, Bundle.class);
```
`getParcelableArrayFromBundle()` は既存 helper で、内部では `Parcelable[]` を対象型の配列へコピーする。`itemClass` が `Bundle.class` の場合、非 `Bundle` 要素が混ざっていると `Bundle[]` へ格納できず例外になり、後段の message 復元に進まない。
## 何が脆弱だったか
`NotificationRecord.calculateGrantableUris()` は通知内に含まれる `content://` URI を集めるため、`notification.visitUris()` を呼ぶ。集められた URI は `NotificationManagerService.updateUriPermissions()` により、通知を受け取る listener / renderer 側パッケージへ read grant される。
修正前の `Notification.visitUris()` は、MessagingStyle 用 extras を読む際に `EXTRA_MESSAGES` を `Parcelable[]` として取得していた。その後の `MessagingStyle.Message.getMessagesFromBundleArray()` は、配列中の `Bundle` だけを message として復元し、`Bundle` ではない要素は無視する。
この組み合わせにより、攻撃者は `EXTRA_MESSAGES` に次の2種類を混在させられた。
- 正規の message `Bundle`: sender `Person` の icon に `content://com.android.contacts/display_photo/1` のような URI を含める。
- 非 `Bundle` の Parcelable: 配列の schema を壊し、typed get の前提を崩す。
修正前は非 `Bundle` 要素が無視される一方、正規 message `Bundle` は処理されるため、message sender icon URI が `visitGrantableUri()` まで到達する。投稿アプリがその URI を grant できる権限を持っていれば、通知リスナーなど別パッケージに read grant が付与され、連絡先写真などの情報が漏えいする。
## 根本原因
根本原因は、通知 extras という Binder 境界越しの非信頼入力に対して、Framework が `MessagingStyle` message 配列の要素型を厳密に検証していなかったこと。
`EXTRA_MESSAGES` / `EXTRA_HISTORIC_MESSAGES` は実質的に `Bundle[]` であり、`Notification.MessagingStyle.Message.toBundle()` / `getMessageFromBundle()` を前提にしている。しかし URI grant 計算、画像有無判定、style 復元では `Parcelable[]` として受けていた。さらに `getMessagesFromBundleArray()` は非 `Bundle` をエラーにせず無視するため、「壊れた Parcelable 配列の中にある有効な message Bundle」だけが処理される状態になっていた。
パッチは message 配列を `Bundle.class` で取得することで、schema 違反の配列を早期に失敗させる。これは URI grant の前提になる `visitUris()` だけでなく、`hasImage()` と `restoreFromExtras()` にも同じ型制約を入れて、MessagingStyle 全体の解釈を揃えている。
## 追加テストから分かる攻撃条件
追加された `NotificationManagerServiceTest.testNoUriGrantsForBadMessagesList()` は、脆弱性の本質をかなり直接示している。
テストは `content://com.android.contacts/display_photo/1` を `Person` の icon URI にした MessagingStyle notification を作成する。その後、`EXTRA_MESSAGING_PERSON` を削除し、`EXTRA_MESSAGES` に `MyParceledListSlice` という不正 Parcelable を追加してから enqueue する。
期待値は次の通り。
- enqueue は message 配列の typed 変換で `ArrayStoreException` になる。
- contacts photo URI に対して `mUgmInternal.checkGrantUriPermission(...)` が呼ばれない。
つまり修正後の正しい挙動は、「壊れた message 配列では、URI grant の事前検査にも進まない」ことである。逆に言えば、修正前は同じような壊れた `EXTRA_MESSAGES` でも正規 message 部分が処理され、contacts photo URI が grant 対象になり得た。
`MyParceledListSlice` は `Intent` を継承しつつ、Parcel 上のクラス名を `android.content.pm.ParceledListSlice` に書き換え、Binder 経由で別 Parcelable を返すテスト用 gadget になっている。これは単純な型不一致だけでなく、Parcelable の遅延復元や typed Bundle API の弱い前提を突く入力を再現している。
## 攻撃シナリオ
1. 攻撃アプリが MessagingStyle notification を作る。
2. message sender の `Person` icon に、攻撃アプリが読み取りまたは grant 可能な `content://` URI を設定する。追加テストでは contacts display photo URI が使われている。
3. `Notification.extras[EXTRA_MESSAGES]` に、正規 message `Bundle` と非 `Bundle` Parcelable を混ぜる。
4. 修正前の system_server は `EXTRA_MESSAGES` を `Parcelable[]` として読み、非 `Bundle` 要素を無視しながら正規 message の URI を列挙する。
5. `NotificationRecord` がその URI を grantable と記録する。
6. 通知リスナー通知前に `NotificationManagerService.updateUriPermissions()` が listener package へ URI read grant を発行する。
7. listener 側は本来持たないプロバイダ上のデータ、例えば連絡先写真 URI を読める。
## 調査中に分かったこと
- コミットメッセージの「Now with fewer class cast exceptions」は、単にクラッシュ修正というより、型違反 message 配列を早期に落として URI grant 計算へ進ませない意味を持つ。
- `Notification.visitUris()` のコメントは、通知を描画する受信者が URI を読めるよう permission grant する前提で URI を列挙すると説明している。今回の ID はこの grant 対象 URI の列挙が攻撃者制御の壊れた extras に影響された問題だった。
- `EXTRA_MESSAGING_PERSON` も `Person.visitUris()` で URI が列挙される。追加テストがこれを削除しているのは、問題の URI が message 配列経由で grant 対象になることを分離して確認するため。
- `getMessagesFromBundleArray()` は公開 API 互換性のためか非 `Bundle` を無視する作りになっており、この寛容さが Binder 境界の入力検証としては危険だった。
- `EXTRA_HISTORIC_MESSAGES` も同じ修正対象であり、過去メッセージ配列にも同根の問題があったと見られる。
## 保存した付帯ファイル
- `artifacts/014dea279c49.commit.json`: Gitiles commit JSON
- `artifacts/014dea279c49.patch`: 公開パッチ差分
- `artifacts/Notification_before.java`: 修正前 `Notification.java`
- `artifacts/Notification_after.java`: 修正後 `Notification.java`
- `artifacts/NotificationManagerService_parent.java`: URI grant 経路確認用
- `artifacts/NotificationRecord_parent.java`: `calculateGrantableUris()` / `visitGrantableUri()` 確認用
- `artifacts/NotificationManagerServiceTest_before.java`: 修正前テスト
- `artifacts/NotificationManagerServiceTest_after.java`: 追加テスト確認用
- `artifacts/Bundle_parent.java`, `artifacts/BaseBundle_parent.java`: typed `Bundle` API 確認用
- `artifacts/ParceledListSlice_parent.java`, `artifacts/BaseParceledListSlice_parent.java`: テスト gadget の復元挙動確認用
- `artifacts/analysis_notes.md`: 調査メモ
- `artifacts/exploit_model.md`: 攻撃モデル
- `artifacts/key_snippets.txt`: 主要コード抜粋
- `artifacts/SHA256SUMS`: 付帯ファイルの SHA-256
## 結論
CVE-2026-0025 は、Framework の Notification/MessagingStyle extras 処理で message 配列の型を `Bundle[]` に固定していなかったことによる情報漏えいだった。攻撃者は `EXTRA_MESSAGES` に正規 message `Bundle` と不正 Parcelable を混在させ、message 内 `Person` icon の `content://` URI を system_server の通知 URI grant 処理に到達させられた。修正は `EXTRA_MESSAGES` / `EXTRA_HISTORIC_MESSAGES` を `Bundle.class` で取得し、壊れた配列を早期に失敗させることで、通知リスナー等への不適切な URI read grant を防いでいる。
cve.md を表示# CVE-2026-0025 - Framework ID High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0025 - Component: Framework - Reference: A-433746973 - Type: ID - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 26 | OK | CVE-2025-48644 - Framework DoS High |
026
ok
CVE-2025-48644 - Framework DoS High026-ok-IME-metadata-subtype-persistent-DoS cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework DoS High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) 攻撃者は IME サービスを持つアプリを用意し、`android.view.im` metadata の `<input-method>` / `<subtype>` 属性に巨大な `@string/...` リソースを参照させる。修正前の `InputMethodInfo` は metadata の raw XML ファイルサイズだけを `MAX_METADATA_SIZE_BYTES`、つまり 200KB で検査していたが、`TypedArray.getString()` が解決した後の文字列サイズを累積検査していなかった。 そのため、XML 自体は小さいまま、大きな string resource を複数属性・複数 subtype から参照できる。システム側が IME 情報をロードすると、解決済み文字列が `InputMethodSubtype` / `InputMethodInfo` に取り込まれ、メモリ消費増大、パース失敗、または Binder 応答の巨大化につながる。IME アプリがインストール/有効化状態に残る限り、再起動後や IME 一覧再構築時にも同じ入力が再処理され得るため「persistent DoS」になる。 原因(根本原因) 根本原因は、信頼境界を越えて取り込む IME metadata のサイズ検証が raw XML に偏っていたこと。Android resource の `@string` 参照は metadata XML ファイル外にあり、`res.openRawResource(resourceId)` による XML バイト数検査では展開後の文字列量を測れない。にもかかわらず修正前コードは、`settingsActivity` など一部のコンポーネント名長だけを個別確認し、subtype の `languageTag` / `imeSubtypeLocale` / `imeSubtypeMode` / `imeSubtypeExtraValue` などの解決後文字列を累積制限していなかった。 どこから特定したか validated.md の「参照した公開情報」「パッチ解析」 / Android bug参照 A-449181366 validated.md を表示# CVE-2025-48644 検証結果 ## 判定 判定: ok タイトル: IME metadata/subtype の巨大リソースによる永続 DoS 根拠: Android Security Bulletin 2026-03-01 の Framework 欄で CVE-2025-48644 / A-449181366 は `platform/frameworks/base` の commit `2bca2265ff3e26b09f9b31c31063147a94e4c5aa` にリンクされている。該当パッチのソース差分から、IME (`InputMethodService`) の metadata XML が参照する巨大 string resource を `InputMethodInfo` 生成時に展開し、従来の 200KB 制限を迂回できることが確認できた。ローカル低権限アプリが IME サービスとしてインストールされると、システムの IME スキャン/問い合わせ処理で OOM や過大 Binder transaction を誘発し得るため、CVE record の「persistent denial of service due to improper input validation」と一致する。 ## 参照した公開情報 - ASB: `artifacts/android-security-bulletin-2026-03-01.html` - CVE record: `artifacts/CVERecord-CVE-2025-48644.html` - 一次パッチ: `artifacts/patch_2bca2265.diff` - Commit: `2bca2265ff3e26b09f9b31c31063147a94e4c5aa` - 件名: `Harden InputMethodInfo parsing against large metadata` - Bug: `449181366` ほか - 関連パッチ: `artifacts/patch_a438ce17.diff` - Commit: `a438ce172b441c8297eadde8d990ab292f5aa7d1` - 件名: `Introduce InputMethodSubtypeSafeList` - 同じ `Bug: 449181366` を含む。同 bug 束の追加 hardening と判断した。 ## 脆弱性の内容 攻撃者は IME サービスを持つアプリを用意し、`android.view.im` metadata の `<input-method>` / `<subtype>` 属性に巨大な `@string/...` リソースを参照させる。修正前の `InputMethodInfo` は metadata の raw XML ファイルサイズだけを `MAX_METADATA_SIZE_BYTES`、つまり 200KB で検査していたが、`TypedArray.getString()` が解決した後の文字列サイズを累積検査していなかった。 そのため、XML 自体は小さいまま、大きな string resource を複数属性・複数 subtype から参照できる。システム側が IME 情報をロードすると、解決済み文字列が `InputMethodSubtype` / `InputMethodInfo` に取り込まれ、メモリ消費増大、パース失敗、または Binder 応答の巨大化につながる。IME アプリがインストール/有効化状態に残る限り、再起動後や IME 一覧再構築時にも同じ入力が再処理され得るため「persistent DoS」になる。 ## 根本原因 根本原因は、信頼境界を越えて取り込む IME metadata のサイズ検証が raw XML に偏っていたこと。Android resource の `@string` 参照は metadata XML ファイル外にあり、`res.openRawResource(resourceId)` による XML バイト数検査では展開後の文字列量を測れない。にもかかわらず修正前コードは、`settingsActivity` など一部のコンポーネント名長だけを個別確認し、subtype の `languageTag` / `imeSubtypeLocale` / `imeSubtypeMode` / `imeSubtypeExtraValue` などの解決後文字列を累積制限していなかった。 ## パッチ解析 ### commit 2bca2265 修正前: - `InputMethodInfo_before_2bca.java` 317-362 行付近で、`res.obtainAttributes()` から得た `TypedArray` を直接読み、`getString()` / `getBoolean()` / `getResourceId()` の読み取り量を追跡していなかった。 - 同 461-498 行付近の `validateXmlMetaData()` は XML raw resource を `skip()` して 200KB 超過を確認するだけだった。 - subtype パースでは `<subtype>` ごとに `TypedArray` を直接読み、複数 subtype による累積サイズ増加を止める仕組みがなかった。 修正後: - `MetadataReadBytesTracker` と `TypedArrayWrapper` を導入。 - `InputMethodInfo_after_2bca.java` 319-409 行付近で `<input-method>` と `<subtype>` の全属性読み取りが wrapper 経由になった。 - 同 1222-1233 行付近で `getString()` は解決後 Java 文字列長を `length * Character.BYTES` として累積。 - 同 1285-1299 行付近で累積読み取り量が `MAX_METADATA_SIZE_BYTES` を超えると `XmlPullParserException` を投げ、IME をロードしない。 - `settingsActivity` / `languageSettingsActivity` は従来の 1000 文字制限も wrapper 側で維持された。 追加テスト `InputMethodInfoTest_after_2bca.java` では、1000 文字 string を 103 回読むと `1000 * 2 * 103 = 206000` bytes となり 200KB 制限を超えて例外になることを確認している。これは修正意図が「解決済み metadata 属性の累積サイズ制限」であることを直接示している。 ### 関連 commit a438ce17 同じ `Bug: 449181366` を持つ後続/関連パッチでは、`IInputMethodManager.getEnabledInputMethodSubtypeList()` の返却型を `List<InputMethodSubtype>` から `InputMethodSubtypeSafeList` に変更している。 - 修正前 AIDL: `IInputMethodManager_before_a438.aidl` 68-71 行で `List<InputMethodSubtype>` を直接返却。 - 修正後 AIDL: `IInputMethodManager_after_a438.aidl` 69-72 行で `InputMethodSubtypeSafeList` を返却。 - サービス側は `InputMethodManagerService_after_a438.java` 1744-1756 行付近で内部リストを `InputMethodSubtypeSafeList.create(...)` に包む。 - `AbstractSafeList_after_a438.java` は `Parcel.writeBlob()` / `readBlob()` を使う。大きな blob は Binder transaction 本体に全量を載せずに扱えるため、`TransactionTooLargeException` を避ける目的の修正である。 ASB の直接リンクは `2bca2265` だが、CVE description の "multiple locations" と、同じ bug ID 束に紐づく `a438ce17` の内容から、IME metadata 由来の巨大 subtype データが Binder 応答でも DoS 面を持っていたことが分かる。 ## 攻撃条件と影響 - 攻撃条件: ローカルアプリとして悪意ある IME サービスをインストールする。追加実行権限は不要とされるが、実際に IME としてシステムが metadata を読む必要がある。 - ユーザー操作: CVE record では不要。パッケージスキャン、IME 一覧取得、入力メソッド設定などシステム側の通常処理で到達可能。 - 影響: system_server または IME 情報を問い合わせるクライアント側のメモリ圧迫、パース失敗、`TransactionTooLargeException` による機能停止。悪意ある IME が残ると再発するため永続 DoS。 ## 数値モデル 補助モデル: `artifacts/ime_metadata_dos_model.py` 出力: `artifacts/ime_metadata_dos_model_output.txt` 興味深い点として、パッチ内コメントは Android resource の string attribute に実質 32768 文字の制限があると述べている。Java 文字列は概算 2 bytes/char なので、32768 文字の属性 1 個で約 65536 bytes になる。4 subtype が同じ巨大文字列属性を 1 個ずつ持つだけで約 262144 bytes となり、修正後の 200KB 累積制限を超える。複数属性を参照させれば 1 subtype でも 200KB を超え、8 subtype 程度で 1MB 前後の Binder transaction 上限にも到達し得る。 ## 調査メモ - CVE record は CWE-20 / improper input validation。これは raw XML のサイズ検証と、解決後 resource 値のサイズ検証を混同した問題として妥当。 - 修正後も subtype 文字列の個別長は `Integer.MAX_VALUE` 扱いで、個別上限ではなく累積 200KB で止めている。コメントには `TODO(b/456008595)` があり、将来的に個別属性上限を検討する余地が残っている。 - `settingsActivity` と `languageSettingsActivity` は component name として 1000 文字上限を維持している一方、`stylusHandwritingSettingsActivity` は TODO に残っている。 - `InputMethodInfoSafeList` は既に存在していた。今回の関連パッチは同じ SafeList パターンを subtype リストにも拡張しているため、過去に IME info 一覧でも同種の Binder サイズ問題が認識されていたと見られる。 ## 保存した付帯ファイル - `artifacts/commit_2bca2265.json` - `artifacts/commit_a438ce17.json` - `artifacts/patch_2bca2265.diff` - `artifacts/patch_a438ce17.diff` - `artifacts/InputMethodInfo_before_2bca.java` - `artifacts/InputMethodInfo_after_2bca.java` - `artifacts/InputMethodInfoTest_after_2bca.java` - `artifacts/IInputMethodManager_before_a438.aidl` - `artifacts/IInputMethodManager_after_a438.aidl` - `artifacts/InputMethodManagerService_before_a438.java` - `artifacts/InputMethodManagerService_after_a438.java` - `artifacts/InputMethodSubtypeSafeList_after_a438.java` - `artifacts/AbstractSafeList_after_a438.java` - `artifacts/ime_metadata_dos_model.py` - `artifacts/ime_metadata_dos_model_output.txt` cve.md を表示# CVE-2025-48644 - Framework DoS High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48644 - Component: Framework - Reference: A-449181366 - Type: DoS - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework DoS High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 27 | OK | CVE-2026-0014 - Framework DoS High |
027
ok
CVE-2026-0014 - Framework DoS High027-ok-AppOps-SDK-sandbox-attribution-tag-DoS cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework DoS High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性が起きる状況) 問題になるのは AppOps の proxy attribution 経路。 `noteProxyOperationImpl()` や `startProxyOperationImpl()` は `AttributionSource` から proxy 側と proxied 側の UID/package/attributionTag を取り出し、最終的に `noteOperationUnchecked()` / `startOperationUnchecked()` へ渡す。そこで `verifyAndGetBypass(uid, packageName, attributionTag, proxyUid, proxyPackageName)` が呼ばれる。 `verifyAndGetBypass()` には、root や non-app UID などの attribution tag 検証を proxy が迂回できるか判定する箇所があり、コメントには「system proxy 以外に attribution tag 検証を迂回させると、abusive apps が proxy calls で AppOps system を unlimited attribution tags で clog できる」と明記されている。この安全弁が `isPackageNullOrSystem(proxyPackageName, proxyUid)` だった。 旧コードでは、SDK sandbox UID が system package として解決される proxy package を使うと、この安全弁が true になり得る。その結果、攻撃者は proxy app-op 呼び出しで未宣言・任意の `attributionTag` を有効扱いにできる。 原因(根本原因) 根本原因は、`isPackageNullOrSystem(packageName, uid)` が **package の system 性** と **呼び出し UID の信頼性** を混同していたこと。 旧実装では以下の順序で trusted 判定をしていた。 1. `packageName == null` なら true 2. `uid` の appId が `FIRST_APPLICATION_UID` 未満なら true 3. `mPackageManagerInternal.isSystemPackage(packageName)` が true なら true SDK sandbox UID は `Process.FIRST_SDK_SANDBOX_UID` から `LAST_SDK_SANDBOX_UID`、つまり `20000..29999` の範囲にある。通常 app UID とは別レンジだが、SDK sandbox の実装に使われる package は system package として存在し得る。そのため旧コードでは、UID 自体は sandbox で untrusted にすべきなのに、package が system package であることだけで `isPackageNullOrSystem()` が true を返していた。 修正版では `packageName` が non-null の場合に `Process.isSdkSandboxUid(uid)` を先に見て false を返す。これにより SDK sandbox UID は、system package 名を伴っていても attribution tag 検証を迂回できなくなった。 どこから特定したか validated.md の「参照情報」「パッチ差分」 / Android bug参照 A-443742082 validated.md を表示# CVE-2026-0014 検証結果
## 判定
**ok - 脆弱性を特定できた。**
対象は Android Framework の `AppOpsService` で、SDK sandbox UID が AppOps の attribution tag 検証において system/trusted proxy として扱われることにより、任意の attribution tag を大量に AppOps 状態へ登録できる DoS だったと判断する。
## 参照情報
- Advisory: Android Security Bulletin - March 2026
- CVE: `CVE-2026-0014`
- Bug reference: `A-443742082`
- Component: Framework
- Severity: High
- Type: DoS
- Patch commit: `b51a58ecec96558e1c6b1d47728f45a8795dc7ab`
- Commit message: `Ensure sandboxed UIDs are treated as untrusted in Appops`
- 変更ファイル: `services/core/java/com/android/server/appop/AppOpsService.java`
保存した主な付帯ファイル:
- `artifacts/b51a58ecec96558e1c6b1d47728f45a8795dc7ab.patch`
- `artifacts/b51a58ecec96558e1c6b1d47728f45a8795dc7ab.commit.txt`
- `artifacts/AppOpsService.before.java`
- `artifacts/AppOpsService.after.java`
- `artifacts/AppOpsService.diff`
- `artifacts/AppOpsService_before_verify_snippet.txt`
- `artifacts/AppOpsService_after_verify_snippet.txt`
- `artifacts/AppOpsService_noteProxyOperation_snippet.txt`
- `artifacts/AppOpsService_startProxyOperation_snippet.txt`
- `artifacts/AppOpsService_getOpsLocked_snippet.txt`
- `artifacts/AppOpsService_attributedOps_snippet.txt`
- `artifacts/AppOpsService_verifyIncomingProxyUid_snippet.txt`
- `artifacts/Process_android16.java`
- `artifacts/AppOpsManager_android16.java`
- `artifacts/exploitability_notes.md`
## パッチ差分
実パッチは非常に小さく、`isPackageNullOrSystem()` に SDK sandbox UID を拒否する分岐を追加しているだけだった。
```diff
private boolean isPackageNullOrSystem(String packageName, int uid) {
if (packageName == null) {
return true;
}
+ if (Process.isSdkSandboxUid(uid)) {
+ return false;
+ }
int appId = UserHandle.getAppId(uid);
if (appId > 0 && appId < Process.FIRST_APPLICATION_UID) {
return true;
}
return mPackageManagerInternal.isSystemPackage(packageName);
}
```
コミットメッセージは「sandboxed UID を AppOps で untrusted として扱う」「attribution tag validation 目的では system app と見なすべきでない」と説明している。`Test: atest AppOpsMemoryUsageTest` とあり、DoS がメモリ消費系であることとも整合する。
## 根本原因
根本原因は、`isPackageNullOrSystem(packageName, uid)` が **package の system 性** と **呼び出し UID の信頼性** を混同していたこと。
旧実装では以下の順序で trusted 判定をしていた。
1. `packageName == null` なら true
2. `uid` の appId が `FIRST_APPLICATION_UID` 未満なら true
3. `mPackageManagerInternal.isSystemPackage(packageName)` が true なら true
SDK sandbox UID は `Process.FIRST_SDK_SANDBOX_UID` から `LAST_SDK_SANDBOX_UID`、つまり `20000..29999` の範囲にある。通常 app UID とは別レンジだが、SDK sandbox の実装に使われる package は system package として存在し得る。そのため旧コードでは、UID 自体は sandbox で untrusted にすべきなのに、package が system package であることだけで `isPackageNullOrSystem()` が true を返していた。
修正版では `packageName` が non-null の場合に `Process.isSdkSandboxUid(uid)` を先に見て false を返す。これにより SDK sandbox UID は、system package 名を伴っていても attribution tag 検証を迂回できなくなった。
## 脆弱性が起きる状況
問題になるのは AppOps の proxy attribution 経路。
`noteProxyOperationImpl()` や `startProxyOperationImpl()` は `AttributionSource` から proxy 側と proxied 側の UID/package/attributionTag を取り出し、最終的に `noteOperationUnchecked()` / `startOperationUnchecked()` へ渡す。そこで `verifyAndGetBypass(uid, packageName, attributionTag, proxyUid, proxyPackageName)` が呼ばれる。
`verifyAndGetBypass()` には、root や non-app UID などの attribution tag 検証を proxy が迂回できるか判定する箇所があり、コメントには「system proxy 以外に attribution tag 検証を迂回させると、abusive apps が proxy calls で AppOps system を unlimited attribution tags で clog できる」と明記されている。この安全弁が `isPackageNullOrSystem(proxyPackageName, proxyUid)` だった。
旧コードでは、SDK sandbox UID が system package として解決される proxy package を使うと、この安全弁が true になり得る。その結果、攻撃者は proxy app-op 呼び出しで未宣言・任意の `attributionTag` を有効扱いにできる。
## DoS メカニズム
`verifyAndGetBypass()` が `isAttributionTagValid = true` を返すと、呼び出し側は attribution tag を null に落とさず、そのまま AppOps の内部状態へ保存する。
具体的には:
- `noteOperationUnchecked()` / `startOperationUnchecked()` が `getOpsLocked(uid, packageName, attributionTag, pvr.isAttributionTagValid, ...)` を呼ぶ
- `getOpsLocked()` は `ops.knownAttributionTags.add(attributionTag)` を実行する
- valid の場合は `ops.validAttributionTags.add(attributionTag)` も実行する
- さらに `Op.getOrCreateAttribution()` が `mDeviceAttributedOps` に `AttributionTag -> AttributedOp` の新規 entry を作る
したがって、sandbox 側から proxy app-op 呼び出しを繰り返し、毎回異なる長い/一意な attribution tag を渡すと、system_server 内の AppOps 状態が unbounded に増える。これが Framework DoS High の実体と考えられる。
パッチ後は SDK sandbox proxy が trusted 扱いされないため、未宣言 attribution tag は invalid になり、`noteOperationUnchecked()` / `startOperationUnchecked()` 側で `attributionTag = null` に落とされる。結果として任意タグごとの `AttributedOp` 増殖が止まる。
## 面白い点・調査メモ
- 差分は 4 行だけだが、影響は AppOps の proxy attribution と SDK sandbox UID モデルの境界にある。
- `Process.isSdkSandboxUid()` は `UserHandle.getAppId(uid)` 後に `20000..29999` を見る。通常 app UID より後ろのレンジで、`getAppUidForSdkSandboxUid()` により app UID へ戻せる 1:1 対応がある。
- 既存コードには「SDK sandbox processes run in their own UID range, but their associated UID for checks should always be the UID of the package implementing SDK sandbox service」という TODO 付きコメントがある。つまり AppOps 内でも sandbox UID と実装 package UID の扱いが暫定的で、今回のバグはその隙間に出ている。
- 最初は `packageName == null` が true になる経路を疑ったが、今回のパッチ位置から見ると null package は修正対象ではない。実際の問題は non-null の sandbox 実装 package が system package と判定される経路だった。
- `verifyIncomingProxyUid()` は `AttributionSource.getUid() == Binder.getCallingUid()` なら通すため、sandbox プロセス自身が proxy 側 UID として AppOps proxy API に入ることは設計上想定されている。
- コミットのテスト名が `AppOpsMemoryUsageTest` であり、コメント中の "unlimited attribution tags" と内部データ構造の増加が一致する。
## 結論
CVE-2026-0014 は、SDK sandbox UID を AppOps attribution tag validation で system/trusted proxy と誤判定したことによる Framework DoS。根本原因は `isPackageNullOrSystem()` が system package 判定だけで trust を与え、SDK sandbox UID を明示的に除外していなかったこと。攻撃条件は、SDK sandbox 経由の proxy AppOps 呼び出しで任意 attribution tag を大量投入できる状況で、結果として system_server の AppOps attribution 状態が増殖する。
cve.md を表示# CVE-2026-0014 - Framework DoS High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0014 - Component: Framework - Reference: A-443742082 - Type: DoS - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework DoS High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 28 | OK | CVE-2026-0015 - Framework DoS High |
028
ok
CVE-2026-0015 - Framework DoS High028-ok-AppOps-untrusted-proxy-attribution-tag-DoS cve.md の Android / Pixel 脆弱性情報
cve.md summary Framework DoS High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(何の脆弱性だったか) CVE-2026-0015 は `frameworks/base` の `AppOpsService.java` にある AppOps attribution tag 検証不備だった。未信頼 proxy 経路の呼び出しでも、proxy package 側の manifest に存在する attribution tag を proxied package の有効な tag として扱ってしまい、攻撃者が AppOps の内部状態に任意の attribution tag を作らせることができた。 これにより、権限不要・ユーザー操作不要のローカルアプリが、大量の tag を使って AppOps の永続状態を膨張させられる。影響は `system_server` 側の永続的な denial of service と整理できる。 原因(根本原因) 根本原因は、`verifyAndGetBypass` が「proxy が信頼済みか」を入力として持っていなかったこと。修正前は tag が本来の package に存在しない場合でも proxy package で `isAttributionInPackage(proxyPkg, attributionTag)` が真なら valid としていた。trusted proxy には必要な互換動作だが、`OP_FLAG_UNTRUSTED_PROXIED` の場合にも同じ fallback が適用されていた。 パッチでは `OP_FLAG_UNTRUSTED_PROXIED` から `proxyTrusted` を計算し、`verifyAndGetBypass(..., isProxyTrusted, ...)` に渡すようになった。`isProxyTrusted=false` のときは proxy package の tag を valid 判定に使わない。 どこから特定したか validated.md の「パッチ解析」 / Android bug参照 A-445917646 validated.md を表示# CVE-2026-0015 検証結果 ## 判定 `ok`。AOSP の公開ソース差分から、脆弱性の場所、根本原因、悪用時に永続 DoS になる状態遷移を特定できた。 ## 何の脆弱性だったか CVE-2026-0015 は `frameworks/base` の `AppOpsService.java` にある AppOps attribution tag 検証不備だった。未信頼 proxy 経路の呼び出しでも、proxy package 側の manifest に存在する attribution tag を proxied package の有効な tag として扱ってしまい、攻撃者が AppOps の内部状態に任意の attribution tag を作らせることができた。 これにより、権限不要・ユーザー操作不要のローカルアプリが、大量の tag を使って AppOps の永続状態を膨張させられる。影響は `system_server` 側の永続的な denial of service と整理できる。 ## 根本原因 根本原因は、`verifyAndGetBypass` が「proxy が信頼済みか」を入力として持っていなかったこと。修正前は tag が本来の package に存在しない場合でも proxy package で `isAttributionInPackage(proxyPkg, attributionTag)` が真なら valid としていた。trusted proxy には必要な互換動作だが、`OP_FLAG_UNTRUSTED_PROXIED` の場合にも同じ fallback が適用されていた。 パッチでは `OP_FLAG_UNTRUSTED_PROXIED` から `proxyTrusted` を計算し、`verifyAndGetBypass(..., isProxyTrusted, ...)` に渡すようになった。`isProxyTrusted=false` のときは proxy package の tag を valid 判定に使わない。 ## パッチ解析 主修正は `a4523e227733ae20eafe4ec3e85474a5b7ebf7c6.diff`。ASB が直接参照する commit で、commit message は "Prohibit untrusted proxys from specifying proxied attribution tags"。 重要な変更点: - `OP_FLAG_UNTRUSTED_PROXIED` を import し、`noteOperationUnchecked`、`startOperationUnchecked`、`startOperationDryRun` で `proxyTrusted = (flags & OP_FLAG_UNTRUSTED_PROXIED) == 0` を計算する。 - `verifyAndGetBypass` に `isProxyTrusted` 引数を追加し、root / sdk sandbox / 通常 package の proxy tag fallback に `isProxyTrusted && ...` を要求する。 - `startOperationDryRun` が attribution tag 付きで永続状態を作らないよう、最終形では `getOpsLocked(uid, packageName, null, ..., edit=true)` を使う。 - `finishOperationUnchecked` は `getOpLocked(..., edit=false)` に変わり、存在しない op/attribution を finish 経路で作らない。 - `getAttributedOpWithClientId` と `AttributedOp.hasInProgressEvent(Predicate)` が追加され、finish 時に clientId と trusted/untrusted flag が一致する既存 in-progress event だけを探す。 補助 commit の意味: - `110db0ac...`: upstream の初期修正。dry-run を `edit=false` にし、未信頼 proxy の tag 指定を拒否する。 - `c5ddffd...`: untrusted event が有効 tag 付きで存在する場合と null tag に落ちる場合を区別し、finish 時に誤った attribution を返さないよう補正。 - `4a63d960...`: dry-run の互換性のため `edit=true` に戻すが、tag は `null` にして任意 tag の記録を防ぐ。 ## 攻撃シナリオ 1. 攻撃者アプリが AppOps の note/start/dry-run 系 API を、proxy 情報付きで呼ぶ。 2. 呼び出しは未信頼 proxy として扱われるべきだが、修正前は proxy package 側に宣言された attribution tag が valid と判定される。 3. `startOperationDryRun` や note/start 経路が、proxied package の AppOps 状態にその tag を作成・記録する。 4. 攻撃者が tag 文字列を大量に変化させると、AppOps の永続状態が膨張する。 5. その状態は一回の Binder 呼び出しで解消されず、AppOps の管理・保存・読み込み処理に負荷を与え続け、persistent DoS になる。 ## 保存した付帯ファイル - `artifacts/ASB-A-445917646.json`: OSV/ASB レコード。 - `artifacts/android-security-bulletin-2026-03-01.html`: Android Security Bulletin 保存コピー。 - `artifacts/asb_cve_2026_0015_excerpt.txt`: ASB の CVE-2026-0015 該当表抜粋。 - `artifacts/a4523e227733ae20eafe4ec3e85474a5b7ebf7c6.diff`: ASB 直リンクの代表パッチ。 - `artifacts/110db0acb84cbd21f9da9391ab242d141ebf390c.diff`: upstream 元修正。 - `artifacts/c5ddffd4869d8e82fba0b0237fa1b50db1b7b9d2.diff`: finish 補正。 - `artifacts/4a63d960496052db7c997bbfbdba11075d06b572.diff`: dry-run 補正。 - `artifacts/*_numbered.txt`: 上記 diff の行番号付きコピー。 - `analysis_notes.md`: 調査時のメモ。 ## 調査メモ 公開 CVE レコードは「AppOpsService.java の複数箇所」としか説明していないが、commit message と差分はかなり直接的だった。面白いのは `startOperationDryRun` の扱いで、単純に `edit=false` にすると互換性問題があったらしく、後続 commit で `edit=true` かつ `attributionTag=null` に変わっている。これは「dry-run で必要な親 `Ops` は作ってよいが、攻撃者制御の tag は known attribution tag として残してはいけない」という、DoS 根本原因に合わせた最小修正になっている。 cve.md を表示# CVE-2026-0015 - Framework DoS High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0015 - Component: Framework - Reference: A-445917646 - Type: DoS - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary Framework DoS High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 29 | OK | CVE-2026-0006 - System RCE Critical |
029
ok
CVE-2026-0006 - System RCE Critical029-ok-libopenapv-bitstream-bounds-rce cve.md の Android / Pixel 脆弱性情報
cve.md summary System RCE Critical vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) OpenAPV の APV bitstream decoder が、攻撃者制御のサイズ値と bitstream 終端を十分に検証しないまま、metadata payload、filler/dummy data、VLC 符号、tile/frame data を読み進めていた。これにより、細工された APV/MP4 入力で heap 上の bitstream buffer を OOB read でき、decode 状態が崩れた場合は `dec_tile_comp()` の block 出力経路から caller が渡した画像 buffer への OOB write に到達し得る。 特に重要な差分: - `src/oapv_bs.c` / `src/oapv_bs.h` - `bs->end = buf + size - 1` から `bs->end = buf + size` へ変更。 - `BSR_IS_EOB`, `BSR_IS_LAST_BYTE`, `BSR_GET_LEFT_BYTE`, `oapv_bsr_peek()`, `oapv_bsr_sink()` が one-past-end 前提に修正。 - 旧実装は inclusive end と `<=` / `+1` 判定が混在し、終端近傍で残量を過大評価しやすい。 - `src/oapv_vlc.c` - `oapvd_vlc_tile_dummy_data()` が `while(bs->cur <= bs->end)` から `while(bs->cur < bs->end)` へ修正。 - `oapvd_vlc_metadata()` に `BSR_GET_LEFT_BYTE(bs) >= payload_size` が追加され、宣言 payload サイズが実残量を超える場合に拒否するようになった。 - metadata payload は旧実装では `payload_size` 分を heap 確保... 原因(根本原因) 根本原因は、OpenAPV decoder の bitstream cursor 境界モデルが不統一で、入力内の宣言サイズを信頼する箇所に実残量チェックが不足していたこと。 旧実装は `end` を「最後の有効 byte」として持つ関数と、「one-past-end」のように扱う判定が混在していた。さらに metadata payload などでは、`metadata_size` という論理カウンタだけで `payload_size <= metadata_size` を確認し、実際の `bs->cur` から `bs->end` までの残り byte 数を確認していなかった。攻撃者は PBU/metadata/tile/VLC のサイズ値を矛盾させることで、decoder に buffer 終端を越えて読み進めさせられる。 どこから特定したか validated.md の「参照した公開情報」 / Android bug参照 A-423894847 validated.md を表示# CVE-2026-0006 検証結果 ## 判定 OK。AOSP 公開ソース差分から、CVE-2026-0006 は Android 16 の Media Codecs Mainline に含まれる OpenAPV decoder (`external/libopenapv`) の bitstream 境界管理不備に起因する RCE と判断できる。 ASB の A-423894847 は `platform/external/libopenapv` の 3 commit にリンクされており、主修正は `cf0a0e7a810e5a0f6e50f433c1d723b12160e8dd` (`Upgrade libopenapv to v0.2.0.0`) だった。この commit だけが `Bug: 423894847` を明記している。 ## 参照した公開情報 - Android Security Bulletin 2026-03-01: `CVE-2026-0006`, `A-423894847`, System / Media Codecs, RCE, Critical, updated AOSP versions 16 - NVD: “possible out of bounds read and write due to a heap buffer overflow” - Gitiles: - `86a76fd73bf7636af018331d4419eaa56ca95083`: local fix revert - `c81fcd419c489dd4aa9efd0ed41fb6c38f853b4f`: libopenapv v0.1.13.1 - `cf0a0e7a810e5a0f6e50f433c1d723b12160e8dd`: libopenapv v0.2.0.0, `Bug: 423894847` 保存物は `artifacts/` 以下。主要ファイルは `git_show_cf0a0e7_v0.2.0.0.patch`, `v0.1.13.1_to_v0.2.0.0_core.diff`, `oapv_bs_*`, `oapv_vlc_*`, `oapv_c_*`。 ## 脆弱性の内容 OpenAPV の APV bitstream decoder が、攻撃者制御のサイズ値と bitstream 終端を十分に検証しないまま、metadata payload、filler/dummy data、VLC 符号、tile/frame data を読み進めていた。これにより、細工された APV/MP4 入力で heap 上の bitstream buffer を OOB read でき、decode 状態が崩れた場合は `dec_tile_comp()` の block 出力経路から caller が渡した画像 buffer への OOB write に到達し得る。 特に重要な差分: - `src/oapv_bs.c` / `src/oapv_bs.h` - `bs->end = buf + size - 1` から `bs->end = buf + size` へ変更。 - `BSR_IS_EOB`, `BSR_IS_LAST_BYTE`, `BSR_GET_LEFT_BYTE`, `oapv_bsr_peek()`, `oapv_bsr_sink()` が one-past-end 前提に修正。 - 旧実装は inclusive end と `<=` / `+1` 判定が混在し、終端近傍で残量を過大評価しやすい。 - `src/oapv_vlc.c` - `oapvd_vlc_tile_dummy_data()` が `while(bs->cur <= bs->end)` から `while(bs->cur < bs->end)` へ修正。 - `oapvd_vlc_metadata()` に `BSR_GET_LEFT_BYTE(bs) >= payload_size` が追加され、宣言 payload サイズが実残量を超える場合に拒否するようになった。 - metadata payload は旧実装では `payload_size` 分を heap 確保して `oapv_bsr_read()` で読み続けていた。v0.2.0.0 では bitstream 内 pointer と明示的な残量確認に変わった。 - DC/AC VLC decode は 4 byte flush 前提の処理から 1 byte flush (`BSR_FLUSH_1BYTE`) 中心に再実装され、終端処理が細かくなった。 - `src/oapv.c` - frame header の寸法から `ctx->w/h` と tile 数を作り、`dec_tile_comp()` が `d16 = dst + blk_y * stride + blk_x` に block を書く。したがって bitstream 側の寸法・tile・VLC 状態が壊れると heap 上の出力画像 buffer OOB write に直結する。 ## 根本原因 根本原因は、OpenAPV decoder の bitstream cursor 境界モデルが不統一で、入力内の宣言サイズを信頼する箇所に実残量チェックが不足していたこと。 旧実装は `end` を「最後の有効 byte」として持つ関数と、「one-past-end」のように扱う判定が混在していた。さらに metadata payload などでは、`metadata_size` という論理カウンタだけで `payload_size <= metadata_size` を確認し、実際の `bs->cur` から `bs->end` までの残り byte 数を確認していなかった。攻撃者は PBU/metadata/tile/VLC のサイズ値を矛盾させることで、decoder に buffer 終端を越えて読み進めさせられる。 ## 攻撃シナリオ 攻撃者は APV bitstream を含むメディアファイルを作る。Android 16 の media stack は Media Codecs Mainline の software APV decoder を使って、プレビュー、サムネイル、再生準備などで入力を処理し得る。追加権限や明示的なユーザー操作なしに parser/decoder が起動するため、ASB の RCE Critical と整合する。 最小モデルとして `artifacts/bitstream_bounds_model.c` を保存した。実残量 4 byte に対して attacker-controlled `payload_size=6` の場合、旧 metadata 経路は 6 byte 読もうとし、新経路は `-1` で拒否する。 ``` actual_left_bytes=4 attacker_payload_size=6 old_path_reads=6 new_path_reads=-1 ``` ## 調査中に分かったこと - ASB の “Google Play system updates” では Media Codecs / CVE-2026-0006 として Mainline 配布対象に入っている。 - `86a76fd...` は “APV: Local fix for OpenAPV library” の revert で、`aPv1` signature check を外している。単体では脆弱性修正ではなく、後続の upstream 更新とまとめて扱う必要がある。 - 第三者 PoC README は `oapvd_info()` と `oapvd_decode()` が異なる PBU の寸法を読む問題を root cause と説明している。ただし AOSP v0.2.0.0 後も `oapvd_info()` は AU_INFO PBU を見つけると後続 frame PBU を読まずに返るため、この仮説だけを今回の修正済み root cause として採用しなかった。興味深い未解決点として `artifacts/analysis_notes.md` に残した。 - 同 README には “actively exploited” とあるが、ASB が悪用の兆候を明記しているのは CVE-2026-21385 であり、CVE-2026-0006 ではない。この表現は採用しない。 ## 付帯ファイル - `artifacts/android-security-bulletin-2026-03-01.html` - `artifacts/CVE-2026-0006-nvd.html` - `artifacts/commit_*.json` - `artifacts/git_show_*.patch` - `artifacts/patch_*.diff` - `artifacts/v0.1.13.1_to_v0.2.0.0_core.diff` - `artifacts/oapv_bs_*`, `artifacts/oapv_vlc_*`, `artifacts/oapv_c_*` - `artifacts/bitstream_bounds_model.c` - `artifacts/bitstream_bounds_model_output.txt` - `artifacts/SHA256SUMS` cve.md を表示# CVE-2026-0006 - System RCE Critical ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0006 - Component: System - Subcomponent: Media Codecs - Reference: A-423894847 - Type: RCE - Severity: Critical - Updated AOSP versions: 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System RCE Critical vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 30 | OK | CVE-2025-48631 - System DoS Critical |
030
ok
CVE-2025-48631 - System DoS Critical030-ok-LocalImageResolver-image-dimension-DoS cve.md の Android / Pixel 脆弱性情報
cve.md summary System DoS Critical vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(判定) ok: 脆弱性をソースコードと公開パッチ差分から特定できた。 対象は AOSP `platform/frameworks/base` の `core/java/com/android/internal/widget/LocalImageResolver.java`。巨大な画像ヘッダ寸法を持つ GIF/JPEG 等を通知画像などとして処理すると、`ImageDecoder` が実際には端末メモリに収まらないサイズのデコード処理へ進み、SystemUI を含むシステム側プロセスでリソース枯渇による DoS / crash loop を起こせる問題だった。 原因(根本原因) 根本原因は、信頼できない画像ヘッダの論理寸法を上限検証せずに `ImageDecoder` へ渡していたこと。 Java 側で表示先を 480 x 480 などへ縮小指定しても、ネイティブ側の `ImageDecoder::decode()` は条件によって元画像寸法の一時 `SkBitmap tmp` を確保してからスケールする。`hwui_ImageDecoder.cpp` では `mDecodeSize` から作った `decodeInfo` で `Bitmap::allocateHeapBitmap(&tmp)` を呼ぶ経路があり、65535 x 65535 x 4 byte は約 16 GiB になる。これは通常の端末メモリを超えるため、SystemUI などが落ちる。 どこから特定したか validated.md の「根拠」「パッチ差分の意味」 / Android bug参照 A-444671303 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://osv.dev/vulnerability/ASB-A-444671303, https://android.googlesource.com/platform/frameworks/base/+/d6df825fda3aa29cff7af05357005322152210fd, https://hulkvision.github.io/blog/android-notification-dos/android-notification-dos/ validated.md を表示# CVE-2025-48631 検証結果 ## 判定 ok: 脆弱性をソースコードと公開パッチ差分から特定できた。 対象は AOSP `platform/frameworks/base` の `core/java/com/android/internal/widget/LocalImageResolver.java`。巨大な画像ヘッダ寸法を持つ GIF/JPEG 等を通知画像などとして処理すると、`ImageDecoder` が実際には端末メモリに収まらないサイズのデコード処理へ進み、SystemUI を含むシステム側プロセスでリソース枯渇による DoS / crash loop を起こせる問題だった。 ## 根拠 - Android OSV `ASB-A-444671303.json` は、`LocalImageResolver.java` の `onHeaderDecoded()` におけるリソース枯渇による persistent DoS として CVE-2025-48631 を記録している。 - 代表パッチ `d6df825fda3aa29cff7af05357005322152210fd` は `DEFAULT_DECODE_HARD_LIMIT_PX = 4096` を追加し、画像ヘッダの width / height が 4096 を超えたら `RuntimeException` でデコードを中断する。 - 同パッチは `test16000x16000.gif` を追加し、巨大画像で `LocalImageResolver.resolveImage(uri, mContext)` が `IOException` を投げることをテストしている。 保存した主な付帯ファイル: - `artifacts/patch_d6df825fda3aa29cff7.diff` - `artifacts/LocalImageResolver_before.java` - `artifacts/LocalImageResolver_after.java` - `artifacts/LocalImageResolverTest_after.java` - `artifacts/jni_ImageDecoder.cpp` - `artifacts/hwui_ImageDecoder.cpp` - `artifacts/memory_model.py` - `artifacts/analysis_notes.md` ## パッチ差分の意味 修正前の `onHeaderDecoded()` は、画像ヘッダから得た `Size` を使って `decoder.setTargetSampleSize(...)` を設定するだけだった。65,535 x 65,535 のような標準上は表現可能だが現実には巨大すぎる寸法でも、ヘッダ段階で拒否しなかった。 修正後は `DEFAULT_DECODE_HARD_LIMIT_PX = 4096` を導入し、どちらか一辺でも 4096 を超える画像をヘッダ段階で拒否する。コミットメッセージにも、65,535 x 65,535 はメモリに収まらないため、通知 crashloop を起こすケースを手動確認したとある。 ## 根本原因 根本原因は、信頼できない画像ヘッダの論理寸法を上限検証せずに `ImageDecoder` へ渡していたこと。 Java 側で表示先を 480 x 480 などへ縮小指定しても、ネイティブ側の `ImageDecoder::decode()` は条件によって元画像寸法の一時 `SkBitmap tmp` を確保してからスケールする。`hwui_ImageDecoder.cpp` では `mDecodeSize` から作った `decodeInfo` で `Bitmap::allocateHeapBitmap(&tmp)` を呼ぶ経路があり、65535 x 65535 x 4 byte は約 16 GiB になる。これは通常の端末メモリを超えるため、SystemUI などが落ちる。 ## 攻撃条件 攻撃者は巨大寸法を持つ小さな GIF などを、通知に画像プレビューが出る経路で被害者へ送る。ユーザー操作は不要。通知が生成されると SystemUI が画像を解決しようとして巨大デコードへ進み、クラッシュする。通知やメッセージが残る場合、SystemUI の再起動後も同じ通知処理が繰り返され、持続的な DoS になり得る。 ## 調査中に分かった面白い点 この修正は完全性に注意が必要。公開パッチは `resolveImage(Uri, Context)` が使う共通 `onHeaderDecoded()` には 4096 のハードリミットを入れているが、`resolveImage(ImageDecoder.Source, int, int)` のラムダには同じチェックが入っていない。この private overload は `maxWidth/maxHeight` に合わせて `decoder.setTargetSize(...)` するだけで、巨大寸法そのものは拒否しない。 公開研究では、December 2025 の修正後も Android 16 25Q4 で不完全修正として扱われ、March 2026 でも通知の max-size 経路に残存する crash loop が報告されている。今回保存した post-patch ソースもこの観察と整合する。つまり、CVE としての元問題は「ヘッダ寸法のハードリミット欠落」で特定できる一方、パッチ品質としては全ての `LocalImageResolver` デコード経路へ同じガードを適用していない点が弱い。 ## 参考URL - Android Security Bulletin March 2026: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - OSV ASB-A-444671303: https://osv.dev/vulnerability/ASB-A-444671303 - AOSP commit: https://android.googlesource.com/platform/frameworks/base/+/d6df825fda3aa29cff7af05357005322152210fd - Public residual analysis: https://hulkvision.github.io/blog/android-notification-dos/android-notification-dos/ cve.md を表示# CVE-2025-48631 - System DoS Critical ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48631 - Component: System - Reference: A-444671303 - Type: DoS - Severity: Critical - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System DoS Critical vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 31 | OK | CVE-2025-48577 - System EoP High |
031
ok
CVE-2025-48577 - System EoP High031-ok-keyguard-user-switch-race-lockscreen-bypass cve.md の Android / Pixel 脆弱性情報
cve.md summary System EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(判定) `ok` 脆弱性を特定できた。AOSP の公開パッチ `platform/frameworks/base` `78760f098fab75ae8e952978768d3c7df6312dbd` により、`KeyguardViewMediator.java` のユーザー切り替え中の非同期 keyguard 解除処理が修正されている。根本原因は、ユーザーに紐づくべき keyguard 解除状態と遅延 Runnable が、修正前はユーザーIDを保持せず、選択ユーザー変更後にも実行され得たこと。 原因(根本原因) 根本原因は、keyguard 解除がユーザー単位のセキュリティ境界であるにもかかわらず、修正前コードがその状態をユーザー単位で管理していなかったこと。 特に問題だった点は次の通り。 - `mKeyguardDonePending` が boolean のため、ユーザーAの pending とユーザーBの pending を区別できない。 - `mHideAnimationFinishedRunnable` がユーザーIDを capture せず、実行時のグローバル状態だけを見る。 - user switching 中に古い delayed dismiss/hide message が残り得る。 - biometric success callback で、渡された `userId` と現在選択ユーザーの一致を最初に検証していなかった。 このため、ユーザー切り替えと keyguard dismiss animation / biometric success / keyguard done の非同期完了が競合すると、古いユーザーの解除許可が新しいユーザーに適用される。 どこから特定したか validated.md の「参照情報」 / Android bug参照 A-413380719 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://android.googlesource.com/platform/frameworks/base/+/78760f098fab75ae8e952978768d3c7df6312dbd^!/ validated.md を表示# CVE-2025-48577 検証結果 ## 判定 `ok` 脆弱性を特定できた。AOSP の公開パッチ `platform/frameworks/base` `78760f098fab75ae8e952978768d3c7df6312dbd` により、`KeyguardViewMediator.java` のユーザー切り替え中の非同期 keyguard 解除処理が修正されている。根本原因は、ユーザーに紐づくべき keyguard 解除状態と遅延 Runnable が、修正前はユーザーIDを保持せず、選択ユーザー変更後にも実行され得たこと。 ## 参照情報 - Android Security Bulletin 2026-03-01: `https://source.android.com/docs/security/bulletin/2026/2026-03-01` - ASB 行: `CVE-2025-48577 / A-413380719 / System / EoP / High / Android 14, 15, 16` - CVE 説明: `KeyguardViewMediator.java` の複数関数における race condition により lockscreen bypass が可能。追加権限不要、ユーザー操作不要の local EoP。 - AOSP パッチ: `https://android.googlesource.com/platform/frameworks/base/+/78760f098fab75ae8e952978768d3c7df6312dbd^!/` - コミット件名: `Validate user on biometric auth and keyguard done` - Android bug: `A-413380719` ## 保存した付帯ファイル - `artifacts/patch_78760f098fab75ae8e952978768d3c7df6312dbd.diff`: 公開パッチ差分 - `artifacts/commit_78760f098fab75ae8e952978768d3c7df6312dbd.json`: Gitiles commit JSON - `artifacts/CVERecord-CVE-2025-48577.html`: CVE Record 取得結果 - `artifacts/analysis_notes.md`: 解析メモ - `artifacts/keyguard_user_switch_race_model.py`: 脆弱/修正版の状態遷移モデル - `artifacts/keyguard_user_switch_race_model.out`: モデル実行結果 - `artifacts/SHA256SUMS`: 付帯ファイルの SHA-256 ## パッチの要点 修正前の `KeyguardViewMediator` は、keyguard done の保留状態を `mKeyguardDonePending` という単一 boolean で持っていた。これは「どのユーザーに対する解除処理か」を表現できない。また、pre-hide animation 完了後に走る `mHideAnimationFinishedRunnable` も単一 Runnable で、スケジュール時点のユーザーIDを保持していなかった。 修正後は次のように変わっている。 - `mKeyguardDonePending` を `mKeyguardDonePendingForUser` に変更し、pending 状態に対象ユーザーIDを持たせた。 - `keyguardDone(int targetUserId)` から `tryKeyguardDone(targetUserId)` へユーザーIDを渡すようにした。 - `keyguardDonePending(int targetUserId)` は `new OnHideAnimationFinished(targetUserId)` を作り、非同期 Runnable にも発行時ユーザーIDを保持させた。 - `OnHideAnimationFinished.run()` は実行時の `mSelectedUserInteractor.getSelectedUserId()` と captured user を比較し、不一致なら `resetStateLocked()` して keyguard 解除へ進まない。 - `onBiometricAuthenticated()` は callback の `userId` が現在選択ユーザーと一致しない場合に即 return する。 - `handleBeforeUserSwitching()` は token 付き delayed dismiss callback、`DISMISS`、`HIDE` を削除し、pending 状態をリセットする。 - keyguard going-away の非同期 runnable も、実行時に `mGoingAwayRequestedForUserId` と現在ユーザーを再検証するようになった。 ## 脆弱性の成立条件 脆弱版では、以下のような順序で lockscreen bypass が成立し得る。 1. ユーザー A が選択されており、keyguard 解除処理が開始される。 2. `keyguardDonePending(A)` が `mKeyguardDonePending = true` を設定し、pre-hide animation 完了 Runnable を登録する。 3. Runnable 実行前、または biometric/keyguard done の非同期処理が完了する前に、選択ユーザーが B に切り替わる。 4. 修正前 Runnable はユーザーAを保持していないため、実行時の現在ユーザーBに対して `tryKeyguardDone()`/`handleKeyguardDone()` が進み得る。 5. 結果として、A 側の古い認証・解除完了イベントで B 側の keyguard が解除される。 これは「認証済みユーザー」と「現在選択ユーザー」の対応関係が非同期境界で失われる問題であり、典型的な race condition / stale authorization の問題である。 ## 根本原因 根本原因は、keyguard 解除がユーザー単位のセキュリティ境界であるにもかかわらず、修正前コードがその状態をユーザー単位で管理していなかったこと。 特に問題だった点は次の通り。 - `mKeyguardDonePending` が boolean のため、ユーザーAの pending とユーザーBの pending を区別できない。 - `mHideAnimationFinishedRunnable` がユーザーIDを capture せず、実行時のグローバル状態だけを見る。 - user switching 中に古い delayed dismiss/hide message が残り得る。 - biometric success callback で、渡された `userId` と現在選択ユーザーの一致を最初に検証していなかった。 このため、ユーザー切り替えと keyguard dismiss animation / biometric success / keyguard done の非同期完了が競合すると、古いユーザーの解除許可が新しいユーザーに適用される。 ## 検証 `artifacts/keyguard_user_switch_race_model.py` で最小状態機械を作り、次のレースを再現した。 - ユーザー25で `keyguardDonePending` を開始 - pre-hide animation 完了 Runnable を保存 - Runnable 実行前に現在ユーザーを40へ変更 - 脆弱版では Runnable がユーザーIDを持たないため、現在ユーザー40の keyguard が解除される - 修正版では Runnable がユーザー25を保持し、現在ユーザー40との不一致を検出して reset する 実行結果: ```text vulnerable: - old global hide-animation runnable executes - keyguard dismissed for current user 40 keyguard_showing=False patched: - user-bound hide-animation runnable executes for 25 - reset instead of dismiss; requested=25, current=40 keyguard_showing=True ``` ## 調査中に分かった面白い点 - パッチのコミットメッセージ自体がかなり直接的で、user switching 中に prior user を validate してしまうこと、dismiss animation 後にスケジュールされた Runnable がユーザー変更後に古い keyguard 解除を完了し得ることを説明している。 - 修正は1箇所の user check 追加ではなく、biometric callback、keyguard done、keyguard done pending、hide animation finished、before user switching、going-away runnable の複数箇所に入っている。これは単一の不備ではなく、非同期 keyguard 解除パス全体で user identity を保存・再検証する設計が不足していたことを示している。 - 追加テストは、異なるユーザーの biometric success が進まないこと、pre-hide animation Runnable がユーザー変更後に終了して shade collapse/reset へ進むことを確認しており、脆弱性の本質と一致している。 ## 結論 CVE-2025-48577 は `KeyguardViewMediator.java` のユーザー切り替え race による lockscreen bypass / local EoP。修正前は keyguard 解除状態と非同期 Runnable がユーザーIDを保持しないため、ユーザーAの解除完了イベントがユーザーBの keyguard に作用し得た。修正は user-scoped pending state と Runnable への user capture、実行時再検証、user switching 時の古い message 除去を追加して、この stale authorization を遮断している。 cve.md を表示# CVE-2025-48577 - System EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48577 - Component: System - Reference: A-413380719 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 32 | OK | CVE-2025-48602 - System EoP High |
032
ok
CVE-2025-48602 - System EoP High032-ok-keyguard-user-switch-exit-animation-lockscreen-bypass cve.md の Android / Pixel 脆弱性情報
cve.md summary System EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(判定) OK。ソースコード差分、公式 OSV/ASB 情報、AOSP の回帰テストから脆弱性の条件と根本原因を特定できた。 タイトル: `keyguard-user-switch-exit-animation-lockscreen-bypass` 原因(根本原因) 根本原因は、KeyguardViewMediator の非同期状態遷移で、keyguard exit animation の完了判定が user switch に対して原子的でなかったこと。 具体的には、keyguard を非表示にする `onKeyguardExitFinished()` が `postAfterTraversal()` で遅延される一方、`handleBeforeUserSwitching()` は pending の `START_KEYGUARD_EXIT_ANIM` を消さず、exit animation 全体をキャンセル状態にもしていなかった。さらに遅延 runnable 内でキャンセル状態を再確認しなかったため、旧ユーザーの unlock 完了処理が新ユーザーの keyguard 状態へ適用された。 どこから特定したか validated.md の「対象」「参照情報」「パッチ解析」 / Android bug参照 A-407562568 validated.md を表示# CVE-2025-48602 検証結果 ## 判定 OK。ソースコード差分、公式 OSV/ASB 情報、AOSP の回帰テストから脆弱性の条件と根本原因を特定できた。 タイトル: `keyguard-user-switch-exit-animation-lockscreen-bypass` ## 対象 - CVE: CVE-2025-48602 - Android bug: A-407562568 - Component: System / SystemUI - Severity: High - Type: EoP - 修正 SPL: 2026-03-01 - 対象ファイル: `packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java` - 主要修正コミット: `c69e16c3efda87ee6435184949549b2f088589b3` ## 参照情報 - Android Security Bulletin 2026-03-01: `artifacts/android-security-bulletin-2026-03-01.html` - OSV JSON: `artifacts/ASB-A-407562568.json` - 公式 diff: `artifacts/official_c69e16c3efda87ee6435184949549b2f088589b3.diff` - ローカル before/after: `artifacts/KeyguardViewMediator_before.java`, `artifacts/KeyguardViewMediator_after.java` - 回帰テスト差分: `artifacts/KeyguardViewMediatorTest.diff` - 状態遷移モデル: `artifacts/keyguard_exit_user_switch_model.py`, `artifacts/keyguard_exit_user_switch_model.out` OSV の説明では、`KeyguardViewMediator.java` の `exitKeyguardAndFinishSurfaceBehindRemoteAnimation` におけるロジックエラーにより lockscreen bypass が起き、追加権限やユーザー操作なしで local EoP につながるとされている。ASB では System の High として掲載されている。 ## 脆弱性の概要 これは、ユーザー切替と keyguard exit animation 完了処理の race による lockscreen bypass である。 問題の経路では、旧ユーザーで keyguard going away / surface-behind remote animation が始まり、`exitKeyguardAndFinishSurfaceBehindRemoteAnimation(false)` が呼ばれる。この関数は実際の keyguard 非表示処理を即時実行せず、`DejankUtils.postAfterTraversal()` で次の traversal 後に遅延実行する。 パッチ前は、`mIsKeyguardExitAnimationCanceled` の確認が runnable を post する前にしかなかった。そのため、post 後 runnable 実行前にセキュアな別ユーザーへの切替が発生しても、遅延 runnable は古い unlock/dismiss の流れとして `onKeyguardExitFinished()` を実行できた。`onKeyguardExitFinished()` は `setShowingLocked(false, ...)` により keyguard を非表示状態として通知するため、切替後のセキュアユーザーで lockscreen が消える。 ## 再現条件 AOSP の追加テスト `testGoingAwayFollowedByBeforeUserSwitchWithDelayedExitAnimationDoesNotHideKeyguard()` が条件を明確に示している。 1. 旧ユーザーを非セキュアとして keyguard を表示状態にする。 2. `showSurfaceBehindKeyguard()` と `startKeyguardExitAnimation()` により WM 側の exit animation を開始する。 3. `keyguardDonePending(oldUser)` と `readyForKeyguardDone()` を呼び、keyguard を完全に dismiss する流れに入る。 4. `postAfterTraversal` の runnable が実行される前に、セキュアな新ユーザーへ `handleBeforeUserSwitching(newUser)` する。 5. パッチ前は遅延 runnable がそのまま keyguard exit を完了し、keyguard が非表示になる。 6. パッチ後は `finishSurfaceBehindRemoteAnimation(true)` と `setShowingLocked(true, ..., "canceled")` に進み、keyguard 表示が維持される。 付帯モデル `artifacts/keyguard_exit_user_switch_model.py` の出力: ```text patched=False showing=False wm_finish_show_keyguard=False exit_animation_canceled=False patched=True showing=True wm_finish_show_keyguard=True exit_animation_canceled=True ``` ## パッチ解析 `handleBeforeUserSwitching()` の修正: - `mHandler.removeMessages(START_KEYGUARD_EXIT_ANIM)` を追加。 - `mIsKeyguardExitAnimationCanceled = true` を追加。 これにより、ユーザー切替開始時点で未処理の keyguard exit animation 開始メッセージを破棄し、進行中/遅延中の exit 完了処理もキャンセル済みとして扱う。 `exitKeyguardAndFinishSurfaceBehindRemoteAnimation()` の修正: - パッチ前に関数冒頭へ置かれていた `mIsKeyguardExitAnimationCanceled` チェックを削除。 - `postAfterTraversal()` の runnable 内、実際に `onKeyguardExitFinished()` を呼ぶ直前へキャンセルチェックを移動。 - キャンセル済みなら `finishSurfaceBehindRemoteAnimation(true)` で WM 側へ keyguard 表示維持を通知し、`setShowingLocked(true, true, "... canceled")` で SystemUI/ATMS 側の lockscreen 表示状態を強制更新する。 この変更は TOCTOU の修正である。呼び出し時には安全でも、遅延 runnable 実行時までに user switch で状態が変わるため、実行時点で再検証する必要があった。 ## 根本原因 根本原因は、KeyguardViewMediator の非同期状態遷移で、keyguard exit animation の完了判定が user switch に対して原子的でなかったこと。 具体的には、keyguard を非表示にする `onKeyguardExitFinished()` が `postAfterTraversal()` で遅延される一方、`handleBeforeUserSwitching()` は pending の `START_KEYGUARD_EXIT_ANIM` を消さず、exit animation 全体をキャンセル状態にもしていなかった。さらに遅延 runnable 内でキャンセル状態を再確認しなかったため、旧ユーザーの unlock 完了処理が新ユーザーの keyguard 状態へ適用された。 ## なぜ EoP になるか Android のユーザー切替では、新ユーザーがセキュアなら lockscreen を表示し、認証前にそのユーザーのセッションへ入れないことが境界になる。この不具合では、非セキュア旧ユーザー由来の keyguard dismiss 完了処理が、切替後のセキュア新ユーザーの keyguard を非表示にできる。結果として、新ユーザーの認証を経ずに lockscreen を bypass できるため local EoP となる。 ## 調査時メモ - `keyguardDonePending()` と `OnHideAnimationFinished` には userId mismatch 防止があるが、今回の脆弱性は remote animation 完了 runnable 経由なのでその保護対象外だった。 - パッチ前にも `mIsKeyguardExitAnimationCanceled` は存在したため、問題は「キャンセル概念の欠如」ではなく「キャンセルを user switch に伝播していないこと」と「遅延実行時点で再検証していないこと」だった。 - 修正テストは `postAfterTraversal()` をテスト用に override し、runnable を捕まえてから user switch 後に実行する。非決定的な UI race を単体テストで決定的に再現する良い形になっている。 - `artifacts/patch_c69e16c3efda87ee6435184949549b2f088589b3.diff` は既存ファイルだが空だったため、公式 Gitiles から `artifacts/official_c69e16c3efda87ee6435184949549b2f088589b3.diff` を取得して保存した。 ## 結論 CVE-2025-48602 は、SystemUI の KeyguardViewMediator において、keyguard exit animation の遅延完了処理とユーザー切替が競合し、セキュアな新ユーザーの lockscreen が旧ユーザーの dismiss 完了処理で非表示になる lockscreen bypass である。修正は user switch 時の exit animation キャンセルと、遅延 runnable 実行直前のキャンセル再検証であり、根本原因に対応している。 cve.md を表示# CVE-2025-48602 - System EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48602 - Component: System - Reference: A-407562568 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 33 | OK | CVE-2025-48641 - System EoP High |
033
ok
CVE-2025-48641 - System EoP High033-ok-Nfc-callback-shared_ptr-UAF-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary System EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(判定) ok。AOSP の修正コミットと該当ソースから、脆弱性の場所、競合条件、根本原因を特定できた。 - CVE: CVE-2025-48641 / A-392699284 - 種別: System EoP High - 対象: `platform/hardware/st/nfc` - 修正対象ファイル: `aidl/Nfc.h` - 問題の関数: `Nfc::eventCallback()` と `Nfc::dataCallback()` - 根本原因: グローバルな `std::shared_ptr<INfcClientCallback> Nfc::mCallback` を、HAL の非同期コールバックスレッドと NFC HAL AIDL サービスの `open()/close()` 側が十分に同期せず共有していたこと。 原因(根本原因) 根本原因は、`Nfc::mCallback` が「現在のクライアント callback」と「非同期 HAL callback 実行中の callback 寿命保持」という二つの役割を同時に担っていたのに、後者に必要なローカル強参照を取っていなかったこと。 旧実装の `if (mCallback != nullptr) mCallback->sendEvent(...)` は、単一スレッドなら自然に見えるが、非同期 callback thread と Binder thread が同時に動く設計ではチェックと使用が不可分ではない。`std::shared_ptr` を static にしているだけでは、別スレッドでの reset/代入と、現在スレッドでの dereference の間のオブジェクト寿命は保証されない。 どこから特定したか validated.md の「参照情報」「パッチ解析」 / Android bug参照 A-392699284 / 参照URL: https://android.googlesource.com/platform/hardware/st/nfc/+/c6da9eeb710c6690d189cb2d1b80b44755860b55, https://android.googlesource.com/platform/hardware/st/nfc/+/fc619c3348188ff0020cdeb7d4c4728a0246fe1a, https://android.googlesource.com/platform/hardware/st/nfc/+/07468d68ad37d8a7a430eb6433d6ca0e9ed9c589 validated.md を表示# CVE-2025-48641 検証メモ
## 判定
ok。AOSP の修正コミットと該当ソースから、脆弱性の場所、競合条件、根本原因を特定できた。
- CVE: CVE-2025-48641 / A-392699284
- 種別: System EoP High
- 対象: `platform/hardware/st/nfc`
- 修正対象ファイル: `aidl/Nfc.h`
- 問題の関数: `Nfc::eventCallback()` と `Nfc::dataCallback()`
- 根本原因: グローバルな `std::shared_ptr<INfcClientCallback> Nfc::mCallback` を、HAL の非同期コールバックスレッドと NFC HAL AIDL サービスの `open()/close()` 側が十分に同期せず共有していたこと。
## 参照情報
- Android Security Bulletin 2026-03-01: `CVE-2025-48641 A-392699284 EoP High 14, 15, 16, 16-qpr2`
- OSV: `ASB-A-392699284`
- OSV details: `In multiple functions of Nfc.h, there is a possible use after free due to a race condition.`
- 修正コミット:
- 共通/公開参照: https://android.googlesource.com/platform/hardware/st/nfc/+/c6da9eeb710c6690d189cb2d1b80b44755860b55
- main 系: https://android.googlesource.com/platform/hardware/st/nfc/+/fc619c3348188ff0020cdeb7d4c4728a0246fe1a
- Android 14: https://android.googlesource.com/platform/hardware/st/nfc/+/07468d68ad37d8a7a430eb6433d6ca0e9ed9c589
取得した OSV JSON と diff は `artifacts/` に保存した。
## パッチ解析
修正コミット `c6da9eeb710c6690d189cb2d1b80b44755860b55` の変更は `aidl/Nfc.h` だけで、差分は 18 行だった。
修正前の `eventCallback()` は次の形だった。
```cpp
if (mCallback != nullptr) {
...
auto ret = mCallback->sendEvent(mEvent, mStatus);
}
```
修正前の `dataCallback()` も同様に、`mCallback != nullptr` を確認した後、同じ static shared pointer を再参照して `sendData()` を呼んでいた。
この形だと、null チェック後から `sendEvent()` / `sendData()` の呼び出しまでの間に別スレッドが `Nfc::mCallback` を差し替えたり `nullptr` に戻したりできる。`std::shared_ptr` の参照先オブジェクトがその瞬間に最後の参照を失うと、コールバックスレッドは解放済みの `INfcClientCallback` に対して Binder 呼び出しを行う可能性がある。
修正後は `sCallbackLock` を追加し、コールバック関数の冒頭で `mCallback` をローカルの `std::shared_ptr<INfcClientCallback> localCallback` にコピーしてから使う。
```cpp
std::shared_ptr<INfcClientCallback> localCallback;
pthread_mutex_lock(&sCallbackLock);
localCallback = mCallback;
pthread_mutex_unlock(&sCallbackLock);
if (localCallback != nullptr) {
...
auto ret = localCallback->sendEvent(mEvent, mStatus);
}
```
重要なのは、ローカルコピーが作られることで `sendEvent()` / `sendData()` の実行中は対象 callback オブジェクトへの強参照が保持される点である。これにより、グローバルな `mCallback` が後続処理でクリアまたは差し替えられても、現在実行中の callback 呼び出しの寿命は保たれる。
## 競合が起きる構造
`aidl/hal_st21nfc.cc` では、HAL からの NFC event callback を直接上位へ返さず、専用スレッドへ載せ替える実装になっている。
- `StNfc_hal_open()` が `StNfc_hal_open(eventCallback, dataCallback)` 経由で callback 関数を登録する。
- `async_callback_thread_start()` が callback 用スレッドを起動する。
- `async_callback_post()` が event を `async_callback_data` に積み、condition variable で callback thread を起こす。
- callback thread の `async_callback_thread_fct()` が `dev.p_cback_unwrap(event, event_status)` を呼ぶ。
- `dev.p_cback_unwrap` が AIDL 側の `Nfc::eventCallback()` に到達する。
一方で `aidl/Nfc.cpp` では、Binder 呼び出しで入る `Nfc::open()` が `Nfc::mCallback = clientCallback` を行い、`Nfc::close()` が `StNfc_hal_close()` の後で `Nfc::mCallback = nullptr` を行う。つまり callback thread と Binder thread が同じ static callback pointer の寿命に関わる。
成立し得るシナリオは次の通り。
1. NFC HAL が開かれ、`Nfc::mCallback` に NFC service 側 callback が入る。
2. HAL/ドライバ側イベントにより `async_callback_post()` が callback thread にイベントを渡す。
3. callback thread が旧実装の `Nfc::eventCallback()` に入り、`mCallback != nullptr` を通過する。
4. 直後に別スレッドで `Nfc::open()` による callback 差し替え、または `Nfc::close()` による callback 解放が進む。
5. 旧 callback オブジェクトの最後の参照が失われた場合、callback thread は `mCallback->sendEvent()` / `mCallback->sendData()` で解放済みオブジェクトを使う。
これは単なる NULL dereference ではなく、`shared_ptr` が指していた Binder callback オブジェクトの寿命管理ミスによる use-after-free である。
## 根本原因
根本原因は、`Nfc::mCallback` が「現在のクライアント callback」と「非同期 HAL callback 実行中の callback 寿命保持」という二つの役割を同時に担っていたのに、後者に必要なローカル強参照を取っていなかったこと。
旧実装の `if (mCallback != nullptr) mCallback->sendEvent(...)` は、単一スレッドなら自然に見えるが、非同期 callback thread と Binder thread が同時に動く設計ではチェックと使用が不可分ではない。`std::shared_ptr` を static にしているだけでは、別スレッドでの reset/代入と、現在スレッドでの dereference の間のオブジェクト寿命は保証されない。
## 影響
公開情報上は local EoP、追加権限不要、ユーザー操作不要。現実の悪用可能性はデバイス構成に依存するが、このコードは STMicroelectronics NFC HAL 実装であり、NFC HAL プロセス内での UAF になる。攻撃者が NFC service/HAL の open/close や NFC イベント発生タイミングを制御または高頻度に誘導できる場合、HAL プロセスのクラッシュや、ヒープ再利用次第で権限昇格につながる可能性がある。
## 調査中に分かった面白い点
- 修正コミットのメッセージは原因をかなり明示しており、`eventCallback` が非同期スレッドで動き、`Nfc::open` が underlying object を破棄した直後に method call される、と説明している。
- 差分は `eventCallback()` だけでなく `dataCallback()` にも同じローカル `shared_ptr` パターンを適用している。OSV の説明が `multiple functions of Nfc.h` となっているのはこのため。
- `hal_st21nfc.cc` には「上位層での deadlock を避けるため常に callback を別スレッドに post する」というコメントがあり、この設計が callback と open/close の競合窓を作っている。
- パッチのコメントでは `read/write of mCallback` を保護すると説明しているが、確認した公開差分では `aidl/Nfc.cpp` の `Nfc::mCallback = clientCallback` / `Nfc::mCallback = nullptr` 自体は変更されていない。少なくとも公開パッチの本質は、callback 側でローカル `shared_ptr` を保持し、呼び出し中の寿命を固定することにある。
- 2026-06 時点の OSV JSON では `modified` が `2026-06-24` になっており、CVE 公開後もメタデータ更新が続いていた。
## 保存した付帯ファイル
- `artifacts/ASB-A-392699284.json`: Android OSV の対象レコード
- `artifacts/commit_metadata.txt`: 修正コミットのメタ情報
- `artifacts/c6da9eeb_fix_use_after_free_eventCallback.patch`: 親コミットとの差分
- `artifacts/Nfc.h.before.txt`: 修正前 `aidl/Nfc.h`
- `artifacts/Nfc.h.after.txt`: 修正後 `aidl/Nfc.h`
- `artifacts/Nfc.cpp.before.txt`: 修正前 `aidl/Nfc.cpp`
- `artifacts/Nfc.cpp.after.txt`: 修正後 `aidl/Nfc.cpp`
- `artifacts/hal_st21nfc_async_callback_excerpt.txt`: 非同期 callback thread 周辺の抜粋
## 最終結論
CVE-2025-48641 は ST NFC HAL AIDL 実装の callback オブジェクト寿命管理不備による race-condition UAF。`Nfc::eventCallback()` / `Nfc::dataCallback()` が static `Nfc::mCallback` を null check 後に直接使っていたため、HAL callback thread と `open()/close()` 側の callback 差し替え・解放が競合すると、解放済み callback への `sendEvent()` / `sendData()` が成立した。修正は callback 冒頭で `mCallback` をローカル `shared_ptr` にコピーし、呼び出し中の強参照を保持するものだった。
cve.md を表示# CVE-2025-48641 - System EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48641 - Component: System - Reference: A-392699284 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 34 | OK | CVE-2026-0017 - System EoP High |
034
ok
CVE-2026-0017 - System EoP High034-ok-biometric-setting-migration-fingerprint-unlock-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary System EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(判定) `ok` 脆弱性を特定できた。CVE-2026-0017 は、Android 16 / 16-qpr2 の生体認証設定移行において、旧統合設定 `BIOMETRIC_KEYGUARD_ENABLED=0` が新しい指紋別設定 `FINGERPRINT_KEYGUARD_ENABLED` 未設定時の既定値に反映されず、`BiometricService` が指紋ロック解除を有効と誤判定する local EoP である。 原因(根本原因) 根本原因は、セキュリティ上の拒否設定を保持する設定キーのスキーマ移行で、旧キーの明示的なOFF値を新キー未設定時の既定値に反映していなかったこと。 より具体的には、旧設計では `BIOMETRIC_KEYGUARD_ENABLED` が顔/指紋をまとめて制御していたが、新設計では `FACE_KEYGUARD_ENABLED` と `FINGERPRINT_KEYGUARD_ENABLED` に分割された。修正前コードは新キーが存在しない状態を「未移行なので旧値を見るべき状態」と扱わず、「新規既定値ON」と同じ意味にしていた。その結果、明示的な拒否 `0` が暗黙の許可 `true` に負けた。 どこから特定したか validated.md の「参照情報」 / Android bug参照 A-444673089 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 validated.md を表示# CVE-2026-0017 検証結果 ## 判定 `ok` 脆弱性を特定できた。CVE-2026-0017 は、Android 16 / 16-qpr2 の生体認証設定移行において、旧統合設定 `BIOMETRIC_KEYGUARD_ENABLED=0` が新しい指紋別設定 `FINGERPRINT_KEYGUARD_ENABLED` 未設定時の既定値に反映されず、`BiometricService` が指紋ロック解除を有効と誤判定する local EoP である。 ## 参照情報 - Android Security Bulletin 2026-03-01: `https://source.android.com/docs/security/bulletin/2026/2026-03-01` - ASB 行: `CVE-2026-0017 / A-444673089 / System / EoP / High / Android 16, 16-qpr2` - CVE API 説明: `BiometricService.java` の `onChange` にロジックエラーがあり、fingerprint unlock を有効化できる可能性がある。追加権限不要、ユーザー操作不要の local EoP。 - AOSP パッチ 1: `platform/frameworks/base` `cea235f00865ff73344f1efa9494e47beecc3fd5` - AOSP パッチ 2: `platform/packages/apps/Settings` `7d8fbee887fc9577337c2a80513ae4399bf60111` - Android bug: `A-444673089` ## 保存した付帯ファイル - `artifacts/frameworks_base_cea235f00865ff73344f1efa9494e47beecc3fd5.diff`: `BiometricService.java` の公開差分 - `artifacts/settings_7d8fbee887fc9577337c2a80513ae4399bf60111.diff`: Settings 側の公開差分 - `artifacts/frameworks_base_cea235f00865ff73344f1efa9494e47beecc3fd5.json`: framework commit JSON - `artifacts/settings_7d8fbee887fc9577337c2a80513ae4399bf60111.json`: Settings commit JSON - `artifacts/CVE-2026-0017.json`: CVE API レコード - `artifacts/CVE-2026-0017-summary.json`: CVE レコード要約 - `artifacts/BiometricService_before.java`, `artifacts/BiometricService_after.java`: 修正前後の対象ソース - `artifacts/FingerprintSettingsKeyguardUnlockPreferenceController_before.java`, `artifacts/FingerprintSettingsKeyguardUnlockPreferenceController_after.java`: Settings 側の指紋ロック解除設定ソース - `artifacts/analysis_notes.md`: 調査メモ - `artifacts/biometric_setting_migration_model.py`: 設定移行の最小モデル - `artifacts/biometric_setting_migration_model.out`: モデル実行結果 ## パッチの要点 `frameworks/base` の修正前 `BiometricService.SettingObserver.onChange()` は、`FINGERPRINT_KEYGUARD_ENABLED` を読むときに、キーが未設定なら `DEFAULT_KEYGUARD_ENABLED=true` を既定値として使っていた。 問題のある修正前ロジック: - `getEnabledOnKeyguard(userId, TYPE_FINGERPRINT)` が初回参照時に `onChange(..., FINGERPRINT_KEYGUARD_ENABLED, userId)` を呼ぶ。 - `onChange()` は `Settings.Secure.FINGERPRINT_KEYGUARD_ENABLED` を読む。 - 新キーが存在しない場合、旧 `BIOMETRIC_KEYGUARD_ENABLED` を見ずに既定値 `true` をキャッシュする。 - そのため、OTA 前にユーザーが生体認証によるロック解除をOFFにしていても、OTA後に指紋ロック解除だけがON扱いになり得る。 修正後は、`FACE_KEYGUARD_ENABLED` / `FINGERPRINT_KEYGUARD_ENABLED` が未設定の場合、旧 `BIOMETRIC_KEYGUARD_ENABLED` が存在すればその値を既定値にする。アプリ認証側も同様に、`FACE_APP_ENABLED` / `FINGERPRINT_APP_ENABLED` の既定値を旧 `BIOMETRIC_APP_ENABLED` から引き継ぐ。 Settings 側の修正は UI 表示と永続化の補強である。各コントローラのコンストラクタで、新しい顔/指紋別キーが未設定かつ旧統合キーが設定済みなら、旧値を新キーへ `putIntForUser()` する。これにより、設定画面を開いた場合にも旧OFF値が新キーへ移行される。 ## 脆弱性の成立条件 成立条件は次の通り。 1. 端末が Android 16 / 16-qpr2 の対象コードにあり、`biometricsOnboardingEducation` の分岐で顔/指紋別設定を使う。 2. ユーザーがOTA前または移行前に、生体認証によるロック解除をOFFにしており、旧キー `BIOMETRIC_KEYGUARD_ENABLED=0` が保存されている。 3. OTA後、新キー `FINGERPRINT_KEYGUARD_ENABLED` がまだ未設定である。 4. `BiometricService` が指紋ロック解除の可否を初期化・参照する。 5. 修正前は旧OFF値を参照せず、新キー未設定の既定値 `true` を採用するため、指紋ロック解除がON扱いになる。 攻撃者が任意コード実行や追加権限を得る必要はない。ユーザーが明示的に無効化したロック解除ポリシーが、OTA/設定移行後にシステム側で有効として扱われること自体が権限昇格である。CVE説明の「User interaction is not needed」は、この状態遷移が設定参照時に自動的に発生することと一致する。 ## 根本原因 根本原因は、セキュリティ上の拒否設定を保持する設定キーのスキーマ移行で、旧キーの明示的なOFF値を新キー未設定時の既定値に反映していなかったこと。 より具体的には、旧設計では `BIOMETRIC_KEYGUARD_ENABLED` が顔/指紋をまとめて制御していたが、新設計では `FACE_KEYGUARD_ENABLED` と `FINGERPRINT_KEYGUARD_ENABLED` に分割された。修正前コードは新キーが存在しない状態を「未移行なので旧値を見るべき状態」と扱わず、「新規既定値ON」と同じ意味にしていた。その結果、明示的な拒否 `0` が暗黙の許可 `true` に負けた。 ## 検証 `artifacts/biometric_setting_migration_model.py` で、旧統合キーと新指紋キーの組み合わせをモデル化した。 重要ケースの実行結果: ```text OTA: user disabled old unified unlock; new per-fingerprint key absent old BIOMETRIC_KEYGUARD_ENABLED=0, new FINGERPRINT_KEYGUARD_ENABLED=-1 vulnerable BiometricService decision: True patched BiometricService decision: False Settings constructor would persist new key as: 0 ``` この結果は公開パッチのテストと一致する。`BiometricServiceTest` には、`BIOMETRIC_KEYGUARD_ENABLED=0` かつ `FINGERPRINT_KEYGUARD_ENABLED` 未設定の場合に `getEnabledOnKeyguard(... TYPE_FINGERPRINT)` が `false` を返すテストが追加されている。Settings 側にも、旧キーOFF・新キー未設定なら `isChecked()` が `false` になるテストが追加されている。 ## 調査中に分かった面白い点 - CVE説明は `BiometricService.java` の `onChange` を明示しており、実際にセキュリティ判断の中核は Settings UI ではなく `BiometricService.SettingObserver` にあった。 - Settings 側パッチはUI表示の修正だけでなく、新キー未設定時に旧値を新キーへ永続化する移行処理として働く。 - framework 側パッチは keyguard unlock だけでなく app authentication の顔/指紋別設定にも同じ移行を追加している。ただし CVE文面が指摘する EoP は、指紋によるロック解除が意図せず有効化される経路が中心。 - `BiometricService.java` の追加コメントには、keyguard 設定を処理している箇所で `BIOMETRIC_APP_ENABLED` と書かれている行がある。実コードは `BIOMETRIC_KEYGUARD_ENABLED` を読んでいるため、これはコピー&ペースト由来のコメント誤記と判断した。 ## 結論 CVE-2026-0017 は、生体認証設定の旧統合キーから顔/指紋別キーへの移行不備による fingerprint unlock の意図しない有効化である。修正前は `FINGERPRINT_KEYGUARD_ENABLED` が未設定の場合に旧 `BIOMETRIC_KEYGUARD_ENABLED=0` を無視し、既定値ONで `BiometricService` の内部状態を初期化していた。修正は、新キー未設定時の既定値を旧キーから派生させ、Settings UI でも旧値を新キーへ永続化することで、ユーザーの明示的なOFF設定を保持している。 cve.md を表示# CVE-2026-0017 - System EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0017 - Component: System - Reference: A-444673089 - Type: EoP - Severity: High - Updated AOSP versions: 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 35 | OK | CVE-2026-0021 - System EoP High |
035
ok
CVE-2026-0021 - System EoP High035-ok-Settings-AppInfoBase-cross-user-confused-deputy-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary System EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(結論) CVE-2026-0021 は Android Settings の `AppInfoBase.hasInteractAcrossUsersFullPermission()` における cross-user permission bypass である。根本原因は、multi-pane / Activity Embedding が有効な Settings で、外部アプリから渡された `Intent.EXTRA_USER_HANDLE` を検証する際に、実際の外部呼び出し元ではなく Settings 側の UID を権限確認してしまう confused deputy である。 公開 CVE 説明は「`AppInfoBase.java` の `hasInteractAcrossUsersFullPermission` における confused deputy により cross-user permission bypass が可能」としている。AOSP の修正コミット `48af8a13dd12ecbd0569c328a56d1a7b61a59ca3` は `Bug: 430047417` を含み、`hasInteractAcrossUsersFullPermission()` に multi-pane 専用の呼び出し元パッケージ確認を追加しているため、この CVE の修正と判断できる。 原因(根本原因) 根本原因は、Activity の起動元 UID を「外部呼び出し元」として扱ったことにある。single-pane の通常起動では `getLaunchedFromUid(activityToken)` が呼び出し元を表すため成立するが、Activity Embedding では Settings 内部で activity/fragment 遷移が再構成される。このとき、activity token に紐づく launched-from UID が Settings 自身になれば、Settings が持つ高権限を外部アプリの代わりに使ってしまう。 これは典型的な confused deputy である。権限を持つ Settings が「誰の依頼か」を誤認し、通常アプリが直接は許可されない cross-user 操作を代行してしまう。 修正は、multi-pane が有効な場合に `getInitialCallingPackage()` で初期呼び出し元 package を取得し、その package の permission を直接確認することで、権限チェック主体を Settings UID から実際の依頼元へ戻している。 どこから特定したか Android bug参照 A-430047417 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://www.cve.org/CVERecord?id=CVE-2026-0021, https://android.googlesource.com/platform/packages/apps/Settings validated.md を表示# CVE-2026-0021 検証結果
## 結論
CVE-2026-0021 は Android Settings の `AppInfoBase.hasInteractAcrossUsersFullPermission()` における cross-user permission bypass である。根本原因は、multi-pane / Activity Embedding が有効な Settings で、外部アプリから渡された `Intent.EXTRA_USER_HANDLE` を検証する際に、実際の外部呼び出し元ではなく Settings 側の UID を権限確認してしまう confused deputy である。
公開 CVE 説明は「`AppInfoBase.java` の `hasInteractAcrossUsersFullPermission` における confused deputy により cross-user permission bypass が可能」としている。AOSP の修正コミット `48af8a13dd12ecbd0569c328a56d1a7b61a59ca3` は `Bug: 430047417` を含み、`hasInteractAcrossUsersFullPermission()` に multi-pane 専用の呼び出し元パッケージ確認を追加しているため、この CVE の修正と判断できる。
## パッチ情報
- Bulletin: Android Security Bulletin - March 2026
- CVE: CVE-2026-0021
- Android bug: A-430047417
- Component: System
- Type: EoP
- Severity: High
- Updated AOSP versions: 14, 15, 16, 16-qpr2
- 修正リポジトリ: `platform/packages/apps/Settings`
- 修正コミット: `48af8a13dd12ecbd0569c328a56d1a7b61a59ca3`
- 親コミット: `059c9678eebeefb97cb9cc075d526df546fe4b84`
- 変更ファイル:
- `AndroidManifest.xml`
- `src/com/android/settings/applications/AppInfoBase.java`
保存した付帯ファイル:
- `artifacts/48af8a13dd12ecbd0569c328a56d1a7b61a59ca3.commit.txt`
- `artifacts/48af8a13dd12ecbd0569c328a56d1a7b61a59ca3.diff`
- `artifacts/AppInfoBase.before.java`
- `artifacts/AppInfoBase.after.java`
- `artifacts/AndroidManifest.before.xml`
- `artifacts/AndroidManifest.after.xml`
- `artifacts/SettingsActivity.after.java`
- `artifacts/ActivityEmbeddingUtils.after.java`
- `artifacts/UsageAccessDetails.after.java`
## 修正内容
`AndroidManifest.xml` では `Settings$AppUsageAccessSettingsActivity` の intent-filter に `android:priority="1"` が追加された。
```diff
- <intent-filter>
+ <intent-filter android:priority="1">
<action android:name="android.settings.USAGE_ACCESS_SETTINGS"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="package"/>
```
主修正は `AppInfoBase.hasInteractAcrossUsersFullPermission()` である。修正前は常に `ActivityManager.getService().getLaunchedFromUid(activity.getActivityToken())` を使い、その UID に `INTERACT_ACROSS_USERS_FULL` があるかを確認していた。
```java
int callerUid = ActivityManager.getService().getLaunchedFromUid(
activity.getActivityToken());
if (ActivityManager.checkUidPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
callerUid) != PackageManager.PERMISSION_GRANTED) {
return false;
}
return true;
```
修正後は、`ActivityEmbeddingUtils.isEmbeddingActivityEnabled(activity)` が true の場合に限り、`SettingsActivity.getInitialCallingPackage()` で初期外部呼び出し元パッケージを取得し、そのパッケージに `INTERACT_ACROSS_USERS_FULL` があるかを `PackageManager.checkPermission()` で確認する。
```java
if (ActivityEmbeddingUtils.isEmbeddingActivityEnabled(activity)) {
final String callingPackageName =
((SettingsActivity) activity).getInitialCallingPackage();
if (TextUtils.isEmpty(callingPackageName)) {
return false;
}
if (mPm.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
callingPackageName) != PackageManager.PERMISSION_GRANTED) {
return false;
}
return true;
}
```
`SettingsActivity.getInitialCallingPackage()` は `PasswordUtils.getCallingAppPackageName(getActivityToken())` を使い、返ってきた package が Settings 自身でない場合のみ呼び出し元として返す。このため、multi-pane Settings 内部の再起動や埋め込みによって `launchedFromUid` が Settings 自身になってしまう場合でも、元の外部アプリに権限確認を戻せる。
## 脆弱性条件
ソースコードから再構成できる条件は次の通り。
1. Settings の Activity Embedding / multi-pane 表示が有効な端末または状態である。
2. 攻撃側アプリが exported な `Settings$AppUsageAccessSettingsActivity` を、`android.settings.USAGE_ACCESS_SETTINGS` と `package:` URI で起動する。
3. intent に `Intent.EXTRA_USER_HANDLE` を付け、自分の現在ユーザーとは異なる user/profile を指定する。
4. `AppInfoBase.retrieveAppEntry()` が `EXTRA_USER_HANDLE` を見つけ、`mUserId != UserHandle.myUserId()` のため `hasInteractAcrossUsersFullPermission()` を呼ぶ。
5. 修正前の multi-pane 経路では、権限確認対象が実際の外部呼び出し元ではなく Settings 側の UID になり得るため、通常アプリが持てない `INTERACT_ACROSS_USERS_FULL` の検査を通過する。
`retrieveAppEntry()` は検査通過後に `mState.getEntry(mPackageName, mUserId)` と `mPm.getPackageInfoAsUser(..., mUserId)` を実行する。`UsageAccessDetails` ではさらに対象 user の package に対して usage access 状態を取得し、switch 変更時には `AppOpsManager.setMode(OP_GET_USAGE_STATS, uid, mPackageName, ...)` を呼ぶ。したがって、`EXTRA_USER_HANDLE` のゲートが破れると、Settings を代理人として別ユーザー/profile のアプリ特殊権限画面を扱える。
## 根本原因
根本原因は、Activity の起動元 UID を「外部呼び出し元」として扱ったことにある。single-pane の通常起動では `getLaunchedFromUid(activityToken)` が呼び出し元を表すため成立するが、Activity Embedding では Settings 内部で activity/fragment 遷移が再構成される。このとき、activity token に紐づく launched-from UID が Settings 自身になれば、Settings が持つ高権限を外部アプリの代わりに使ってしまう。
これは典型的な confused deputy である。権限を持つ Settings が「誰の依頼か」を誤認し、通常アプリが直接は許可されない cross-user 操作を代行してしまう。
修正は、multi-pane が有効な場合に `getInitialCallingPackage()` で初期呼び出し元 package を取得し、その package の permission を直接確認することで、権限チェック主体を Settings UID から実際の依頼元へ戻している。
## 影響
`INTERACT_ACROSS_USERS_FULL` は signature permission であり、通常アプリは保持できない。これが bypass されると、通常アプリが別 user/profile を対象に Settings の app info / special access 処理へ到達できる。少なくとも `UsageAccessDetails` では usage access special permission の対象 user/package を選択でき、Settings の権限で対象 app op 状態を扱う経路に入る。
このため Android bulletin の分類通り local EoP と評価できる。メモリ破壊ではなく、exported Settings activity、cross-user extra、Activity Embedding 時の呼び出し元誤認が組み合わさった権限境界の破綻である。
## 検証メモ
- 修正コミットは `Bug: 430047417` を明記しており、`cve.md` の A-430047417 と一致する。
- patch は 21 insertions / 1 deletion だけだが、追加された 20 行はすべて `hasInteractAcrossUsersFullPermission()` の権限主体修正であり、CVE 説明と一致する。
- `ActivityEmbeddingUtils.isEmbeddingActivityEnabled()` は Settings large-screen optimization、feature flag `SETTINGS_SUPPORT_LARGE_SCREEN`、setup 完了を条件に true を返す。したがって全端末常時ではなく、multi-pane Settings が有効な構成が重要である。
- `NotificationAccessDetails` には既に `getInitialCallingPackage()` で package permission を見る類似実装があり、今回の修正は `AppInfoBase` 側にも同じ防御を入れた形に見える。
- source-level に脆弱性と修正意図を確認できたため `ok` 判定にする。
## 参考
- Android Security Bulletin - March 2026: https://source.android.com/docs/security/bulletin/2026/2026-03-01
- CVE Record: https://www.cve.org/CVERecord?id=CVE-2026-0021
- AOSP Settings repository: https://android.googlesource.com/platform/packages/apps/Settings
cve.md を表示# CVE-2026-0021 - System EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0021 - Component: System - Reference: A-430047417 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 36 | OK | CVE-2026-0035 - System EoP High |
036
ok
CVE-2026-0035 - System EoP High036-ok-MediaProvider-createRequest-nonexistent-uri-grant-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary System EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) 脆弱版の `createRequest()` は、`MediaStore.createWriteRequest()` などから来る `ClipData` 内のUriについて、Uri形式だけを検証していた。具体的には `content://media/.../images/media/<id>`、`audio/media/<id>`、`video/media/<id>`、playlist、または字幕用の `files/<id>` であることは確認するが、その `<id>` がMediaProviderのデータベース上に実在するかは確認していなかった。 その後、MediaProviderは検証済みとみなしたextrasを `PermissionActivity` 向けの immutable PendingIntent に詰める。ユーザーが許可すると、`PermissionActivity#onPositiveAction()` は `CREATE_WRITE_REQUEST_CALL` の場合、各Uriに対して `grantUriPermission(appInfo.packageName, uri, READ | WRITE)` を実行する。 このため攻撃アプリは、まだ存在しないMediaStoreの行IDを指すUriに対して `MediaStore.createWriteRequest()` を呼び出し、ユーザー承認を得ることで、そのUri文字列への読み書き権限を先に取得できる。後で同じIDのメディア行が作成されると、MediaProvider側の通常アクセス判定は `checkUriPermission(uri, pid, uid, modeFlags)` の既存grantを見て許可するため、攻撃アプリは本来アクセスできない他アプリ/ユーザー由来のメディアアイテムを読み書きできる。 これは「存在しないオブジェクトに対する権限付与」が、後から作られた別オブジェクトに再束縛... 原因(根本原因) 根本原因は、MediaStoreの権限リクエスト作成時に「Uriの構文上の種別」と「そのUriが指す行の実在性」を同一視したこと。 `createRequest()` のコメントには「privileged PendingIntentを作る前にsecurity目的で引数をチェックする」とあるが、脆弱版で実施していたのは `matchUri()` によるパターン検証と、`FILES_ID` の字幕判定、変更可能カラムの制限だけだった。`IMAGES_MEDIA_ID` などの個別ID Uriについては、実在確認をせずに `break` していた。 一方、作成されたPendingIntentはMediaProvider/PermissionActivity側の特権的な流れで実行され、`grantUriPermission()` はMediaProviderのDB行実在性ではなくUri文字列に対してgrantを登録する。この設計差により、将来作られる行に対する先行grantが可能になった。 どこから特定したか Android bug参照 A-418773439 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://android.googlesource.com/platform/packages/providers/MediaProvider/+/119013a3d7e8f1eab671bce4c6a85748752081ed validated.md を表示# CVE-2026-0035 MediaProvider EoP パッチ解析
## 判定
ok: 脆弱性の原因コミット、修正内容、悪用条件、権限昇格の流れをAOSPソースコード差分から特定できた。
対象は Android Security Bulletin - March 2026 の System / MediaProvider の `CVE-2026-0035`、参照バグは `A-418773439`。公開ブリテンでは EoP / High、更新対象は Android 14, 15, 16, 16-qpr2 とされている。
## 関連パッチ
- リポジトリ: `platform/packages/providers/MediaProvider`
- 修正コミット: `119013a3d7e8f1eab671bce4c6a85748752081ed`
- 件名: `Throw exception on MediaStore createRequest for non-existent uri`
- 親コミット: `69a25763cdb46c8f23fe9eb976132acbe2af82d6`
- 変更ファイル:
- `src/com/android/providers/media/MediaProvider.java`
- `tests/src/com/android/providers/media/MediaProviderTest.java`
修正は `MediaProvider#createRequest()` に、渡された全Uriを `queryForSingleItem(uri, new String[]{FileColumns._ID}, ...)` で実在確認する処理を追加している。該当UriがFiles tableに存在しない、または単一行として解決できない場合は `FileNotFoundException` を `IllegalArgumentException("Invalid Uri: ...")` に変換し、PendingIntent作成自体を拒否する。
## 脆弱性の内容
脆弱版の `createRequest()` は、`MediaStore.createWriteRequest()` などから来る `ClipData` 内のUriについて、Uri形式だけを検証していた。具体的には `content://media/.../images/media/<id>`、`audio/media/<id>`、`video/media/<id>`、playlist、または字幕用の `files/<id>` であることは確認するが、その `<id>` がMediaProviderのデータベース上に実在するかは確認していなかった。
その後、MediaProviderは検証済みとみなしたextrasを `PermissionActivity` 向けの immutable PendingIntent に詰める。ユーザーが許可すると、`PermissionActivity#onPositiveAction()` は `CREATE_WRITE_REQUEST_CALL` の場合、各Uriに対して `grantUriPermission(appInfo.packageName, uri, READ | WRITE)` を実行する。
このため攻撃アプリは、まだ存在しないMediaStoreの行IDを指すUriに対して `MediaStore.createWriteRequest()` を呼び出し、ユーザー承認を得ることで、そのUri文字列への読み書き権限を先に取得できる。後で同じIDのメディア行が作成されると、MediaProvider側の通常アクセス判定は `checkUriPermission(uri, pid, uid, modeFlags)` の既存grantを見て許可するため、攻撃アプリは本来アクセスできない他アプリ/ユーザー由来のメディアアイテムを読み書きできる。
これは「存在しないオブジェクトに対する権限付与」が、後から作られた別オブジェクトに再束縛される時間差の権限昇格である。
## 根本原因
根本原因は、MediaStoreの権限リクエスト作成時に「Uriの構文上の種別」と「そのUriが指す行の実在性」を同一視したこと。
`createRequest()` のコメントには「privileged PendingIntentを作る前にsecurity目的で引数をチェックする」とあるが、脆弱版で実施していたのは `matchUri()` によるパターン検証と、`FILES_ID` の字幕判定、変更可能カラムの制限だけだった。`IMAGES_MEDIA_ID` などの個別ID Uriについては、実在確認をせずに `break` していた。
一方、作成されたPendingIntentはMediaProvider/PermissionActivity側の特権的な流れで実行され、`grantUriPermission()` はMediaProviderのDB行実在性ではなくUri文字列に対してgrantを登録する。この設計差により、将来作られる行に対する先行grantが可能になった。
## 悪用シナリオ
1. 攻撃アプリが `content://media/external_primary/images/media/42` のような、形式は正しいが現時点では存在しないUriを用意する。
2. 脆弱版では `MediaStore.createWriteRequest(resolver, listOf(uri))` が成功し、MediaProvider作成のPendingIntentが返る。
3. ユーザーが許可すると、`PermissionActivity` が攻撃アプリのpackageにそのUriへのREAD/WRITE grantを付与する。
4. 後でMediaProviderのDBに同じIDの行が作られる。
5. 攻撃アプリがそのUriを `openFile()` / `update()` などで使うと、MediaProviderのアクセス判定で既存Uri grantが通り、対象メディアにアクセスできる。
IDを完全に予測する必要はあるが、MediaStoreのrow IDは単調増加的に観測・推測できる場面があり、攻撃アプリ自身の挿入/削除や既存メディア列挙で近い値を推定できる可能性がある。少なくとも修正コミットと追加テストは「存在しないUriのcreateRequest成功」を明確にセキュリティ欠陥として扱っている。
## 修正後の挙動
修正版では `createRequest()` がPendingIntentを返す前に全UriをMediaProvider権限で問い合わせる。`queryForSingleItem()` は0件、複数件、読み取り失敗を `FileNotFoundException` として扱うため、存在しないIDは `IllegalArgumentException` になり、権限リクエストを開始できない。
追加テスト `testCreateRequest_invalidUri_throwsException()` は、従来テストで使っていた `images/media/42` のような固定IDの非実在Uriに対して、`MediaStore.createWriteRequest()` が `IllegalArgumentException` を投げることを検証している。既存の `testCreateRequest()` は、実際にaudio行をinsertして得たUriを使う形に変更された。
## 面白い点・調査メモ
- 修正前の単体テスト自体が、非実在と思われる `images/media/42` を正常系として使っていた。これが仕様誤認の痕跡になっている。
- `CREATE_FAVORITE_REQUEST_CALL` は `shouldShowActionDialog()` でダイアログなし自動許可されるが、実際の処理は即時 `applyBatch(update)` なので、非実在Uriへの先行grant問題として特に危険なのは `CREATE_WRITE_REQUEST_CALL`。
- `CREATE_DELETE_REQUEST_CALL` / trash / favorite は非実在Uriに対して即時操作を試みるだけなので、将来行へ持ち越されるgrantではない。ただし修正は全createRequest系をまとめて拒否している。
- パッチはMediaProvider側のみで完結しており、Pixel固有バイナリ解析は不要だった。CVEはGoogle Play system updatesにもMediaProviderとして掲載されているため、Mainline MediaProviderモジュールとして配布される修正でもある。
## 保存した付帯ファイル
- `analysis/119013a3_patch.diff`: 修正コミットの全文diff
- `analysis/119013a3_commit_metadata.txt`: コミットメタ情報
- `analysis/vulnerable_createRequest_snippet.txt`: 脆弱版 `createRequest()` 抜粋
- `analysis/fixed_createRequest_snippet.txt`: 修正版 `createRequest()` 抜粋
- `analysis/permission_activity_positive_action_snippet.txt`: 許可時のgrant/applyBatch処理
- `analysis/media_provider_uri_permission_check_snippet.txt`: MediaProviderのUri grant判定箇所
- `analysis/query_for_single_item_snippet.txt`: 実在確認に使われる `queryForSingleItem()`
- `analysis/related_commits.txt`: 同件名/バグの関連コミット一覧
- `analysis/branches_containing_fix.txt`, `analysis/tags_containing_fix.txt`: 修正を含むrefs
## 参照
- Android Security Bulletin - March 2026: https://source.android.com/docs/security/bulletin/2026/2026-03-01
- AOSP修正コミット: https://android.googlesource.com/platform/packages/providers/MediaProvider/+/119013a3d7e8f1eab671bce4c6a85748752081ed
cve.md を表示# CVE-2026-0035 - System EoP High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0035 - Component: System - Subcomponent: MediaProvider - Reference: A-418773439 - Type: EoP - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 37 | OK | CVE-2024-43766 - System ID High |
037
ok
CVE-2024-43766 - System ID High037-ok-Bluetooth-LE-bonded-SMP-failure-unencrypted-ID cve.md の Android / Pixel 脆弱性情報
cve.md summary System ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) Android端末がBLE peripheral roleで、既にbond済みのcentralデバイスと再接続する場面が問題になる。 修正系列では、bond済みLEデバイスとの再接続時にリンクを直ちに暗号化するようになっている。しかしperipheral roleでは、この暗号化要求がSMP Security Requestとしてcentralへ送られる。一部のcentralデバイスは、リンクが既に暗号化済みの場合や、Security Request送信後に切断が起きた場合、このSMP手順に応答しない。その結果、SMP側では `SMP_COMPLT_EVT` の失敗やtimeoutが発生する。 パッチ前の `btm_ble_complete_evt()` は、この失敗が「実際のpairing失敗」なのか、「bond済み・暗号化済みリンクへの余分なSMP Security Requestが失敗しただけ」なのかを区別していなかった。失敗は `BTM_LE_COMPLT_EVT` として上位へ通知され、`BTM_ERR_PROCESSING` として処理が進むため、bond削除やbond状態の破壊につながる。 結果として、本来bond済みで暗号化されるべきBLE通信が、再接続後にbond喪失や暗号化保証の喪失を起こしうる。OSVの説明では「possible unencrypted communication due to Invalid error handling」とされ、近接するリモート攻撃者による情報漏えい、ユーザー操作不要、追加権限不要とされている。 原因(根本原因) 根本原因は、BLE peripheral roleにおける暗号化要求由来のSMP失敗を、文脈なしにpairing失敗として処理していたこと。 特にパッチ前は、bond済みデバイスであること、LE link keyが存在すること、現在のpairing対象ではないこと、既にリンクが暗号化済みであること、または暗号化待ち中に切断timeoutしただけであることを確認しないまま、SMP失敗を通常の完了失敗として扱っていた。 どこから特定したか validated.md の「パッチ解析」 / Android bug参照 A-288144143 validated.md を表示# CVE-2024-43766 検証結果 ## 判定 特定できた。`ok` と判断する。 CVE-2024-43766 / A-288144143 は、Android Bluetooth stack のBLE security処理における、bond済みLEデバイス再接続時のSMP失敗イベント処理ミスによる情報漏えい(ID)である。影響箇所は `platform/packages/modules/Bluetooth` の `system/stack/btm/btm_ble_sec.cc` を中心とする。 ## 脆弱性の内容 Android端末がBLE peripheral roleで、既にbond済みのcentralデバイスと再接続する場面が問題になる。 修正系列では、bond済みLEデバイスとの再接続時にリンクを直ちに暗号化するようになっている。しかしperipheral roleでは、この暗号化要求がSMP Security Requestとしてcentralへ送られる。一部のcentralデバイスは、リンクが既に暗号化済みの場合や、Security Request送信後に切断が起きた場合、このSMP手順に応答しない。その結果、SMP側では `SMP_COMPLT_EVT` の失敗やtimeoutが発生する。 パッチ前の `btm_ble_complete_evt()` は、この失敗が「実際のpairing失敗」なのか、「bond済み・暗号化済みリンクへの余分なSMP Security Requestが失敗しただけ」なのかを区別していなかった。失敗は `BTM_LE_COMPLT_EVT` として上位へ通知され、`BTM_ERR_PROCESSING` として処理が進むため、bond削除やbond状態の破壊につながる。 結果として、本来bond済みで暗号化されるべきBLE通信が、再接続後にbond喪失や暗号化保証の喪失を起こしうる。OSVの説明では「possible unencrypted communication due to Invalid error handling」とされ、近接するリモート攻撃者による情報漏えい、ユーザー操作不要、追加権限不要とされている。 ## 根本原因 根本原因は、BLE peripheral roleにおける暗号化要求由来のSMP失敗を、文脈なしにpairing失敗として処理していたこと。 特にパッチ前は、bond済みデバイスであること、LE link keyが存在すること、現在のpairing対象ではないこと、既にリンクが暗号化済みであること、または暗号化待ち中に切断timeoutしただけであることを確認しないまま、SMP失敗を通常の完了失敗として扱っていた。 ## パッチ解析 Bulletinが直接リンクしている `7ccb456f6d29cc6077a4d1c6a9b515033378ec32` は、修正本体ではなく `bonded_device_smp_failure_handling` フラグ削除だった。OSV JSONのfix commit群を追うと、本体は次の変更だった。 - `829d89814846`: bond済みLEデバイス再接続時に `btm_ble_set_encryption()` を呼び、リンク暗号化を開始する。 - `92e627ea85ba`: `btm_ble_set_encryption()` で既に暗号化済みなら `BTM_SUCCESS` を返し、不要なSMP Security Requestを避ける。 - `7ed69cff1392`: `btm_ble_complete_evt_ignore()` を追加し、peripheral role、bond済み、pairing対象外、既存keyあり、既に暗号化済みまたは `SMP_CONN_TOUT` の場合にSMP失敗を無視する。 - `77cc20f000ef` / `7ccb456f6d29`: フラグを削除して修正を常時有効化する。`PairingTest.testBondLePeripheral_WhenEncryptionFail` もフラグ不要になり、期待値はbond維持。 ## 検証メモ 保存した差分と前後ソースから、脆弱条件をソースコード上で説明できる。特に `7ed69cff...diff` の追加条件は、まさに「bond済みperipheralのSMP失敗でbondを壊さない」ためのものだった。 面白い点として、Bulletinのリンク先だけを見るとcleanupに見える。実際の修正はフラグ配下で先に導入され、その後のフラグ削除コミットがBulletinに出ているため、OSVの `fixes` 一覧とVanir signatureを追う必要があった。 ## 付帯ファイル 解析成果は `artifacts/` に保存した。主なファイルは `analysis_notes.md`、`ASB-A-288144143.osv.json`、各fix commitのdiff、`btm_ble_sec_*_snippets.txt`、`l2c_ble_*_snippets.txt`。 cve.md を表示# CVE-2024-43766 - System ID High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2024-43766 - Component: System - Reference: A-288144143 - Type: ID - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 38 | OK | CVE-2025-48642 - System ID High |
038
ok
CVE-2025-48642 - System ID High038-ok-AVF-dcache-PoC-secret-leak cve.md の Android / Pixel 脆弱性情報
cve.md summary System ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) ARM64 の `dc cvau` は data/unified cache line を Point of Unification まで clean します。一方、`dc cvac` は Point of Coherency まで clean します。今回のコードは「主記憶上の内容が更新済みであること」を期待する箇所で `cvau` を使っていました。 問題になる典型ケースは pVM firmware の終了処理です。`jump_to_payload()` は pVM firmware の `.data/.bss`、stack、EH stack をゼロ化し、レジスタや page table も落として payload にジャンプします。この処理の目的は、payload 側に pVM firmware の秘密や一時データを残さないことです。しかしゼロ化後の cache clean が PoU 止まりだと、対象 SoC ではゼロが主記憶に到達せず、RAM 側には古い秘密データが残り得ます。payload 移行後、cache/page table 状態の変化や別 observer の物理メモリアクセスにより、ゼロ化済みであるべき領域から stale data が見える可能性があります。 もう一つの影響範囲は vmbase の `flush_region()` 利用箇所です。`flushed_zeroize()` は slice をゼロ化して flush します。また `MemoryTracker::drop()` は dirty page を flush してから shared memory を unshare します。ここでも PoU までの clean では、host / hypervisor / device など PoC 側で整合すべき相手に対して、最新値ではなく stale な主記憶内容を露出する可能性があります。 原因(根本原因) 根本原因は、PoU と PoC のセキュリティ上の意味を取り違えたことです。I-cache/D-cache の自己整合や命令フェッチとの整合には PoU で足りる場面がありますが、主記憶を読む別 agent、cache 無効化後の実行、共有/返却される物理ページに対して「書いた値が RAM にある」ことを保証するには PoC まで clean する必要があります。 修正後は `dc cvac` により、該当 cache line が Point of Coherency まで clean されます。これにより、pVM firmware のゼロ化結果や vmbase の dirty/zeroized memory が、主記憶を含む coherent observer に見える状態になります。 どこから特定したか validated.md の「公開情報」「パッチ解析」 / Android bug参照 A-455777515 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://android.googlesource.com/platform/packages/modules/Virtualization/+/f0271f36388ec9630d89ff8b3ee4cb22e2ca3eaf validated.md を表示# CVE-2025-48642 検証結果
## 結論
CVE-2025-48642 は Android Virtualization Framework の `pvmfw` / `vmbase` における ARM64 data cache clean 範囲の誤りによる情報漏えいです。修正は AOSP の `platform/packages/modules/Virtualization` コミット `f0271f36388ec9630d89ff8b3ee4cb22e2ca3eaf` で、`dc cvau` を `dc cvac` に置き換えています。
`ok` 判定です。公開 AOSP ソース diff で修正箇所を確認でき、脆弱性が起きる条件も「PoU への clean では主記憶まで書き戻されない SoC で、pVM firmware / vmbase が主記憶上の値更新をセキュリティ境界として期待した場合」と説明できます。
## 公開情報
- Android Security Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-03-01
- Bulletin 記載: `CVE-2025-48642`, `A-455777515`, `System`, `ID`, `High`, affected AOSP versions `14, 15, 16, 16-qpr2`
- 修正コミット: https://android.googlesource.com/platform/packages/modules/Virtualization/+/f0271f36388ec9630d89ff8b3ee4cb22e2ca3eaf
- コミット件名: `vmbase,pvmfw: aarch64: Clean dcache to PoC not PoU`
- コミットメッセージ上の要点: 一部 SoC では PoC の手前に unified cache があり、PoU への cache maintenance では data が main memory まで flush されない可能性がある。
## パッチ解析
変更ファイルは 2 つだけです。
- `guest/pvmfw/src/arch/aarch64/payload.rs`
- `libs/libvmbase/src/arch.rs`
`payload.rs` では、payload に制御を渡す直前に `.data/.bss`、stack、EH stack をゼロ化した後の cache clean がすべて以下のように変更されています。
```diff
- dc cvau, {cache_line}
+ dc cvac, {cache_line}
```
`libs/libvmbase/src/arch.rs` では、共通 primitive の `flush_region(start, size)` が同じく `cvau` から `cvac` に変更されています。このため `memory::flush()`、`memory::flushed_zeroize()`、dirty page flush 経路にも影響します。
## 脆弱性の内容
ARM64 の `dc cvau` は data/unified cache line を Point of Unification まで clean します。一方、`dc cvac` は Point of Coherency まで clean します。今回のコードは「主記憶上の内容が更新済みであること」を期待する箇所で `cvau` を使っていました。
問題になる典型ケースは pVM firmware の終了処理です。`jump_to_payload()` は pVM firmware の `.data/.bss`、stack、EH stack をゼロ化し、レジスタや page table も落として payload にジャンプします。この処理の目的は、payload 側に pVM firmware の秘密や一時データを残さないことです。しかしゼロ化後の cache clean が PoU 止まりだと、対象 SoC ではゼロが主記憶に到達せず、RAM 側には古い秘密データが残り得ます。payload 移行後、cache/page table 状態の変化や別 observer の物理メモリアクセスにより、ゼロ化済みであるべき領域から stale data が見える可能性があります。
もう一つの影響範囲は vmbase の `flush_region()` 利用箇所です。`flushed_zeroize()` は slice をゼロ化して flush します。また `MemoryTracker::drop()` は dirty page を flush してから shared memory を unshare します。ここでも PoU までの clean では、host / hypervisor / device など PoC 側で整合すべき相手に対して、最新値ではなく stale な主記憶内容を露出する可能性があります。
## 根本原因
根本原因は、PoU と PoC のセキュリティ上の意味を取り違えたことです。I-cache/D-cache の自己整合や命令フェッチとの整合には PoU で足りる場面がありますが、主記憶を読む別 agent、cache 無効化後の実行、共有/返却される物理ページに対して「書いた値が RAM にある」ことを保証するには PoC まで clean する必要があります。
修正後は `dc cvac` により、該当 cache line が Point of Coherency まで clean されます。これにより、pVM firmware のゼロ化結果や vmbase の dirty/zeroized memory が、主記憶を含む coherent observer に見える状態になります。
## 面白い点・調査メモ
- Bulletin 上は `System` ですが、実体は `packages/modules/Virtualization` の AVF / pVM 関連コードでした。
- patch は 4 箇所の命令差し替えだけで、制御フローや権限チェックの追加はありません。それでも High severity の ID になるのは、pVM firmware の秘密消去という境界に直結するためです。
- `libs/libvmbase/src/memory/util.rs` のコメントは親コミット時点で `Flushes the slice to the point of unification` / `Overwrites ... to the point of unification` と書かれており、修正コミットではコメントは変わっていません。実装は PoC clean に変わるため、コメントが古くなる点は小さな不整合です。
- この脆弱性は全 ARM64 デバイスで同じように再現するタイプではなく、PoU と PoC の間に unified cache がある SoC で顕在化します。コミットメッセージもこの hardware-dependent 条件を明示しています。
- Origin の patch-diffing pipeline 的には、今回はバイナリ差分ではなく AOSP ソース diff が直接得られたため、コミットメッセージ、最小 diff、呼び出し元、セキュリティ境界の順に絞り込む方が有効でした。
## 保存した付帯ファイル
- `analysis_notes.md`: 解析メモ
- `artifacts/f0271f36388e.diff`: 修正コミットの raw diff
- `artifacts/f0271f36388e.commit.json`: Gitiles commit metadata
- `artifacts/payload.rs.before`, `artifacts/payload.rs.after`
- `artifacts/arch.rs.before`, `artifacts/arch.rs.after`
- `artifacts/memory_util.rs.before`
- `artifacts/aarch64_dbm.rs.before`
- `artifacts/tracker.rs.before`
- `artifacts/shared.rs.before`
cve.md を表示# CVE-2025-48642 - System ID High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48642 - Component: System - Reference: A-455777515 - Type: ID - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 39 | OK | CVE-2025-64783 - System ID High |
039
ok
CVE-2025-64783 - System ID High039-ok-DNG-SDK-areaSpec-overflow-ID cve.md の Android / Pixel 脆弱性情報
cve.md summary System ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性が起きる状況) 攻撃者はDNGファイルの opcode list に `DeltaPerColumn` などの opcode を入れ、`AreaSpec` の `top/left/bottom/right`、`plane/planes`、`rowPitch/colPitch`、delta/table 値を制御できる。パーサがこのDNGを処理すると、stage 2/3 の画像バッファに対して opcode が適用される。 修正前の実装では、`Overlap` で処理領域を画像領域と交差させた後でも、反復制御に絶対座標を直接使っていた。そのため、座標が `INT32_MAX` 付近にあり pitch 加算で折り返すケースでは、処理回数が `overlap` の要素数に縛られず、負座標や範囲外座標で `DirtyPixel_*` に到達し得る。これはOOB read/writeの根本原因であり、Android上では画像処理経路から情報漏えい、実装や呼び出し元によってはメモリ破壊に発展する。 `artifacts/opcode_pitch_model.py` でこの性質を小さくモデル化した。出力では、`[2147483640, 2147483647), pitch=16` のような境界条件で、修正前相当のループが `2147483640 -> -2147483640 -> ...` と折り返して継続する一方、修正後相当のループは事前計算された1回で停止することを確認した。 原因(根本原因を含む段落) 修正前の実装では、`Overlap` で処理領域を画像領域と交差させた後でも、反復制御に絶対座標を直接使っていた。そのため、座標が `INT32_MAX` 付近にあり pitch 加算で折り返すケースでは、処理回数が `overlap` の要素数に縛られず、負座標や範囲外座標で `DirtyPixel_*` に到達し得る。これはOOB read/writeの根本原因であり、Android上では画像処理経路から情報漏えい、実装や呼び出し元によってはメモリ破壊に発展する。 どこから特定したか validated.md の「根拠」「パッチ解析」 / Android bug参照 A-483074175 validated.md を表示# CVE-2025-64783 検証結果
## 判定
判定: ok
脆弱性は、Android が取り込んでいる Adobe DNG SDK の DNG opcode 処理における整数オーバーフロー/境界計算不備である。攻撃者が細工した DNG ファイルをパーサに処理させると、`areaSpec` の座標・plane・pitch に由来する処理範囲が正しく制限されず、DNG画像バッファ外の読み書きにつながる。Android Security Bulletin では System の Information Disclosure として扱われているが、Adobe 側の分類は `Integer Overflow or Wraparound (CWE-190)` で、DNG SDK 1.7.0 以前から 1.7.1 build 2410 への更新で修正されている。
## 根拠
- Android Security Bulletin 2026-03-01 は `CVE-2025-64783` を System / ID / High とし、参照 `A-483074175` を AOSP コミット `6b5cf2a88ebd2b099e56d0d4717e962772ff9067` にリンクしている。
- 該当コミットは `platform/external/dng_sdk` の `Update to DNG SDK 1.7.1 2410` で、同じコミットが `CVE-2025-64784` と `CVE-2025-64893` にも使われている。
- Adobe APSB25-118 は `CVE-2025-64783` を DNG SDK 1.7.0 以前の `Integer Overflow or Wraparound` として公開し、修正版を `DNG SDK 1.7.1 build 2410` としている。
- Project Zero の公開情報では、同CVEに対応する問題として「areaSpec overlap miscalculation lead to integer overflow, leading to OOB read/write」というタイトルが確認できる。P0ブログ「A look at an Android ITW DNG exploit」は別実装の Quram/Samsung 側解析を含むが、DNG opcode list、`DeltaPerColumn`、`MapTable`、攻撃者制御の `AreaSpec` が実際のDNG攻撃面になることを示す補助情報として保存した。
## パッチ解析
AOSP 取り込み差分は大きいが、CVE-2025-64783 の説明と一致する中核は `source/dng_misc_opcodes.cpp` の `dng_area_spec` を使う opcode 処理である。特に以下の4系統が同じ形で修正されている。
- `dng_opcode_DeltaPerRow::ProcessArea`
- `dng_opcode_DeltaPerColumn::ProcessArea`
- `dng_opcode_ScalePerRow::ProcessArea`
- `dng_opcode_ScalePerColumn::ProcessArea`
修正前は、`Overlap(dstArea)` の結果から得た絶対座標 `row` / `col` をそのまま `int32` のループ変数にし、攻撃者がDNGファイル内で指定できる `rowPitch` / `colPitch` を足していた。DNG SDK の `dng_area_spec::GetData` は `fArea` の矩形と pitch の基本的な整合性は見るが、座標は `int32`、pitch は `uint32` であるため、右端に近い座標や大きな pitch の組み合わせでは `int32 + uint32` の変換/代入で折り返しが起き得る。
修正後は、先に以下のような bounded count を計算し、ループ条件を絶対座標ではなく `rowIdx` / `colIdx` の反復回数で制御する。
```cpp
const uint32 rows = (overlap.H () + rowPitch - 1) / rowPitch;
const uint32 cols = (overlap.W () + colPitch - 1) / colPitch;
...
for (uint32 colIdx = 0; colIdx < cols; colIdx++) {
...
col += colPitch;
}
```
これにより、座標加算が折り返しても次のループ継続条件に使われなくなる。`DeltaPerColumn` では修正前に `for (int32 col = overlap.l; col < overlap.r; col += fAreaSpec.ColPitch())` という形だったため、`col` が負値に折り返すと `col < overlap.r` が真のままになり、`buffer.DirtyPixel_real32(overlap.t, col, plane)` が意図しない位置を指す危険がある。
同じ更新では `source/dng_pixel_buffer.cpp` にも `SetConstant` / `CopyArea` の範囲検証が追加されている。具体的には area がソース/宛先 bounds 内に完全に含まれること、plane 範囲が加算でオーバーフローしないこと、`fPlane..fPlane+fPlanes` 内に収まることを `DNG_REQUIRE` で確認する。これは別CVEも含む防御強化の可能性があるが、DNG SDK 全体として「矩形/plane 範囲を信頼していた」問題が修正対象だったことを裏付ける。
## 脆弱性が起きる状況
攻撃者はDNGファイルの opcode list に `DeltaPerColumn` などの opcode を入れ、`AreaSpec` の `top/left/bottom/right`、`plane/planes`、`rowPitch/colPitch`、delta/table 値を制御できる。パーサがこのDNGを処理すると、stage 2/3 の画像バッファに対して opcode が適用される。
修正前の実装では、`Overlap` で処理領域を画像領域と交差させた後でも、反復制御に絶対座標を直接使っていた。そのため、座標が `INT32_MAX` 付近にあり pitch 加算で折り返すケースでは、処理回数が `overlap` の要素数に縛られず、負座標や範囲外座標で `DirtyPixel_*` に到達し得る。これはOOB read/writeの根本原因であり、Android上では画像処理経路から情報漏えい、実装や呼び出し元によってはメモリ破壊に発展する。
`artifacts/opcode_pitch_model.py` でこの性質を小さくモデル化した。出力では、`[2147483640, 2147483647), pitch=16` のような境界条件で、修正前相当のループが `2147483640 -> -2147483640 -> ...` と折り返して継続する一方、修正後相当のループは事前計算された1回で停止することを確認した。
## 面白い点・調査メモ
- Android bulletin 上は System / ID だが、Adobe advisory は同じCVEを Arbitrary Code Execution につながる CWE-190 としている。Android側の影響評価は、AOSPでの到達経路・権限・利用形態に基づき情報漏えいに落としていると考えられる。
- AOSPコミットは `CVE-2025-64783` だけの最小パッチではなく、DNG SDK 1.7.1 build 2410 の大きな取り込みである。そのため同じコミットが `CVE-2025-64784`、`CVE-2025-64893` にも紐付いている。
- `README.version` は古い `Version: 1.4.0` のままで、コミットメッセージと実コード更新内容に比べてメタデータが追従していない。バージョン判定は `README.version` ではなく bulletin / commit message / upstream advisory を見る必要がある。
- Project Zero のDNG exploit解説では、実際の攻撃ファイルが拡張子 `.jpeg` でも実体はDNG/TIFFであり、DNG opcode list が巨大な攻撃プログラムのように使われていた。CVE-2025-64783そのもののAOSP実装とは別だが、DNG opcode がAndroid画像処理面で危険な入力言語になることをよく示している。
## 付帯ファイル
- `artifacts/android-security-bulletin-2026-03-01.html`: Android bulletin 保存版
- `artifacts/adobe_APSB25-118.html`: Adobe advisory 保存版
- `artifacts/projectzero_android_itw_dng.html`: Project Zero DNG exploit blog 保存版
- `artifacts/projectzero_android_itw_dng.txt`: 上記HTMLから抽出した本文
- `artifacts/commit_6b5cf2a88ebd2b099e56d0d4717e962772ff9067.txt`: AOSPコミットメタデータ
- `artifacts/patch_6b5cf2a88ebd2b099e56d0d4717e962772ff9067.diff`: AOSP取り込み全差分
- `artifacts/dng_opcode_related_patch.diff`: opcode / pixel buffer 周辺の抽出差分
- `artifacts/delta_row_column_excerpt.diff`: row/column opcode 修正箇所の抜粋差分
- `artifacts/pixel_buffer_bounds_excerpt.diff`: pixel buffer 境界検証追加の抜粋差分
- `artifacts/opcode_pitch_model.py`: ループ折り返しモデル
- `artifacts/opcode_pitch_model_output.txt`: モデル実行結果
- `artifacts/SHA256SUMS`: 付帯ファイルのハッシュ
cve.md を表示# CVE-2025-64783 - System ID High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-64783 - Component: System - Reference: A-483074175 - Type: ID - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 40 | OK | CVE-2025-64784 - System ID High |
040
ok
CVE-2025-64784 - System ID High040-ok-DNG-SDK-Linearize-trimmed-source-OOB-read cve.md の Android / Pixel 脆弱性情報
cve.md summary System ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(判定) OK。ソースコード差分と公開Project Zero検索結果から、CVE-2025-64784 の発生箇所、攻撃条件、根本原因、修正方針を説明できる。 原因(根本原因) 根本原因は、DNGタグ由来の論理処理範囲 `fActiveArea` と、実際にメモリ上へ存在する画像バッファ範囲 `srcImage.Bounds()` を同一視していたこと。トリムや派生画像生成により両者がずれた場合、画像処理タスクが存在しないソース画素を処理対象に含めてしまう。 パッチは「ActiveAreaを信用する」のではなく、`fActiveArea & srcImage.Bounds()` を使って実入力画像の範囲に制限する設計に変えているため、根本原因に直接対応している。 どこから特定したか validated.md の「参照情報」「パッチ差分の要点」 / Android bug参照 A-483074618 validated.md を表示# CVE-2025-64784 検証結果
## 結論
このフォルダのCVEは特定できた。CVE-2025-64784 は Android の System コンポーネントとして掲載されているが、実体は AOSP `platform/external/dng_sdk` に取り込まれた Adobe DNG SDK 1.7.1 build 2410 への更新に含まれる修正である。
脆弱性は、DNG SDK の `dng_linearization_info::Linearize()` が、実際の入力画像 `srcImage.Bounds()` ではなく、DNGメタデータ由来の `fActiveArea` 全体を処理範囲として使っていたことにより、トリム済み/小さいソース画像に対して範囲外のタイルを読み出す問題だった。Project Zero の公開検索結果でも、Issue 452483592 は `Adobe DNG SDK: Linearize uses full image on trimmed source image, leading to out-of-bounds read` とされ、CVE-2025-64784 に対応している。
Android Security Bulletin 上の種別は ID、Adobe/NVD 上の種別は Heap-based Buffer Overflow / CWE-122 だが、Project Zero の題名とパッチ内容から見ると、少なくともAndroidに取り込まれた修正で説明できる直接の不具合は「ヒープ上の画像バッファ範囲外読み取りによる情報漏えい」である。分類には公開情報間の不整合がある。
## 参照情報
- Android Security Bulletin March 2026: `CVE-2025-64784 / A-483074618 / System / ID / High / 14,15,16,16-qpr2`
- AOSP commit: `6b5cf2a88ebd2b099e56d0d4717e962772ff9067` (`Update to DNG SDK 1.7.1 2410`)
- AOSP parent: `68764928faa1d15f76bbf8f03c6e630c570a4354`
- Adobe APSB25-118: DNG SDK 1.7.0 and earlier affected, fixed in DNG SDK 1.7.1 build 2410
- Project Zero search evidence: Issue 452483592, CVE-2025-64784, title above
## パッチ差分の要点
主修正は `source/dng_linearization_info.cpp`。
修正前:
```cpp
host.PerformAreaTask (processor,
fActiveArea);
```
修正後:
```cpp
dng_rect overlap = fActiveArea & srcImage.Bounds ();
host.PerformAreaTask (processor,
overlap);
```
さらに `dng_linearize_plane::Process()` に、処理対象タイルが入力画像・出力画像の範囲内であることを確認するアサーションが追加された。
```cpp
DNG_REQUIRE ((fSrcImage.Bounds () & srcTile) == srcTile,
"Invalid srcTile in dng_linearize_plane::Process");
DNG_REQUIRE ((fDstImage.Bounds () & dstTile) == dstTile,
"Invalid dstTile in dng_linearize_plane::Process");
```
この2点により、メタデータ上の `ActiveArea` が実画像より大きい、またはトリム後の画像と一致しない場合でも、実在する画像領域との交差部分だけが処理される。
## 脆弱性の発生条件
1. 攻撃者が細工したDNGファイルを被害者に開かせる。
2. DNG内の画像本体はトリム済み、または実際の `srcImage.Bounds()` が小さい状態になる。
3. 一方で `ActiveArea` はより広い領域を指すように構成される。
4. SDKはStage1からStage2を作る `dng_negative::DoBuildStage2()` で `info.Linearize(host, *this, stage1, *fStage2Image)` を呼ぶ。
5. 修正前の `Linearize()` は `srcImage.Bounds()` を見ずに `fActiveArea` 全体で `PerformAreaTask()` を実行する。
6. `dng_linearize_plane::Process()` は `srcTile` をそのまま `dng_const_tile_buffer` に渡し、タイル内の画素を読み出す。
7. `srcTile` が実際のソース画像範囲を越えている場合、ヒープ上の画像バッファ外を読み、情報漏えいまたはクラッシュにつながる。
## 根本原因
根本原因は、DNGタグ由来の論理処理範囲 `fActiveArea` と、実際にメモリ上へ存在する画像バッファ範囲 `srcImage.Bounds()` を同一視していたこと。トリムや派生画像生成により両者がずれた場合、画像処理タスクが存在しないソース画素を処理対象に含めてしまう。
パッチは「ActiveAreaを信用する」のではなく、`fActiveArea & srcImage.Bounds()` を使って実入力画像の範囲に制限する設計に変えているため、根本原因に直接対応している。
## Androidでの影響
Androidでは `external/dng_sdk` が画像処理コードとして取り込まれており、悪意あるDNG/JXL関連画像をローカルで処理する経路が影響を受ける。Android Bulletin の影響分類が ID High であることから、想定影響は任意コード実行ではなく、画像デコード/処理時のメモリ内容漏えいとして扱うのが妥当。
ユーザー操作については公開情報に差がある。Adobe/NVDは「被害者が悪意あるファイルを開く必要がある」としている。Android Bulletin/OSV側はSystem IDとして掲載しているが、OSV JSONのdetailsにはEoP風の文言も混じっており、このCVEについては自動生成メタデータが正確でない可能性がある。
## 面白い点・調査メモ
- Android Bulletinでは `CVE-2025-64783`、`CVE-2025-64784`、`CVE-2025-64893` が同じAOSPリンク `external/dng_sdk` 更新に束ねられている。
- Adobe APSB25-118では CVE-2025-64784 を `Heap-based Buffer Overflow` としているが、Project Zero の公開題名は `out-of-bounds read`。Android側のID分類とはProject Zero題名の方が整合する。
- パッチはDNG SDK全体のバージョン更新で61ファイルが変わるため、単純なdiffだけだとJXL出力バッファや `dng_pixel_buffer::CopyArea()` の防御追加も候補に見える。CVE番号との対応はProject Zero検索結果で `Linearize uses full image on trimmed source image` と確認して切り分けた。
- 追加防御として `dng_pixel_buffer::SetConstant()` / `CopyArea()` にも範囲検証が入っており、同じ更新内の別CVEまたは防御強化に関連している可能性が高い。
## 付帯ファイル
- `analysis/aosp_external_dng_sdk_1.7.0_to_1.7.1.diff`: AOSP公開コミット全体差分
- `analysis/linearize_activearea_fix.diff`: 今回のCVEに対応する主要差分
- `analysis/linearize_prepatch_relevant_snippet.txt`: 修正前の関連コード抜粋
- `analysis/linearize_postpatch_relevant_snippet.txt`: 修正後の関連コード抜粋
- `analysis/stage2_linearize_call_path.txt`: `dng_negative::DoBuildStage2()` から `Linearize()` への呼び出し経路
- `analysis/project_zero_search_evidence.txt`: Project Zero検索結果から確認したCVE対応情報
- `analysis/ASB-A-483074618.json`: Android OSV JSON
- `analysis/commit_stat.txt`, `analysis/aosp_commit_metadata.txt`: AOSPコミット情報
## 判定
OK。ソースコード差分と公開Project Zero検索結果から、CVE-2025-64784 の発生箇所、攻撃条件、根本原因、修正方針を説明できる。
cve.md を表示# CVE-2025-64784 - System ID High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-64784 - Component: System - Reference: A-483074618 - Type: ID - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 41 | OK | CVE-2025-64893 - System ID High |
041
ok
CVE-2025-64893 - System ID High041-ok-DNG-SDK-RefBaselineABCDtoRGB-OOB-read cve.md の Android / Pixel 脆弱性情報
cve.md summary System ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(判定) ok。AOSP に取り込まれた DNG SDK 1.7.1 build 2410 への更新差分と、Project Zero の公開メタデータに一致するソースコード上の修正点から、脆弱性の発生条件と根本原因を特定できた。 原因(根本原因) レンダリング処理の入力不変条件がコードで保証されていなかったことが根本原因である。 `dng_render_task::ProcessArea()` は設計上 `fSrcPlanes` が 1、3、4 のいずれかであることを前提にしていた。しかし旧コードは `else` 分岐を「4 プレーン」ではなく「1/3 以外すべて」として書いていた。結果として、IFD 側で許容された 2 プレーン入力が 4 プレーン変換関数に渡り、変換関数側はポインタが 4 本とも有効であると信じて読み込んでいた。 これは単純な境界チェック漏れというより、パーサ/画像モデルの許容範囲と render パスの対応可能プレーン数の不一致である。パッチは render パスの境界で `fSrcPlanes == 4` を明示し、入力不変条件を実行時チェックにした。 どこから特定したか validated.md の「参照情報」「パッチ解析」 / Android bug参照 A-483075215 validated.md を表示# CVE-2025-64893 検証結果
## 判定
ok。AOSP に取り込まれた DNG SDK 1.7.1 build 2410 への更新差分と、Project Zero の公開メタデータに一致するソースコード上の修正点から、脆弱性の発生条件と根本原因を特定できた。
## 要約
CVE-2025-64893 は Adobe DNG SDK 1.7.0 以前の DNG レンダリング処理にある out-of-bounds read である。悪意ある DNG/RAW ファイルを被害者が開くと、SDK が存在しない画像プレーンを読み、プロセス内メモリの露出またはクラッシュにつながり得る。
Android では 2026-03-01 Android Security Bulletin の System コンポーネント ID High として登録され、AOSP では `platform/external/dng_sdk` の `6b5cf2a88ebd2b099e56d0d4717e962772ff9067` により DNG SDK 1.7.1 build 2410 へ更新されている。同じ AOSP 変更は `CVE-2025-64783`、`CVE-2025-64784`、`CVE-2025-64893` にまとめてリンクされている。
## 参照情報
- Android Security Bulletin 2026-03-01: `CVE-2025-64893 / A-483075215 / System / ID / High / 14, 15, 16, 16-qpr2`
- AOSP commit: `platform/external/dng_sdk` `6b5cf2a88ebd2b099e56d0d4717e962772ff9067`、`Update to DNG SDK 1.7.1 2410`
- Adobe APSB25-118: DNG SDK 1.7.0 and earlier, out-of-bounds read, memory exposure, CVSS 7.1, user interaction required
- NVD: `CWE-125 Out-of-bounds Read`
- Project Zero 公開検索結果: issue `457419672`、タイトルは `Adobe DNG SDK: out-of-bounds read in RefBaselineABCDtoRGB during the Render phase`、CVE ID は `CVE-2025-64893`
## パッチ解析
最小のセキュリティ修正は `source/dng_render.cpp` の `dng_render_task::ProcessArea()` にある。旧コードは次の分岐だった。
```cpp
if (fSrcPlanes == 1) {
...
} else {
const real32 *sPtrB = sPtrA + srcBuffer.fPlaneStep;
const real32 *sPtrC = sPtrB + srcBuffer.fPlaneStep;
if (fSrcPlanes == 3) {
DoBaselineABCtoRGB(...);
} else {
const real32 *sPtrD = sPtrC + srcBuffer.fPlaneStep;
DoBaselineABCDtoRGB(... sPtrC, sPtrD, ...);
}
}
```
つまり `fSrcPlanes == 2` のような「1 でも 3 でもない複数プレーン」が来ると、4 プレーン画像として扱われる。`sPtrC` は 3 番目のプレーン、`sPtrD` は 4 番目のプレーンを指す前提で計算されるが、2 プレーン画像にはその領域が存在しない。
修正後は 4 プレーン変換に入る直前に次のチェックが追加された。
```cpp
// Expect 4 src planes here. This method expects and only
// supports fSrcPlanes being 1,3 or 4.
DNG_REQUIRE (fSrcPlanes == 4, "fSrcPlanes");
```
`DNG_REQUIRE` は release 構成でも条件不成立時に `ThrowProgramError()` を投げるため、存在しない C/D プレーンを読む前に処理が止まる。
## 脆弱性の発生条件
攻撃者は `SamplesPerPixel=2` など、SDK の render パスが扱う `fSrcPlanes` を 2 にできる DNG/RAW 入力を作る。pre-patch の `dng_ifd::PostParse()` では `PhotometricInterpretation == piCFA` の場合、`SamplesPerPixel` は `1..kMaxSamplesPerPixel` の範囲として扱われ、2 プレーン値そのものはここでは排除されない。
その入力が render フェーズに進むと、`dng_filter_task` のコンストラクタが `fSrcPlanes = srcImage.Planes()` として入力画像のプレーン数をそのまま保持する。`dng_render_task::ProcessArea()` は `fSrcPlanes == 1` と `fSrcPlanes == 3` だけを特別扱いし、それ以外を 4 プレーン用の `DoBaselineABCDtoRGB()` に流す。
`DoBaselineABCDtoRGB()` は `RefBaselineABCDtoRGB()` を呼び、同関数は各列で `sPtrC[col]` と `sPtrD[col]` を読み取る。2 プレーン画像では C/D プレーンがないため、行バッファ外の `real32` 配列を読み、out-of-bounds read が成立する。
## 根本原因
レンダリング処理の入力不変条件がコードで保証されていなかったことが根本原因である。
`dng_render_task::ProcessArea()` は設計上 `fSrcPlanes` が 1、3、4 のいずれかであることを前提にしていた。しかし旧コードは `else` 分岐を「4 プレーン」ではなく「1/3 以外すべて」として書いていた。結果として、IFD 側で許容された 2 プレーン入力が 4 プレーン変換関数に渡り、変換関数側はポインタが 4 本とも有効であると信じて読み込んでいた。
これは単純な境界チェック漏れというより、パーサ/画像モデルの許容範囲と render パスの対応可能プレーン数の不一致である。パッチは render パスの境界で `fSrcPlanes == 4` を明示し、入力不変条件を実行時チェックにした。
## 影響
- 種別: information disclosure (`CWE-125`)
- 影響: SDK 利用プロセス内の隣接メモリ読み取り、またはクラッシュ
- 攻撃条件: 被害者が悪意ある DNG/RAW ファイルを開く必要がある
- Android での扱い: System component の ID High
`RefBaselineABCDtoRGB()` は読み取った A/B/C/D 値を `cameraWhite` でクリップし、`cameraToRGB` 行列に乗算して RGB 出力へ反映する。したがって OOB read の値は出力画像ピクセルに影響し得る。クラッシュだけでなく memory exposure と評価されているのはこのためと考えられる。
## 調査中に分かったこと
- Android bulletin の CVE 行は Android bug ID `A-483075215` だが、リンク先の公開修正は個別 CVE 用の小パッチではなく Adobe DNG SDK 全体の 1.7.1 build 2410 への大きな更新である。
- Adobe APSB25-118 には DNG SDK の CVE が 4 件載っているが、Android bulletin では少なくとも `CVE-2025-64783`、`CVE-2025-64784`、`CVE-2025-64893` が同じ AOSP commit に紐づく。`CVE-2025-64894` は Adobe advisory にはあるが、この Android bulletin 行には直接出ていない。
- Project Zero issue 本文はブラウザ上ではサインイン要求になったが、公開検索結果のタイトルが `RefBaselineABCDtoRGB during the Render phase` を明示しており、AOSP diff の最小修正点と一致した。
- 修正は入力ファイルの IFD 検証側で `SamplesPerPixel=2` を拒否する形ではなく、render 側で 4 プレーン専用分岐の前提を明示する形だった。DNG SDK 内には 2 プレーンを意味のあるケースとして扱う別経路もあるため、局所修正として自然。
## 保存した付帯ファイル
- `artifacts/aosp_commit_metadata.txt`: AOSP commit メタデータ
- `artifacts/aosp_commit_stat.txt`: 変更統計
- `artifacts/aosp_commit_full.diff`: AOSP commit 全差分
- `artifacts/dng_render_fix.diff`: `dng_render.cpp` の焦点差分
- `artifacts/prepatch_render_call.txt`: 旧 `ProcessArea()` の該当箇所
- `artifacts/postpatch_render_call.txt`: 修正後 `ProcessArea()` の該当箇所
- `artifacts/ref_baseline_abcd_read.txt`: `RefBaselineABCDtoRGB()` の C/D プレーン読み取り箇所
- `artifacts/prepatch_samples_per_pixel_validation.txt`: 旧 IFD `SamplesPerPixel` 検証箇所
- `artifacts/dng_require_behavior.txt`: `DNG_REQUIRE` の release 時挙動
- `artifacts/adobe_APSB25-118.html`: Adobe advisory 保存コピー
- `artifacts/nvd_CVE-2025-64893.html`: NVD 保存コピー
## 結論
CVE-2025-64893 は、DNG render パスが対応可能プレーン数を `1/3/4` に限定しているにもかかわらず、旧コードで `1/3 以外` を 4 プレーンとして処理していたことにより発生した out-of-bounds read である。悪意ある 2 プレーン DNG 入力が render フェーズに到達すると、`RefBaselineABCDtoRGB()` が存在しない C/D プレーンを読み、メモリ露出または DoS を引き起こし得る。修正は 4 プレーン変換直前に `fSrcPlanes == 4` を要求し、誤ったプレーン数を読み取り前に停止させるものだった。
cve.md を表示# CVE-2025-64893 - System ID High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-64893 - Component: System - Reference: A-483075215 - Type: ID - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 42 | OK | CVE-2026-0005 - System ID High |
042
ok
CVE-2026-0005 - System ID High042-ok-app-pinning-partial-bypass cve.md の Android / Pixel 脆弱性情報
cve.md summary System ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性が起きる状況) 成立条件は次の通り。 1. App pinning / screen pinning が有効。 2. 端末があるアプリを pinned mode にしている。 3. 通常は pinned mode 解除や他アプリ操作に LSKF が必要。 4. pinned mode 中に SystemUI/keyguard service がクラッシュまたは再起動する。 5. 未修正版では `system_server` 側の lock task 状態は pinned のままだが、SystemUI/keyguard 側の制限が再構築されない。 6. 攻撃者は LSKF を知らずに pinned app 外の UI や他アプリへ限定的に触れられる可能性があり、通知、最近のアプリ、背後の画面、他アプリの表示内容などから情報漏えいが起き得る。 「限定的」なのは、lock task の内部状態が完全に解除されるわけではなく、壊れるのが SystemUI/keyguard 側の制限復元だから。情報漏えいの大きさは、その時に表示・操作可能になるアプリや通知内容に依存する。 原因(脆弱性の根本原因) 根本原因は、pinned mode の状態管理が分断されていたこと。 `system_server` の `LockTaskController` には `mLockTaskModeState == LOCK_TASK_MODE_PINNED` と `mLockTaskModeTasks` が残る。しかし、実際にユーザーを pinned app 内へ閉じ込める副作用の一部は SystemUI/keyguard service 側にある。 pinned mode 開始時、古い `LockTaskController` は次を実行していた。 - status bar に `STATUS_BAR_MASK_PINNED` を設定。 - keyguard に `disableKeyguard()` を設定。 ところが SystemUI/keyguard service が切断されると、古い `KeyguardServiceDelegate.onServiceDisconnected()` は `mKeyguardState.reset()` を呼び、`reset()` は `enabled = true` に戻していた。再接続時の `onServiceConnected()` は `enabled=false` の場合だけ `setKeyguardEnabled(false)` を再送するため、pinned mode 中だった事実が消え、keyguard 無効化が復元されない。 さらに、SystemUI 再起動後に status bar disable flag を pinned mode として再設定する経路もなかった。このため内部状態は pinned のままなのに、UI/keyguard 制限だけが抜け落ちる。 どこから特定したか validated.md の「参照した一次情報」 / Android bug参照 A-366405211 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://android.googlesource.com/platform/frameworks/base/+/92b109b6041452f6e713dcce512fa8de18556360, https://storage.googleapis.com/android-osv/ASB-A-366405211.json, https://cveawg.mitre.org/api/cve/CVE-2026-0005 validated.md を表示# CVE-2026-0005 検証結果
## 判定
ok。公開 AOSP ソース差分から脆弱性の原因と修正内容を特定できた。
対象は Android `platform/frameworks/base` の app pinning / lock task / keyguard 復旧処理。CVE の実体は、app pinning 中に SystemUI/keyguard service がクラッシュまたは再起動した場合、pinned mode の内部状態は `system_server` に残る一方で、SystemUI/keyguard 側に適用されていた UI 制限が復元されず、LSKF を知らないローカル攻撃者が pinned app 外へ限定的に触れて情報を見られる可能性がある、という情報漏えい。
## 参照した一次情報
- Android Security Bulletin 2026-03-01: `CVE-2026-0005`, `A-366405211`, System, ID, High, affected Android 14/15/16
- https://source.android.com/docs/security/bulletin/2026/2026-03-01
- 公開メインライン修正:
- https://android.googlesource.com/platform/frameworks/base/+/92b109b6041452f6e713dcce512fa8de18556360
- Android OSV:
- https://storage.googleapis.com/android-osv/ASB-A-366405211.json
- CVE Record:
- https://cveawg.mitre.org/api/cve/CVE-2026-0005
## 公式説明との対応
CVE Record / OSV の説明は次の内容だった。
- `KeyguardServiceDelegate.java` の `onServiceDisconnected` における app pinning の部分バイパス。
- LSKF を知らなくても他アプリとの限定的な interaction が可能。
- 影響はローカル情報漏えいで、範囲はアプリ依存。
- 追加権限もユーザー操作も不要。
パッチ差分はこの説明と一致する。修正は `KeyguardServiceDelegate.onServiceDisconnected()`、`KeyguardViewMediator.onBootCompleted()`、`LockTaskController` の pinned mode 再構築処理に集中していた。
## パッチで追加されたもの
公開メインライン差分 `patch_92b109b6041452f6.diff` と Android 14 差分 `patch_android14_35fb7e8e9014.diff` を確認した。
主な変更:
- `IActivityTaskManager.aidl`
- `rebuildSystemLockTaskPinnedMode()` を追加。
- `ActivityTaskManagerService`
- `rebuildSystemLockTaskPinnedMode()` を実装。
- `enforceTaskPermission("rebuildSystemLockTaskPinnedMode")` で Binder 呼び出しを保護。
- `LockTaskController.rebuildSystemLockTaskPinnedMode()` へ委譲。
- `KeyguardServiceDelegate.onServiceDisconnected()`
- `mKeyguardState.reset()` の前に `enabled` を退避。
- reset 後に `mKeyguardState.enabled = wasEnabled` として復元。
- `KeyguardViewMediator.onBootCompleted()`
- 現在の lock task mode が `LOCK_TASK_MODE_PINNED` なら `ActivityTaskManagerService.rebuildSystemLockTaskPinnedMode()` を呼ぶ。
- `LockTaskController`
- 既存の `mLockTaskModeTasks` を使って pinned mode の UI 制限を再適用する `rebuildSystemLockTaskPinnedMode()` を追加。
- 再適用内容は `notifyLockTaskModeChanged()`、`setStatusBarState()`、`setKeyguardState()` など。
## 脆弱性の根本原因
根本原因は、pinned mode の状態管理が分断されていたこと。
`system_server` の `LockTaskController` には `mLockTaskModeState == LOCK_TASK_MODE_PINNED` と `mLockTaskModeTasks` が残る。しかし、実際にユーザーを pinned app 内へ閉じ込める副作用の一部は SystemUI/keyguard service 側にある。
pinned mode 開始時、古い `LockTaskController` は次を実行していた。
- status bar に `STATUS_BAR_MASK_PINNED` を設定。
- keyguard に `disableKeyguard()` を設定。
ところが SystemUI/keyguard service が切断されると、古い `KeyguardServiceDelegate.onServiceDisconnected()` は `mKeyguardState.reset()` を呼び、`reset()` は `enabled = true` に戻していた。再接続時の `onServiceConnected()` は `enabled=false` の場合だけ `setKeyguardEnabled(false)` を再送するため、pinned mode 中だった事実が消え、keyguard 無効化が復元されない。
さらに、SystemUI 再起動後に status bar disable flag を pinned mode として再設定する経路もなかった。このため内部状態は pinned のままなのに、UI/keyguard 制限だけが抜け落ちる。
## 脆弱性が起きる状況
成立条件は次の通り。
1. App pinning / screen pinning が有効。
2. 端末があるアプリを pinned mode にしている。
3. 通常は pinned mode 解除や他アプリ操作に LSKF が必要。
4. pinned mode 中に SystemUI/keyguard service がクラッシュまたは再起動する。
5. 未修正版では `system_server` 側の lock task 状態は pinned のままだが、SystemUI/keyguard 側の制限が再構築されない。
6. 攻撃者は LSKF を知らずに pinned app 外の UI や他アプリへ限定的に触れられる可能性があり、通知、最近のアプリ、背後の画面、他アプリの表示内容などから情報漏えいが起き得る。
「限定的」なのは、lock task の内部状態が完全に解除されるわけではなく、壊れるのが SystemUI/keyguard 側の制限復元だから。情報漏えいの大きさは、その時に表示・操作可能になるアプリや通知内容に依存する。
## 修正の効果
修正後は二段で復旧する。
1. `KeyguardServiceDelegate.onServiceDisconnected()` が `enabled` を保持するため、pinned mode による keyguard disabled 状態が reset で失われない。
2. `KeyguardViewMediator.onBootCompleted()` が pinned mode を検出し、`LockTaskController.rebuildSystemLockTaskPinnedMode()` で status bar と keyguard の pinned mode 制限を再適用する。
これにより、SystemUI/keyguard service が再起動しても、pinned mode の内部状態と UI 制限が再び一致する。
## 調査時メモ
- CVE/OSV の文言は「missing permission check」としているが、差分を見る限り、主修正は「SystemUI/keyguard 再起動時の pinned mode 副作用の再構築」。追加 Binder API には `enforceTaskPermission()` が入っている。
- `mLockTaskModeState` が pinned のまま残るため、単に dumpsys などで内部状態を見るだけでは問題を見落としやすい。壊れていたのは state そのものではなく、その state を SystemUI/keyguard 側へ反映する復旧経路。
- Android 14 の公開差分と公開メインライン差分は同じ構造。OSV は Android 15/16 の修正 URL も列挙しているが、2026-06-25 時点で `android.googlesource.com` の直接取得は 404 だった。
- Pixel 固有バイナリ解析は不要だった。脆弱性と修正が AOSP `frameworks/base` の Java ソースで完結しているため。
## 付帯ファイル
- `patch_analysis.md`: 詳細なパッチ解析メモ。
- `patch_92b109b6041452f6.diff`: 公開メインライン修正差分。
- `patch_qpr2next_575845147cb4.diff`: 16-qpr2-next 元修正差分。
- `patch_android14_35fb7e8e9014.diff`: Android 14 修正差分。
- `ASB-A-366405211.osv.json`: Android OSV JSON。
- `CVE-2026-0005.cve.json`: CVE Record JSON。
- `KeyguardServiceDelegate_*.java`, `KeyguardViewMediator_*.java`, `LockTaskController_*.java`: 比較用に取得した親版・修正版ソース断片。
cve.md を表示# CVE-2026-0005 - System ID High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0005 - Component: System - Reference: A-366405211 - Type: ID - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 43 | OK | CVE-2026-0024 - System ID High |
043
ok
CVE-2026-0024 - System ID High043-ok-ACCESS_MEDIA_LOCATION-SAF-picker-ID cve.md の Android / Pixel 脆弱性情報
cve.md summary System ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) Android は画像・動画の EXIF 位置情報を privacy-sensitive として扱う。通常、アプリが元ファイルの位置情報へアクセスするには `ACCESS_MEDIA_LOCATION` が必要で、権限がない場合は MediaProvider がファイル内容を redaction して位置情報を隠す。 脆弱版では、Storage Access Framework / MediaDocumentsProvider 経由でメディアを開く場合に、この redaction 判定が実際の受け取りアプリではなく、MediaProvider へ代理呼び出ししている側の identity で行われていた。 該当経路は次の通り。 1. アプリが SAF picker でメディアを選び、DocumentsProvider 形式の URI への read 権限を得る。 2. アプリがその URI を `ContentResolver.openFileDescriptor()` などで開く。 3. `MediaDocumentsProvider.openDocument()` は Binder caller の UID を `callingUid` として取得する。 4. その後 `Binder.clearCallingIdentity()` して、MediaStore の実 URI を `openTypedAssetFileDescriptor()` で開く。 5. このとき `opts.putInt(MediaStore.EXTRA_MEDIA_CAPABILITIES_UID, callingUid)` として、元のアプリ UID は Bundle に入る。 6. しかしパッチ前の `isRedactionNeededForOpenViaContentResolver()` は `opts` を見ず、MediaProvider 側の `mCallingIdentity` だ... 原因(根本原因) 根本原因は、「ファイルを開く Binder caller」と「ファイル内容を受け取る実際のアプリ」の identity を分けて扱う代理オープン経路で、redaction / `ACCESS_MEDIA_LOCATION` 判定だけが代理対象 UID を参照していなかったこと。 `EXTRA_MEDIA_CAPABILITIES_UID` は既にトランスコード判定では「どのアプリのメディア対応能力を使うか」を表す UID として渡されていた。MediaDocumentsProvider も元のアプリ UID をこの extra に入れていた。しかし、パッチ前の redaction 判定は `ownerPackageName`、File Manager / System Gallery 例外、現在の calling identity の `PERMISSION_IS_REDACTION_NEEDED` だけを見ており、`mediaCapabilitiesUid` 側の `ACCESS_MEDIA_LOCATION` 不足を見落としていた。 これは SQL injection やパス検証ミスではなく、代理実行における authorization subject の取り違えである。 どこから特定したか Android bug参照 A-326211886 / 参照URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://android.googlesource.com/platform/packages/providers/MediaProvider/+/69a25763cdb46c8f23fe9eb976132acbe2af82d6, https://www.cve.org/CVERecord?id=CVE-2026-0024 validated.md を表示# CVE-2026-0024 MediaProvider ID パッチ解析
## 判定
ok: ソースコード差分から、脆弱性の発生条件、情報漏えい内容、根本原因、修正内容を特定できた。
対象は Android Security Bulletin - March 2026 の System / MediaProvider `CVE-2026-0024`、参照バグは `A-326211886`。公開CVE本文では、`MediaProvider.java` の `isRedactionNeededForOpenViaContentResolver` で permission check が不足し、media の location を漏えいできる local information disclosure と説明されている。
## 関連パッチ
- リポジトリ: `platform/packages/providers/MediaProvider`
- 修正コミット: `69a25763cdb46c8f23fe9eb976132acbe2af82d6`
- 件名: `Fix ACCESS_MEDIA_LOCATION bypass via SAF picker`
- 親コミット: `8a710e8508880a2af058ad93b58b4fe5e770be57`
- 変更ファイル:
- `src/com/android/providers/media/MediaProvider.java`
パッチは `openFileAndEnforcePathPermissionsHelper()` から `isRedactionNeededForOpenViaContentResolver()` へ `Bundle opts` を渡すようにし、`opts` 内の `MediaStore.EXTRA_MEDIA_CAPABILITIES_UID` で示される UID についても `PERMISSION_IS_REDACTION_NEEDED` を評価する。
## 脆弱性の内容
Android は画像・動画の EXIF 位置情報を privacy-sensitive として扱う。通常、アプリが元ファイルの位置情報へアクセスするには `ACCESS_MEDIA_LOCATION` が必要で、権限がない場合は MediaProvider がファイル内容を redaction して位置情報を隠す。
脆弱版では、Storage Access Framework / MediaDocumentsProvider 経由でメディアを開く場合に、この redaction 判定が実際の受け取りアプリではなく、MediaProvider へ代理呼び出ししている側の identity で行われていた。
該当経路は次の通り。
1. アプリが SAF picker でメディアを選び、DocumentsProvider 形式の URI への read 権限を得る。
2. アプリがその URI を `ContentResolver.openFileDescriptor()` などで開く。
3. `MediaDocumentsProvider.openDocument()` は Binder caller の UID を `callingUid` として取得する。
4. その後 `Binder.clearCallingIdentity()` して、MediaStore の実 URI を `openTypedAssetFileDescriptor()` で開く。
5. このとき `opts.putInt(MediaStore.EXTRA_MEDIA_CAPABILITIES_UID, callingUid)` として、元のアプリ UID は Bundle に入る。
6. しかしパッチ前の `isRedactionNeededForOpenViaContentResolver()` は `opts` を見ず、MediaProvider 側の `mCallingIdentity` だけで redaction 要否を決めていた。
その結果、`ACCESS_MEDIA_LOCATION` を持たないアプリでも、SAF picker で選択した画像を開くと、redaction されていない EXIF GPS 位置情報を受け取れる可能性があった。直接 MediaStore URI を開く通常経路では caller identity がアプリ自身なので redaction されるが、SAF 代理経路では capability UID が redaction 判定に使われていなかった点が bypass になっている。
## 根本原因
根本原因は、「ファイルを開く Binder caller」と「ファイル内容を受け取る実際のアプリ」の identity を分けて扱う代理オープン経路で、redaction / `ACCESS_MEDIA_LOCATION` 判定だけが代理対象 UID を参照していなかったこと。
`EXTRA_MEDIA_CAPABILITIES_UID` は既にトランスコード判定では「どのアプリのメディア対応能力を使うか」を表す UID として渡されていた。MediaDocumentsProvider も元のアプリ UID をこの extra に入れていた。しかし、パッチ前の redaction 判定は `ownerPackageName`、File Manager / System Gallery 例外、現在の calling identity の `PERMISSION_IS_REDACTION_NEEDED` だけを見ており、`mediaCapabilitiesUid` 側の `ACCESS_MEDIA_LOCATION` 不足を見落としていた。
これは SQL injection やパス検証ミスではなく、代理実行における authorization subject の取り違えである。
## 修正後の挙動
修正後の `isRedactionNeededForOpenViaContentResolver(redactedUri, ownerPackageName, file, opts)` は、通常の caller 判定より前に次を行う。
```java
final int mediaCapabilitiesUid = opts.getInt(MediaStore.EXTRA_MEDIA_CAPABILITIES_UID);
if (mediaCapabilitiesUid > 0) {
final LocalCallingIdentity identity = LocalCallingIdentity.fromExternal(
getContext(), mUserCache, mediaCapabilitiesUid, null, null);
if (identity.hasPermission(PERMISSION_IS_REDACTION_NEEDED)) {
return true;
}
}
```
`PERMISSION_IS_REDACTION_NEEDED` は、対象 UID が `ACCESS_MEDIA_LOCATION` などの条件を満たさず位置情報 redaction が必要な場合に true になる。したがって、SAF が代理で開いていても、実際にファイルを受け取るアプリが位置情報権限を持たなければ redaction される。
## 悪用シナリオ
1. 攻撃アプリは `ACCESS_MEDIA_LOCATION` を持たない。
2. 攻撃アプリは SAF picker で、位置情報 EXIF を含む画像をユーザーに選ばせる。
3. 攻撃アプリは返ってきた DocumentsProvider URI を開く。
4. 脆弱版では MediaDocumentsProvider が MediaProvider に代理で open し、MediaProvider の redaction 判定が代理対象アプリ UID を見ない。
5. 画像が redaction されず、攻撃アプリは EXIF GPS 位置情報を読み取れる。
ユーザーが picker でファイルを選ぶ操作は必要だが、CVE本文の「User interaction is not needed」は、権限昇格ダイアログや追加の実行権限が不要という意味のCVSS整理と思われる。少なくともパッチ件名は SAF picker 経由の bypass を明示している。
## ローカル検証
実機で MediaProvider を差し替えた再現はしていない。代わりに AOSP ソース差分と最小モデルで、パッチ前後の判定差を確認した。
`artifacts/redaction_decision_model.py` の結果:
```text
SAF picker opens for ordinary app without ACCESS_MEDIA_LOCATION: pre_patch_redact=False, post_patch_redact=True
Direct ContentResolver open by ordinary app without ACCESS_MEDIA_LOCATION: pre_patch_redact=True, post_patch_redact=True
Owner opens own media: pre_patch_redact=False, post_patch_redact=False
```
このモデルは Android 権限実装そのものではなく、差分で変わった制御フローを抽象化したもの。重要なのは、SAF 代理 open のケースだけが `pre_patch_redact=False` から `post_patch_redact=True` に変わる点である。
## 面白い点・調査メモ
- 修正差分は 1 ファイル 20 行程度と小さいが、実際の問題は `MediaDocumentsProvider`、`MediaStore.EXTRA_MEDIA_CAPABILITIES_UID`、transcode/redaction の代理 UID 設計をまたぐ。
- `mediaCapabilitiesUid` は名前だけ見るとメディア形式変換用だが、ここでは「代理対象アプリの能力」というより一般的な authorization subject として使われている。
- パッチ前でも `mediaCapabilitiesUid` は FUSE/transcode 経路へ渡されていた。つまり UID の情報は存在していたが、EXIF redaction 判定だけがその情報を消費していなかった。
- 直接 MediaStore を開く一般的な API 経路では caller が攻撃アプリ自身なので redaction される。SAF picker の代理呼び出しが必要条件。
- このコミットは `origin/android16-security-release` に含まれていた。ローカル mirror に Android 14/15 向け cherry-pick もあり、同じ件名・Bug ID の複数コミットが存在する。
- Pixel 固有バイナリ解析は不要だった。対象は AOSP MediaProvider の Java 実装で、ソース差分から特定可能。
## 保存した付帯ファイル
- `artifacts/android-security-bulletin-2026-03-01.html`: Android Security Bulletin の保存
- `artifacts/commit_69a25763cdb46c8f23fe9eb976132acbe2af82d6.txt`: コミットメタ情報
- `artifacts/patch_69a25763cdb46c8f23fe9eb976132acbe2af82d6.diff`: 修正diff
- `artifacts/MediaProvider_open_redaction_before.java`: 修正前の open/redaction 周辺抜粋
- `artifacts/MediaProvider_open_redaction_after.java`: 修正後の open/redaction 周辺抜粋
- `artifacts/MediaDocumentsProvider_openFile_uid_opts.java`: SAF 側で `EXTRA_MEDIA_CAPABILITIES_UID` を入れる箇所
- `artifacts/MediaStore_EXTRA_MEDIA_CAPABILITIES_UID.java`: extra の定義コメント
- `artifacts/related_commits_bug_326211886.txt`: 同 Bug ID の関連コミット一覧
- `artifacts/branches_containing_fix.txt`: 修正コミットを含むローカル refs
- `artifacts/redaction_decision_model.py`: パッチ前後の redaction 判定モデル
- `artifacts/redaction_decision_model_output.txt`: モデル実行結果
- `artifacts/analysis_notes.md`: 調査メモ
- `artifacts/SHA256SUMS`: 付帯ファイルの SHA-256
## 参照
- Android Security Bulletin - March 2026: https://source.android.com/docs/security/bulletin/2026/2026-03-01
- AOSP 修正コミット: https://android.googlesource.com/platform/packages/providers/MediaProvider/+/69a25763cdb46c8f23fe9eb976132acbe2af82d6
- CVE Record: https://www.cve.org/CVERecord?id=CVE-2026-0024
cve.md を表示# CVE-2026-0024 - System ID High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2026-0024 - Component: System - Subcomponent: MediaProvider - Reference: A-326211886 - Type: ID - Severity: High - Updated AOSP versions: 14, 15, 16, 16-qpr2 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 44 | OK | CVE-2025-48585 - System DoS High |
044
ok
CVE-2025-48585 - System DoS High044-ok-Profiling-trigger-packageName-spoof-DoS cve.md の Android / Pixel 脆弱性情報
cve.md summary System DoS High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) 修正前の `ProfilingService` は、trigger 管理 API に渡された `packageName` を信頼していた。通常の Java API では `ProfilingManager` が `mContext.getPackageName()` を渡すため正しい packageName になるが、実際の境界は `IProfilingService` Binder であり、ここでは `String packageName` が呼び出し元から直接渡る。 そのため、同一端末上のアプリは manager 経由ではなく Binder 経由で `addProfilingTriggers()` を呼び、呼び出し UID は攻撃者のまま、packageName だけを別アプリ名に偽装できた。修正前コードはその値を `mAppTriggers.put(packageName, Binder.getCallingUid(), ...)` に保存し、永続化対象にもしていた。 原因(根本原因) 信頼境界の取り違え。`ProfilingManager` 側で packageName を生成していることを前提に、サービス側 Binder API が呼び出し元提供の packageName を再検証していなかった。`requestProfiling()` には既に packageName と UID の検証があった一方、trigger 管理 API には同等の検証が欠けていた。 どこから特定したか validated.md の「何が修正されたか」 / Android bug参照 A-425360742 validated.md を表示# CVE-2025-48585 検証結果 ## 判定 ok: AOSP の公開ソース差分から脆弱性と根本原因を特定できた。 対象は Android Security Bulletin 2026-03-01 の System / Profiling / DoS / High、参照は A-425360742。公式 bulletin では CVE-2025-48585 が `platform/packages/modules/Profiling` の commit `1215317dfc1d88a4b5ea47185fb8f10afd1f78b0` にリンクされ、Updated AOSP versions は 16 とされている。 ## 何が修正されたか 修正コミットのタイトルは `Enforce caller provided package names to service`。`ProfilingService.java` に `enforceCallerMatchesPackageName(String packageName)` が追加され、以下の Binder API の先頭で呼ばれるようになった。 - `addProfilingTriggers(List<ProfilingTriggerValueParcel> triggers, String packageName)` - `removeProfilingTriggers(int[] triggerTypesToRemove, String packageName)` - `clearProfilingTriggers(String packageName)` 追加された検証は `Binder.getCallingUid()` から `PackageManager.getPackagesForUid(callingUid)` を引き、Binder 引数の `packageName` がその UID に属していることを確認する。空文字、解決不能 UID、不一致 packageName は `SecurityException` で拒否される。 ## 脆弱性の内容 修正前の `ProfilingService` は、trigger 管理 API に渡された `packageName` を信頼していた。通常の Java API では `ProfilingManager` が `mContext.getPackageName()` を渡すため正しい packageName になるが、実際の境界は `IProfilingService` Binder であり、ここでは `String packageName` が呼び出し元から直接渡る。 そのため、同一端末上のアプリは manager 経由ではなく Binder 経由で `addProfilingTriggers()` を呼び、呼び出し UID は攻撃者のまま、packageName だけを別アプリ名に偽装できた。修正前コードはその値を `mAppTriggers.put(packageName, Binder.getCallingUid(), ...)` に保存し、永続化対象にもしていた。 ## DoS になる理由 System-triggered Profiling は登録済み trigger の packageName 集合を `getActiveTriggerPackageNames()` で取り出し、`Configs.generateSystemTriggeredTraceConfig()` に渡す。この config では各 packageName が Perfetto の `atraceApps` と `android.packages_list` の filter に入る。デフォルト設定では system-triggered trace は最大 30 分のバックグラウンド trace で、trigger 発火時には `perfetto --clone-by-name ... --out ...` による clone、redaction、結果キュー処理が走る。 攻撃者が所有していない packageName を trigger 登録に混入できると、ProfilingService は不正な対象 package を含む system-triggered trace を開始・維持し、後続の clone/redaction/永続化処理を行う可能性がある。これはアプリ権限から system の profiling 資源消費を誘発できる DoS であり、packageName と UID の紐付けをサービス側で検証していなかったことが根本原因。 ## 根本原因 信頼境界の取り違え。`ProfilingManager` 側で packageName を生成していることを前提に、サービス側 Binder API が呼び出し元提供の packageName を再検証していなかった。`requestProfiling()` には既に packageName と UID の検証があった一方、trigger 管理 API には同等の検証が欠けていた。 ## 付帯ファイル - `artifacts/ProfilingService_1215317d.diff`: CVE 対応コミットの差分 - `artifacts/ProfilingService_before.java`, `artifacts/ProfilingService_after.java`: 修正前後の対象ファイル - `artifacts/trigger_api_before_snippet.java`, `artifacts/trigger_api_after_snippet.java`: trigger API 周辺抜粋 - `artifacts/Configs_system_triggered_trace_snippet.java`: packageName が Perfetto config に入る箇所 - `artifacts/profiling_package_spoof_model.py`: 最小再現モデル - `artifacts/profiling_package_spoof_model_output.txt`: モデル実行結果 - `artifacts/related_tests_6d425fa.patch`: 後続の packageName 不一致テスト追加コミット ## 調査メモ - 同じ bulletin の CVE-2025-48587 は `Validate triggers when added to service` で、trigger type/rate limit のサービス側検証不足を修正している。044 の CVE-2025-48585 は packageName/UID の検証不足に限定される。 - 後続 commit `6d425fa65f833dc2047235d6d62627d6b17f03cd` は「packageName が呼び出し UID と一致しない場合に SecurityException を投げる」テストを追加しており、この解析結果と一致する。 - Pixel バイナリ解析は不要だった。影響箇所は AOSP Mainline Profiling モジュールの Java ソースとして公開され、公式 ASB から修正コミットへ直接辿れる。 cve.md を表示# CVE-2025-48585 - System DoS High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48585 - Component: System - Subcomponent: Profiling - Reference: A-425360742 - Type: DoS - Severity: High - Updated AOSP versions: 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System DoS High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 45 | OK | CVE-2025-48587 - System DoS High |
045
ok
CVE-2025-48587 - System DoS High045-ok-system-profiling-trigger-validation-dos cve.md の Android / Pixel 脆弱性情報
cve.md summary System DoS High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) `ProfilingManager` の通常 API は `ProfilingTrigger` オブジェクトを受け取る。`ProfilingTrigger.Builder` は `ProfilingTrigger.java:83` で type を検証し、`ProfilingTrigger.java:161` の `isValidRequestTriggerType()` は `TRIGGER_TYPE_APP_FULLY_DRAWN` と `TRIGGER_TYPE_ANR` だけを許可する。 しかし、サービス境界は Binder の `IProfilingService.addProfilingTriggers(in List<ProfilingTriggerValueParcel> triggers, String packageName)` であり、AIDL では `IProfilingService.aidl:41` のように生の parcel list が渡る。パッチ前の `ProfilingService` は「manager 側で検証済み」という前提で Binder 入力を信頼していた。そのため、直接 Binder 呼び出しや hidden API/parcel 生成などで `ProfilingTriggerValueParcel.triggerType` に任意の int を入れると、サービス側の `mAppTriggers` に任意 key として追加できた。 正規 API 経由なら type は 1/2 の 2 種類だけなので、同一 uid/package では最大 2 エントリに上書き収束する。一方、パッチ前サービスに直接任意 type を渡すと、`SparseArray` の key 空間が事実上無制限になる。さらに `maybePersist` が true の通常追加経路では `maybePersistToDisk()` 経由で `profi... 原因(根本原因) 根本原因は **クライアント側検証をサービス側の信用境界でも再実施していなかったこと**。 `ProfilingManager` / `ProfilingTrigger.Builder` の検証は API 利用者向けの防御であり、Binder service が受け取る parcel の真正性を保証しない。`ProfilingService` は永続化と system_server 内状態を持つ権限側コンポーネントなので、`triggerType` のように内部データ構造の key になる値は service 側で必ず検証する必要があった。 面白い点として、パッチコメントは `mAppTriggers` に「追加は必ず `addTrigger()` 経由にすること」と明記している。これは修正後に `addTrigger()` を単一の検証ゲートにした設計意図を示している。 どこから特定したか validated.md の「参照した公開情報」 / Android bug参照 A-425360073 validated.md を表示# CVE-2025-48587 検証結果 ## 判定 **ok - system-profiling-trigger-validation-dos** CVE-2025-48587 は Android 16 の `platform/packages/modules/Profiling` にある `ProfilingService` の DoS 脆弱性と判断できる。公開 AOSP 修正コミット `ceaaf1330d3a0697e52691d223ee700824a5b4fa` は、`Bug: 425360073` として Android Security Bulletin March 2026 の `CVE-2025-48587 / A-425360073 / Profiling / DoS / High / Android 16` に対応している。 ## 参照した公開情報 - Android Security Bulletin 2026-03-01: `artifacts/android-security-bulletin-2026-03-01.html` - AOSP Gitiles commit: `artifacts/commit_ceaaf1330d3a.json` - パッチ差分: `artifacts/patch_ceaaf1330d3a.diff` - 解析手法の参考: `artifacts/originhq-patch-diffing-pipeline.html` ## パッチ概要 修正は `service/java/com/android/os/profiling/ProfilingService.java` だけに入っている。 主な変更は次の 2 点。 1. `addTrigger(ProfilingTriggerData trigger, boolean maybePersist)` の入口で `ProfilingTrigger.isValidRequestTriggerType(trigger.getTriggerType())` を呼び、無効な trigger type を `IllegalArgumentException` で拒否する。 2. 永続化ファイルから trigger をロードする処理で、無効 trigger による `IllegalArgumentException` を捕捉し、その trigger だけ無視してロード継続する。 パッチ前: - `ProfilingService_before.java:1211` から Binder 経由の `addProfilingTriggers()` が `ProfilingTriggerValueParcel.triggerType` を取り出す。 - `ProfilingService_before.java:1218` でその値をそのまま `addTrigger()` に渡す。 - `ProfilingService_before.java:1813` 以降の `addTrigger()` は `Flags.systemTriggeredProfilingNew()` 以外を検証せず、`ProfilingService_before.java:1829` で `triggerType` を `SparseArray` の key として保存する。 - `ProfilingService_before.java:590` 以降の永続化ロードでも、proto から復元した trigger を無検証で同じ `addTrigger()` に戻す。 パッチ後: - `ProfilingService_after.java:1830` で trigger type が正規の request trigger か検証される。 - `ProfilingService_after.java:598` から `603` で、古い永続化データ内の無効 trigger を無視できるようになった。 ## 脆弱性の内容 `ProfilingManager` の通常 API は `ProfilingTrigger` オブジェクトを受け取る。`ProfilingTrigger.Builder` は `ProfilingTrigger.java:83` で type を検証し、`ProfilingTrigger.java:161` の `isValidRequestTriggerType()` は `TRIGGER_TYPE_APP_FULLY_DRAWN` と `TRIGGER_TYPE_ANR` だけを許可する。 しかし、サービス境界は Binder の `IProfilingService.addProfilingTriggers(in List<ProfilingTriggerValueParcel> triggers, String packageName)` であり、AIDL では `IProfilingService.aidl:41` のように生の parcel list が渡る。パッチ前の `ProfilingService` は「manager 側で検証済み」という前提で Binder 入力を信頼していた。そのため、直接 Binder 呼び出しや hidden API/parcel 生成などで `ProfilingTriggerValueParcel.triggerType` に任意の int を入れると、サービス側の `mAppTriggers` に任意 key として追加できた。 正規 API 経由なら type は 1/2 の 2 種類だけなので、同一 uid/package では最大 2 エントリに上書き収束する。一方、パッチ前サービスに直接任意 type を渡すと、`SparseArray` の key 空間が事実上無制限になる。さらに `maybePersist` が true の通常追加経路では `maybePersistToDisk()` 経由で `profiling_app_triggers_info` に保存され、再起動後も `loadAppTriggersFromPersistedData()` で復元される。 このため攻撃者アプリは、自分の packageName と uid の範囲内でも、無効 trigger type を大量に登録して system_server のメモリ、永続化ファイル、system-triggered profiling の管理対象を膨張させられる。これが DoS の本質である。 ## 根本原因 根本原因は **クライアント側検証をサービス側の信用境界でも再実施していなかったこと**。 `ProfilingManager` / `ProfilingTrigger.Builder` の検証は API 利用者向けの防御であり、Binder service が受け取る parcel の真正性を保証しない。`ProfilingService` は永続化と system_server 内状態を持つ権限側コンポーネントなので、`triggerType` のように内部データ構造の key になる値は service 側で必ず検証する必要があった。 面白い点として、パッチコメントは `mAppTriggers` に「追加は必ず `addTrigger()` 経由にすること」と明記している。これは修正後に `addTrigger()` を単一の検証ゲートにした設計意図を示している。 ## 検証メモ `artifacts/trigger_validation_model.py` で key 空間の違いをモデル化した。 実行結果: ```text manager/API-valid entries after 10,000 adds: 2 pre-patch direct-Binder entries after 10,000 invalid adds: 10000 post-patch direct-Binder entries after 10,000 invalid adds: 0 pre-patch pseudo persisted bytes: 480000 ``` このモデルは実機 PoC ではないが、ソースコード上のデータ構造とパッチ条件に対応している。正規 API の 2 エントリ上限、パッチ前 Binder 入力での無制限 key 追加、パッチ後の拒否を確認する目的で作成した。 ## 付帯ファイル - `artifacts/ProfilingService_before.java`: 親コミット `1215317dfc1d88a4b5ea47185fb8f10afd1f78b0` のサービス実装 - `artifacts/ProfilingService_after.java`: 修正コミット `ceaaf1330d3a0697e52691d223ee700824a5b4fa` のサービス実装 - `artifacts/ProfilingManager.java`: manager 側 API - `artifacts/ProfilingTrigger.java`: trigger type 検証ロジック - `artifacts/IProfilingService.aidl`: Binder 境界 - `artifacts/ProfilingTriggerData.java`: 永続化される trigger データ - `artifacts/Configs.java`: system-triggered trace 設定生成 - `artifacts/trigger_validation_model.py`: DoS 条件の簡易モデル - `artifacts/trigger_validation_model_output.txt`: モデル実行結果 - `artifacts/SHA256SUMS`: 付帯ファイルの SHA-256 ## 結論 この CVE は、Profiling の system-triggered trigger 登録で、サービス側が `triggerType` を検証せずに内部 map と永続化ストアへ保存していた不備である。攻撃者は本来 2 種類に限定される trigger key を任意 int に拡張し、多数の永続 trigger を作って system_server/永続化領域に負荷を与えられる。修正はサービス境界の `addTrigger()` に正規 trigger type 検証を追加し、既存永続データ中の不正 trigger をロード時に捨てることで成立している。 cve.md を表示# CVE-2025-48587 - System DoS High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48587 - Component: System - Subcomponent: Profiling - Reference: A-425360073 - Type: DoS - Severity: High - Updated AOSP versions: 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System DoS High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 46 | OK | CVE-2025-48609 - System DoS High |
046
ok
CVE-2025-48609 - System DoS High046-ok-MmsProvider-arbitrary-file-delete-DoS cve.md の Android / Pixel 脆弱性情報
cve.md summary System DoS High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(何が脆弱だったか) `MmsProvider` は MMS part や一時 DRM データを削除するとき、DB の `_data` カラムに保存されたファイルパスを読み、対応する実ファイルを削除してから DB 行を削除する。 修正前の `deleteDataRows()` は、選択された各行について次の処理をしていた。 [コードブロック省略] この時点で、`path` が MMS 添付ファイル保存先である `app_parts` ディレクトリ配下かどうかを確認していなかった。そのため、`part._data` または `drm._data` が provider の想定外ファイルを指している場合、削除 API の実行だけでそのファイルが unlink される。 原因(根本原因) 根本原因は、DB 内の `_data` を「MMS 添付ファイル保存先を指す信頼済みパス」として扱い、削除時に canonical path 検証をしていなかったこと。 `insert()` と `openFile()` には `_data` を直接入れさせない処理や canonical check が既にあった。一方で削除処理だけが同等の検証を欠いていたため、DB 行が何らかの経路で汚染された場合に、削除処理が任意ファイル削除プリミティブになっていた。 どこから特定したか validated.md の「パッチ内容」 / Android bug参照 A-414388731 validated.md を表示# CVE-2025-48609 検証結果
## 判定
`ok`。AOSP の公開修正コミットと OSV 情報から、脆弱なコード位置、修正内容、根本原因をソースコードレベルで特定できた。
- CVE: CVE-2025-48609
- Android bug: A-414388731
- コンポーネント: `platform/packages/providers/TelephonyProvider`
- 対象ファイル: `src/com/android/providers/telephony/MmsProvider.java`
- 影響: System / DoS / High
- 公開説明: `MmsProvider.java` の複数関数で path traversal により telephony / SMS / MMS 機能に影響するファイルを任意削除できる可能性
- 修正コミット: `37babc702849821595634b6ecfda6f04404e2cf1`
- 元コミット: `fce8998a1770d05a768c30e5822c25db1b758208`
## 何が脆弱だったか
`MmsProvider` は MMS part や一時 DRM データを削除するとき、DB の `_data` カラムに保存されたファイルパスを読み、対応する実ファイルを削除してから DB 行を削除する。
修正前の `deleteDataRows()` は、選択された各行について次の処理をしていた。
```java
String path = cursor.getString(0);
if (path != null) {
new File(path).delete();
}
```
この時点で、`path` が MMS 添付ファイル保存先である `app_parts` ディレクトリ配下かどうかを確認していなかった。そのため、`part._data` または `drm._data` が provider の想定外ファイルを指している場合、削除 API の実行だけでそのファイルが unlink される。
## 到達する関数
主な到達経路は以下。
- `MmsProvider.delete()` -> `deleteParts()` -> `deleteDataRows()`
- `MmsProvider.delete()` -> `deleteTempDrmData()` -> `deleteDataRows()`
- `MmsProvider.delete()` -> `deleteMessages()` -> 各 MMS の `deleteParts()` -> `deleteDataRows()`
OSV の Vanir signature も `delete`, `deleteParts`, `deleteTempDrmData`, `deleteDataRows` 周辺を対象にしており、差分解析と一致する。
## 根本原因
根本原因は、DB 内の `_data` を「MMS 添付ファイル保存先を指す信頼済みパス」として扱い、削除時に canonical path 検証をしていなかったこと。
`insert()` と `openFile()` には `_data` を直接入れさせない処理や canonical check が既にあった。一方で削除処理だけが同等の検証を欠いていたため、DB 行が何らかの経路で汚染された場合に、削除処理が任意ファイル削除プリミティブになっていた。
## パッチ内容
修正コミット `37babc70` は、削除系関数に `Context` を渡すようにし、`deleteDataRows()` 内で次の検証を追加している。
- `_data == null` はスキップ
- `File.getCanonicalPath()` で正規化
- `context.getDir(PARTS_DIR_NAME, 0).getCanonicalPath()` で MMS parts ディレクトリを取得
- ファイルの canonical path が parts ディレクトリ配下でなければ実ファイル削除をスキップ
- DB 行の削除自体は従来通り実行
追加テストは `isFilePathCanonical()` に対し、parts ディレクトリ内のファイルは true、外のファイルは false になることを確認している。
## 攻撃条件と影響
攻撃の本質は「MmsProvider が削除する `part` または `drm` 行の `_data` を、`app_parts` 外の provider 権限で消せるファイルへ向ける」こと。成立後に該当 MMS part / DRM / MMS メッセージを削除すると、修正前はそのファイルが削除される。
`TelephonyProvider` は manifest 上 `android.uid.phone` の `com.android.phone` プロセスで動作するため、provider 自身がアクセスできる telephony / SMS / MMS 関連ファイルを壊せる。これにより SMS/MMS DB や関連状態が失われ、ローカル DoS になる。
## 調査中に分かった点
- 修正コミットのメッセージには「recent sql injection protection changes により冗長かもしれない」とある。
- 関連コミット `d3b6d700d84f468826ad08ff34d78b0d8ca7477f` は `A-388530367` の SQL injection 修正で、`query()` の `selection` に `SqlQueryChecker.checkSelection()` を追加している。
- ただし CVE-2025-48609 の直接修正は SQL injection の遮断ではなく、削除時の `_data` パス検証である。
- 既存の `openFile()` は以前から canonical path を確認していたため、読み書き時より削除時の検証抜けが問題だった。
- `MmsProvider.update()` の `resetFilePerm` には過去の `Bug: 240685104` / `Bug: 264880895` で canonical path 修正が入っており、MMS 添付ファイル周辺では過去にも path traversal / TOCTOU 系の修正履歴がある。
## 保存した付帯ファイル
- `artifacts/ASB-A-414388731.osv.pretty.json`: OSV の整形済み JSON
- `artifacts/37babc70.commit.txt`: 修正コミットのメタ情報
- `artifacts/37babc70.patch`: 修正差分
- `artifacts/MmsProvider.before.java`: 修正前 `MmsProvider.java`
- `artifacts/MmsProvider.after.java`: 修正後 `MmsProvider.java`
- `artifacts/MmsProviderTest.after.java`: 修正後テスト
- `artifacts/related-sql-injection-d3b6d700.patch`: 関連する SQL injection 修正差分
- `artifacts/root_cause_trace.md`: 呼び出し経路と根本原因のメモ
- `artifacts/branches-containing-fix.txt`: 修正を含む branch
- `artifacts/tags-containing-fix.txt`: 修正を含む tag
## 結論
CVE-2025-48609 は、`MmsProvider` の MMS part / DRM 削除処理が `_data` パスを検証せずに `File.delete()` していたことによる任意ファイル削除型のローカル DoS。パッチは削除前に canonical path が MMS parts ディレクトリ配下であることを確認し、範囲外ファイルの削除を拒否することで修正している。
cve.md を表示# CVE-2025-48609 - System DoS High ## Advisory - Program: Android Security Reward Program - Bulletin: Android Security Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-03-01 - Security patch level: 2026-03-01 ## CVE details - CVE: CVE-2025-48609 - Component: System - Reference: A-414388731 - Type: DoS - Severity: High - Updated AOSP versions: 14, 15, 16 ## Scope decision - Bounty target: yes - Reason: Included: Android platform component listed in Framework/System. Excluded Linux kernel, other OSS, and vendor/OEM component sections. ## Summary System DoS High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 47 | NG | CVE-2026-0114 - Pixel Modem RCE Critical |
047
ng
CVE-2026-0114 - Pixel Modem RCE Critical047-ng-Pixel-Modem-OOB-write-unattributed cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel Modem RCE Critical vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容NG理由・判定範囲 このジョブのOK条件は「ソースコード、もしくは脆弱性が起きる状況を完璧に説明できる場合」。今回の成果は以下に留まる。 - 公式 pre/post firmware の取得と `modem.bin` 抽出はできた。 - firmware TOC と `MAIN` 差分は取れた。 - OOB write / incorrect bounds check / zero-click RCE という公開説明は確認した。 - しかし、CVE-2026-0114 単体の関数、修正された条件分岐、書き込み先バッファ、攻撃入力フォーマットを特定できていない。 - March 2026 の同じ modem 更新には複数CVEが混在し、CVE単位の差分帰属ができない。 従って、脆弱性の根本原因を完全に特定したとは扱えない。 原因 未確定。OK条件を満たすだけの具体的な根本原因までは判定できていない。 確認元 validated.md の「公開情報」 / Android bug参照 A-454604426 * / 参照URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01, https://nvd.nist.gov/vuln/detail/CVE-2026-0114, https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://www.originhq.com/research/patch-diffing-pipeline validated.md を表示# CVE-2026-0114 検証メモ ## 判定 判定: **NG** CVE-2026-0114 が Pixel の Modem コンポーネントにおける Critical RCE であり、原因分類が out-of-bounds write / incorrect bounds check であることは、Pixel Update Bulletin と NVD で確認できた。しかし、今回取得できた Pixel modem firmware の 2026年2月版と2026年3月版の差分には、同じ March 2026 bulletin に載る複数の Pixel Modem / Cellular Modem CVE の修正と通常更新が混在している。ソースコード、シンボル、公開Bug、CVE別パッチが無いため、CVE-2026-0114 固有の関数・入力メッセージ・境界チェック不備を一意に確定できなかった。 このため、フォルダは `047-ng-Pixel-Modem-OOB-write-unattributed` にリネームする。 ## 公開情報 - Pixel Update Bulletin March 2026 は、`CVE-2026-0114 / A-454604426 / RCE / Critical / Modem` を Pixel セクションに掲載している。 - 同じ表には `CVE-2026-0120` も `Modem / RCE / Critical` として掲載され、さらに `CVE-2026-0110`, `CVE-2026-0111`, `CVE-2026-0113` など Modem / Cellular Modem 系の修正も同時に含まれる。 - Bulletin の `*` は Android bug が非公開で、修正は通常 Pixel の binary driver / firmware に含まれることを意味する。 - NVD の説明は「Modem に incorrect bounds check による possible out of bounds write があり、追加権限不要・ユーザー操作不要で RCE につながる可能性」としている。CWE は CWE-787、CVSS v3.1 は CISA-ADP 評価で 9.8 Critical。 参照: - https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - https://nvd.nist.gov/vuln/detail/CVE-2026-0114 - https://source.android.com/docs/security/bulletin/2026/2026-03-01 - https://www.originhq.com/research/patch-diffing-pipeline ## 取得・抽出したファームウェア 対象機種は既存キャッシュに合わせて Pixel 8 `shiba` を使った。OTA 全体の取得は帯域が遅かったため中止し、公式 factory image から HTTP Range で `radio-shiba-*.img` エントリのみを抽出した。 - pre-patch 候補: `BP4A.260205.001` / `radio-shiba-g5300i-250909-251024-b-14326967.img` - post-patch 候補: `CP1A.260305.018` / `radio-shiba-g5300i-251202-260127-b-14784800.img` 共有キャッシュ: - `../binaries/pixel_shiba_modem_0114/radio-shiba-bp4a.260205.001.img` - `../binaries/pixel_shiba_modem_0114/radio-shiba-cp1a.260305.018.img` - `../binaries/pixel_shiba_modem_0114/modem_bins/feb-modem.bin` - `../binaries/pixel_shiba_modem_0114/modem_bins/mar-modem.bin` 抽出構造: 1. factory zip の central directory を Range 取得。 2. `radio-shiba-*.img` だけを展開。 3. `radio-shiba-*.img` は先頭 140 byte の `FBPK` ヘッダの後ろが tar。 4. tar 内の `*.ext4` は ext4 superblock が通常位置より 1024 byte 前にある形式だったため、解析用に 1024 byte のゼロ前置ビューを作成。 5. ext4 内の `/images/<build>/modem.bin` を抽出。 6. `modem.bin` は `TOC\0` 形式で、`BOOT`, `MAIN`, `VSS`, `APM`, `NV_*` などのセクションを持つ。 ## ハッシュ `modem.bin`: - 2026年2月版: `214a97055cd7d86b5fdb5fe737f24aa0ac604df68e95e31fb8f1cf3f7d98f820` - 2026年3月版: `7cba729c106e702d284d7f7fa97248615af8ba746ed5762fd8aa5d27c9ad7a5b` - サイズはいずれも `103020932` bytes。 radio image: - 2026年2月版: `7f0004a41e24019b54259dabcc393e6e555371c7f04d37a16812cc2b3a94308f` - 2026年3月版: `db5a0c8161d9cc674ec348c07460495f36ef9209740c03f44c14386501c2f80d` ## TOC差分 `artifacts/toc_diff.csv` に記録した。主要セクションはすべて同一サイズ・同一オフセットのまま内容が変わっていた。 - `MAIN`: `98176000` bytes, load `0x40010000`, changed - `BOOT`: `92160` bytes, changed - `VSS`: `4705292` bytes, changed - `APM`: `46232` bytes, changed `MAIN` はロードアドレス `0x40010000` の大きな実行コード領域と見られる。`artifacts/main_diff_windows.csv` では `MAIN` 内の差分を 128 byte 以上の一致でクラスタ化し、3547 個の変更範囲を得た。大きな変更範囲が複数あり、単一の境界チェック追加という形には見えない。 ## 文字列差分で見えたこと `MAIN` には大量のログ文字列が残っている。差分文字列には以下のような領域が含まれる。 - ATI / AT command parser 周辺: `ATI Command line Exceeded`, `Length = %d out of range`, `UART character ignore has exceeded ATI_MAX_CMDLINE_LEN` - NR/LTE/RRC/SSM 周辺のログ - IMS / RCS / conference call 周辺のログ - decoder / parser / invalid input 系のログ ただし、これらは3月 modem firmware 全体の更新による文字列移動・追加を含んでおり、CVE-2026-0114 固有の修正とは結び付けられない。`Length = %d out of range` や ATI command line の上限チェックは OOB write と相性が良い候補ではあるが、CVE-2026-0114 はユーザー操作不要・ネットワーク攻撃ベクトルの RCE とされているため、ローカルATコマンド系だけを根本原因と断定するのは危険。 ## 根本原因について言える範囲 公開情報から確実に言える根本原因は、Modem firmware のどこかで外部入力由来の長さ・インデックス・個数を誤って検証し、固定長または割当済みバッファを越えて書き込める境界チェック不備があった、という範囲までである。 攻撃条件としては、CVSS `AV:N/AC:L/PR:N/UI:N` から、端末所有者の操作やAndroid側権限なしに、セルラー/ベースバンドが処理するネットワーク由来メッセージで到達可能なパーサである可能性が高い。ただし、今回のバイナリ差分だけでは LTE/NR NAS、RRC、IMS、SMS、AT/diagnostic などのどの入力面かを確定できなかった。 ## なぜ OK にしなかったか このジョブのOK条件は「ソースコード、もしくは脆弱性が起きる状況を完璧に説明できる場合」。今回の成果は以下に留まる。 - 公式 pre/post firmware の取得と `modem.bin` 抽出はできた。 - firmware TOC と `MAIN` 差分は取れた。 - OOB write / incorrect bounds check / zero-click RCE という公開説明は確認した。 - しかし、CVE-2026-0114 単体の関数、修正された条件分岐、書き込み先バッファ、攻撃入力フォーマットを特定できていない。 - March 2026 の同じ modem 更新には複数CVEが混在し、CVE単位の差分帰属ができない。 従って、脆弱性の根本原因を完全に特定したとは扱えない。 ## 付帯ファイル - `artifacts/remote_zip_fetch.py`: factory zip から Range で radio image を抽出するスクリプト。 - `artifacts/analyze_modem_toc.py`: `modem.bin` TOC を解析し、セクションハッシュと差分CSVを出すスクリプト。 - `artifacts/modem_diff_windows.py`: `MAIN` セクションの変更範囲クラスタ化スクリプト。 - `artifacts/toc_old.json`, `artifacts/toc_new.json`, `artifacts/toc_diff.csv`: TOC解析結果。 - `artifacts/main_diff_windows.csv`: `MAIN` の差分範囲。 - `artifacts/feb_MAIN.strings`, `artifacts/mar_MAIN.strings`: MAIN文字列一覧。 - `artifacts/interesting_added_strings.txt`, `artifacts/interesting_removed_strings.txt`: 長さ検査・parser・RRC/NAS/ATI等に関係しそうな文字列差分。 - `artifacts/sections/`: `BOOT`, `MAIN`, `VSS`, `APM` の抽出セクション。 cve.md を表示# CVE-2026-0114 - Pixel Modem RCE Critical ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0114 - Component: Pixel - Subcomponent: Modem - Reference: A-454604426 * - Type: RCE - Severity: Critical ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel Modem RCE Critical vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 48 | NG | CVE-2026-0120 - Pixel Modem RCE Critical |
048
ng
CVE-2026-0120 - Pixel Modem RCE Critical048-ng-pixel-modem-oob-write-unattributed cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel Modem RCE Critical vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容NG理由・判定範囲 判定: **ng** 理由: 公開情報とPixel 8 (`shiba`) の2月/3月ファームウェア差分から、CVE-2026-0120 が「Modem内の incorrect bounds check による out-of-bounds write で、無操作・追加権限なしにRCEへ至り得る」問題であること、また3月パッチでモデムradioイメージが更新されたことは確認できた。一方で、Pixelモデムはソース非公開の大きな独自バイナリで、3月radio差分には複数のModem/Baseband系CVEと機能変更が混在していた。CVE-2026-0120単独の修正関数、対象プロトコル、境界チェック式、攻撃入力条件を一意に特定できていないため、ok条件は満たさない。 原因 未確定。OK条件を満たすだけの具体的な根本原因までは判定できていない。 確認元 validated.md の「パッチ差分の結果」 / Android bug参照 A-454076522 * / 参照URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01, https://www.cve.org/CVERecord?id=CVE-2026-0120, https://nvd.nist.gov/vuln/detail/CVE-2026-0120 validated.md を表示# CVE-2026-0120 Pixel Modem RCE 調査メモ ## 判定 判定: **ng** 理由: 公開情報とPixel 8 (`shiba`) の2月/3月ファームウェア差分から、CVE-2026-0120 が「Modem内の incorrect bounds check による out-of-bounds write で、無操作・追加権限なしにRCEへ至り得る」問題であること、また3月パッチでモデムradioイメージが更新されたことは確認できた。一方で、Pixelモデムはソース非公開の大きな独自バイナリで、3月radio差分には複数のModem/Baseband系CVEと機能変更が混在していた。CVE-2026-0120単独の修正関数、対象プロトコル、境界チェック式、攻撃入力条件を一意に特定できていないため、ok条件は満たさない。 ## 公式情報 - Pixel Bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - CVE Record: https://www.cve.org/CVERecord?id=CVE-2026-0120 - NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-0120 Pixel Bulletin上の対象行は `CVE-2026-0120 / A-454076522 / RCE / Critical / Modem`。CVE/NVDの説明は「modem内の incorrect bounds check による possible out of bounds write。追加権限不要、ユーザー操作不要でRCEにつながる可能性」。 ## 取得・再利用したファームウェア 共有キャッシュ `../binaries` を使用した。 - 2月 vulnerable 側: `../binaries/pixel_shiba_modem_0114/radio-shiba-bp4a.260205.001.img` - baseband: `g5300i-250909-251024-B-14326967` - SHA-256: `7f0004a41e24019b54259dabcc393e6e555371c7f04d37a16812cc2b3a94308f` - 3月 patched 側: `../binaries/pixel_shiba_modem_0114/radio-shiba-cp1a.260305.018.img` - baseband: `g5300i-251202-260127-B-14784800` - SHA-256: `db5a0c8161d9cc674ec348c07460495f36ef9209740c03f44c14386501c2f80d` Factory zipの中央ディレクトリだけをRange取得し、radioエントリを確認した。 - 2月Factory: `shiba-bp4a.260205.001-factory-35b8480d.zip` - radio entry: `radio-shiba-g5300i-250909-251024-b-14326967.img` - 3月Factory: `shiba-cp1a.260305.018-factory-e3607b56.zip` - radio entry: `radio-shiba-g5300i-251202-260127-b-14784800.img` ## パッチ差分の結果 展開済みコンテナ: - old: `../binaries/pixel_shiba_modem_0114/extracted_feb/g5300i-250909-251024-B-14326967.ext4` - size: `112917504` - SHA-256: `7b4f05efadb2301c72ad5bc7a347a22f53affea455e214acf24cf07e410e7133` - new: `../binaries/pixel_shiba_modem_0114/extracted_mar/g5300i-251202-260127-B-14784800.ext4` - size: `112962560` - SHA-256: `0d64899c121a4478142823284ce397ee14b8743cd9c851e72b327329040404a6` `file` は通常のELF/ext4として認識しなかった。先頭付近に `PIXELMODEM` マジックと多数のSHA-1らしきハッシュ列があり、通常の単一ELFではなくGoogle/Samsung modem用の独自コンテナと見える。 全体バイナリ差分: - changed ranges: `2,909,782` - changed bytes sum: `107,785,633` - つまり約108MBのうち大半が変化しており、単純な `cmp` や文字列差分ではCVE-2026-0120だけに対応する変更を切り分けられない。 ## 面白い観察 - 3月更新はradioファイル名自体が変わっており、モデムの実体更新は明確。 - 3月差分には `RCSSH_SessMgr_*`, `MIME`, `SDP`, `SIP`, `ROHC`, `USIM`, `RRC_NR`, `NR`, `MAC` など、遠隔入力に関係し得る多数の領域の文字列差分がある。 - 追加文字列には例として以下が見えた。 - `[RCSSH_SessMgr_AddToMIMEList] Invalid bodyPtr PTR` - `[RCSSH_SessMgr_Build_MIME_Body]Length of Body : %d` - `[RCSSH_SessMgr_GetSDPBody_FromMIME] SDP length:%d` - `[USIM_%d] DataSize > allocated size: %d` - `[RF LNA] ... cc_type overflow [%d/%d]` - `[OEM][CHPP] ... len=%u` - ただし、これらはCVE-2026-0120に対応する証拠ではなく、同じ3月radioに含まれる別修正やログ文字列再配置の可能性がある。 - CVE-2026-0114も同じ3月Pixel Bulletinで `Modem / RCE / Critical`、説明文もほぼ同型の out-of-bounds write であり、CVE番号だけから差分内のどの修正かを分離できない。 ## 推定される脆弱性像 公開情報から言える範囲では、脆弱性はモデムが外部から受け取る通信データまたはネットワーク制御メッセージを処理する際、長さ・個数・オフセット等の境界チェックが誤っており、固定長または確保済みバッファの外側へ書き込める問題と考えられる。攻撃面は端末AP側アプリではなくbaseband/modem側で、ユーザー操作不要・追加権限不要という記述から、セルラー網、IMS/SIP/SDP、RRC/NAS、圧縮ヘッダ処理などのリモート入力経路が候補になる。 ただし、今回の解析では「どの入力フィールドがどのバッファに対して何バイト超過するか」までは特定できなかった。そのため根本原因は高水準には incorrect bounds check / OOB write だが、コードレベルの根本原因は未特定。 ## 付帯ファイル - `artifacts/pixel-bulletin-2026-03-01.html`: Pixel Bulletin保存版 - `artifacts/CVERecord-CVE-2026-0120.html`: CVE Record保存版 - `artifacts/NVD-CVE-2026-0120.html`: NVD保存版 - `artifacts/android_images.csv`: Factory image URL特定に使ったCSV - `artifacts/google_factory_images.html`, `artifacts/google_ota_images.html`: Googleページ保存版 - `artifacts/shiba_*_factory_entries.txt`: Factory zip中央ディレクトリ解析結果 - `artifacts/radio_extract_manifest.json`: Range抽出対象メタデータ - `artifacts/remote_zip_fetch.py`, `artifacts/extract_radio_ranges.py`: Range抽出補助スクリプト - `artifacts/binary_diff_summary.py`, `artifacts/binary_diff_summary.txt`: バイナリ差分サマリ - `artifacts/feb_interesting_strings.txt`, `artifacts/mar_interesting_strings.txt`, `artifacts/added_security_strings.txt`: 文字列調査メモ ## 次にやるなら ok判定に近づけるには、独自コンテナを構成要素へ分解し、各CPU/RTOSイメージ単位で関数同定できる環境が必要。Ghidra/IDAでロードアドレスと命令セットを合わせ、2月/3月の同一関数マッチングを行い、追加された長さ比較・上限比較・memcpy/memmove呼び出し周辺を追う必要がある。現状のmacOS標準ツールと文字列/バイト差分だけでは、3月radioに含まれる複数CVEのうちCVE-2026-0120だけを特定できない。 cve.md を表示# CVE-2026-0120 - Pixel Modem RCE Critical ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0120 - Component: Pixel - Subcomponent: Modem - Reference: A-454076522 * - Type: RCE - Severity: Critical ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel Modem RCE Critical vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 49 | NG | CVE-2026-0122 - Pixel Baseband RCE Critical |
049
ng
CVE-2026-0122 - Pixel Baseband RCE Critical049-ng-Pixel-Baseband-OOB-write-unattributed cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel Baseband RCE Critical vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容NG理由・判定範囲 公開情報から確実に言える根本原因は、Baseband firmware の複数箇所で、外部入力に由来する長さ・個数・オフセット・インデックス等を誤って扱い、確保済みバッファの外へ書き込める memory corruption があったという範囲まで。 攻撃条件は「追加権限不要・ユーザー操作不要の RCE」とされているため、Android アプリ API ではなく、baseband が処理する通信入力が攻撃面になる可能性が高い。一方、CISA ADP の CVSS は `AV:L` で、Pixel Bulletin の `Baseband RCE Critical` と完全には整合しない。今回の証拠だけでは、セルラー網、IMS/SIP、NAS/RRC、SMS/CBCH、診断/IPC のどれが CVE-2026-0122 の入力面かは確定できない。 原因 未確定。OK条件を満たすだけの具体的な根本原因までは判定できていない。 確認元 validated.md の「公開情報」「パッチ差分」 / Android bug参照 A-454078934 * validated.md を表示# CVE-2026-0122 Pixel Baseband RCE 調査結果 ## 判定 判定: **ng** CVE-2026-0122 は Pixel Update Bulletin 2026-03-01 の `Pixel / Baseband / RCE / Critical` 行にあり、参照バグは `A-454078934`。CVE レコードの説明は「multiple places に memory corruption による out-of-bounds write があり、追加権限なし・ユーザー操作なしで remote code execution につながる可能性」だった。 ただし、公開情報は関数名・ソースファイル名・入力プロトコル名を開示していない。Pixel 8 (`shiba`) の 2026年2月/3月 factory image から baseband/radio を抽出して差分を取ったが、3月の modem/baseband 更新には複数の Modem / Cellular Modem / Baseband CVE と通常更新が混在しており、CVE-2026-0122 固有の修正関数、境界チェック式、書き込み先バッファ、攻撃入力条件を一意に特定できなかった。 このジョブの `ok` 条件である「ソースコード、もしくは脆弱性が起きる状況を完璧に説明できる場合」には届かないため `ng` とする。 ## 公開情報 - Pixel Bulletin: `CVE-2026-0122 / A-454078934 / RCE / Critical / Baseband` - CVE Record: `In multiple places, there is a possible out of bounds write due to memory corruption.` - CISA ADP CVSS v3.1: `CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H`, base score `8.4` - CISA SSVC: exploitation `none`, automatable `no`, technical impact `total` 注意点として、Pixel Bulletin では `Baseband / RCE / Critical` だが、CVE Record の affected entry は `Android kernel` という粗い表記になっている。実体は Pixel radio/baseband firmware 側の更新として扱うのが自然。 ## 使用したファームウェア 対象機種は既存解析と共有キャッシュに合わせて Pixel 8 `shiba` を使った。OTA 全体ではなく、公式 factory image の ZIP central directory を HTTP Range で読み、`radio-shiba-*.img` だけを抽出した。 - pre-patch 候補: `BP4A.260205.001` - factory: `shiba-bp4a.260205.001-factory-35b8480d.zip` - radio entry: `radio-shiba-g5300i-250909-251024-b-14326967.img` - radio SHA-256: `7f0004a41e24019b54259dabcc393e6e555371c7f04d37a16812cc2b3a94308f` - extracted `modem.bin` SHA-256: `214a97055cd7d86b5fdb5fe737f24aa0ac604df68e95e31fb8f1cf3f7d98f820` - post-patch 候補: `CP1A.260305.018` - factory: `shiba-cp1a.260305.018-factory-e3607b56.zip` - radio entry: `radio-shiba-g5300i-251202-260127-b-14784800.img` - radio SHA-256: `db5a0c8161d9cc674ec348c07460495f36ef9209740c03f44c14386501c2f80d` - extracted `modem.bin` SHA-256: `7cba729c106e702d284d7f7fa97248615af8ba746ed5762fd8aa5d27c9ad7a5b` 共有キャッシュの保存先は `../binaries/pixel_shiba_baseband_0122/`。 ## 抽出構造 `radio-shiba-*.img` は先頭に `FBPK` ヘッダを持ち、その後ろに ext4 ファイルシステムがある。ext4 内の主なファイルは次の形だった。 - `/images/g5300i-250909-251024-B-14326967/modem.bin` - `/images/g5300i-250909-251024-B-14326967/confpack/cfg.db` - `/images/g5300i-251202-260127-B-14784800/modem.bin` - `/images/g5300i-251202-260127-B-14784800/confpack/cfg.db` `confpack/build.info` では、2月版の modem commit は `681d4efe48c893e5de47a930e8a319511b9fe3fa`、3月版は `71397974fd703fea590e831e69d92cb9e5d0f5c9` と記録されていた。 ## パッチ差分 `modem.bin` は `TOC\0` 形式で、主要セクションは同じサイズ・同じロードアドレスのまま内容が変わっていた。 - `BOOT`: size `92160`, changed - `MAIN`: load `0x40010000`, size `98176000`, changed - `VSS`: load `0x4f900000`, size `4705292`,ほぼ同一 - `APM`: load `0x0202e000`, size `46232`,ほぼ同一 `MAIN` は 3547 個の変更窓にクラスタ化され、変更窓の合計は `81221325` bytes だった。これは isolated patch ではなく、firmware drop 全体の差分に近い。文字列差分でも `ATI`, `NR`, `RRC`, `IMS`, `SIP/SDP`, `SMS`, `NAS`, `RF` など広い範囲に追加・削除があり、CVE-2026-0122 の「multiple places」を示唆する可能性はあるが、CVE 固有の場所を確定する証拠にはならない。 ## 根本原因について言える範囲 公開情報から確実に言える根本原因は、Baseband firmware の複数箇所で、外部入力に由来する長さ・個数・オフセット・インデックス等を誤って扱い、確保済みバッファの外へ書き込める memory corruption があったという範囲まで。 攻撃条件は「追加権限不要・ユーザー操作不要の RCE」とされているため、Android アプリ API ではなく、baseband が処理する通信入力が攻撃面になる可能性が高い。一方、CISA ADP の CVSS は `AV:L` で、Pixel Bulletin の `Baseband RCE Critical` と完全には整合しない。今回の証拠だけでは、セルラー網、IMS/SIP、NAS/RRC、SMS/CBCH、診断/IPC のどれが CVE-2026-0122 の入力面かは確定できない。 ## 調査で分かった面白い点 - `CVE-2026-0122` は、同じ3月 bulletins の `CVE-2026-0110`, `CVE-2026-0111`, `CVE-2026-0113`, `CVE-2026-0114`, `CVE-2026-0120` と同じ radio 更新に含まれる可能性が高い。 - 他の CVE は `cn_NrSmMsgHdlrFromMM.cpp` や `ns_SmscbUtilities.c` などの関数名が CVE レコードに出るものがあるが、`CVE-2026-0122` は `multiple places` だけで帰属情報が最も弱い。 - `modem.bin` 内には C/C++ ソースパスやログ文字列が大量に残っているが、差分が大きすぎるため文字列近傍だけでは修正関数を特定できない。 - `radio` は通常 ZIP/ELF ではなく、`FBPK` + ext4 + `/images/<baseband>/modem.bin` という構造だった。`modem.bin` はさらに TOC で `BOOT`, `MAIN`, `VSS`, `APM` に分かれる。 - 3月版の `confpack/cfg.db` も変わっていたが、文字列差分はキャリア/設定値中心で、CVE-2026-0122 の根本原因を示すものは見つからなかった。 ## 付帯ファイル - `artifacts/CVE-2026-0122.cvelist.json`: CVE Project cvelistV5 の保存版。 - `artifacts/cve_record_summary.txt`: CVE レコードの要約。 - `artifacts/pixel-bulletin-2026-03-01.html`: Pixel Bulletin 保存版。 - `artifacts/NVD-CVE-2026-0122.html`: NVD 保存版。 - `artifacts/*factory_tail*.bin`, `artifacts/*factory_cd.bin`: factory ZIP central directory 解析に使った断片。 - `artifacts/modem_bin_toc_sections.txt`: `modem.bin` TOC 解析結果。 - `artifacts/modem_bin_section_sha256.txt`: 抽出セクションのハッシュ。 - `artifacts/ext4_file_listing.txt`: radio 内 ext4 のファイル一覧。 - `artifacts/ext4_key_extractions.txt`: 抽出した key file 一覧。 - `artifacts/main_diff_windows.csv`: `MAIN` セクションの差分窓。 - `artifacts/main_diff_summary.txt`: `MAIN` 差分の集計。 - `artifacts/MAIN_strings_added.txt`, `artifacts/MAIN_strings_removed.txt`: 文字列差分。 - `artifacts/cfg_strings_added.txt`, `artifacts/cfg_strings_removed.txt`: confpack 設定DBの文字列差分。 - `artifacts/build_info.txt`: `confpack/build.info` の比較。 - `artifacts/artifacts_sha256.txt`: 付帯ファイルの SHA-256。 ## 結論 CVE-2026-0122 は Pixel Baseband firmware の複数箇所にある out-of-bounds write / memory corruption による RCE と見てよい。3月 Pixel patch では `shiba` の baseband が `g5300i-250909-251024-B-14326967` から `g5300i-251202-260127-B-14784800` へ更新され、`MAIN` 実行コード領域も大規模に変化していた。 しかし、CVE 固有のソース、関数、攻撃入力、境界条件、修正命令を特定できていない。したがって、根本原因を「完全に特定した」とは扱わず `ng` とする。 cve.md を表示# CVE-2026-0122 - Pixel Baseband RCE Critical ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0122 - Component: Pixel - Subcomponent: Baseband - Reference: A-454078934 * - Type: RCE - Severity: Critical ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel Baseband RCE Critical vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 50 | OK | CVE-2026-0124 - Pixel Bootloader EoP Critical |
050
ok
CVE-2026-0124 - Pixel Bootloader EoP Critical050-ok-kcmdline-bounds-check-OOB-write cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel Bootloader EoP Critical vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性が起きる状況) ABL は起動時にカーネルへ渡す command line を 0x1000 バイト固定バッファへ組み立てている。`oem cmdline add/set` や `kcmdline-test` 系の経路から長い cmdline 文字列が入ると、脆弱版では「現在の index」と「追加する文字列長」の合計を事前に検査しない。 そのため、現在 index がバッファ終端付近または不正な値になっている状態で追記が行われると、`g_kcmdline + idx` が終端または範囲外を指し、`0x1000 - idx` が 0 または size_t underflow した状態でコピー/整形関数に渡る。結果として、NVD が記載する missing bounds check 起因の out-of-bounds write になる。 このバグはメモリ破壊型の Bootloader EoP であり、単にカーネル引数を追加できる設計上の問題ではない。修正も権限チェック追加ではなく、バッファ残容量チェックと truncation 検出の追加である。 原因(根本原因) - `kcmdline` 本体は 0x1000 バイト固定なのに、別管理の `g_kcmdline_idx` を信頼しすぎていた。 - direct append と formatted append の両方で、追記後も終端 NUL を含めてバッファ内に収まるという invariant を強制していなかった。 - 旧実装は「コピー関数にサイズを渡している」ことに依存していたが、そもそも渡す destination と residual size を作る段階で index の上限確認が必要だった。 どこから特定したか validated.md の「解析対象」「公開情報」「パッチ差分」 / Android bug参照 A-308585798 * validated.md を表示# CVE-2026-0124 Pixel Bootloader EoP Critical 検証結果
## 結論
この CVE は、Pixel ABL の `kcmdline` 構築処理における境界チェック漏れによる out-of-bounds write と判断した。March 2026 の修正版 ABL では、`kcmdline` の 0x1000 バイト固定バッファへユーザ由来文字列を追加する前に `現在 index + 追加文字列長 < 0x1000` を確認し、入らない場合はログを出して `-5` 相当で拒否する処理が追加されている。February 2026 の脆弱版にはこの事前チェックがなく、現在 index を信頼したまま `buffer + index` と `0x1000 - index` を作ってコピー/整形関数へ渡していた。
したがって根本原因は、固定長 `kcmdline` バッファと別管理の論理 index の整合性を保証しないまま、fastboot/OEM cmdline 系の入力を追記していたこと。
判定: `ok`
## 公開情報
- Pixel Update Bulletin March 2026 では、`CVE-2026-0124 / A-308585798 / EoP / Critical / Bootloader` として掲載されている。
- NVD/CVE 側の説明は「missing bounds check による possible out of bounds write。local escalation of privilege。追加権限不要、UI 不要」。CWE は `CWE-787`。
- Android bug ID には `*` が付いており、詳細は非公開。ソース差分は出ていないため、Pixel firmware の ABL バイナリ差分で検証した。
## 解析対象
- 脆弱候補: `artifacts/extracted_bp4a260205/abl.img`
- SHA-256: `f41c5a1d8eecbd516fa3bb2b05c051c3b37866b6dd92170b9b08277951d2918b`
- 修正候補: `artifacts/extracted_cp1a260305/abl.img`
- SHA-256: `77a43b56355aa666cf62f9e855095843267bd13bab83d0275588186124ab940f`
- 後続修正確認: `artifacts/extracted_cp2a260605/abl.img`
- SHA-256: `89cb78a1777391846f0a65f62023c762ea0c9c131e408347debab14f8da21ec7`
## パッチ差分
March 版で追加された特徴的な文字列:
```text
kcmdline buffer has no space left for '%s'. Current index: %zu, Max size: %d
kcmdline buffer has no space left. Current index: %zu, Max size: %d
kcmdline: %s
```
同じ周辺には以下の fastboot/OEM cmdline 文字列がある:
```text
INFOoem cmdline set [cmdline]
INFOoem cmdline add <cmdline>
INFOoem cmdline del <cmdline>
INFOoem cmdline show
kcmdline-test enabled
"fastboot get_staged kcmdline-test.bin" or
```
主要修正箇所は direct append helper。February 版の `0x41a28` は以下の形だった。
```c
idx = g_kcmdline_idx;
remaining = 0x1000 - idx;
written_or_len = strlcpy(g_kcmdline + idx, user_string, remaining);
g_kcmdline_idx = min(idx + written_or_len, 0x1000);
return 0;
```
March 版の対応関数 `0x42ab8` は、コピー前に以下を追加している。
```c
len = strlen(user_string);
idx = g_kcmdline_idx;
if (idx + len >= 0x1000) {
log("kcmdline buffer has no space left for ...", user_string, idx, 0x1000);
log("kcmdline: %s", g_kcmdline);
return -5;
}
strlcpy(g_kcmdline + idx, user_string, 0x1000 - idx);
```
また、`printf` 形式で `kcmdline` に追記する helper も修正されている。February 版 `0x4191c` は `vsnprintf` 相当の戻り値が残容量以上でも、戻り値を index に足して 0x1000 に丸めるだけだった。March 版 `0x42870` は `ret >= remaining` をエラーとして扱い、`g_kcmdline[idx] = '\0'` で終端を保ち、同じ no-space ログを出して `-5` を返す。
## 脆弱性が起きる状況
ABL は起動時にカーネルへ渡す command line を 0x1000 バイト固定バッファへ組み立てている。`oem cmdline add/set` や `kcmdline-test` 系の経路から長い cmdline 文字列が入ると、脆弱版では「現在の index」と「追加する文字列長」の合計を事前に検査しない。
そのため、現在 index がバッファ終端付近または不正な値になっている状態で追記が行われると、`g_kcmdline + idx` が終端または範囲外を指し、`0x1000 - idx` が 0 または size_t underflow した状態でコピー/整形関数に渡る。結果として、NVD が記載する missing bounds check 起因の out-of-bounds write になる。
このバグはメモリ破壊型の Bootloader EoP であり、単にカーネル引数を追加できる設計上の問題ではない。修正も権限チェック追加ではなく、バッファ残容量チェックと truncation 検出の追加である。
## 根本原因
- `kcmdline` 本体は 0x1000 バイト固定なのに、別管理の `g_kcmdline_idx` を信頼しすぎていた。
- direct append と formatted append の両方で、追記後も終端 NUL を含めてバッファ内に収まるという invariant を強制していなかった。
- 旧実装は「コピー関数にサイズを渡している」ことに依存していたが、そもそも渡す destination と residual size を作る段階で index の上限確認が必要だった。
## 面白い点・調査メモ
- March 版では `kcmdline buffer has no space left...` という非常に説明的なログ文字列が追加されており、差分探索の強いシグナルになった。
- `oem cmdline del` 相当の重複削除処理は Feb/Mar でほぼ同じ。既存 key を検索し、`key` または `key=value` の単位でインプレース削除してから `strlen(g_kcmdline)` で index を再計算する。
- `printf` 系 helper は元から `0x1000 - idx` を渡していたが、`vsnprintf` の「必要だった長さ」を index に反映していたため、truncation を正常成功として扱う設計になっていた。March 版はここも明示的に失敗に変えている。
- `cp2a.260605` の ABL 文字列にも同系統の no-space ログが残っており、March 以後も修正は維持されている。
## 付帯ファイル
- `artifacts/cve0124_kcmdline_patch_notes.md`: 関数単位の疑似コードと差分メモ。
- `artifacts/kcmdline_append_before_after_disasm.txt`: Feb/Mar の主要関数逆アセンブル。
- `artifacts/mar_kcmdline_append_full_disasm.txt`: March direct append helper。
- `artifacts/feb_potential_kcmdline_append.txt`: February の関連 helper 候補。
- `artifacts/abl_strings_added_feb_to_mar.txt`: 追加文字列。
- `artifacts/abl_sha256.txt`: ABL ハッシュ。
## 制限
実機でのクラッシュ/制御フロー奪取までは行っていない。Pixel Bootloader は閉ソースで、Android bug も非公開である。ただし、公開 CVE の CWE-787/missing bounds check 記述と、March ABL の実パッチが `kcmdline` 追記前の境界チェック追加であることは一致しており、脆弱関数と根本原因は特定できた。
cve.md を表示# CVE-2026-0124 - Pixel Bootloader EoP Critical ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0124 - Component: Pixel - Subcomponent: Bootloader - Reference: A-308585798 * - Type: EoP - Severity: Critical ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel Bootloader EoP Critical vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 51 | OK | CVE-2026-0116 - Pixel MFC RCE High |
051
ok
CVE-2026-0116 - Pixel MFC RCE High051-ok-MFC-DPB-refcnt-OOB-RCE cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel MFC RCE High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の詳細) 関連する配列サイズは以下。 [コードブロック省略] 通常 ISR 経路の `__mfc_handle_released_buf()` と NAL-Q 経路の `__mfc_core_nal_q_handle_released_buf()` は、`dynamic_used` と前回値の差分から `released_flag` を作り、release された DPB の fd を `dec->ref_buf` に積む。ループ範囲は `MFC_MAX_DPBS`、つまり最大 64 DPB を扱える。一方、積み先は 32 要素しかない。 修正前は、次の条件に入るたびに無制限に `refcnt++` していた。 - release された DPB が queued かつ `new_fd != -1` - release された DPB が queued ではない - display 済みかつ reference されていない DPB を解放する場合 - unused output frame を処理する場合 その後、表示バッファ `mfc_buf` が存在するフレームで以下が実行される。 [コードブロック省略] したがって `refcnt > 32` になると、少なくとも次の問題が起きる。 - release 蓄積時に `dec->ref_buf[32]` 以降へ OOB write - display buffer が来た時に `dec->ref_buf[32]` 以降を OOB read - `ref_info->dpb[32]` 以降へ OOB write - display buffer が来ない間は `refcnt` がリセットされず、後続 interrupt で蓄積が継続する 攻撃面としては、アプリやリモートコンテンツが Android media stack を通じて MFC ハードウェアデコーダを使わせる経路がある。細工した動画ストリームにより DPB の参照/解放... 原因(根本原因を含む段落) 脆弱性の根本原因は、MFC デコーダが firmware/HW から得た DPB 使用状況に基づいて release 済み DPB の fd を `dec->ref_buf[dec->refcnt]` に蓄積する際、`refcnt` が 32 要素配列の上限を超えないことを確認せずにインクリメントしていたこと。`MFC_MAX_DPBS` は 64 だが、release 情報を積む `ref_buf` とユーザー共有用の `ref_info->dpb` は `MFC_MAX_BUFFERS`、つまり 32 要素しかない。このサイズ差が境界外アクセスの直接原因だった。 どこから特定したか validated.md の「参照した公開情報」「特定したパッチ」 / Android bug参照 A-321712082 * / 参照URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01, https://android.googlesource.com/kernel/google-modules/soc/gs/+/548b226108d27a85d77e7d15b240ea7b06c8bc9e, https://android.googlesource.com/kernel/google-modules/soc/gs validated.md を表示# CVE-2026-0116 Pixel MFC RCE High 検証結果
## 結論
判定: ok
CVE-2026-0116 は、Pixel の Exynos/Samsung MFC ドライバにある dynamic DPB release 情報の個数管理不備によるカーネルメモリ破壊と判断した。公開ソース上で Android bug ID `321712082` と一致する修正コミットを特定でき、パッチは `dec->refcnt` の上限チェックを追加して `dec->ref_buf[MFC_MAX_BUFFERS]` 以降への OOB write/read を止めている。
脆弱性の根本原因は、MFC デコーダが firmware/HW から得た DPB 使用状況に基づいて release 済み DPB の fd を `dec->ref_buf[dec->refcnt]` に蓄積する際、`refcnt` が 32 要素配列の上限を超えないことを確認せずにインクリメントしていたこと。`MFC_MAX_DPBS` は 64 だが、release 情報を積む `ref_buf` とユーザー共有用の `ref_info->dpb` は `MFC_MAX_BUFFERS`、つまり 32 要素しかない。このサイズ差が境界外アクセスの直接原因だった。
## 参照した公開情報
- Pixel Update Bulletin - March 2026: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01
- 対象エントリ: `CVE-2026-0116 / A-321712082 * / RCE / High / MFC`
- 修正コミット: https://android.googlesource.com/kernel/google-modules/soc/gs/+/548b226108d27a85d77e7d15b240ea7b06c8bc9e
- ローカル取得先: `../../binaries/kernel_google-modules_soc_gs.git`
## 特定したパッチ
コミット:
```text
548b226108d27a85d77e7d15b240ea7b06c8bc9e
media: mfc: add refcnt condition check to avoid OOB
Bug: 321712082
AuthorDate: 2024-03-05 11:54:44 +0900
```
同内容の automerge も確認した:
```text
57e960ab28987971fb42a1ab250a023a69fb1f5f
add3c5392dec8e4d10f90a47c9af98d41d483968
```
変更ファイル:
- `drivers/media/platform/exynos/mfc/mfc_core_isr.c`
- `drivers/media/platform/exynos/mfc/mfc_core_nal_q.c`
修正前は以下の形で、`refcnt` の境界チェックがなかった。
```c
dec->ref_buf[dec->refcnt].fd[0] = dec->dpb[i].fd[0];
dec->refcnt++;
```
修正後は全該当箇所で次の条件が追加された。
```c
dec->ref_buf[dec->refcnt].fd[0] = dec->dpb[i].fd[0];
if (dec->refcnt < MFC_MAX_BUFFERS - 1)
dec->refcnt++;
```
`MFC_MAX_BUFFERS - 1` で止めている点が重要。後続処理では `refcnt != MFC_MAX_BUFFERS` の場合に sentinel として `MFC_INFO_INIT_FD` を `ref_info->dpb[i]` に書くため、最大 31 個の fd + sentinel という扱いに寄せた修正と読める。
## 脆弱性の詳細
関連する配列サイズは以下。
```c
#define MFC_MAX_DPBS 64
#define MFC_MAX_BUFFERS 32
struct dec_dpb_ref_info {
int index;
struct stored_dpb_info dpb[MFC_MAX_BUFFERS];
};
struct mfc_dec {
struct dpb_table dpb[MFC_MAX_DPBS];
struct dec_dpb_ref_info *ref_info;
struct stored_dpb_info ref_buf[MFC_MAX_BUFFERS];
int refcnt;
};
```
通常 ISR 経路の `__mfc_handle_released_buf()` と NAL-Q 経路の `__mfc_core_nal_q_handle_released_buf()` は、`dynamic_used` と前回値の差分から `released_flag` を作り、release された DPB の fd を `dec->ref_buf` に積む。ループ範囲は `MFC_MAX_DPBS`、つまり最大 64 DPB を扱える。一方、積み先は 32 要素しかない。
修正前は、次の条件に入るたびに無制限に `refcnt++` していた。
- release された DPB が queued かつ `new_fd != -1`
- release された DPB が queued ではない
- display 済みかつ reference されていない DPB を解放する場合
- unused output frame を処理する場合
その後、表示バッファ `mfc_buf` が存在するフレームで以下が実行される。
```c
for (i = 0; i < dec->refcnt; i++)
ref_info->dpb[i].fd[0] = dec->ref_buf[i].fd[0];
if (dec->refcnt != MFC_MAX_BUFFERS)
ref_info->dpb[i].fd[0] = MFC_INFO_INIT_FD;
dec->refcnt = 0;
```
したがって `refcnt > 32` になると、少なくとも次の問題が起きる。
- release 蓄積時に `dec->ref_buf[32]` 以降へ OOB write
- display buffer が来た時に `dec->ref_buf[32]` 以降を OOB read
- `ref_info->dpb[32]` 以降へ OOB write
- display buffer が来ない間は `refcnt` がリセットされず、後続 interrupt で蓄積が継続する
攻撃面としては、アプリやリモートコンテンツが Android media stack を通じて MFC ハードウェアデコーダを使わせる経路がある。細工した動画ストリームにより DPB の参照/解放パターン、表示遅延、unused/display-only などの状態を誘導できる場合、MFC ドライバの interrupt/NAL-Q 処理で `refcnt` を 32 超に増やし、カーネル空間の隣接メモリを fd 値で破壊できる。Pixel bulletin が RCE High と分類しているのは、メディア入力を起点にカーネルドライバのメモリ破壊へ到達できるためと考えられる。
## 面白い点・調査メモ
- Bulletin は 2026-03-05 patch level の CVE として出ているが、該当 bug ID 付きの修正コミット自体は 2024-03-05 に公開ソースへ入っていた。Pixel の公開 bulletin とソース公開/ブランチ反映の時系列が一致しない例。
- Pixel bulletin では Android bug ID に `*` が付いており、Issue Tracker 側は非公開扱い。通常は binary driver 側にしかヒントがないことが多いが、今回は `kernel/google-modules/soc/gs` の commit message に `Bug: 321712082` がそのまま残っていた。
- パッチ名は `add refcnt condition check to avoid OOB` で、CVE 名や RCE という語は出ていない。OriginHQ の patch diffing pipeline 的には、bulletin の bug ID で `git log --all --grep` するのが最短だった。
- 修正は「書き込み前に index を検査する」形ではなく、「書き込み後の `refcnt` 増加を 31 で止める」形。これにより以後の release fd は `ref_buf[31]` を上書きし続け、後続の `ref_info` コピーでは 31 個までを渡して `dpb[31]` を sentinel にする。
- `MFC_MAX_DPBS=64` と `MFC_MAX_BUFFERS=32` の二重上限があり、DPB テーブル側の上限を安全と誤認すると release 情報配列側が溢れる。根本原因は、この 2 種類の上限の意味を分離して扱わなかったこと。
## 保存した付帯ファイル
- `artifacts/548b226108.patch`: bug ID 付き修正コミットの全文 diff
- `artifacts/relevant_structs.txt`: `MFC_MAX_DPBS` / `MFC_MAX_BUFFERS` / `ref_buf` / `ref_info` の構造体抜粋
- `artifacts/prepatch_isr_snippet.txt`: 通常 ISR 経路の修正前コード抜粋
- `artifacts/postpatch_isr_snippet.txt`: 通常 ISR 経路の修正後コード抜粋
- `artifacts/prepatch_nalq_snippet.txt`: NAL-Q 経路の修正前コード抜粋
- `artifacts/commit_search.txt`: `Bug: 321712082` とパッチ名での git log 検索結果
## 再現・検証コマンド
```bash
git clone https://android.googlesource.com/kernel/google-modules/soc/gs ../../binaries/kernel_google-modules_soc_gs.git
git -C ../../binaries/kernel_google-modules_soc_gs.git log --all --grep='321712082\\|add refcnt condition check to avoid OOB' --format='%H %ad %D%n%s%n%b' --date=iso-strict
git -C ../../binaries/kernel_google-modules_soc_gs.git show --patch --stat 548b226108 -- drivers/media/platform/exynos/mfc/mfc_core_isr.c drivers/media/platform/exynos/mfc/mfc_core_nal_q.c
git -C ../../binaries/kernel_google-modules_soc_gs.git show 548b226108:drivers/media/platform/exynos/mfc/mfc_data_struct.h
```
cve.md を表示# CVE-2026-0116 - Pixel MFC RCE High ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0116 - Component: Pixel - Subcomponent: MFC - Reference: A-321712082 * - Type: RCE - Severity: High ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel MFC RCE High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 52 | OK | CVE-2025-48611 - Pixel Companion EoP High |
052
ok
CVE-2025-48611 - Pixel Companion EoP High052-ok-DeviceId-customId-bounds-validation-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel Companion EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) 攻撃者は、Companion Device Manager の association を持つローカルアプリとして、`CompanionDeviceManager.setDeviceId(associationId, DeviceId)` に巨大な `customId` を渡す。呼び出しは `ICompanionDeviceManager` Binder を経由して `system_server` の `CompanionDeviceManagerService` に入り、Association の状態として保存される。 `DeviceId.customId` は「アプリが管理するデバイス識別子」だが、CDM 側では association state の一部として扱われ、XML/backup payload などの永続化対象になる。長さ制限がないと、攻撃者制御の巨大文字列が `system_server` のメモリ、ディスク書き込み、再読み込み処理へ流入する。 公開DBはこの問題を EoP/High、ローカルアプリによる任意コード実行と分類している。今回ソースから確実に説明できる根本原因は「永続化される CDM メタデータの境界チェック欠落」であり、実際の影響は少なくとも system_server の特権コンテキストに対するリソース消費/状態汚染を含む。CVE分類上の EoP は、通常アプリが直接制御すべきでないシステム管理状態を過大入力で操作できる点に基づくと考えられる。 原因(根本原因) `DeviceId` の `customId` は外部アプリ入力なのに、永続化されるシステムデータとしてのサイズ上限が API 境界で強制されていなかったこと。Companion association は通常アプリから開始でき、association 所有アプリは自身の association に対する DeviceId 更新面に到達できるため、`customId` は信頼境界を越える入力である。 修正は 1024 文字の固定上限を導入し、公開 Builder API で過大値を拒否するもの。面白い点として、`DeviceId` には Parcelable 経路もあるため、堅牢な実装では Builder だけでなく Binder unparcel 後または service 永続化前にも同じ不変条件を確認するのが望ましい。公開現行ソースで確認できた主な修正点は Builder 側だった。 どこから特定したか validated.md の「参照情報」「パッチ解析」 / Android bug参照 A-416259739 * / 参照URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01, https://android.googlesource.com/platform/frameworks/base/+/refs/heads/main/core/java/android/companion/DeviceId.java, https://android.googlesource.com/platform/frameworks/base/+/refs/heads/main/core/java/android/companion/CompanionDeviceManager.java, https://android.googlesource.com/platform/frameworks/base/+/master/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java, https://developer.android.com/reference/android/companion/DeviceId.Builder ほか1件 validated.md を表示# CVE-2025-48611 Pixel Companion EoP High 検証結果
## 判定
`ok`。脆弱性の中心は、Companion Device Manager の `android.companion.DeviceId` で、アプリ管理の `customId` に十分な長さ制限がなく、ローカルアプリが巨大な識別子を CDM のシステム管理状態へ持ち込める入力検証不備だと判断した。
ただし、このジョブ中はローカル shell から `android.googlesource.com` / `storage.googleapis.com` の DNS 解決に失敗したため、AOSP履歴の exact commit hash は取得できなかった。根拠は公開 Gitiles の現行ソース、Android Developers API reference、Pixel bulletin、脆弱性ミラーの説明で突き合わせた。
## 参照情報
- Pixel Update Bulletin - March 2026 は `CVE-2025-48611 / A-416259739 / EoP / High / Companion` を掲載している。
- Android OSV index には `PUB-A-416259739.json` が存在するが、shell からの直接取得は DNS 障害で失敗した。
- Cybersecurity Help は CWE-20、ローカルアプリ、低権限、UI不要、Companion subcomponent の improper input validation と説明している。
- Aliyun AVD の検索結果は `DeviceId.java` の境界チェック欠落に言及していた。
- AOSP Gitiles の現行 `DeviceId.java` では `CUSTOM_ID_LENGTH_LIMIT = 1024` と `Builder.setCustomId()` の長さチェックが確認できる。
- Android Developers の `DeviceId.Builder.setCustomId()` API reference も、1024文字超過で `IllegalArgumentException` を投げると説明している。
参照URL:
- https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01
- https://android.googlesource.com/platform/frameworks/base/+/refs/heads/main/core/java/android/companion/DeviceId.java
- https://android.googlesource.com/platform/frameworks/base/+/refs/heads/main/core/java/android/companion/CompanionDeviceManager.java
- https://android.googlesource.com/platform/frameworks/base/+/master/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
- https://developer.android.com/reference/android/companion/DeviceId.Builder
- https://storage.googleapis.com/android-osv/index.html
## パッチ解析
修正後の `DeviceId.java` には次のロジックがある。
```java
private static final int CUSTOM_ID_LENGTH_LIMIT = 1024;
public Builder setCustomId(@Nullable String customId) {
if (customId != null && customId.length() > CUSTOM_ID_LENGTH_LIMIT) {
throw new IllegalArgumentException(...);
}
this.mCustomId = customId;
return this;
}
```
差分としては、`DeviceId.Builder.setCustomId()` に「null でなく、1024文字を超える場合は拒否する」チェックが追加された形と見てよい。付帯ファイル `artifacts/reconstructed_patch_diff.md` に再構成した差分とデータフローを残した。
## 脆弱性の内容
攻撃者は、Companion Device Manager の association を持つローカルアプリとして、`CompanionDeviceManager.setDeviceId(associationId, DeviceId)` に巨大な `customId` を渡す。呼び出しは `ICompanionDeviceManager` Binder を経由して `system_server` の `CompanionDeviceManagerService` に入り、Association の状態として保存される。
`DeviceId.customId` は「アプリが管理するデバイス識別子」だが、CDM 側では association state の一部として扱われ、XML/backup payload などの永続化対象になる。長さ制限がないと、攻撃者制御の巨大文字列が `system_server` のメモリ、ディスク書き込み、再読み込み処理へ流入する。
公開DBはこの問題を EoP/High、ローカルアプリによる任意コード実行と分類している。今回ソースから確実に説明できる根本原因は「永続化される CDM メタデータの境界チェック欠落」であり、実際の影響は少なくとも system_server の特権コンテキストに対するリソース消費/状態汚染を含む。CVE分類上の EoP は、通常アプリが直接制御すべきでないシステム管理状態を過大入力で操作できる点に基づくと考えられる。
## 根本原因
`DeviceId` の `customId` は外部アプリ入力なのに、永続化されるシステムデータとしてのサイズ上限が API 境界で強制されていなかったこと。Companion association は通常アプリから開始でき、association 所有アプリは自身の association に対する DeviceId 更新面に到達できるため、`customId` は信頼境界を越える入力である。
修正は 1024 文字の固定上限を導入し、公開 Builder API で過大値を拒否するもの。面白い点として、`DeviceId` には Parcelable 経路もあるため、堅牢な実装では Builder だけでなく Binder unparcel 後または service 永続化前にも同じ不変条件を確認するのが望ましい。公開現行ソースで確認できた主な修正点は Builder 側だった。
## 付帯ファイル
- `artifacts/reconstructed_patch_diff.md`: 再構成したパッチ差分とデータフロー。
- `artifacts/analysis_notes.md`: 調査ログ、参照情報、環境制約。
- `artifacts/poc_scenario.md`: 概念PoC手順と期待される修正後挙動。
## 結論
CVE-2025-48611 は、Pixel bulletin では Pixel/Companion として扱われているが、実体は Companion Device Manager の `DeviceId.customId` 入力検証不備としてソースレベルで説明できる。根本原因は、アプリ制御の識別子を CDM association の永続化データへ保存する前にサイズを制限していなかったこと。修正は 1024 文字上限の導入で、過大な `customId` を API レイヤで拒否する。
cve.md を表示# CVE-2025-48611 - Pixel Companion EoP High ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2025-48611 - Component: Pixel - Subcomponent: Companion - Reference: A-416259739 * - Type: EoP - Severity: High ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel Companion EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 53 | NG | CVE-2026-0107 - Pixel CPM EoP High |
053
ng
CVE-2026-0107 - Pixel CPM EoP High053-ng-gmc-mba-ddr-confused-deputy cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel CPM EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容NG理由・判定範囲 **ng - gmc-mba-ddr-confused-deputy** 脆弱性の対象関数と種類は特定できたが、修正前後のソースコードまたは十分なバイナリ差分を取得できず、要求条件の「okとしていいのはソースコード、もしくは脆弱性が起きる状況を完璧に説明できる場合」を満たさなかった。 原因 未確定。OK条件を満たすだけの具体的な根本原因までは判定できていない。 確認元 validated.md の「パッチ解析の結果」 / Android bug参照 A-449752657 * validated.md を表示# CVE-2026-0107 検証結果 ## 判定 **ng - gmc-mba-ddr-confused-deputy** 脆弱性の対象関数と種類は特定できたが、修正前後のソースコードまたは十分なバイナリ差分を取得できず、要求条件の「okとしていいのはソースコード、もしくは脆弱性が起きる状況を完璧に説明できる場合」を満たさなかった。 ## 確認できた事実 - Pixel Update Bulletin March 2026 では、CVE-2026-0107 は Pixel / CPM / EoP / High、参照 A-449752657 `*` として掲載されている。 - 同 Bulletin の FAQ では、`*` 付きの Android bug ID は公開されておらず、通常 Pixel binary driver 更新に含まれると説明されている。 - CVE.org / NVD の機械可読データでは、脆弱性説明がより具体的で、以下が確認できる。 - 対象: Android kernel - ファイル: `gmc_mba_ddr.c` - 関数: `gmc_ddr_handle_mba_mr_req` - 種類: CWE-441 confused deputy - 影響: ローカル権限昇格。追加の実行権限不要、ユーザー操作不要。 ## 脆弱性の推定 `gmc_ddr_handle_mba_mr_req` は名前から Google Memory Controller / DDR / MBA MR request のハンドラと考えられる。CWE-441 confused deputy という分類から、根本問題は、より強い権限を持つカーネル側ドライバが、呼び出し元または要求対象を十分に検証せず、依頼者の代理として DDR/MBA 関連の特権操作を実行してしまうことだった可能性が高い。 ただし、これは CVE 記述と関数名からの推定であり、パッチの条件分岐、権限チェック、入力検証、または拒否条件をソース/逆アセンブルで確認できていない。そのため、根本原因は「要求元/要求内容の認可不足による confused deputy」とまでは言えるが、脆弱な入力フィールドや攻撃可能な ioctl/sysfs/debugfs/IPC 経路までは確定できない。 ## パッチ解析の結果 公開 AOSP/Pixel のローカル Git キャッシュを検索したが、`gmc_mba_ddr.c` と `gmc_ddr_handle_mba_mr_req` は見つからなかった。`kernel/google-modules/soc/gs` には ACPM/SoC 電源管理系の公開コードはあるが、該当 GMC MBA DDR ドライバは含まれていない。 March 2026 の shiba Factory Image から Pixel binary driver を比較する方針で進めたが、ローカルの March OTA は ZIP として破損/不完全で、公式 Factory Image の Range 取得も接続リセットで失敗した。このため、修正差分の抽出は未達。 ## 調査で分かった面白い点 - Bulletin ではサブコンポーネントが `CPM` とだけ書かれているが、CVE JSON では `gmc_mba_ddr.c` まで出ている。Bulletin だけを見るより、CVE.org/NVD の JSON を引いた方が実体に近い。 - `A-449752657 *` の `*` は、公開 CL ではなく Pixel binary driver 更新に入ることを示す。今回のように AOSP diff が取れない案件では、この印が早い段階で重要なシグナルになる。 - 公開 `kernel/google-modules/soc/gs` には ACPM など近い名前の電源管理/SoC ドライバは存在するが、GMC MBA DDR の該当ファイルは存在しなかった。少なくとも手元の公開ツリーだけでのソースパッチ解析はできない。 ## 保存した付帯ファイル - `artifacts/CVE-2026-0107.cveawg.pretty.json`: CVE.org JSON - `artifacts/NVD-CVE-2026-0107.pretty.json`: NVD JSON - `artifacts/pixel-bulletin-2026-03-01.html`: 公式 Pixel Bulletin - `artifacts/soc_gs_exact_gmc_grep.txt`: 公開 `soc/gs` に対する完全一致検索結果。0件。 - `artifacts/soc_gs_candidate_files.txt`: CPM/ACPM/GMC 周辺候補ファイルの一覧 - `artifacts/download_attempts.md`: Factory/OTA 取得と抽出の試行記録 - `artifacts/analysis_notes.md`: 調査メモ cve.md を表示# CVE-2026-0107 - Pixel CPM EoP High ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0107 - Component: Pixel - Subcomponent: CPM - Reference: A-449752657 * - Type: EoP - Severity: High ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel CPM EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 54 | NG | CVE-2026-0110 - Pixel Modem EoP High |
054
ng
CVE-2026-0110 - Pixel Modem EoP High054-ng-NrSm-MM_DATA_IND-memory-corruption-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel Modem EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容NG理由・判定範囲 確定できる根本原因は、`cn_NrSmMsgHdlrFromMM.cpp` の `MM_DATA_IND` 処理で、MM から受け取った入力を扱う際に memory corruption が起きる実装不備があった、という範囲まで。 状況としては、`SMT_MM_DATA_IND` ログが `(P=%d L=%d C=%d)` を出しているため、payload pointer、length、cause/code のようなフィールドを受け取り、その payload を NRSM の air message として decode/dispatch する処理が存在する。ここで長さ、IE 数、offset、またはセッション/QoS などの可変長データを十分に検証せずにコピー・decode・状態反映すると、modem 内メモリ破壊になり得る。 ただし、次は未特定: - 破損する具体的なバッファまたはオブジェクト - 問題のあるフィールド、IE、長さ値 - 2月版に存在した誤った境界条件 - 3月版で追加/変更された比較命令やエラー分岐 - EoP の到達先、つまり modem 内でどの権限境界を越えるか 原因 未確定。OK条件を満たすだけの具体的な根本原因までは判定できていない。 確認元 validated.md の「対象コンポーネントの推定」「公開情報」 / Android bug参照 A-440358226 * validated.md を表示# CVE-2026-0110 Pixel Modem EoP 調査メモ ## 判定 判定: **ng** 理由: CVE レコードから、CVE-2026-0110 は `cn_NrSmMsgHdlrFromMM.cpp` の `MM_DATA_IND` 処理にある memory corruption による remote EoP だと特定できた。Pixel 8 (`shiba`) の 2026年2月/3月 modem firmware を再利用し、`MAIN` セクション内に `../../../SMPF/Protocol/CoreNetwork/SM/NRSM/cn_NrSmMsgHdlrFromMM.cpp`、`SMT_MM_DATA_IND`、`N2cn2sm17NrSmMsgHdlrFromMME` などの証跡が残っていることも確認した。 ただし、今回の環境では `MAIN` はシンボルなしの生バイナリとしてしか扱えず、Ghidra/r2 などの関数 diff 環境もなかった。3月 radio には同じ Bulletin の複数 Modem/Baseband CVE と通常更新が混在しており、`MM_DATA_IND` ハンドラ内のどの条件分岐・どのコピー・どのデータ構造が修正されたかまでは確定できていない。OK 条件である「ソースコード、または脆弱性が起きる状況を完璧に説明できる」には届かないため ng とする。 ## 公開情報 - Pixel Update Bulletin March 2026: `CVE-2026-0110 / A-440358226 / EoP / High / Modem` - CVE レコードの説明: `In MM_DATA_IND of cn_NrSmMsgHdlrFromMM.cpp, there is a possible EoP due to memory corruption. This could lead to remote escalation of privilege with no additional execution privileges needed. User interaction is not needed for exploitation.` - CISA ADP の CVSS v3.1: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H`, 9.8 Critical Pixel Bulletin 上の severity は High だが、CVE ADP enrichment ではネットワーク到達・低複雑度・権限不要・UI不要・C/I/A 高の Critical 相当として評価されている。 ## 対象コンポーネントの推定 `cn_NrSmMsgHdlrFromMM.cpp` はファームウェア文字列上のパスから、Samsung/Google modem firmware の `SMPF/Protocol/CoreNetwork/SM/NRSM`、つまり 5G NR Session Management の MM 由来メッセージハンドラに属する。 確認できた関連文字列: - `../../../SMPF/Protocol/CoreNetwork/SM/NRSM/cn_NrSmMsgHdlrFromMM.cpp` - `SMT_MM_DATA_IND` - `@[D :SM,%d] SMT_MM_DATA_IND w/ AirMsg(%s)` - `@[N :SM,%d] <<SMT_MM_DATA_IND>> (P=%d L=%d C=%d(0x%X))` - `N2cn2sm17NrSmMsgHdlrFromMME` このため、攻撃入力は NRMM/MM から NRSM へ配送される `MM_DATA_IND` の NAS/SM payload、つまり 5G セッション管理メッセージの処理経路と見るのが自然。CVE が remote EoP かつ UI 不要であることから、端末上アプリの API ではなく、基地局/ネットワーク側から届く制御メッセージを modem 内で処理する経路が攻撃面になる可能性が高い。 ## ファームウェア差分 共有キャッシュ `../binaries` の既存ファイルを再利用した。 - pre-patch: `../binaries/pixel_shiba_modem_0114/radio-shiba-bp4a.260205.001.img` - post-patch: `../binaries/pixel_shiba_modem_0114/radio-shiba-cp1a.260305.018.img` - 抽出済み modem: `../binaries/pixel_shiba_modem_0114/modem_bins/feb-modem.bin` - 抽出済み modem: `../binaries/pixel_shiba_modem_0114/modem_bins/mar-modem.bin` ハッシュ: - 2月 radio: `7f0004a41e24019b54259dabcc393e6e555371c7f04d37a16812cc2b3a94308f` - 3月 radio: `db5a0c8161d9cc674ec348c07460495f36ef9209740c03f44c14386501c2f80d` - 2月 `modem.bin`: `214a97055cd7d86b5fdb5fe737f24aa0ac604df68e95e31fb8f1cf3f7d98f820` - 3月 `modem.bin`: `7cba729c106e702d284d7f7fa97248615af8ba746ed5762fd8aa5d27c9ad7a5b` `modem.bin` は `TOC\0` 形式で、主要セクションは同一サイズ・同一ロードアドレスのまま更新されていた。 - `MAIN`: `98176000` bytes, load `0x40010000`, changed - `BOOT`: `92160` bytes, changed - `VSS`: `4705292` bytes, changed - `APM`: `46232` bytes, changed `MAIN` の差分は 3547 個の変更範囲にクラスタ化された。NRSM 付近の文字列/ログ領域も大きく動いており、単純な文字列差分だけでは `MM_DATA_IND` の修正関数を復元できない。 ## 根本原因について言える範囲 確定できる根本原因は、`cn_NrSmMsgHdlrFromMM.cpp` の `MM_DATA_IND` 処理で、MM から受け取った入力を扱う際に memory corruption が起きる実装不備があった、という範囲まで。 状況としては、`SMT_MM_DATA_IND` ログが `(P=%d L=%d C=%d)` を出しているため、payload pointer、length、cause/code のようなフィールドを受け取り、その payload を NRSM の air message として decode/dispatch する処理が存在する。ここで長さ、IE 数、offset、またはセッション/QoS などの可変長データを十分に検証せずにコピー・decode・状態反映すると、modem 内メモリ破壊になり得る。 ただし、次は未特定: - 破損する具体的なバッファまたはオブジェクト - 問題のあるフィールド、IE、長さ値 - 2月版に存在した誤った境界条件 - 3月版で追加/変更された比較命令やエラー分岐 - EoP の到達先、つまり modem 内でどの権限境界を越えるか ## 面白いこと・調査メモ - CVE レコードが `cn_NrSmMsgHdlrFromMM.cpp` と `MM_DATA_IND` まで明かしているため、同じ Modem 表の CVE-2026-0114/CVE-2026-0120 より帰属情報はかなり強い。 - Pixel Bulletin の High と CISA ADP の CVSS 9.8 Critical が食い違っている。Google の分類は Pixel Bulletin の EoP/High、CISA enrichment は remote total impact と評価している。 - ファームウェアには C++ の型名らしき `N2cn2sm17NrSmMsgHdlrFromMME` が残っており、NRSM 実装が C++ クラス構造を持つことが分かる。 - `cn_NrSmSessionProcessQosFlowData.cpp`、`cn_NrSmSessionProcessQosRuleData.cpp`、`Update mapped TrafficFlow by NRSM (Length = %d)` など、可変長データ処理に関係しそうな周辺文字列はあるが、CVE-2026-0110 への直接証拠ではない。 - 3月の `MAIN` 更新は差分量が大きく、CVE 単体の isolated patch ではなく firmware drop 全体を diff している状態だった。 ## 付帯ファイル - `artifacts/CVE-2026-0110.cvelist.json`: CVE Project cvelistV5 から取得した CVE レコード。 - `artifacts/cve_record_summary.txt`: CVE レコードの要約。 - `artifacts/pixel-bulletin-2026-03-01.html`: Pixel Bulletin 保存版。 - `artifacts/nrsm_evidence.txt`: 2月/3月 `MAIN` 内の NRSM/MM_DATA_IND 関連文字列とオフセット。 - `artifacts/toc_old.json`, `artifacts/toc_new.json`, `artifacts/toc_diff.csv`: `modem.bin` TOC 解析結果。 - `artifacts/main_diff_windows.csv`: `MAIN` セクション差分のクラスタ。 - `artifacts/strings_added_main.txt`, `artifacts/interesting_added_strings.txt`: 3月版で増えた文字列と興味深い文字列。 - `artifacts/analyze_modem_toc.py`, `artifacts/modem_diff_windows.py`: 解析補助スクリプト。 - `artifacts/SHA256SUMS`: 主要成果物のハッシュ。 ## 次にやるなら OK に近づけるには、`MAIN` を正しい CPU/ABI/ロードアドレスで Ghidra/IDA に読み込み、`N2cn2sm17NrSmMsgHdlrFromMME` もしくは `SMT_MM_DATA_IND` の文字列参照から関数を同定する必要がある。そのうえで 2月/3月の関数 diff を取り、追加された長さ検証、`memcpy`/decode 呼び出し、可変長 IE 処理の変化を追う。今回の調査結果は、その入口を `cn_NrSmMsgHdlrFromMM.cpp` / `MM_DATA_IND` へ絞るところまで。 cve.md を表示# CVE-2026-0110 - Pixel Modem EoP High ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0110 - Component: Pixel - Subcomponent: Modem - Reference: A-440358226 * - Type: EoP - Severity: High ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel Modem EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 55 | NG | CVE-2026-0111 - Pixel Cellular Modem EoP High |
055
ng
CVE-2026-0111 - Pixel Cellular Modem EoP High055-ng-SMSCB-ns_GetUserData-OOB-write cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel Cellular Modem EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容NG理由・判定範囲 判定: **ng** 公開CVE情報から、CVE-2026-0111 は Pixel/Android の Cellular Modem にある `ns_SmscbUtilities.c` の `ns_GetUserData` における out-of-bounds write で、原因は incorrect bounds check だと特定できた。SMS Cell Broadcast (SMSCB/CBCH) のユーザーデータ処理に関係する脆弱性と判断できる。 ただし、Pixel modem firmware は非公開ソースの大きな独自バイナリで、2026年3月の radio 更新には複数の Modem / Cellular Modem / Baseband CVE と通常更新が混在している。今回のバイナリ差分では、`ns_GetUserData` の修正済み比較式、コピー先バッファ、攻撃入力の正確な長さ条件を一意に復元できなかった。指定条件の「ソースコード、もしくは脆弱性が起きる状況を完璧に説明できる場合」には届かないため `ng` とする。 原因 未確定。OK条件を満たすだけの具体的な根本原因までは判定できていない。 確認元 validated.md の「公式・公開情報」「パッチ差分解析」 / Android bug参照 A-461921661 * / 参照URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01, https://source.android.com/docs/security/bulletin/2026/2026-03-01, https://nvd.nist.gov/vuln/detail/CVE-2026-0111, https://github.com/advisories/GHSA-225v-w4gw-cgwv validated.md を表示# CVE-2026-0111 Pixel Cellular Modem EoP High 検証結果 ## 判定 判定: **ng** 公開CVE情報から、CVE-2026-0111 は Pixel/Android の Cellular Modem にある `ns_SmscbUtilities.c` の `ns_GetUserData` における out-of-bounds write で、原因は incorrect bounds check だと特定できた。SMS Cell Broadcast (SMSCB/CBCH) のユーザーデータ処理に関係する脆弱性と判断できる。 ただし、Pixel modem firmware は非公開ソースの大きな独自バイナリで、2026年3月の radio 更新には複数の Modem / Cellular Modem / Baseband CVE と通常更新が混在している。今回のバイナリ差分では、`ns_GetUserData` の修正済み比較式、コピー先バッファ、攻撃入力の正確な長さ条件を一意に復元できなかった。指定条件の「ソースコード、もしくは脆弱性が起きる状況を完璧に説明できる場合」には届かないため `ng` とする。 ## 公式・公開情報 - Pixel Update Bulletin March 2026: `CVE-2026-0111 / A-461921661 / EoP / High / Cellular Modem` - NVD: `In ns_GetUserData of ns_SmscbUtilities.c, there is a possible out of bounds write due to an incorrect bounds check.` - CISA ADP CVSS v3.1: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H` - CWE: `CWE-787 Out-of-bounds Write` 参照: - https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - https://source.android.com/docs/security/bulletin/2026/2026-03-01 - https://nvd.nist.gov/vuln/detail/CVE-2026-0111 - https://github.com/advisories/GHSA-225v-w4gw-cgwv ## 使用したファームウェア 共有キャッシュ `../binaries` の既存ファイルを再利用した。対象機種は既存解析に合わせて Pixel 8 `shiba`。 - pre-patch: `../binaries/pixel_shiba_modem_0114/radio-shiba-bp4a.260205.001.img` - baseband: `g5300i-250909-251024-B-14326967` - SHA-256: `7f0004a41e24019b54259dabcc393e6e555371c7f04d37a16812cc2b3a94308f` - post-patch: `../binaries/pixel_shiba_modem_0114/radio-shiba-cp1a.260305.018.img` - baseband: `g5300i-251202-260127-B-14784800` - SHA-256: `db5a0c8161d9cc674ec348c07460495f36ef9209740c03f44c14386501c2f80d` - extracted modem, pre-patch: `../binaries/pixel_shiba_modem_0114/modem_bins/feb-modem.bin` - SHA-256: `214a97055cd7d86b5fdb5fe737f24aa0ac604df68e95e31fb8f1cf3f7d98f820` - extracted modem, post-patch: `../binaries/pixel_shiba_modem_0114/modem_bins/mar-modem.bin` - SHA-256: `7cba729c106e702d284d7f7fa97248615af8ba746ed5762fd8aa5d27c9ad7a5b` ## パッチ差分解析 既存の 047 ジョブで抽出済みの `modem.bin` TOC 解析結果を再利用した。`modem.bin` は `TOC\0` 形式で、主な実行コードは `MAIN` セクションにある。 `MAIN` には以下の SMSCB 関連ソースパスが残っていた。 - `../../../PSS/StackService/CNS/SmsSap/Code/Src/ns_ServiceHandlerSmscb.c` - `../../../PSS/StackService/CNS/SmsSap/Code/Src/ns_SmscbUtilities.c` - `../../../PSS/StackService/CNS/SmsSap/Code/Src/ns_DcsUtilities.c` SMSCB/CBCH 関連のログ文字列も確認できた。 - `SMS <== PH_CBCH_IND` - `SMS ==> PH_CBCHSCHED_REQ` - `sms_SendGsmSmsCbInd` - `sms_SendUmtsSmsCbInd` - `MessageIdentifer=%d, SerialNumber=%d, DataCodingScheme=%d, DataSize=%d, Data addr=%d NotiType=%d` - `sms_ProcessSmsCbLangReqMsg - Language Out of Bounds` `focused_smscb_near_diff_windows.csv` では SMSCB 文字列近傍の変更窓を抽出したが、SMSCB ソースパス付近を含む変更は数MBから二十数MB規模だった。これは単一の `if (len > dst_size)` 追加のような小さなパッチではなく、広範な firmware rebuild/relink や複数修正が混在している状態を示す。したがって、この差分だけから CVE-2026-0111 固有の修正箇所を切り出せない。 ## 脆弱性像 公開情報とバイナリ内の SMSCB 証跡から、脆弱性は以下の形だと考えられる。 1. ネットワーク由来の SMS Cell Broadcast メッセージが modem の CNS SMS stack に入る。 2. `ns_GetUserData` が SMSCB の user data を取り出す。 3. user data の長さ、ページ長、残り入力長、またはコピー先容量の検証が誤っている。 4. 細工された SMSCB メッセージにより、固定長または割当済みバッファを越えて書き込みが発生する。 5. modem コンテキストのメモリ破壊により、リモート EoP につながり得る。 根本原因を高水準に言えば、信頼できないセルブロードキャスト入力の user data 長を、出力バッファ容量に対して正しく制約していなかったこと。ただし、正確なフィールド値、境界値、コピー先構造体、修正後条件式は未特定。 ## 調査で分かった面白い点 - CVE-2026-0111 と CVE-2026-0113 は、公開データ上ではどちらも `ns_GetUserData` / `ns_SmscbUtilities.c` / OOB write として説明されている。少なくとも外部から見える説明だけでは2件を差分レベルで分離できない。 - Pixel Bulletin 上は `Cellular Modem` だが、NVD の affected entry には `Android kernel` という粗い表記も見える。実体は Android kernel ソースではなく、Pixel modem firmware 内の Samsung/Pixel modem CNS SMS stack と見てよい。 - `MAIN` には `PSS/StackService/CNS/SmsSap` のソースパスが残っており、非公開バイナリでもコンポーネント境界の推定には役立つ。 - SMSCB 周辺には `CBMI/CBMID/CBMIR`、`PH_CBCH_IND`、`DataCodingScheme`、`DataSize` など、攻撃入力面を示す文字列が残っている。 - 3月 radio はモデム全体の大規模更新で、同じ差分に `CVE-2026-0110`, `CVE-2026-0111`, `CVE-2026-0113`, `CVE-2026-0114`, `CVE-2026-0120`, `CVE-2026-0122` などが混在し得る。 ## 付帯ファイル - `artifacts/analysis_notes.md`: 調査メモと判定理由。 - `artifacts/firmware_sha256.txt`: 使用した radio/modem バイナリのハッシュ。 - `artifacts/toc_old.json`, `artifacts/toc_new.json`, `artifacts/toc_diff.csv`: modem TOC 解析結果。 - `artifacts/main_diff_windows.csv`: `MAIN` セクションの変更窓。 - `artifacts/feb_focused_smscb_strings_offsets.txt`, `artifacts/mar_focused_smscb_strings_offsets.txt`: SMSCB/CBCH 関連文字列のオフセット。 - `artifacts/focused_smscb_near_diff_windows.csv`: SMSCB 関連文字列近傍の変更窓。 - `artifacts/mar_added_smscb_high_signal.txt`, `artifacts/feb_removed_smscb_high_signal.txt`: SMSCB/境界チェック関連の追加・削除候補文字列。 - `artifacts/pixel-bulletin-2026-03-01.html`: Pixel Bulletin 保存版。 ## 結論 CVE-2026-0111 は、SMS Cell Broadcast の user data 抽出処理 `ns_GetUserData` における境界チェック不備による out-of-bounds write だった可能性が高い。攻撃者はネットワーク経由で細工した SMSCB/CBCH メッセージを処理させ、modem 側でメモリ破壊を起こせる。 一方で、今回のパッチ差分解析では、CVE固有の修正関数本体や境界チェック式までは復元できなかった。根本原因は公開情報レベルでは特定できたが、コード/バイナリ命令レベルで完全に検証できていないため `ng` とした。 cve.md を表示# CVE-2026-0111 - Pixel Cellular Modem EoP High ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0111 - Component: Pixel - Subcomponent: Cellular Modem - Reference: A-461921661 * - Type: EoP - Severity: High ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel Cellular Modem EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 56 | OK | CVE-2026-0112 - Pixel VPU EoP High |
056
ok
CVE-2026-0112 - Pixel VPU EoP High056-ok-vpu-open-close-instance-race-UAF cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel VPU EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) 対象は Pixel VPU kernel driver の `/dev/vpu` ioctl 経路。Project Zero の記述では `/dev/vpu` は `mediacodec` など一部 SELinux context から到達可能で、メディア解析経由の 1-click/0-click 攻撃面につながり得る。 問題の中心は `vpu_open_inst()` と `vpu_close_inst()` が共有配列 `core->instances` 上の VPU instance の lifetime を一貫して保護していないこと。 再現される競合は次の形になる。 1. Thread A が `VPU_IOCX_OPEN_INSTANCE` を呼び、`vpu_open_inst()` が `inst` を確保する。 2. Thread A は `vpu_set_inst()` で `inst` を `core->instances[inst_idx]` に公開する。このとき `core->inst_lock` は取得されるが、その後すぐ解放される。 3. Thread B が同じ `inst_idx` で `VPU_IOCX_CLOSE_INSTANCE` を呼ぶ。 4. Thread B の `vpu_get_inst()` は `core->inst_lock` を取って `core->instances` から同じ `inst` を取得するが、取得後に lock を解放する。 5. Thread B が `vpu_close_inst()` で `inst` を解放する。 6. Thread A が `vpu_open_inst()` の残り処理に戻り、すでに解放済みの `inst` ポインタを使い続ける。 このため open/close 競合では use-after-free が起きる。さらに Project Zero は、同じコードパターンが `VPU... 原因(根本原因) 根本原因は instance lifetime の所有権モデルが壊れていること。 - `core->instances` への公開、参照取得、削除、解放が一つの不可分な状態遷移として扱われていない。 - `core->inst_lock` は配列アクセスの短い区間だけを守っており、取得した `inst` ポインタの利用期間までは守っていない。 - `vpu_open_inst()` は instance を完全初期化する前にグローバル配列へ公開している。 - `vpu_get_inst()` は refcount/kref/in-use flag のような lifetime pin を返していない。 - close 側は「その instance が初期化中ではない」「別 thread が同時 close 中ではない」「利用者が残っていない」ことを保証せずに free できる。 つまり単なる NULL check 不足ではなく、共有オブジェクトの publish/get/free プロトコルそのものが race-safe ではなかった。 どこから特定したか validated.md の「参照した一次情報」「パッチ解析」 / Android bug参照 A-463676597 * / 参照URL: https://dl.google.com/dl/android/aosp/shiba-ota-bp4a.260205.001-3d2eff34.zip, https://dl.google.com/dl/android/aosp/shiba-ota-cp1a.260305.018-592992df.zip, https://dl.google.com/dl/android/aosp/frankel-ota-bp4a.260205.001-e7319588.zip, https://dl.google.com/dl/android/aosp/frankel-ota-cp1a.260305.018-1c48e8fa.zip validated.md を表示# CVE-2026-0112 Pixel VPU EoP High 検証結果 ## 判定 ok。 ソース差分そのものは取得できなかったが、Project Zero の公開 Issue Tracker JSON から、脆弱な関数、競合する ioctl、到達条件、PoC 実行時の kernel oops、修正日、Security Bulletin 日付まで確認できた。脆弱性が起きる状況は完全に説明できるため、フォルダ名変更条件の ok に該当すると判断した。 ## 参照した一次情報 - Pixel Update Bulletin - March 2026: `CVE-2026-0112 / A-463676597 / High / VPU`。2026-03-05 以降の SPL で修正。 - Project Zero issue 463672550: `vpu driver open and close instance ioctls race causing UAF`。公開 JSON を `artifacts/project_zero_issue_463672550.raw.jsonish` と `artifacts/project_zero_issue_463672550.decoded.txt` に保存。 - CVE レコード/OSV 系記述: `vpu_ioctl.c` の `vpu_open_inst` における race condition による use-after-free。EoP、PR:N、UI:N、AC:H。 ## 脆弱性の内容 対象は Pixel VPU kernel driver の `/dev/vpu` ioctl 経路。Project Zero の記述では `/dev/vpu` は `mediacodec` など一部 SELinux context から到達可能で、メディア解析経由の 1-click/0-click 攻撃面につながり得る。 問題の中心は `vpu_open_inst()` と `vpu_close_inst()` が共有配列 `core->instances` 上の VPU instance の lifetime を一貫して保護していないこと。 再現される競合は次の形になる。 1. Thread A が `VPU_IOCX_OPEN_INSTANCE` を呼び、`vpu_open_inst()` が `inst` を確保する。 2. Thread A は `vpu_set_inst()` で `inst` を `core->instances[inst_idx]` に公開する。このとき `core->inst_lock` は取得されるが、その後すぐ解放される。 3. Thread B が同じ `inst_idx` で `VPU_IOCX_CLOSE_INSTANCE` を呼ぶ。 4. Thread B の `vpu_get_inst()` は `core->inst_lock` を取って `core->instances` から同じ `inst` を取得するが、取得後に lock を解放する。 5. Thread B が `vpu_close_inst()` で `inst` を解放する。 6. Thread A が `vpu_open_inst()` の残り処理に戻り、すでに解放済みの `inst` ポインタを使い続ける。 このため open/close 競合では use-after-free が起きる。さらに Project Zero は、同じコードパターンが `VPU_IOCX_CLOSE_INSTANCE` 同士にもあり、close/close が競合すると double free になり得る、と説明している。 ## 根本原因 根本原因は instance lifetime の所有権モデルが壊れていること。 - `core->instances` への公開、参照取得、削除、解放が一つの不可分な状態遷移として扱われていない。 - `core->inst_lock` は配列アクセスの短い区間だけを守っており、取得した `inst` ポインタの利用期間までは守っていない。 - `vpu_open_inst()` は instance を完全初期化する前にグローバル配列へ公開している。 - `vpu_get_inst()` は refcount/kref/in-use flag のような lifetime pin を返していない。 - close 側は「その instance が初期化中ではない」「別 thread が同時 close 中ではない」「利用者が残っていない」ことを保証せずに free できる。 つまり単なる NULL check 不足ではなく、共有オブジェクトの publish/get/free プロトコルそのものが race-safe ではなかった。 ## パッチ解析 公開ソース diff は取得できなかった。GoogleSource で単純な `kernel/google-modules/video` 系の公開リポジトリは見つからず、`dl.google.com` からの OTA 直接取得もこの環境では TLS handshake timeout / connection reset で安定しなかった。既存キャッシュの March `shiba` OTA は 1.0GB の途中切れで、zip central directory がなく `payload.bin` も不完全だった。 ただし Project Zero issue のメタデータで以下を確認した。 - Reported: 2025-11-25 - Fixed: 2026-03-03 - Security Bulletin date: 2026-03-03 - CVE ID: CVE-2026-0112 - VendorID: 463671148 - Methodology: Source review - racy?: `racy (non-det.)` 修正の本質は、少なくとも次のいずれか、または組み合わせであるはず。 - `vpu_open_inst()` が初期化完了前の instance を `core->instances` に公開しない。 - `vpu_get_inst()` が参照カウントを上げ、利用終了時に put する lifetime pin を導入する。 - `VPU_IOCX_CLOSE_INSTANCE` が instance を配列から取り外す操作と「close 中」状態設定を同じ lock 下で行い、二重 close を拒否する。 - free は全利用者が消えた後にだけ行う。 - open/close/close-close の全経路で同じ lock または state machine を使う。 Project Zero の報告内容から見ると、パッチは「境界チェック追加」ではなく「instance lifetime と排他制御の修正」と評価するのが正しい。 ## バイナリ・OTA 確認メモ 共有キャッシュ `/Users/eric/workspace/android/binaries` を確認した。 - `pixel_shiba_ota/shiba-ota-cp1a.260305.018-592992df.zip`: 1.0GB の不完全 zip。`bsdtar` では `Truncated input file`。 - `pixel_shiba_ota/shiba-ota-cp2a.260605.012-b315a1a2.zip`: zip として正常。 - `pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.truncated.zip`: zip として読めるが名前どおり truncated 扱いの既存ファイル。 `payload-dumper-go` で post-patch の `shiba` May/June OTA から `vendor_dlkm.img` を抽出した。 - `artifacts/shiba_may_extract/vendor_dlkm.img` - `artifacts/shiba_june_extract/vendor_dlkm.img` 両方とも ext2 `vendor_dlkm` image だったが、`strings` では `vpu_open_inst`、`vpu_close_inst`、`VPU_IOCX_*`、`/dev/vpu`、`inst_lock` は出なかった。Project Zero の PoC 実行端末は Pixel 10 `frankel` (`google/frankel/frankel:16/BD3A.251105.010.E1/14337626`) なので、手元の Pixel 8 `shiba` OTA には同一 VPU module が含まれていない可能性が高い。 公式 OTA URL として以下を控えた。 - `shiba` pre: `https://dl.google.com/dl/android/aosp/shiba-ota-bp4a.260205.001-3d2eff34.zip` - `shiba` post: `https://dl.google.com/dl/android/aosp/shiba-ota-cp1a.260305.018-592992df.zip` - `frankel` pre: `https://dl.google.com/dl/android/aosp/frankel-ota-bp4a.260205.001-e7319588.zip` - `frankel` post: `https://dl.google.com/dl/android/aosp/frankel-ota-cp1a.260305.018-1c48e8fa.zip` ## PoC/クラッシュ情報 Project Zero issue には、PoC 実行で Pixel 10 上に kernel splat が出ることが記録されている。ログ上の要点は以下。 - device/build: `google/frankel/frankel:16/BD3A.251105.010.E1/14337626` - kernel: `6.6.82-android15-8-gd4aed7ed470e-ab13759939-4k` - crashing command: `poc` - fault: NULL pointer dereference near `0x16c` - LR / stack: `vpu_close_inst+0x50/0x98 [vpu]` これは free 済み、または close により壊れた instance 状態を close/open 後続処理が参照していることと整合する。 ## 付帯ファイル - `artifacts/project_zero_issue_excerpt.txt`: Project Zero issue の重要部分抽出。 - `artifacts/vpu_instance_race_model.py`: open/close と close/close の race を単純化した状態モデル。 - `artifacts/vpu_instance_race_model.out`: モデル実行結果。 - `artifacts/pixel-bulletin-2026-03-01.html`: Pixel bulletin 保存。 - `artifacts/origin_patch_diffing_pipeline.html`: 指定された patch diffing pipeline 記事の保存。 - `artifacts/ota_urls_considered.txt`: 検討した OTA URL。 - `artifacts/SHA256SUMS`: 成果物ハッシュ。 ## 面白い点・調査メモ - CVE 文面は `vpu_open_inst` だけを名指ししているが、Project Zero issue では close/close の double free も同じ設計不備として指摘されている。実際のパッチは CVE-2026-0112 だけでなく、後続の VPU race 系 CVE の variant fix と関連している可能性がある。 - CVSS は PR:N/UI:N だが、`/dev/vpu` に直接触れる app sandbox ではなく `mediacodec` などの SELinux context が現実的な到達面として挙げられている。メディア処理経由で VPU を使わせる攻撃面が重要。 - Project Zero issue の methodology は `Source review`。この CVE はファームウェア blob 解析というより、Pixel kernel driver の lifetime bug と見るべき。 - 競合は `racy (non-det.)` と記録されており、決定的同期で常に勝てるタイプではない。ただし kernel object lifetime の破壊なので、勝てた場合の影響は EoP として十分大きい。 cve.md を表示# CVE-2026-0112 - Pixel VPU EoP High ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0112 - Component: Pixel - Subcomponent: VPU - Reference: A-463676597 * - Type: EoP - Severity: High ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel VPU EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 57 | NG | CVE-2026-0113 - Pixel Cellular Modem EoP High |
057
ng
CVE-2026-0113 - Pixel Cellular Modem EoP High057-ng-SMSCB-ns_GetUserData-OOB-write-duplicate-public-description cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel Cellular Modem EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容NG理由・判定範囲 判定: **ng** 公開 CVE/OSV 情報から、CVE-2026-0113 は Pixel Cellular Modem の `ns_SmscbUtilities.c` にある `ns_GetUserData` で、誤った境界チェックにより out-of-bounds write が起きる脆弱性だと分かった。影響は remote escalation of privilege、追加権限不要、ユーザー操作不要とされている。 ただし、Pixel modem firmware は非公開ソースの大きなバイナリで、2026年3月 radio 更新には複数の Modem / Cellular Modem / Baseband CVE と通常更新が混在している。今回の patch diff では `ns_SmscbUtilities.c` と SMSCB/CBCH 経路の存在は firmware 内で確認できたが、`ns_GetUserData` の関数本体、修正された比較式、破壊されるバッファ、CVE-2026-0111 との差分を一意に復元できなかった。 指定条件の「ソースコード、もしくは脆弱性が起きる状況を完璧に説明できる場合」には届かないため `ng` とする。 原因 未確定。OK条件を満たすだけの具体的な根本原因までは判定できていない。 確認元 validated.md の「公式・公開情報」 / Android bug参照 A-441209133 * / 参照URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01, https://osv.dev/vulnerability/PUB-A-441209133, https://www.cve.org/CVERecord?id=CVE-2026-0113 validated.md を表示# CVE-2026-0113 Pixel Cellular Modem EoP 検証結果 ## 判定 判定: **ng** 公開 CVE/OSV 情報から、CVE-2026-0113 は Pixel Cellular Modem の `ns_SmscbUtilities.c` にある `ns_GetUserData` で、誤った境界チェックにより out-of-bounds write が起きる脆弱性だと分かった。影響は remote escalation of privilege、追加権限不要、ユーザー操作不要とされている。 ただし、Pixel modem firmware は非公開ソースの大きなバイナリで、2026年3月 radio 更新には複数の Modem / Cellular Modem / Baseband CVE と通常更新が混在している。今回の patch diff では `ns_SmscbUtilities.c` と SMSCB/CBCH 経路の存在は firmware 内で確認できたが、`ns_GetUserData` の関数本体、修正された比較式、破壊されるバッファ、CVE-2026-0111 との差分を一意に復元できなかった。 指定条件の「ソースコード、もしくは脆弱性が起きる状況を完璧に説明できる場合」には届かないため `ng` とする。 ## 公式・公開情報 - Pixel Update Bulletin March 2026: `CVE-2026-0113 / A-441209133 / EoP / High / Cellular Modem` - OSV `PUB-A-441209133`: `In ns_GetUserData of ns_SmscbUtilities.c, there is a possible out of bounds write due to an incorrect bounds check.` - CVE Record: 同じ説明で、remote EoP、追加権限不要、ユーザー操作不要。 - Pixel Bulletin では Android bug ID の後ろに `*` が付いており、詳細 bug は非公開。Google の説明では、この種の修正は Pixel 用 binary drivers / firmware に含まれる。 参照: - https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - https://osv.dev/vulnerability/PUB-A-441209133 - https://www.cve.org/CVERecord?id=CVE-2026-0113 ## 使用したファームウェア 共有キャッシュ `../binaries` の既存ファイルを再利用した。対象機種は既存ジョブと同じ Pixel 8 `shiba`。 - pre-patch radio: `../binaries/pixel_shiba_modem_0114/radio-shiba-bp4a.260205.001.img` - baseband: `g5300i-250909-251024-B-14326967` - SHA-256: `7f0004a41e24019b54259dabcc393e6e555371c7f04d37a16812cc2b3a94308f` - post-patch radio: `../binaries/pixel_shiba_modem_0114/radio-shiba-cp1a.260305.018.img` - baseband: `g5300i-251202-260127-B-14784800` - SHA-256: `db5a0c8161d9cc674ec348c07460495f36ef9209740c03f44c14386501c2f80d` - extracted modem, pre-patch: `../binaries/pixel_shiba_modem_0114/modem_bins/feb-modem.bin` - SHA-256: `214a97055cd7d86b5fdb5fe737f24aa0ac604df68e95e31fb8f1cf3f7d98f820` - extracted modem, post-patch: `../binaries/pixel_shiba_modem_0114/modem_bins/mar-modem.bin` - SHA-256: `7cba729c106e702d284d7f7fa97248615af8ba746ed5762fd8aa5d27c9ad7a5b` ## Patch Diff 解析 `modem.bin` は `TOC\0` 形式で、主要実行コードは `MAIN` セクションにある。2月版と3月版でセクションのサイズ・ロードアドレスは同じだが、内容 hash は変わっていた。 - `MAIN`: size `98176000`, load `0x40010000`, changed - `BOOT`: size `92160`, changed - `VSS`: size `4705292`, changed - `APM`: size `46232`, changed `MAIN` の byte-level diff は 3547 個の変更窓にまとまった。SMSCB 関連文字列の近傍は、以下のように大きな変更窓に含まれており、単一関数パッチとしては切り出せなかった。 - `ns_SmscbUtilities.c`: `idx=705`, `0xee21b0-0x13c17cb`, 約 5.1 MB - `CBS Data Ind ... DataSize=%d`: `idx=3543`, `0x4defd00-0x58aa682`, 約 11.2 MB - `sms_SendGsmSmsCbInd`, `sms_SendUmtsSmsCbInd`, `CbsDataSize is %d`: 同じ `idx=3543` この規模の変更窓は、firmware 全体の rebuild/relink、文字列配置の移動、同月の複数 CVE 修正が混ざっていることを示している。Origin の記事のような「pre/post binary の候補関数 diff から修正ロジックを抜く」流れは試みたが、手元に Ghidra/r2 がなく、かつ生バイナリで関数境界がないため、命令レベルでの確定には届かなかった。 ## Firmware 内で確認した証跡 `MAIN` には公開説明と一致する SMSCB 実装のソースパスとログ文字列が残っていた。 - `../../../PSS/StackService/CNS/SmsSap/Code/Src/ns_ServiceHandlerSmscb.c` - `../../../PSS/StackService/CNS/SmsSap/Code/Src/ns_SmscbUtilities.c` - `SMS <== PH_CBCH_IND` - `SMS ==> PH_CBCHSCHED_REQ` - `sms_SendGsmSmsCbInd in %s state` - `sms_SendUmtsSmsCbInd in %s state` - `MessageIdentifer=%d, SerialNumber=%d, DataCodingScheme=%d, DataSize=%d, Data addr=%d NotiType=%d` - `CbsDataSize is %d` - `sms_ProcessSmsCbLangReqMsg - Language Out of Bounds` - `CB_CBMI`, `CB_CBMID`, `CB_CBMIR`, `EF_CBMI`, `EF_CBMID`, `EF_CBMIR` これらから、対象は SMS Cell Broadcast / CBCH の受信・通知処理であり、ネットワーク由来の cell broadcast payload が CNS SMS stack に渡される経路だと判断できる。 ## 脆弱性像 公開情報と firmware 証跡から、脆弱性は以下の形だと考えられる。 1. ネットワーク側から SMS Cell Broadcast / CBCH メッセージが届く。 2. modem firmware の CNS SMS stack が `PH_CBCH_IND` などの経路で cell broadcast data indication を処理する。 3. `ns_SmscbUtilities.c` の `ns_GetUserData` が message identifier、serial number、data coding scheme、user data / data size などを取り出す。 4. user data 長、ページ長、残り入力長、またはコピー先容量の境界チェックが誤っており、細工された入力で out-of-bounds write が起きる。 5. modem 内メモリ破壊により、remote EoP につながる可能性がある。 根本原因を高水準で言えば、信頼できない SMSCB user data の長さを、実際の入力残量または出力バッファ容量に対して正しく制約していなかったこと。ただし、正確な境界値、問題フィールド、コピー先構造体、修正後条件式は未特定。 ## 面白いこと・調査メモ - CVE-2026-0111 と CVE-2026-0113 は、OSV の公開説明が完全に同一だった。どちらも `ns_GetUserData of ns_SmscbUtilities.c`、incorrect bounds check、OOB write、remote EoP とされる。 - 057 の `cve.md` は CVE-2026-0113 だが、隣の 055 ジョブは CVE-2026-0111 を同じ SMSCB `ns_GetUserData` 問題として調査している。公開情報だけでは 2件が同一関数内の別境界条件なのか、重複した説明なのか、別コードパスなのか分離できない。 - Pixel Bulletin の subcomponent は `Cellular Modem` だが、CVE Record の affected version は `Android kernel` と粗く書かれている。実体は AOSP kernel ソースではなく、Pixel の modem firmware 内 CNS SMS stack と見るのが自然。 - `MAIN` にはソースパスやログ文字列がかなり残っており、非公開 firmware でもコンポーネント境界の推定には有効だった。 - `CbsDataSize is %d` や `DataSize=%d, Data addr=%d` など、CVE 説明の user data / size 処理と整合するログがある一方、`ns_GetUserData` という関数名そのものは `strings` では見つからなかった。 ## 付帯ファイル - `artifacts/PUB-A-441209133.osv.json`, `artifacts/PUB-A-441209133.osv.pretty.json`: OSV レコード。 - `artifacts/CVE-2026-0113.cveawg.json`, `artifacts/CVE-2026-0113.cveawg.pretty.json`: CVE Record。 - `artifacts/PUB-A-461921661-CVE-2026-0111.osv.pretty.json`: CVE-2026-0111 との公開説明比較用。 - `artifacts/cve0111_vs_0113_public_description.diff`: 0111 と 0113 の OSV details 比較。空ファイルで、説明が同一であることを示す。 - `artifacts/pixel-bulletin-2026-03-01.html`: Pixel Bulletin 保存版。 - `artifacts/firmware_sha256.txt`: 使用した radio/modem バイナリの hash。 - `artifacts/toc_old.json`, `artifacts/toc_new.json`, `artifacts/toc_diff.csv`: modem TOC 解析結果。 - `artifacts/main_diff_windows.csv`: `MAIN` セクションの byte-level diff 窓。 - `artifacts/feb_smscb_strings_offsets.txt`, `artifacts/mar_smscb_strings_offsets.txt`: SMSCB/CBCH 関連文字列と offset。 - `artifacts/smscb_nearest_diff_windows.txt`: SMSCB 関連文字列から最も近い変更窓。 - `artifacts/mar_added_smscb_bounds_strings.txt`, `artifacts/feb_removed_smscb_bounds_strings.txt`: SMSCB/bounds/length 系の追加・削除候補文字列。 - `artifacts/analyze_modem_toc.py`, `artifacts/modem_diff_windows.py`: 解析補助スクリプト。 - `artifacts/SHA256SUMS`: 付帯ファイル hash。 ## 次にやるなら OK 判定に近づけるには、`MAIN` をロードアドレス `0x40010000` で Ghidra/IDA に読み込み、`ns_SmscbUtilities.c` や `CbsDataSize is %d` などの文字列参照から SMSCB 関数群を同定する必要がある。そのうえで 2月/3月の該当関数を decompile/diff し、`ns_GetUserData` 内で追加された長さ検証やコピー条件を確認する。さらに CVE-2026-0111 と CVE-2026-0113 の public description が同一であるため、両者を分離するには Android bug ID または関数内の複数修正点との対応付けが必要になる。 cve.md を表示# CVE-2026-0113 - Pixel Cellular Modem EoP High ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0113 - Component: Pixel - Subcomponent: Cellular Modem - Reference: A-441209133 * - Type: EoP - Severity: High ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel Cellular Modem EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 58 | OK | CVE-2026-0117 - Pixel MFC EoP High |
058
ok
CVE-2026-0117 - Pixel MFC EoP High058-ok-MFC-DQBUF-ref-info-index-OOB-write-EoP cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel MFC EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の詳細) 関連するサイズ定義と構造体は以下。 [コードブロック省略] `mfc.c` の decoder 初期化では、`dec->ref_info` は次の通り32要素分だけ確保される。 [コードブロック省略] 修正前の `mfc_dec_dqbuf()` は capture queue の `vb2_dqbuf()` 後に `buf->index` を検査するが、検査上限が64だった。 [コードブロック省略] このため、`buf->index` が 32..63 の場合でもチェックを通過する。`srcBuf = &dec->ref_info[buf->index]` は `dec->ref_info[32]` 以降のOOB readになり、ユーザー共有ハンドルが設定されていれば `dstBuf = sh_handle_dpb.vaddr + buf->index` と `memcpy()` により、同じ32要素想定の共有領域にも範囲外書き込みを行う。最後の `dstBuf->index = buf->index` も範囲外書き込みになる。 攻撃条件は、ローカルアプリがMFCデコーダのV4L2インターフェースを使い、capture buffer dequeue 経路で32以上の capture buffer index が返る状態を作ること。NVDは「追加実行権限不要、ユーザー操作不要」としており、通常のメディアデコード用デバイスノード経由で到達可能なローカルEoPとして扱っている。パッチが `mfc_dec_dqbuf()` の post-dequeue index 検査だけを直しているため、脆弱な振る舞いの本質は動画ビットストリームの構文ではなく、V4L2 buffer index とMFC内部配列サイズの不整合にある。 補足として、同じMFCのCVE-2026-0116も `MFC_MAX_DPBS=64` と `MFC_MAX_BUFFERS=32` の混同に由来していたが... 原因(根本原因を含む段落) 根本原因は、MFC内部のDPBテーブル上限 `MFC_MAX_DPBS=64` と、ユーザー共有用に確保される `dec->ref_info` の要素数 `MFC_MAX_BUFFERS=32` を混同したこと。修正前の `mfc_dec_dqbuf()` は capture buffer の dequeue 後、`buf->index < 64` なら有効として `dec->ref_info[buf->index]` と `dec->sh_handle_dpb.vaddr + buf->index` にアクセスしていた。したがって `buf->index` が 32..63 の場合、32要素配列の外側を `sizeof(struct dec_dpb_ref_info)` 単位で読み書きし、カーネルメモリ破壊に至る。 どこから特定したか validated.md の「参照した公開情報」「特定したパッチ」 / Android bug参照 A-337803567 * / 参照URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01, https://nvd.nist.gov/vuln/detail/CVE-2026-0117, https://android.googlesource.com/kernel/google-modules/soc/gs/+/044ef10d4d51a74709246de6de5f018d9953e6b7 validated.md を表示# CVE-2026-0117 Pixel MFC EoP High 検証結果
## 結論
判定: ok
CVE-2026-0117 は、Pixel の Exynos/Samsung MFC デコーダドライバ `mfc_dec_dqbuf()` における DPB 参照情報配列の境界チェック誤りによる kernel out-of-bounds write と特定した。公開ソース `kernel/google-modules/soc/gs` に Android bug ID `337803567` と一致する修正コミットがあり、パッチは `buf->index` の上限を `MFC_MAX_DPBS` から `MFC_MAX_BUFFERS` へ変更している。
根本原因は、MFC内部のDPBテーブル上限 `MFC_MAX_DPBS=64` と、ユーザー共有用に確保される `dec->ref_info` の要素数 `MFC_MAX_BUFFERS=32` を混同したこと。修正前の `mfc_dec_dqbuf()` は capture buffer の dequeue 後、`buf->index < 64` なら有効として `dec->ref_info[buf->index]` と `dec->sh_handle_dpb.vaddr + buf->index` にアクセスしていた。したがって `buf->index` が 32..63 の場合、32要素配列の外側を `sizeof(struct dec_dpb_ref_info)` 単位で読み書きし、カーネルメモリ破壊に至る。
## 参照した公開情報
- Pixel Update Bulletin - March 2026: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01
- 対象エントリ: `CVE-2026-0117 / A-337803567 * / EoP / High / MFC`
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-0117
- NVD説明: `mfc_dec_dqbuf` in `mfc_dec_v4l2.c` の incorrect bounds check による out-of-bounds write、local EoP、追加権限不要、ユーザー操作不要。
- 修正コミット: https://android.googlesource.com/kernel/google-modules/soc/gs/+/044ef10d4d51a74709246de6de5f018d9953e6b7
- ローカル取得先: `../../binaries/kernel_google-modules_soc_gs.git`
## 特定したパッチ
コミット:
```text
044ef10d4d51a74709246de6de5f018d9953e6b7
media: mfc: modify condition to check dpb buf index
Bug: 337803567
AuthorDate: 2024-06-03 18:21:47 +0900
```
コミットメッセージは、`ref_info of mfc_dec is allocated as size of MFC_MAX_BUFFERS(32)` なのに、`mfc_dec_dqbuf` のエラー条件が `MFC_MAX_DPBS` を見ていたためOOBになり得る、と明記している。
差分は1行のみ。
```diff
- if (buf->index >= MFC_MAX_DPBS) {
+ if (buf->index >= MFC_MAX_BUFFERS) {
```
同じ Change-Id の反映コミットとして `63e6d7058edef3de20c80b9a34c296cfccac9609` と `fb354d868c3305755ac40dffa467478dcb2214dd` も確認した。
## 脆弱性の詳細
関連するサイズ定義と構造体は以下。
```c
#define MFC_MAX_DPBS 64
#define MFC_MAX_BUFFERS 32
struct dec_dpb_ref_info {
int index;
struct stored_dpb_info dpb[MFC_MAX_BUFFERS];
};
struct mfc_dec {
struct dpb_table dpb[MFC_MAX_DPBS];
struct dec_dpb_ref_info *ref_info;
struct stored_dpb_info ref_buf[MFC_MAX_BUFFERS];
int refcnt;
struct mfc_user_shared_handle sh_handle_dpb;
};
```
`mfc.c` の decoder 初期化では、`dec->ref_info` は次の通り32要素分だけ確保される。
```c
dec->sh_handle_dpb.data_size = sizeof(struct dec_dpb_ref_info) * MFC_MAX_BUFFERS;
dec->ref_info = vmalloc(dec->sh_handle_dpb.data_size);
```
修正前の `mfc_dec_dqbuf()` は capture queue の `vb2_dqbuf()` 後に `buf->index` を検査するが、検査上限が64だった。
```c
ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
if (buf->index >= MFC_MAX_DPBS)
return -EINVAL;
srcBuf = &dec->ref_info[buf->index];
...
dstBuf = (struct dec_dpb_ref_info *)dec->sh_handle_dpb.vaddr + buf->index;
memcpy(dstBuf, srcBuf, sizeof(struct dec_dpb_ref_info));
dstBuf->index = buf->index;
```
このため、`buf->index` が 32..63 の場合でもチェックを通過する。`srcBuf = &dec->ref_info[buf->index]` は `dec->ref_info[32]` 以降のOOB readになり、ユーザー共有ハンドルが設定されていれば `dstBuf = sh_handle_dpb.vaddr + buf->index` と `memcpy()` により、同じ32要素想定の共有領域にも範囲外書き込みを行う。最後の `dstBuf->index = buf->index` も範囲外書き込みになる。
攻撃条件は、ローカルアプリがMFCデコーダのV4L2インターフェースを使い、capture buffer dequeue 経路で32以上の capture buffer index が返る状態を作ること。NVDは「追加実行権限不要、ユーザー操作不要」としており、通常のメディアデコード用デバイスノード経由で到達可能なローカルEoPとして扱っている。パッチが `mfc_dec_dqbuf()` の post-dequeue index 検査だけを直しているため、脆弱な振る舞いの本質は動画ビットストリームの構文ではなく、V4L2 buffer index とMFC内部配列サイズの不整合にある。
補足として、同じMFCのCVE-2026-0116も `MFC_MAX_DPBS=64` と `MFC_MAX_BUFFERS=32` の混同に由来していたが、CVE-2026-0116 は release DPB を積む `refcnt` の増加上限不備だった。CVE-2026-0117 は `mfc_dec_dqbuf()` の `buf->index` 検査不備で、入口も修正コミットも別である。
## 面白い点・調査メモ
- Pixel bulletin では `A-337803567 *` でIssue Trackerは非公開扱いだが、公開kernel moduleのコミットメッセージにBug IDと根本原因がそのまま残っていた。
- CVE説明とパッチは完全に一致する。NVDは `mfc_dec_dqbuf of mfc_dec_v4l2.c` の incorrect bounds check と明記し、該当パッチも同じ関数の境界条件だけを変更している。
- 修正は `vb2_dqbuf()` より前ではなく後のチェックを直している。これは `buf->index` がユーザー入力そのものではなく、dequeueされたbuffer indexとして確定した値を、MFC固有の補助配列へ転記する直前に検査する設計だったため。
- `mfc_dec_queue_setup()` は capture buffer count を `MFC_MAX_BUFFERS` に丸めるが、脆弱性として修正された場所は `mfc_dec_dqbuf()` 側である。つまり開発者は、queue setup側の制限だけに依存せず、補助配列アクセス直前の上限も配列実体に合わせる必要があると判断している。
- `dec->ref_info` と `dec->sh_handle_dpb` は同じ `sizeof(struct dec_dpb_ref_info) * 32` という前提で動くため、読み元と書き先の両方に同じ添字混同が伝播する。
- 2026年3月bulletinのCVEだが、修正コミットのAuthorDateは2024-06-03だった。Pixelの公開bulletin掲載時期と公開ソース上の修正時期には大きな差がある。
## 保存した付帯ファイル
- `artifacts/044ef10d4d51.patch`: Bug ID付き修正コミットの全文diff
- `artifacts/commit_search_337803567.txt`: `337803567` / `CVE-2026-0117` によるgit log検索結果
- `artifacts/mfc_dec_dqbuf_before.txt`: 修正前 `mfc_dec_dqbuf()` 抜粋
- `artifacts/mfc_dec_dqbuf_after.txt`: 修正後 `mfc_dec_dqbuf()` 抜粋
- `artifacts/ref_info_size_context.txt`: `MFC_MAX_DPBS` / `MFC_MAX_BUFFERS` / `ref_info` 確保箇所 / queue setupの抜粋
- `artifacts/oob_index_model.py`: index 32..63 が修正前だけチェックを通過することを示す小モデル
- `artifacts/oob_index_model.out`: 上記モデルの出力
- `artifacts/pixel-bulletin-2026-03-01-excerpt.txt`: Pixel bulletin該当行のメモ
- `artifacts/nvd_cve_2026_0117_excerpt.txt`: NVD説明のメモ
- `artifacts/SHA256SUMS`: 付帯ファイルのハッシュ
## 再現・検証コマンド
```bash
git -C ../../binaries/kernel_google-modules_soc_gs.git log --all --grep='337803567\|CVE-2026-0117' --format='%H %ad %D%n%s%n%b' --date=iso-strict
git -C ../../binaries/kernel_google-modules_soc_gs.git show --patch --stat 044ef10d4d51a74709246de6de5f018d9953e6b7
git -C ../../binaries/kernel_google-modules_soc_gs.git show 044ef10d4d51a74709246de6de5f018d9953e6b7^:drivers/media/platform/exynos/mfc/mfc_dec_v4l2.c
git -C ../../binaries/kernel_google-modules_soc_gs.git show 044ef10d4d51a74709246de6de5f018d9953e6b7:drivers/media/platform/exynos/mfc/mfc_dec_v4l2.c
python3 artifacts/oob_index_model.py
```
cve.md を表示# CVE-2026-0117 - Pixel MFC EoP High ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0117 - Component: Pixel - Subcomponent: MFC - Reference: A-337803567 * - Type: EoP - Severity: High ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel MFC EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 59 | NG | CVE-2026-0118 - Pixel oobconfig EoP High |
059
ng
CVE-2026-0118 - Pixel oobconfig EoP High059-ng-oobconfig-carrier-restriction-bypass-unresolved cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel oobconfig EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容NG理由・判定範囲 NG。脆弱性の概要と修正対象と思われるパッケージ更新はかなり絞れたが、根本原因となった具体的なロジック分岐、または悪用条件を完全には特定できなかった。 `ok` としなかった理由は、脆弱版と見られる `OTAConfigNoZeroTouchPrebuilt-v510` の APK 本体を完全に抽出できず、修正版 `v588` とのコード差分を取れていないためである。また、修正版側の raw extent から `oobconfig` のクラス名・ログ文字列・一部 ZIP 構造は確認できたが、ext4 上の APK が断片化しており、単純な連続領域切り出しでは `classes.dex` を正しく復元できなかった。 原因 未確定。OK条件を満たすだけの具体的な根本原因までは判定できていない。 確認元 validated.md の「公開情報」 / Android bug参照 A-427469428 * validated.md を表示# CVE-2026-0118 Pixel oobconfig EoP 検証メモ ## 判定 NG。脆弱性の概要と修正対象と思われるパッケージ更新はかなり絞れたが、根本原因となった具体的なロジック分岐、または悪用条件を完全には特定できなかった。 `ok` としなかった理由は、脆弱版と見られる `OTAConfigNoZeroTouchPrebuilt-v510` の APK 本体を完全に抽出できず、修正版 `v588` とのコード差分を取れていないためである。また、修正版側の raw extent から `oobconfig` のクラス名・ログ文字列・一部 ZIP 構造は確認できたが、ext4 上の APK が断片化しており、単純な連続領域切り出しでは `classes.dex` を正しく復元できなかった。 ## 公開情報 - Pixel Security Bulletin 2026-03-01 では、`CVE-2026-0118` は `oobconfig` サブコンポーネント、参照 `A-427469428`、種別 EoP、重大度 High とされている。 - NVD/OpenCVE 系の説明では、「`oobconfig` に carrier restrictions の bypass が可能な logic error があり、追加実行権限なし・ユーザー操作なしで local escalation of privilege につながる可能性がある」と説明されている。 ## 実施した解析 ### OTA と対象パッケージ `../binaries` を共有キャッシュとして使い、Pixel 8 / shiba の OTA を調査した。 - 2026-02: `shiba-ota-bp4a.260205.001-3d2eff34.zip` - 2026-03: `shiba-ota-cp1a.260305.018-592992df.zip` - 2026-05: `shiba-ota-cp1a.260505.005.a1-7c6aa727.zip` いくつかの OTA zip は central directory が欠落またはダウンロード途中だったが、local file header から `payload.bin` の開始オフセットを特定し、`payload-dumper-go` で `product` / `system_ext` を部分抽出した。 確認した `payload.bin` 開始位置: - BP4A.260205.001: byte offset 4498、`tail -c +4499` - CP1A.260305.018: byte offset 4506、`tail -c +4507` - CP1A.260505.005.A1: byte offset 4548、`tail -c +4549` `product` 側の release config 文字列から、2026-02 では以下の値を確認した。 ```text "name": "RELEASE_PACKAGE_OOBCONFIG" "description": "Control which version of the Pixel SimLock (OobConfig/OTAConfigNoZeroTouchPrebuilt) app is installed." "StringValue": "OTAConfigNoZeroTouchPrebuilt-v510" ``` 2026-03 および 2026-05 では、同じ release config が `OTAConfigNoZeroTouchPrebuilt-v588` になっていた。 ```text "StringValue": "OTAConfigNoZeroTouchPrebuilt-v588" ``` このため、CVE-2026-0118 の修正候補は stock Pixel の privileged app である以下の更新と見るのが自然である。 ```text /product/priv-app/OTAConfigNoZeroTouchPrebuilt/OTAConfigNoZeroTouchPrebuilt.apk package: com.google.android.apps.work.oobconfig v510 -> v588 ``` ### allowlist 変更ではなさそうな点 `oobconfig` がネットワーク取得を継続できるようにする sysconfig allowlist も確認した。 ```xml <!-- OobConfig must always have network access to fetch enterprise and carrier lock config. --> <allow-in-power-save-except-idle package="com.google.android.apps.work.oobconfig" /> <allow-in-data-usage-save package="com.google.android.apps.work.oobconfig" /> ``` この allowlist は 2026-03/2026-05 だけでなく、2026-02 の部分抽出済み `product.img` にも存在した。したがって、「Data Saver や Doze で OobConfig の通信を止められること」自体を 2026-03 で初めて塞いだ、という単純な修正ではない。 ### 修正版 v588 断片から見えた攻撃面 2026-05 の `product.img` から `OTAConfigNoZeroTouchPrebuilt.apk` 周辺の raw extent を切り出し、文字列を抽出した。完全な APK 復元には失敗したが、以下のクラス・処理名・ログ文字列は確認できた。 主なクラス名: - `BootCompletedReceiver` - `BusinessLogicController` - `DeviceRestrictionsTask` - `DialerCodeReceiver` - `ForegroundService` - `NetworkJobService` - `NetworkTask` - `OobConfigTask` - `OobConfigUtils` - `ProvisioningDataService` - `SimLockProvider` - `SimLockTask` - `SimLockTrampolineActivity` - `DroidGuardClientWrapper` carrier restriction / SIM lock / OEM unlock に関係する文字列: - `Carrier restrictions set successfully` - `Failed to set carrier restriction` - `Failed to set carrier restriction status` - `Removing carrier restrictions` - `Trying to allow oem unlock` - `OEM unlock can be applied only by admin user` - `Oem Unlock failed. Skip simlock logic` - `Oem unlock token is invalid` - `Unrecognized carrier restriction mode: %d, using DEFAULT_ALLOWED instead.` - `getCarrierRestrictionRules` - `getCarrierRestrictionRulesInModem` - `getDefaultCarrierRestriction` - `getAllowedCarriers` - `getExcludedCarriers` - `getLastAppliedSimLockConfig` - `last_applied_simlock_config` - `last_applied_multisim_restriction` - `isOemUnlockAllowedByCarrier` - `hasOemUnlockRestriction` - `hasOemUnlockRestriction: %s, isSimLockConfigPresent: %s, attestation: %s` - `hasSimLockClaim` - `Sim details are not sent to server yet. Skipping simlock logic.` - `Simlock has been cleaned up! Skip simlock logic.` - `SimLock secret code entered...` - `SimLockProvider.queryStatus` - `getRestrictBackgroundStatus` これらから、`oobconfig` はサーバーから取得した enterprise/carrier lock config、DroidGuard/attestation、SIM 情報、過去に適用した simlock 設定を見て、`CarrierRestrictionRules` や OEM unlock carrier restriction 状態を更新する privileged component だと判断できる。 ## 推定される脆弱性 公開説明とバイナリ断片からの推定では、CVE-2026-0118 は `com.google.android.apps.work.oobconfig` の SIM lock / carrier restriction 適用ロジックにある logic error で、特定状態の端末で本来維持されるべき carrier restriction が解除、未適用、または `DEFAULT_ALLOWED` 扱いになる問題だった可能性が高い。 特に疑わしい箇所は以下である。 - carrier restriction mode が未知または異常値の場合に `DEFAULT_ALLOWED` に倒す処理 - `last_applied_simlock_config` / `last_applied_multisim_restriction` と現在のサーバー設定の整合性判定 - SIM 詳細が未送信、simlock cleanup 済み、attestation あり/なしのときの skip 条件 - `hasOemUnlockRestriction` と `isOemUnlockAllowedByCarrier` の判定 - `SimLockProvider` や secret code receiver 経由で観測または遷移できる SIM lock 状態 ただし、これは状況証拠に基づく推定であり、v510 側の該当メソッドと v588 側の修正後メソッドを比較できていない。そのため、「どの入力・端末状態・SIM 状態で carrier restriction が bypass されるか」までは確定していない。 ## 面白い点・調査中に分かったこと - Pixel の stock OobConfig は `oobconfig` という名前だが、APK パスは `OTAConfigNoZeroTouchPrebuilt`、パッケージ名は `com.google.android.apps.work.oobconfig` である。 - 2026-02 から 2026-03 の差分として、release config 上は `OTAConfigNoZeroTouchPrebuilt-v510` から `v588` に更新されている。 - 既知の「OobConfig の通信をユーザーが制限できる」系の話と似て見えるが、少なくとも `allow-in-data-usage-save` と `allow-in-power-save-except-idle` は 2026-02 側にも存在したため、この CVE の直接修正とは判断できなかった。 - `product.img` の raw strings だけでも、OobConfig が SIM lock、carrier restriction、OEM unlock carrier restriction をまとめて扱う privileged app であることは十分確認できる。 - `apkanalyzer` は環境に存在したが Java Runtime が無く、Manifest/DEX 解析には使えなかった。 - `jadx`、`apktool`、`baksmali`、`dexdump`、`debugfs`、`7z`、`ext4fuse` はこの環境では利用できなかった。 - ext4 image 内の APK は断片化しており、`PK` header と EOCD だけを頼りに連続領域を切り出しても `classes.dex` の展開に失敗した。 ## 付帯ファイル 主な付帯ファイルは `artifacts/` に保存した。 - `pixel-bulletin-2026-03-01.html`: Pixel Security Bulletin 2026-03-01 の保存コピー - `NVD-CVE-2026-0118.html`: NVD CVE ページの保存コピー - `google_factory_images.html`: Google factory/OTA image ページの保存コピー - `bp4a260205_payload_head_list.txt`: 2026-02 OTA payload head から得た partition list - `cp1a260305_payload_head_list.txt`: 2026-03 OTA payload head から得た partition list - `cp1a260505a1_payload_head_list.txt`: 2026-05 OTA payload head から得た partition list - `bp4a260205_partial_product_oob_code_strings.txt`: 2026-02 部分 `product.img` から抽出した OobConfig 関連文字列 - `cp1a260305_partial_product_oob_patch_strings.txt`: 2026-03 部分 `product.img` の release config / allowlist 関連文字列 - `cp1a260505a1_product_oob_strings.txt`: 2026-05 `product.img` の OobConfig 関連文字列 - `cp1a260505a1_oob_allowlist_context.txt`: 2026-05 `product.img` の OobConfig allowlist 周辺 - `oobconfig_cp1a260505a1_raw_extent.bin`: 2026-05 `product.img` から切り出した OobConfig APK 周辺 raw extent - `oobconfig_extent_interesting_strings.txt`: raw extent から抽出した重要文字列 - `OTAConfigNoZeroTouchPrebuilt_cp1a260505a1*.apk`: 2026-05 APK 復元試行ファイル。ZIP 構造は一部読めるが DEX 展開に失敗するため、完全な APK としては扱わない。 - `SHA256SUMS`: 付帯ファイルの SHA-256 ## 次にやるなら 完全特定には、脆弱版 `OTAConfigNoZeroTouchPrebuilt-v510` と修正版 `v588` の APK を正しく取り出し、`BusinessLogicController`、`SimLockTask`、`DeviceRestrictionsTask`、`OobConfigUtils`、`SimLockProvider` 周辺の DEX 差分を確認する必要がある。 特に `Unrecognized carrier restriction mode: %d, using DEFAULT_ALLOWED instead.`、`hasOemUnlockRestriction`、`last_applied_simlock_config`、`Sim details are not sent to server yet. Skipping simlock logic.` の周辺メソッドに差分があるかを優先して見るべきである。 cve.md を表示# CVE-2026-0118 - Pixel oobconfig EoP High ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0118 - Component: Pixel - Subcomponent: oobconfig - Reference: A-427469428 * - Type: EoP - Severity: High ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel oobconfig EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 60 | NG | CVE-2026-0119 - Pixel Shannon Baseband EoP High |
060
ng
CVE-2026-0119 - Pixel Shannon Baseband EoP High060-ng-Shannon-usim-MCCMNC-OOB-write-unresolved cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel Shannon Baseband EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容NG理由・判定範囲 `ng` とする。公開情報から脆弱関数・ファイル名・バグ種別は確認できたが、手元の Pixel/Shannon baseband バイナリ差分から修正箇所を関数単位で同定できず、根本原因をソースコードまたは完全な実行条件として検証するところまでは到達していない。 `ok` にしない理由は、対象が closed-source の Shannon Baseband で、手元の February/March modem binary が strip されており、`usim_SendMCCMNCIndMsg` の関数境界、追加された bounds check、または問題の write 先バッファを直接確認できなかったためである。 原因 未確定。OK条件を満たすだけの具体的な根本原因までは判定できていない。 確認元 validated.md の「公開情報で確認できた内容」 / Android bug参照 A-439846057 * / 参照URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01, https://www.cve.org/CVERecord?id=CVE-2026-0119, https://nvd.nist.gov/vuln/detail/CVE-2026-0119 validated.md を表示# CVE-2026-0119 検証結果 ## 判定 `ng` とする。公開情報から脆弱関数・ファイル名・バグ種別は確認できたが、手元の Pixel/Shannon baseband バイナリ差分から修正箇所を関数単位で同定できず、根本原因をソースコードまたは完全な実行条件として検証するところまでは到達していない。 `ok` にしない理由は、対象が closed-source の Shannon Baseband で、手元の February/March modem binary が strip されており、`usim_SendMCCMNCIndMsg` の関数境界、追加された bounds check、または問題の write 先バッファを直接確認できなかったためである。 ## 公開情報で確認できた内容 - Bulletin: Pixel Update Bulletin - March 2026 - CVE: CVE-2026-0119 - Android bug: A-439846057 - Component: Pixel - Subcomponent: Shannon Baseband - Type: EoP - Severity: High - CVE/NVD description: `usim_Registration.c` の `usim_SendMCCMNCIndMsg` に out-of-bounds write があり、memory corruption により physical escalation of privilege につながる可能性がある。 - CWE: CWE-787 Out-of-bounds Write - CVSS v3.1: `AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H` この説明から、攻撃面は Android application processor 側ではなく Shannon modem / baseband 側で、USIM 登録処理が MCC/MNC indication message を生成または送信する経路にあると考えられる。MCC は Mobile Country Code、MNC は Mobile Network Code で、PLMN/registration/SIM state 更新に関わる値である。 ## 手元で確認したバイナリ 既存キャッシュ `../binaries/pixel_shiba_baseband_0122` を使用した。 - February 側: - `../binaries/pixel_shiba_baseband_0122/modem-from-radio-shiba-feb-bp4a.260205.001-g5300i-250909-251024-b-14326967.bin` - SHA-256: `d7fa59a686c7c11a0d359ae4fa0b2efe3e548d1556843949edb9ab060a1f0fb8` - section extract: `feb_sections/MAIN.bin` ほか - March 側: - `../binaries/pixel_shiba_baseband_0122/mar_key_files/images__g5300i-251202-260127-B-14784800__modem.bin` - SHA-256: `7cba729c106e702d284d7f7fa97248615af8ba746ed5762fd8aa5d27c9ad7a5b` - section extract: `mar_sections/MAIN.bin` ほか 保存した付帯ファイル: - `artifacts/binary_inventory.txt` - `artifacts/PUB-A-439846057.json` - `artifacts/feb_usim_mcc_strings.txt` - `artifacts/mar_usim_mcc_strings.txt` - `artifacts/feb_only_usim_mcc_strings.txt` - `artifacts/mar_only_usim_mcc_strings.txt` ## 実施した解析 ### 1. 公開情報確認 Pixel bulletin で CVE-2026-0119 / A-439846057 / Shannon Baseband / EoP / High を確認した。CVE Record と NVD で、`usim_SendMCCMNCIndMsg` in `usim_Registration.c` の out-of-bounds write であることを確認した。 ### 2. バイナリ inventory February と March の modem binary はサイズも hash も異なる。 - February modem: 約 91 MB - March modem: 約 98 MB - `MAIN.bin` も February 約 91 MB、March 約 94 MB - March 側には February では空だった `APM.bin` と `VSS.bin` も存在する このため、単純な byte diff は広範囲になり、1 CVE の修正だけを直接抽出するには不向きだった。 ### 3. 文字列探索 `strings` で `usim_SendMCCMNCIndMsg` と `usim_Registration` を探索したが、関数名・ソースファイル名は見つからなかった。strip 済み、または該当ログが削除されていると考えられる。 一方で、USIM/MCC/MNC/PLMN/registration 関連の文字列は大量に存在した。例: - `USIM` - `SIM_MM_REGISTRATION_REQ` - `MM_SIM_REGISTRATION_CNF` - `Invalid PLMN (MCC: %d %d %d)` - `INSIGHT_SIM_INFO_EVENT_UPDATE_MCC` - `INSIGHT_SIM_INFO_EVENT_UPDATE_MNC` - `mncLen = %d, changed to %d` - `RetRecordOffset(%d) is over the buffSize(%d)` ただし February/March の string 差分は数千行単位で、build 差・配置差・広範なbaseband更新が混ざっている。`usim_SendMCCMNCIndMsg` に固有の新規エラーログや bounds check ログは特定できなかった。 ## 推定できる脆弱性像 公開情報と周辺文字列からの推定に留まるが、脆弱性は以下の形だった可能性が高い。 1. USIM registration 処理で、SIM/USIM から得た MCC/MNC または PLMN 情報を modem 内部の別タスクへ indication message として送る。 2. `usim_SendMCCMNCIndMsg` が MCC/MNC の長さ、桁数、record length、または message payload buffer length を十分に検証せずにコピーする。 3. 異常な SIM/USIM 情報、物理的に制御されたSIM/eSIMプロファイル、またはbasebandが受け取るMCC/MNC関連状態により、固定長バッファを越えて write する。 4. modem memory corruption が起き、baseband 内の権限昇格に繋がる。 CVSS が physical attack vector であることから、リモート基地局由来というより、SIM/USIM/eSIM/物理アクセスに近い入力が想定される。ただし、具体的にどのフィールドが境界外 write を起こすかは今回の差分からは確定できなかった。 ## 未解決点 - `usim_SendMCCMNCIndMsg` のバイナリ上の関数アドレスを特定できていない。 - 修正前後で追加された bounds check を確認できていない。 - write 先バッファの構造、MCC/MNC length の最大値、問題の入力フィールドを特定できていない。 - February/March 差分には他の複数CVEや通常更新が混在しており、CVE-2026-0119 の修正だけを分離できていない。 ## 次に必要な作業 `ok` にするには、以下のいずれかが必要である。 - Shannon baseband の symbol 付きビルド、crash log、または該当関数のソース/疑似コード。 - Ghidra/BinDiff/Diaphora などで February/March `MAIN.bin` の関数マッチングを行い、USIM/MCC/MNC 関連関数のうち bounds check が追加された関数を特定する。 - `usim_SendMCCMNCIndMsg` 近傍を特定できる固有ログ文字列またはxrefを見つけ、修正前後の逆アセンブルを比較する。 ## 参考 - Pixel Update Bulletin - March 2026: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - CVE Record: https://www.cve.org/CVERecord?id=CVE-2026-0119 - NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-0119 cve.md を表示# CVE-2026-0119 - Pixel Shannon Baseband EoP High ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0119 - Component: Pixel - Subcomponent: Shannon Baseband - Reference: A-439846057 * - Type: EoP - Severity: High ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel Shannon Baseband EoP High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 61 | OK | CVE-2026-0108 - Pixel GPU ID High |
061
ok
CVE-2026-0108 - Pixel GPU ID High061-ok-PowerVR-secure-register-leak cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel GPU ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(何が脆弱だったか) PowerVR GPU で secure workload が実行された後、その内部レジスタに残った中間値が non-secure 環境から投入された GPU workload に漏れる問題。 攻撃者は通常アプリ相当の非特権コードから GPU workload を投入し、直前または同時期に secure world / protected path が使った GPU レジスタ内容を non-secure 側の shader/compute workload で観測できる。漏れる対象は GPU の内部 register value で、フレームバッファや通常メモリの単純な読み出しではなく、secure workload の中間計算値が保護境界を越えて残留・露出する形の information disclosure である。 原因(根本原因) 根本原因は、PowerVR DDK の secure/non-secure workload 切り替え時の register protection 設定または register sanitization が不十分だったこと。 本来、secure workload が使った GPU 内部レジスタは、non-secure workload から読めないように保護されるか、コンテキスト切り替え時にクリアされる必要がある。脆弱版ではこの保護が正しく有効化されておらず、secure 側の中間 register value が次の non-secure workload に可観測な状態で残った。CVE の "register protection incorrectly configured" はこの境界設定ミスを指している。 どこから特定したか validated.md の「パッチ解析メモ」 / Android bug参照 A-467269839 * validated.md を表示# CVE-2026-0108 Pixel GPU ID High 検証結果 ## 判定 判定: ok タイトル: PowerVR secure workload register leak CVE-2026-0108 は、Pixel 10 世代の PowerVR/Imagination GPU DDK における情報漏えいと判断した。公開ソース差分は取れなかったが、CVE レコードの「PowerVR GPU の register protection が誤設定」という説明と、Imagination Technologies の DDK advisory PSP-19「secure workloads から non-secure world へ GPU register 値が漏れる」が実質的に一致する。脆弱性が起きる状況は十分具体化できたため ok とした。 ## 何が脆弱だったか PowerVR GPU で secure workload が実行された後、その内部レジスタに残った中間値が non-secure 環境から投入された GPU workload に漏れる問題。 攻撃者は通常アプリ相当の非特権コードから GPU workload を投入し、直前または同時期に secure world / protected path が使った GPU レジスタ内容を non-secure 側の shader/compute workload で観測できる。漏れる対象は GPU の内部 register value で、フレームバッファや通常メモリの単純な読み出しではなく、secure workload の中間計算値が保護境界を越えて残留・露出する形の information disclosure である。 ## 根本原因 根本原因は、PowerVR DDK の secure/non-secure workload 切り替え時の register protection 設定または register sanitization が不十分だったこと。 本来、secure workload が使った GPU 内部レジスタは、non-secure workload から読めないように保護されるか、コンテキスト切り替え時にクリアされる必要がある。脆弱版ではこの保護が正しく有効化されておらず、secure 側の中間 register value が次の non-secure workload に可観測な状態で残った。CVE の "register protection incorrectly configured" はこの境界設定ミスを指している。 ## パッチ解析メモ - Pixel March 2026 bulletin では CVE-2026-0108 / A-467269839 / ID / High / GPU として Pixel 固有欄に掲載されている。 - CVE系DBでは「PowerVR GPU の register protection が incorrectly configured。local information disclosure。追加権限不要、ユーザー操作不要」と説明されている。 - Imagination Technologies の GPU Driver Vulnerabilities ページには、2026年1月の PSP-19 として「GPU Register value contents leaked from secure workloads to non-secure world」が掲載されている。影響範囲は DDK 25.2 RTM まで、解決は情報漏えいを防ぐ protection の導入。 - Google の公開 `kernel/google-modules/gpu` は取得して確認したが、Pixel 10 / PowerVR / RGX / PVRSRV 系の実装は存在せず、Mali kbase の公開ソースのみだった。March 2026 近辺の公開コミットも kernel version / mmap helper 程度で、本CVEに対応する register protection 修正は見つからない。 - したがってパッチ本体は、Pixel OTA/factory image に含まれる proprietary PowerVR DDK の kernel module、user-mode driver、または GPU firmware 側の binary update と見るのが妥当。 ## 面白い点・調査中に分かったこと - Pixel bulletin は CVE-2026-0108 として出しているが、Imagination advisory 側の類似項目 PSP-19 は CVE-2025-25176 として掲載されている。Google が Pixel 側の取り込み・影響範囲に別CVEを割り当てた、または同根のベンダー問題を Pixel 固有CVEとして再分類した可能性がある。 - Pixel 10 系は Tensor G5 で Imagination/PowerVR GPU に移行しており、March 2026 の機能修正にも Pixel 10 GPU/OpenCL 改善が含まれる。性能・機能更新と同じドライバ更新経路で security fix も取り込まれた可能性が高い。 - AOSP/公開Pixel kernelソースだけを見るとこのCVEは見えない。Origin の patch-diffing pipeline 的には、対象バイナリを OTA から抜き、pre/post の proprietary GPU driver/firmware を diff する必要があるタイプ。 ## 取得・作成した付帯ファイル - `artifacts/imagination_gpu_driver_vulnerabilities.html`: Imagination の GPU Driver Vulnerabilities ページ保存。 - `artifacts/imagination_psp19_evidence.txt`: PSP-19 該当行の抽出。 - `artifacts/public_gpu_repo_evidence.txt`: `kernel/google-modules/gpu` の公開ソース確認結果。PowerVR/RGX/PVRSRV 系ファイルなし。 - `artifacts/ota_attempts.txt`: Frankel Pixel 10 の Feb/March OTA URL と Range 取得試行ログ。 - `artifacts/remote_zip_fetch_resolved.py`: DNS不調回避のために作った remote ZIP range fetcher。 ## 未完了・制約 OTA の中央ディレクトリだけを Range 取得して必要パーティションを抜く予定だったが、ローカル環境の通常DNSが `dl.google.com` を解決できず、`curl --resolve` でも接続リセットまたはハングが発生した。March Frankel OTA の HEAD 取得では `content-length: 3349931505` と `accept-ranges: bytes` までは確認できたが、中央ディレクトリ listing と実バイナリ抽出は完了していない。 そのため、今回の ok は「公開ソースでのパッチ行特定」ではなく、「CVE説明とGPUベンダーadvisoryにより脆弱性の発生条件と根本原因を説明できる」という基準での ok である。 cve.md を表示# CVE-2026-0108 - Pixel GPU ID High ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0108 - Component: Pixel - Subcomponent: GPU - Reference: A-467269839 * - Type: ID - Severity: High ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel GPU ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 62 | OK | CVE-2026-0121 - Pixel VPU ID High |
062
ok
CVE-2026-0121 - Pixel VPU ID High062-ok-vpu-dmabuf-iova-uaf-read-infoleak cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel VPU ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(脆弱性の内容) 対象は Pixel VPU kernel driver の `/dev/vpu` ioctl 経路。Project Zero によると `/dev/vpu` は `mediacodec` SELinux context から到達可能で、別の media parsing RCE と組み合わさると 1-click/0-click 攻撃面から到達し得る。 問題の中心は `VPU_IOCX_ALLOC_DMABUF` から到達する `vpu_alloc_dma_buf()` と、`VPU_IOCX_FREE_DMABUF` の競合。`vpu_alloc_dma_buf()` は `dma_info` を確保した後、`alloc_list` に登録し、その後で `dma_info->iova` と `dma_info->fd` を読んで `dmabuf` 側へ反映する。 Project Zero が示した該当パターンは次の通り。 [コードブロック省略] この順序だと、`dma_info` が `alloc_list` に載った瞬間に別 thread の `VPU_IOCX_FREE_DMABUF` が同じ fd の `dma_info` を探して `kfree()` できる。free が `dmabuf->iova = dma_info->iova` / `dmabuf->fd = dma_info->fd` より前に入ると、allocate ioctl 側は解放済み object の field を読む。 読み出された `iova` と `fd` は後で userland に返るため、これは kernel heap の UAF read による情報漏えいになる。Project Zero の PoC は kmalloc-128 slab に `A` を spray し、解放済み `dma_info` が再利用された場合に `0x41414141` が返ることを確認している。 代表的... 原因(根本原因) 根本原因は `dma_info` の publish/free/read の lifetime protocol が壊れていること。 - `dma_info` を `alloc_list` に公開した後も、allocate path が同じ object を参照し続ける。 - `list_lock` は list への追加操作だけを守っており、公開後に続く `dma_info->iova` / `dma_info->fd` の読み出し期間を保護していない。 - free path は list に載った `dma_info` を fd で見つけると、allocate path がまだ初期化/返却処理中かどうかを確認せずに `kfree()` できる。 - `dma_info` に refcount、in-use state、completion、または allocate 完了後に初めて公開する設計がない。 つまり単なる NULL check や bounds check 不足ではなく、共有 list に object を出すタイミングと、その object の所有権・参照寿命を同期していないことが根本原因。 どこから特定したか validated.md の「参照した一次情報」「パッチ解析」 / Android bug参照 A-466090114 * / 参照URL: https://www.originhq.com/research/patch-diffing-pipeline, https://dl.google.com/dl/android/aosp/frankel-ota-bp4a.260205.001-e7319588.zip, https://dl.google.com/dl/android/aosp/frankel-ota-cp1a.260305.018-1c48e8fa.zip validated.md を表示# CVE-2026-0121 Pixel VPU ID High 検証結果 ## 判定 ok。 公開ソースリポジトリ上のパッチ diff や `vpu.ko` の pre/post バイナリ diff は取得できなかったが、Project Zero の公開 Issue Tracker 本文から、脆弱な関数、到達 ioctl、競合する free 経路、UAF read の発生順序、実際に userland へ返る値、PoC 実行対象端末、修正日まで確認できた。脆弱性が起きる状況は完全に説明できるため、フォルダ名変更条件の ok に該当すると判断した。 ## 参照した一次情報 - Pixel Update Bulletin - March 2026: `CVE-2026-0121 / A-466090114 / ID / High / VPU`。2026-03-05 以降の SPL で修正。 - Project Zero issue 465824679: `vpu driver allocation and free of dmabuf and iova can race causing UAF read`。保存先は `artifacts/project_zero_issue_465824679.html` と要約 `artifacts/project_zero_issue_excerpt.txt`。 - Project Zero metadata: CVE `CVE-2026-0121`、VendorID `465823601`、Reported `2025-12-03`、Fixed `2026-03-03`、Security Bulletin date `2026-03-03`、Methodology `Source review`、racy `racy (non-det.)`。 - 指定記事 `https://www.originhq.com/research/patch-diffing-pipeline` は `artifacts/origin_patch_diffing_pipeline.html` に保存し、pre/post artifact を比較する観点の参照として使った。 ## 脆弱性の内容 対象は Pixel VPU kernel driver の `/dev/vpu` ioctl 経路。Project Zero によると `/dev/vpu` は `mediacodec` SELinux context から到達可能で、別の media parsing RCE と組み合わさると 1-click/0-click 攻撃面から到達し得る。 問題の中心は `VPU_IOCX_ALLOC_DMABUF` から到達する `vpu_alloc_dma_buf()` と、`VPU_IOCX_FREE_DMABUF` の競合。`vpu_alloc_dma_buf()` は `dma_info` を確保した後、`alloc_list` に登録し、その後で `dma_info->iova` と `dma_info->fd` を読んで `dmabuf` 側へ反映する。 Project Zero が示した該当パターンは次の通り。 ```c dma_info = kzalloc(sizeof(*dma_info), GFP_KERNEL); ... mutex_lock(list_lock); list_add_tail(&dma_info->list, alloc_list); mutex_unlock(list_lock); dmabuf->iova = dma_info->iova; dmabuf->fd = dma_info->fd; ``` この順序だと、`dma_info` が `alloc_list` に載った瞬間に別 thread の `VPU_IOCX_FREE_DMABUF` が同じ fd の `dma_info` を探して `kfree()` できる。free が `dmabuf->iova = dma_info->iova` / `dmabuf->fd = dma_info->fd` より前に入ると、allocate ioctl 側は解放済み object の field を読む。 読み出された `iova` と `fd` は後で userland に返るため、これは kernel heap の UAF read による情報漏えいになる。Project Zero の PoC は kmalloc-128 slab に `A` を spray し、解放済み `dma_info` が再利用された場合に `0x41414141` が返ることを確認している。 代表的な成功出力: ```text dmabuf info 0 Success 1094795585 41414141 ``` `1094795585` は `0x41414141` の10進表現で、返却された `iova` と `fd` の両方が spray 由来の値になったことを示す。 ## 根本原因 根本原因は `dma_info` の publish/free/read の lifetime protocol が壊れていること。 - `dma_info` を `alloc_list` に公開した後も、allocate path が同じ object を参照し続ける。 - `list_lock` は list への追加操作だけを守っており、公開後に続く `dma_info->iova` / `dma_info->fd` の読み出し期間を保護していない。 - free path は list に載った `dma_info` を fd で見つけると、allocate path がまだ初期化/返却処理中かどうかを確認せずに `kfree()` できる。 - `dma_info` に refcount、in-use state、completion、または allocate 完了後に初めて公開する設計がない。 つまり単なる NULL check や bounds check 不足ではなく、共有 list に object を出すタイミングと、その object の所有権・参照寿命を同期していないことが根本原因。 ## パッチ解析 実際の修正 diff は公開ソースとしては確認できなかった。Pixel VPU driver は AOSP の通常ツリーではなく Pixel device/kernel module 側にあり、手元の共有キャッシュにも Pixel 10 `frankel` の該当 OTA/factory image は存在しなかった。 ただし Project Zero 本文の race window から、修正の本質はかなり狭く特定できる。正しい修正は少なくとも次のいずれか、または組み合わせになる。 - `dma_info->iova` と `dma_info->fd` を `dmabuf` へコピーし終えるまで、`dma_info` を `alloc_list` に公開しない。 - `alloc_list` に載せる前に userland へ返すための値をローカル変数や別 object に退避し、公開後に `dma_info` を読む必要をなくす。 - `VPU_IOCX_FREE_DMABUF` が `dma_info` を free する前に、allocate path の利用が完了したことを refcount/state/lock で保証する。 - list lock の保護範囲を「list 操作」だけでなく「公開された object の lifetime」まで拡張する。ただし長い lock 保持は避け、state machine/refcount の方が自然。 この CVE は ID なので、パッチの目的は control flow hijack 対策よりも、解放済み kmalloc-128 object の内容が `iova` / `fd` として userland にコピーされる情報漏えいを止めること。 ## バイナリ・OTA 確認メモ 共有キャッシュ `/Users/eric/workspace/android/binaries` を確認したが、`frankel` OTA/factory image と抽出済み `vpu.ko` は見つからなかった。既存キャッシュの中心は `shiba` OTA/baseband と AOSP 系ソースで、Pixel 10 VPU の直接 diff には使えない。 PoC 実行対象は `google/frankel/frankel:16/BD3A.251105.010.E1/14337626`。比較対象として検討した URL は `artifacts/ota_urls_considered.txt` に保存した。 - pre: `https://dl.google.com/dl/android/aosp/frankel-ota-bp4a.260205.001-e7319588.zip` - post: `https://dl.google.com/dl/android/aosp/frankel-ota-cp1a.260305.018-1c48e8fa.zip` 今回のジョブでは巨大 OTA の新規取得は行わず、公開 issue の source-level 情報で根本原因を確定した。 ## 付帯ファイル - `artifacts/project_zero_issue_465824679.html`: Project Zero 公開 issue の保存。 - `artifacts/project_zero_issue_excerpt.txt`: issue の重要部分とメタデータの抽出。 - `artifacts/pixel-bulletin-2026-03-01.html`: Pixel March 2026 bulletin の保存。 - `artifacts/origin_patch_diffing_pipeline.html`: 指定された patch diffing pipeline 記事の保存。 - `artifacts/ota_urls_considered.txt`: 検討した Pixel 10 `frankel` pre/post image URL。 - `artifacts/vpu_dmabuf_race_model.py`: publish/free/read race の最小状態モデル。 - `artifacts/vpu_dmabuf_race_model.out`: モデル実行結果。 - `artifacts/SHA256SUMS`: 成果物ハッシュ。 ## 面白い点・調査メモ - Bulletin の bug ID は `A-466090114` だが、Project Zero metadata の VendorID は `465823601`。同じ CVE に対して bulletin 用の Android bug と vendor/PZ 連携 ID が別に見える。 - 056番の VPU CVE-2026-0112 も `/dev/vpu` の race だが、こちらは instance open/close の UAF/double free。CVE-2026-0121 は dmabuf/iova allocation object の UAF read で、同じ VPU driver 内の別 lifetime bug と見た方がよい。 - PoC の成功値 `0x41414141` は典型的な slab spray signal で、クラッシュではなく「返却値が spray に置き換わる」ことで情報漏えいを証明している。 - Project Zero は race を `racy (non-det.)` としており、PoC 成功は不安定。ただし不安定さは exploitability の難しさであって、根本原因の有無とは別問題。 - `alloc_list` への追加直後に lock を外してから `dma_info` を読む、という順序が特に危険。list に載せることは他 thread への公開であり、公開後の field read は lifetime pin なしには安全ではない。 cve.md を表示# CVE-2026-0121 - Pixel VPU ID High ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0121 - Component: Pixel - Subcomponent: VPU - Reference: A-466090114 * - Type: ID - Severity: High ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel VPU ID High vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 63 | OK | CVE-2025-36920 - Pixel pKVM EoP Moderate |
063
ok
CVE-2025-36920 - Pixel pKVM EoP Moderate063-ok-pKVM-hyp_alloc-size-validation-OOB-write cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel pKVM EoP Moderate vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容具体的な脆弱性(何が起きていたか) CVE-2025-36920 は Pixel Update Bulletin March 2026 の Pixel/pKVM 欄に掲載された EoP Moderate で、参照番号は `A-431949921`。NVD の説明では、問題箇所は `arch/arm64/kvm/hyp/nvhe/alloc.c` の `hyp_alloc()`、問題種別は improper input validation による out-of-bounds write とされている。 実際の修正差分では、`hyp_alloc(size_t size)` の冒頭に次の検証が追加されていた。 [コードブロック省略] 修正前は `size_t` の要求サイズを `U32_MAX` 以下に制限せず、`ALIGN(size ?: MIN_ALLOC, MIN_ALLOC)` 以降の allocator ロジックへ渡していた。一方、pKVM hyp allocator のチャンクメタデータは `struct chunk_hdr` 内で `alloc_size` と `mapped_size` を `u32` として保持している。 [コードブロック省略] このため、64-bit `size_t` と 32-bit メタデータの境界が検証されない。巨大な `size` が `chunk_install()` まで到達すると、実際に要求されたサイズと `chunk->alloc_size` に保存されるサイズが食い違い、後続のチャンク配置、再利用、free/merge、マップ量計算が誤ったメタデータを信じる状態になる。結果として、pKVM の hyp allocator が管理領域外に書き込む可能性がある。 根本原因は、外部から到達し得る `hyp_alloc(size_t size)` の入力範囲を、内部メタデータ型で表現できる範囲へ正規化・拒否していなかったこと。修正は、ロック取得前に `size >... 原因(根本原因を含む段落) `ok`: ソースコード差分から、脆弱性の場所、修正内容、根本原因を特定できた。 どこから特定したか validated.md の「パッチ解析」 / Android bug参照 A-431949921 * / 参照URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01, https://nvd.nist.gov/vuln/detail/CVE-2025-36920, https://android.googlesource.com/kernel/common/+/67ac45176dfdefbde966fcb1a4a9360ec1dde1db%5E2..67ac45176dfdefbde966fcb1a4a9360ec1dde1db/arch/arm64/kvm/hyp/nvhe/alloc.c validated.md を表示# CVE-2025-36920 Pixel pKVM EoP Moderate 検証結果
## 判定
`ok`: ソースコード差分から、脆弱性の場所、修正内容、根本原因を特定できた。
フォルダ名は `063-ok-pKVM-hyp_alloc-size-validation-OOB-write` に変更する。
## 何が起きていたか
CVE-2025-36920 は Pixel Update Bulletin March 2026 の Pixel/pKVM 欄に掲載された EoP Moderate で、参照番号は `A-431949921`。NVD の説明では、問題箇所は `arch/arm64/kvm/hyp/nvhe/alloc.c` の `hyp_alloc()`、問題種別は improper input validation による out-of-bounds write とされている。
実際の修正差分では、`hyp_alloc(size_t size)` の冒頭に次の検証が追加されていた。
```c
/* constrained by chunk_hdr *_size types */
if (size > U32_MAX) {
ret = -E2BIG;
goto end_unlocked;
}
```
修正前は `size_t` の要求サイズを `U32_MAX` 以下に制限せず、`ALIGN(size ?: MIN_ALLOC, MIN_ALLOC)` 以降の allocator ロジックへ渡していた。一方、pKVM hyp allocator のチャンクメタデータは `struct chunk_hdr` 内で `alloc_size` と `mapped_size` を `u32` として保持している。
```c
struct chunk_hdr {
u32 alloc_size;
u32 mapped_size;
struct list_head node;
u32 hash;
char data __aligned(8);
};
```
このため、64-bit `size_t` と 32-bit メタデータの境界が検証されない。巨大な `size` が `chunk_install()` まで到達すると、実際に要求されたサイズと `chunk->alloc_size` に保存されるサイズが食い違い、後続のチャンク配置、再利用、free/merge、マップ量計算が誤ったメタデータを信じる状態になる。結果として、pKVM の hyp allocator が管理領域外に書き込む可能性がある。
根本原因は、外部から到達し得る `hyp_alloc(size_t size)` の入力範囲を、内部メタデータ型で表現できる範囲へ正規化・拒否していなかったこと。修正は、ロック取得前に `size > U32_MAX` を `-E2BIG` で拒否し、以降の allocator 状態を一切変更しない形になっている。
## パッチ解析
対象差分は Android common kernel Gitiles の `67ac45176dfdefbde966fcb1a4a9360ec1dde1db^2..67ac45176dfdefbde966fcb1a4a9360ec1dde1db` から抽出した。`alloc.c` だけを見ると、実質的な修正は `hyp_alloc()` 冒頭の `U32_MAX` チェック追加である。
興味深い点として、Android common 6.12 の `android16-6.12-2025-12` と `android16-6.12-2026-03` ではこのファイル差分は空だった。つまり修正自体は common kernel には March 2026 より前に入っており、Pixel Bulletin では後から CVE として公開された形に見える。
## 攻撃面と影響
CVE/NVD の評価は local、権限不要、UI不要で、技術的影響は高い。Pixel Bulletin 上の severity は Moderate だが、NVD 側の CVSS v3.1 は `AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H` の 8.4 High として扱われている。
脆弱なオブジェクトは通常のユーザー空間ヒープではなく、pKVM の EL2/hyp allocator のチャンク管理情報である。したがって、単純なクラッシュよりも、pKVM 内部メタデータ破壊からホスト/ゲスト分離境界に影響する EoP として扱われたと考えられる。
## 調査中メモ
- Pixel 固有ファームウェアのバイナリ解析は不要だった。CVE 本文が AOSP common kernel の具体的なソースファイルと関数を示しており、対応するパッチが Gitiles から取得できた。
- `hyp_alloc_init(size_t size)` には既に `size > U32_MAX` の拒否があるが、個々の `hyp_alloc(size)` に同じ制約がなかった。allocator 全体サイズは制限していたが、各 allocation request の型境界を守っていなかった点が問題だった。
- パッチの `end_unlocked` ラベル追加は、エラー時に `hyp_spin_unlock()` へ流れないためのもの。サイズ拒否はロック取得前に行うため、この制御フロー変更も必要。
- 2026-03 の common 6.12 と 2025-12 の common 6.12 が同一だったため、月次差分だけを見ると見逃す。CVE公開月ではなく、関数名と古い親との差分を追う必要があった。
## 保存した付帯ファイル
- `artifacts/patch_67ac45176dfd_alloc.diff`
- `artifacts/alloc_before_67ac_parent2.c`
- `artifacts/alloc_android16-6.12-2026-03.c`
- `artifacts/nvd-CVE-2025-36920.json`
- `artifacts/pixel-bulletin-2026-03-01.html`
- `artifacts/android-googlesource-67ac-diff.html`
- `artifacts/analysis_notes.md`
- `artifacts/SHA256SUMS`
## 参照URL
- Pixel Update Bulletin March 2026: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01
- NVD CVE-2025-36920: https://nvd.nist.gov/vuln/detail/CVE-2025-36920
- Android common kernel diff: https://android.googlesource.com/kernel/common/+/67ac45176dfdefbde966fcb1a4a9360ec1dde1db%5E2..67ac45176dfdefbde966fcb1a4a9360ec1dde1db/arch/arm64/kvm/hyp/nvhe/alloc.c
cve.md を表示# CVE-2025-36920 - Pixel pKVM EoP Moderate ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2025-36920 - Component: Pixel - Subcomponent: pKVM - Reference: A-431949921 * - Type: EoP - Severity: Moderate ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel pKVM EoP Moderate vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
| 64 | NG | CVE-2026-0123 - Pixel AOC EoP Moderate |
064
ng
CVE-2026-0123 - Pixel AOC EoP Moderate064-ng-AOC-Weaver-slot-migration-unresolved cve.md の Android / Pixel 脆弱性情報
cve.md summary Pixel AOC EoP Moderate vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. 判定内容NG理由・判定範囲 NG。具体的な関数・入力・パッチ箇所を一意に特定できていない。 原因 未確定。OK条件を満たすだけの具体的な根本原因までは判定できていない。 確認元 validated.md の「公開情報」 / Android bug参照 A-430693465 * / 参照URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01, https://developers.google.com/android/images, https://source.android.com/docs/security/features/authentication/weaver validated.md を表示# CVE-2026-0123 Pixel AOC EoP Moderate 検証メモ ## 結論 判定: **ng** CVE-2026-0123 は 2026-03 Pixel Update Bulletin の Pixel / AOC / EoP / Moderate として公開されており、参照バグは非公開の `A-430693465 *` だった。公開ソース差分は無く、Pixel factory image から取得できるAOC/EC系ファームウェア差分を解析した。 Pixel 8 (`shiba`) の 2026-02 build `BP4A.260205.001` と 2026-03 build `CP1A.260305.018` を比較すると、factory ZIP内の `d3m2.ec.bin` / `proto11.ec.bin` / `evt.ec.bin` が更新されていた。追加文字列から、修正の中心は `WeaverRust` の永続スロットデータ形式で、`app/weaver_rs/src/weaver/slots.rs`、`read_slice_at`、`crypto_sha256_digest somehow failed:`、`Migrating slot $ from V3 to V4`、`Migrating slot $ from V4 to V5` が新規に入っていた。 したがって、最も可能性が高い脆弱性は **AOC上のWeaver TAが管理するロック画面資格情報スロットの永続データ検証/移行不備**。旧V3スロット形式では、履歴/スロットデータの一部について完全性検証または読み出し境界検証が不足し、攻撃者がAOC/Weaverの永続領域を不整合な状態にできた場合、認証失敗回数、履歴、またはslot valueの扱いを崩してロック解除/認証レート制限を弱めるEoPにつながった可能性が高い。 ただし、復号済みソースコードまたは関数単位の確定diffまでは得られていない。要件上、`ok` にするには「ソースコード」または「脆弱性が起きる状況を完璧に説明できる」必要があるため、今回は `ng` とする。 ## 公開情報 - Bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - 該当行: `CVE-2026-0123 A-430693465 * EoP Moderate AOC` - `*` 付きAndroid bugは非公開で、GoogleのFAQでは通常Pixel用バイナリドライバに修正が含まれると説明されている。 - Factory image配布元: https://developers.google.com/android/images - Weaver概要: https://source.android.com/docs/security/features/authentication/weaver - Weaverは固定数の永続slotにkey/valueを保存し、正しいkeyが与えられたときのみvalueを返す。 - Weaver TAはLSKF検証とレート制限を担う。 ## 解析したファイル Factory image: - `shiba-bp4a.260205.001-factory-35b8480d.zip` - `shiba-cp1a.260305.018-factory-e3607b56.zip` 保存場所: - `../binaries/pixel_aoc/064/shiba-bp4a-factory-small/` - `../binaries/pixel_aoc/064/shiba-cp1a-factory-small/` 対象フォルダ内の付帯ファイル: - `ec_diff_summary.txt`: ECファームのSHA-256と差分バイト数 - `ec-string-diff-interesting.txt`: 追加/削除された興味深い文字列 - `d3m2-weaver-strings.txt`: Weaver関連文字列とオフセット - `range_extract_payload_partition.py`: OTA payloadをHTTP Rangeで部分取得する調査用スクリプト - `ota_urls.txt`: 試したOTA URL ## 差分観察 `shiba` のfull OTA `payload.bin` には `aoc` partitionは存在しなかった。通常のA/B payloadではなく、factory ZIP直下のEC/bootloader系ファイルにAOC相当の更新が含まれると判断した。 ECファーム3種はいずれも1MiBで、Feb→Marでハッシュが変化した。 - `d3m2.ec.bin`: 486,026 bytes changed - `proto11.ec.bin`: 486,025 bytes changed - `evt.ec.bin`: 486,025 bytes changed 3ファイルとも完全一致するprefixは `0x20004`、完全一致するsuffixは `0x20d0c`。つまり中間のRW payload領域が差し替わり、RO/末尾メタデータらしき領域は多くが共通だった。 ## 重要な追加文字列 Mar版で追加: ```text app/weaver_rs/src/weaver/slots.rs app/weaver_rs/src/weaver/slots/history.rs crypto_sha256_digest somehow failed: assertion failed: false Migrating slot $ from V3 to V4 Migrating slot $ from V4 to V5 read_slice_at ``` Feb版には `app/weaver_rs/src/weaver/slots.rs`、`crypto_sha256_digest somehow failed:`、`Migrating slot $ from V3 to V4` が無く、Weaver slot migrationの追加が明確に見える。 ## 根本原因の推定 根本原因候補: - 旧Weaver slot V3形式では、slot履歴またはslot recordの読み出し時に、永続ストレージ上の構造を十分に検証していなかった。 - Mar版では `read_slice_at` と `crypto_sha256_digest` が追加され、slotデータの部分読み出しとハッシュ計算を伴うV4/V5移行が導入された。 - これは、古い形式のslot/historyを新形式へ移行し、改ざん・破損・境界外参照を検出するための修正に見える。 想定される脆弱性の状況: 1. 攻撃者が通常OS側から直接Weaver TAを破るのではなく、AOC/Weaver永続領域の古いslot recordまたはhistory recordを不正/古い形式にする。 2. 旧ファームはslot履歴またはrecordの完全性・境界を十分に検証せず、認証失敗履歴、レート制限状態、またはslot value復元を誤る。 3. 結果として、ロック画面資格情報の照合に関わるWeaverの保護が弱まり、認証制御の迂回またはレート制限回避につながる。 ## 未確定点 - `A-430693465` は非公開で、CVEの技術説明は公開されていない。 - `nugget`/AOCファームのソースコードは見つからなかった。 - ECファームの関数単位diffや復号済み制御フローは未取得。 - V3/V4/V5 slot構造の具体的なフィールド差分、攻撃者がどの経路で永続slotを不整合にするかは確定できていない。 ## 面白い点 - AOCとして公開されているが、factory image上では `*.ec.bin` に `nugget_v0.0...`、`WeaverRust`、`GscFaceAuth`、`Keymint` などが含まれていた。AOC/EC/GSC系の境界が製品内部ではかなり密接に見える。 - 同じ1MiB ECファーム内に、同一の文字列群が2回現れる。RO/RWまたはA/B相当の領域を含む構造の可能性がある。 - Feb→Marの変更は単一関数パッチではなく、`ab13707562-865dc30-r` から `ab14367875-bf8c16a-r` へのファーム更新で、ビルド日時も 2025-06-27 から 2025-10-31 に進んでいる。CVE修正以外の変更も混在している可能性が高い。 cve.md を表示# CVE-2026-0123 - Pixel AOC EoP Moderate ## Advisory - Program: Pixel Security Reward Program / Android and Google Devices Security Reward Program - Bulletin: Pixel Update Bulletin - March 2026 - Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-03-01 - Security patch level: 2026-03-05 ## CVE details - CVE: CVE-2026-0123 - Component: Pixel - Subcomponent: AOC - Reference: A-430693465 * - Type: EoP - Severity: Moderate ## Scope decision - Bounty target: yes - Reason: Included: listed in the Pixel bulletin Pixel component section for supported Google devices. Android bulletin vendor/OEM sections are not included here. ## Summary Pixel AOC EoP Moderate vulnerability from the March 2026 advisory. Use the linked advisory and Android bug reference as the starting point for patch analysis and reproduction work. | ||
該当する項目がありません