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

001 OK

CVE-2025-65018

001-ok-libpng-png_combine_row-overflow

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityCritical
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-463998243
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-65018 is listed in the Android Security Bulletin as a Critical severity EoP issue in Framework.

特定した具体的な脆弱性

特定できた。CVE-2025-65018 は Android Framework 枠で告知されているが、修正対象の実体は platform/external/libpng の simplified read API である。脆弱性は、16-bit Adam7 interlace PNG を png_image_finish_read() で 8-bit 出力形式、例: PNG_FORMAT_RGBA、へ変換して読むときに、png_combine_row() が変換前の IHDR bit depth に基づく row 幅でユーザー出力バッファへ書き、PNG_IMAGE_SIZE(image) で確保された 8-bit 出力サイズを超えるヒープバッファオーバーフローである。

Android の分類は Framework / EoP / Critical、参照 ID は A-463998243。OSV では GHSA-7wv6-48j4-hj3g と対応し、詳細は「heap buffer overflow による remote code execution / remote escalation of privilege の可能性」とされている。

原因

根本原因は simplified API の公開契約と interlace 内部処理の不整合である。

PNG_IMAGE_SIZE(image) は要求された出力形式を基準にバッファサイズを返す。通常これは png_image_finish_read() の出力サイズと一致するべきだが、16-bit interlaced PNG の 16-to-8 変換では、Adam7 pass の合成処理が bit-depth 変換完了前に走る。そこで png_combine_row() は IHDR の 16-bit depth を基準に destination row へ書くため、destination がすでに最終 8-bit 出力バッファである場合に境界外書き込みになる。

非 interlace PNG は同じ interlace 合成経路を通らないため、この特定の overflow は起きない。これが初期修正の「全 16-to-8 変換拒否」が過剰で、最終修正が interlace の場合だけ中間 row バッファを使う設計になった理由である。

どこから特定したか

パッチ解析: Android Bulletin の対象行には libpng の 6 コミットが並ぶ。うち Bug: 463998243 として直接この CVE を直すのは次の 2 つ。

保存した付帯ファイル: ・2cafeca8_rearchitect.diff: Android 最終修正 diff。
・960064f_initial_fix.diff: Android 初期修正 diff。
・upstream_218612dd_final.patch: upstream 最終修正 patch。
・upstream_16b5e382_initial.patch: upstream 初期修正 patch。
・pngread_vulnerable_parent_2113a245.c: 対象修正直前の pngread.c。
・pngread_after_initial_960064f.c: 初期修正後の pngread.c。
・pngread_after_final_2cafeca8.c: 最終修正後の pngread.…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://osv.dev/vulnerability/ASB-A-463998243 / https://github.com/pnggroup/libpng/security/advisories/GHSA-7wv6-48j4-hj3g / https://android.googlesource.com/platform/external/libpng/+/960064fdb5f41cc085ab81cd97443dd51…

validated.md を表示
# CVE-2025-65018 検証メモ

## 結論

特定できた。CVE-2025-65018 は Android Framework 枠で告知されているが、修正対象の実体は `platform/external/libpng` の simplified read API である。脆弱性は、16-bit Adam7 interlace PNG を `png_image_finish_read()` で 8-bit 出力形式、例: `PNG_FORMAT_RGBA`、へ変換して読むときに、`png_combine_row()` が変換前の IHDR bit depth に基づく row 幅でユーザー出力バッファへ書き、`PNG_IMAGE_SIZE(image)` で確保された 8-bit 出力サイズを超えるヒープバッファオーバーフローである。

Android の分類は Framework / EoP / Critical、参照 ID は `A-463998243`。OSV では `GHSA-7wv6-48j4-hj3g` と対応し、詳細は「heap buffer overflow による remote code execution / remote escalation of privilege の可能性」とされている。

## 対象情報

- CVE: `CVE-2025-65018`
- Android bug/reference: `A-463998243`
- Component: `Framework`
- Type: `EoP`
- Severity: `Critical`
- Updated AOSP versions: `14, 15, 16, 16-qpr2`
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Android OSV: https://osv.dev/vulnerability/ASB-A-463998243
- Upstream advisory: https://github.com/pnggroup/libpng/security/advisories/GHSA-7wv6-48j4-hj3g

## パッチ解析

Android Bulletin の対象行には libpng の 6 コミットが並ぶ。うち `Bug: 463998243` として直接この CVE を直すのは次の 2 つ。

- `960064fdb5f41cc085ab81cd97443dd51736c4aa`
  - URL: https://android.googlesource.com/platform/external/libpng/+/960064fdb5f41cc085ab81cd97443dd51736c4aa
  - upstream 相当: `16b5e3823918840aae65c0a6da57c78a5a496a4d`
  - 内容: `png_image_finish_read()` の先頭付近で、IHDR が 16-bit なのに要求出力が 8-bit、またはその逆、という bit-depth mismatch を拒否する暫定修正。
  - 問題: interlace でない 16-to-8 変換まで拒否し、simplified API の正当なユースケースを壊す。

- `2cafeca8cbf2fa636b658b7bef0aebe900447f40`
  - URL: https://android.googlesource.com/platform/external/libpng/+/2cafeca8cbf2fa636b658b7bef0aebe900447f40
  - upstream 相当: `218612ddd6b17944e21eda56caf8b4bf7779d1ea`
  - 内容: 暫定修正を削除し、16-to-8 変換かつ interlace の場合のみ `do_local_scale` を立て、`png_image_read_direct_scaled()` で中間 row バッファに `png_read_row()` してからユーザーバッファへ `memcpy()` する。

Bulletin 同行の残り 4 コミットは同じ libpng 更新束に含まれる別脆弱性/別 bug の修正だった。

- `2113a245b832fe86bb2c61a99778d8e70149bd3b`: `Bug: 463995203`, `png_init_read_transformations`, CVE-2025-64720 側。
- `93147074acc1bebdda8316d9a891a5d4d122ca80`: `Bug: 463980379`, `png_do_quantize`。
- `3f148ea688b5dc631c51699947ce5dd3654a5eb0`: `Bug: 463980379`, `png_set_quantize` memory leak/refactor。
- `2ccc385b188d5f4856c1ea441db21a06eb420534`: `Bug: 463990846`, `png_write_image_8bit`。

## 脆弱条件

攻撃に必要な条件は以下。

- アプリ/Framework 側が libpng simplified API、特に `png_image_begin_read_*()` と `png_image_finish_read()` を使う。
- 入力 PNG の IHDR が 16-bit color depth で、interlace method が Adam7。
- 呼び出し側が `image.format = PNG_FORMAT_RGBA` など、`PNG_FORMAT_FLAG_LINEAR` を含まない 8-bit 出力を要求する。
- 呼び出し側が documented pattern 通り `PNG_IMAGE_SIZE(image)` で出力バッファを確保し、そのバッファを `png_image_finish_read()` に渡す。

`png.h` では `PNG_FORMAT_FLAG_LINEAR` がない形式の component size は 1 byte、ある形式は 2 bytes と定義される。`PNG_IMAGE_SIZE(image)` は `PNG_IMAGE_PIXEL_COMPONENT_SIZE(image.format) * image.height * PNG_IMAGE_ROW_STRIDE(image)` で計算されるため、`PNG_FORMAT_RGBA` なら 8-bit RGBA、つまり 4 bytes/pixel 分しか確保されない。

一方、脆弱版 `pngread.c` は bit-depth 変更を検出すると 8-bit 出力側で `png_set_scale_16(png_ptr)` を設定するだけだった。そのまま通常の direct read path に入り、interlace の pass 処理中に `png_read_row(png_ptr, row, NULL)` の `row` がユーザー出力バッファを直接指す。interlace 合成では内部の `png_combine_row()` が変換前の IHDR 16-bit row として書くタイミングがあり、8-bit 出力サイズのバッファに 16-bit 幅のデータを書いてしまう。

例として 32x32, 16-bit RGB, Adam7 interlace PNG を 8-bit RGBA で読む場合:

- 呼び出し側の想定出力: 32 * 32 * 4 bytes = 4096 bytes
- interlace 合成時の変換前 row: 32 * 32 * 3 channels * 2 bytes = 6144 bytes
- 差分: 2048 bytes の過剰書き込み

256x256 なら差分は 131072 bytes になり、画像サイズに比例して増える。

## 根本原因

根本原因は simplified API の公開契約と interlace 内部処理の不整合である。

`PNG_IMAGE_SIZE(image)` は要求された出力形式を基準にバッファサイズを返す。通常これは `png_image_finish_read()` の出力サイズと一致するべきだが、16-bit interlaced PNG の 16-to-8 変換では、Adam7 pass の合成処理が bit-depth 変換完了前に走る。そこで `png_combine_row()` は IHDR の 16-bit depth を基準に destination row へ書くため、destination がすでに最終 8-bit 出力バッファである場合に境界外書き込みになる。

非 interlace PNG は同じ interlace 合成経路を通らないため、この特定の overflow は起きない。これが初期修正の「全 16-to-8 変換拒否」が過剰で、最終修正が interlace の場合だけ中間 row バッファを使う設計になった理由である。

## 修正内容

最終修正 `2cafeca8...` は以下を追加した。

- `png_image_read_direct()` に `do_local_scale` を追加。
- bit-depth change で 8-bit 出力を選び、かつ `png_ptr->interlaced != 0` のとき `do_local_scale = 1`。
- `do_local_scale` のとき、`png_get_rowbytes(png_ptr, info_ptr)` で中間 row バッファを確保。
- 新規 `png_image_read_direct_scaled()` で各 Adam7 pass/row を中間バッファへ `png_read_row()` し、変換済みの `display->row_bytes` だけユーザー出力バッファへコピー。
- 初期修正の bit-depth mismatch 拒否ロジックを削除し、非 interlace の正当な 16-to-8 変換は維持。

重要な点は、危険な `png_read_row()` の destination をユーザーが `PNG_IMAGE_SIZE(image)` で確保した最終出力バッファから、libpng 内部が十分な row サイズで確保した中間バッファに切り替えたこと。これにより `png_combine_row()` が IHDR 16-bit 幅で一時的に書いても、ユーザー出力バッファは破壊されない。

## 検証で見つかったこと

- Android Bulletin では Framework 扱いだが、ソースレベルの修正は `external/libpng/pngread.c` で、AOSP Framework Java/Kotlin の権限チェック欠陥ではない。
- Bulletin の `CVE-2025-65018` 行に 6 コミットがあるため、単純に全リンクを同一 CVE の直接修正と見ると誤る。`Bug: 463998243` は `960064f...` と `2cafeca8...` の 2 つで、他は同じ libpng 更新束の別 bug。
- OSV の `ASB-A-463998243` は Android 14/15/16/16-qpr2/17-next それぞれの backport commit を列挙している。`osv-fixes-summary.txt` に保存した。
- upstream advisory では影響範囲が libpng `>= 1.6.0, < 1.6.51`、patched version が `1.6.51` とされている。
- `png_safe_execute()` は libpng の `png_error()`/longjmp を安全に扱うための枠であり、境界外 `memcpy`/row write そのものを事前に防ぐものではない。今回のように内部 row サイズ計算が契約とずれる場合は、safe wrapper だけでは防げない。

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

- `2cafeca8_rearchitect.diff`: Android 最終修正 diff。
- `960064f_initial_fix.diff`: Android 初期修正 diff。
- `upstream_218612dd_final.patch`: upstream 最終修正 patch。
- `upstream_16b5e382_initial.patch`: upstream 初期修正 patch。
- `pngread_vulnerable_parent_2113a245.c`: 対象修正直前の `pngread.c`。
- `pngread_after_initial_960064f.c`: 初期修正後の `pngread.c`。
- `pngread_after_final_2cafeca8.c`: 最終修正後の `pngread.c`。
- `png_h_android16_r2.txt`: `PNG_FORMAT_*` / `PNG_IMAGE_SIZE` マクロ確認用。
- `osv-ASB-A-463998243.json`: Android OSV raw JSON。
- `osv-fixes-summary.txt`: OSV から抽出した aliases/details/branch fixes。

## 判定

`ok`。公開ソースコード差分、修正前後の `pngread.c`、upstream advisory、Android OSV の対応を照合し、脆弱性が起きる入力条件、オーバーフローの理由、根本原因、修正方式を説明できる。
002 OK

CVE-2025-64720

002-ok-libpng-palette-alpha-oob-read-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeDoS
SeverityCritical
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-463995203
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-64720 is listed in the Android Security Bulletin as a Critical severity DoS issue in Framework.

特定した具体的な脆弱性

このCVEは特定できた。Android bulletin上は Framework / DoS / Critical として掲載されているが、実際の修正対象はAOSP同梱の platform/external/libpng で、上流libpngの GHSA-hfc7-ph9c-wcww と同一の問題である。

脆弱性は、パレットPNGの透明度処理で PNG_FLAG_OPTIMIZE_ALPHA が有効な場合に、png_init_read_transformations() が本来「premultiplyのみ」にすべき色成分へ背景合成まで先に適用していたことが原因。後段の png_image_read_composite() は入力が premultiplied alpha の不変条件を満たす前提で PNG_sRGB_FROM_LINEAR() を呼ぶため、条件次第で png_sRGB_base[512] / png_sRGB_delta[512] 以降を読む global out-of-bounds read になる。Android上では画像デコード経路のクラッシュ、すなわちローカルDoSとして扱われている。

原因

根本原因は、PNG_FLAG_OPTIMIZE_ALPHA の意味と png_init_read_transformations() のパレット前処理が矛盾していたこと。

PNG_ALPHA_OPTIMIZED は、非不透明ピクセルのcomponentを「背景未合成のpremultiplied alpha」として後段へ渡すモードである。しかし修正前のパレット処理は、optimized modeでも png_composite() により背景色を混ぜていた。背景色が明るい場合、透明度が低いpalette entryでもcomponentがalphaより大きくなり、後段の png_image_read_composite() の前提を壊す。

その結果、PNG_sRGB_FROM_LINEAR(linear) の添字 (linear)>>15 が512以上になり得る。pngpriv.h では png_sRGB_base と png_sRGB_delta はどちらも512要素なので、添字512以上は範囲外読み取りになる。

どこから特定したか

参照した公開情報: ・Android Security Bulletin June 2026: https://source.android.com/docs/security/bulletin/2026/2026-06-01
・Android OSV: https://api.osv.dev/v1/vulns/ASB-A-463995203
・OSV HTML: https://osv.dev/vulnerability/ASB-A-463995203
・GitHub advisory: https://github.com/pnggroup/libpng/security/advisories/GHSA-hfc7-ph9c-wcww
・AOSP修正commit: https://android.googlesource.co…

保存した付帯ファイル: ・artifacts/2113a245.diff: AOSP commit 2113a245... のdiff。
・artifacts/2113a245.commit.json: Gitiles commit metadata。
・artifacts/ASB-A-463995203.osv.json: Android OSV JSON。
・artifacts/pngrtran.before.c: 親commit 93147074... の修正前 pngrtran.c。
・artifacts/pngrtran.after.c: 修正commit後の pngrtran.c。
・artifacts/pngread.before.c: 修正前の png_image_read_composite() 確認用。
・art…

URL: https://…

validated.md を表示
# CVE-2025-64720 検証結果

## 結論

このCVEは特定できた。Android bulletin上は Framework / DoS / Critical として掲載されているが、実際の修正対象はAOSP同梱の `platform/external/libpng` で、上流libpngの `GHSA-hfc7-ph9c-wcww` と同一の問題である。

脆弱性は、パレットPNGの透明度処理で `PNG_FLAG_OPTIMIZE_ALPHA` が有効な場合に、`png_init_read_transformations()` が本来「premultiplyのみ」にすべき色成分へ背景合成まで先に適用していたことが原因。後段の `png_image_read_composite()` は入力が premultiplied alpha の不変条件を満たす前提で `PNG_sRGB_FROM_LINEAR()` を呼ぶため、条件次第で `png_sRGB_base[512]` / `png_sRGB_delta[512]` 以降を読む global out-of-bounds read になる。Android上では画像デコード経路のクラッシュ、すなわちローカルDoSとして扱われている。

## cve.mdから確認した情報

- CVE: `CVE-2025-64720`
- Android bug / 参照ID: `A-463995203`
- Component: `Framework`
- Type: `DoS`
- Severity: `Critical`
- Updated AOSP versions: `14, 15, 16, 16-qpr2`
- Bulletin URL: `https://source.android.com/docs/security/bulletin/2026/2026-06-01`

## 参照した公開情報

- Android Security Bulletin June 2026: `https://source.android.com/docs/security/bulletin/2026/2026-06-01`
- Android OSV: `https://api.osv.dev/v1/vulns/ASB-A-463995203`
- OSV HTML: `https://osv.dev/vulnerability/ASB-A-463995203`
- GitHub advisory: `https://github.com/pnggroup/libpng/security/advisories/GHSA-hfc7-ph9c-wcww`
- AOSP修正commit: `https://android.googlesource.com/platform/external/libpng/+/2113a245b832fe86bb2c61a99778d8e70149bd3b`
- AOSP diff: `https://android.googlesource.com/platform/external/libpng/+/2113a245b832fe86bb2c61a99778d8e70149bd3b^!/`

## パッチ

対象commit:

```text
2113a245b832fe86bb2c61a99778d8e70149bd3b
Fix a buffer overflow in `png_init_read_transformations`
Bug: 463995203
```

変更ファイルは `pngrtran.c` のみ。修正前は、パレットエントリに `tRNS` 由来の透明度があり `0 < alpha < 255` のとき、常に次の背景合成を行っていた。

```c
v = png_ptr->gamma_to_1[palette[i].red];
png_composite(w, v, png_ptr->trans_alpha[i], back_1.red);
palette[i].red = png_ptr->gamma_from_1[w];
```

修正後は `PNG_FLAG_OPTIMIZE_ALPHA` が立っている場合だけ分岐し、背景合成ではなく premultiply のみに変更された。

```c
if ((png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0) {
    component = png_ptr->gamma_to_1[palette[i].red];
    component = (component * png_ptr->trans_alpha[i] + 128) / 255;
    palette[i].red = png_ptr->gamma_from_1[component];
} else {
    png_composite(...);
}
```

## 脆弱性の成立条件

攻撃者が用意する入力は、少なくとも次の条件を満たすPNG。

- palette image、つまり PNG color type 3。
- `tRNS` chunkにより一部のpalette entryが `0 < alpha < 255` になる。
- 呼び出し側がlibpng simplified APIの `png_image_finish_read()` 系を使い、alpha除去や行上の背景合成が必要な8-bit sRGB出力経路に入る。
- 内部で `PNG_ALPHA_OPTIMIZED` / `PNG_FLAG_OPTIMIZE_ALPHA` が有効になり、`png_image_read_composite()` が実行される。

`png_image_read_composite()` は `inrow[c]` を「alphaでpremultiply済みのlinear 8-bit component」として扱う。`0 < alpha < 255` の場合、次の計算をしてから `PNG_sRGB_FROM_LINEAR(component)` を呼ぶ。

```c
component *= 257*255;
component += (255-alpha)*png_sRGB_table[outrow[c]];
component = PNG_sRGB_FROM_LINEAR(component);
```

ここで期待される不変条件は `inrow[c] <= alpha`。これが守られていれば、最大値は `alpha*65535 + (255-alpha)*65535 = 255*65535` に収まり、`PNG_sRGB_FROM_LINEAR()` の想定範囲内になる。

## 根本原因

根本原因は、`PNG_FLAG_OPTIMIZE_ALPHA` の意味と `png_init_read_transformations()` のパレット前処理が矛盾していたこと。

`PNG_ALPHA_OPTIMIZED` は、非不透明ピクセルのcomponentを「背景未合成のpremultiplied alpha」として後段へ渡すモードである。しかし修正前のパレット処理は、optimized modeでも `png_composite()` により背景色を混ぜていた。背景色が明るい場合、透明度が低いpalette entryでもcomponentがalphaより大きくなり、後段の `png_image_read_composite()` の前提を壊す。

その結果、`PNG_sRGB_FROM_LINEAR(linear)` の添字 `(linear)>>15` が512以上になり得る。`pngpriv.h` では `png_sRGB_base` と `png_sRGB_delta` はどちらも512要素なので、添字512以上は範囲外読み取りになる。

算術例は `artifacts/arithmetic-notes.md` に残した。例えば `alpha=253` で修正前の背景合成により `inrow[c] ~= 255` になると、後段で `16842495 >> 15 = 513` となり、512要素テーブルを越える。

## 影響

- 実体は out-of-bounds read / global-buffer-overflow。
- 上流advisoryでは情報漏えいとクラッシュの両方が説明されている。
- Android ASB / OSVでは「local denial of service」「追加権限不要」「ユーザー操作不要」と記載されている。
- Android Frameworkとして分類されているのは、画像処理がFramework/API面で露出するためと思われるが、パッチ自体はFramework Java/C++ではなく `external/libpng`。

## 調査中に分かったこと

- bulletinの表では `CVE-2025-65018` と `CVE-2025-64720` が同じ番号リンク群を共有しているが、commit messageの `Bug:` を見ると `A-463995203` に対応する本件の実体は `2113a245...`。
- 同じlibpng更新セットには別CVE用の `png_image_finish_read` 16-to-8 bit変換overflow修正も含まれる。`Bug: 463998243` は別件なので混同しない。
- ローカルにAOSP checkoutは見当たらなかったため、Gitilesから対象commit、diff、修正前後ソースを取得して解析した。Pixel固有バイナリ解析は不要だった。

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

- `artifacts/2113a245.diff`: AOSP commit `2113a245...` のdiff。
- `artifacts/2113a245.commit.json`: Gitiles commit metadata。
- `artifacts/ASB-A-463995203.osv.json`: Android OSV JSON。
- `artifacts/pngrtran.before.c`: 親commit `93147074...` の修正前 `pngrtran.c`。
- `artifacts/pngrtran.after.c`: 修正commit後の `pngrtran.c`。
- `artifacts/pngread.before.c`: 修正前の `png_image_read_composite()` 確認用。
- `artifacts/pngread.after.c`: 修正後同版の `pngread.c`。
- `artifacts/pngpriv.before.h`: `PNG_sRGB_FROM_LINEAR()` とテーブルサイズ確認用。
- `artifacts/png.before.h`: `png_composite()` macro確認用。
- `artifacts/arithmetic-notes.md`: 境界外添字に至る算術メモ。

## 判定

`ok`。公開AOSP commitとソース差分から、脆弱な処理、修正内容、到達条件、範囲外読み取りの理由をコードレベルで説明できる。
003 OK

CVE-2025-22424

003-ok-resolveContentProvider-userId-check

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-350456241
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-22424 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

この CVE は PackageManagerService 側の ComputerEngine#resolveContentProvider() における userId 検証順序の不備だった。ContentProvider authority は userId@authority 形式で userId を含められるが、修正前コードはメソッド引数の userId だけを先に mUserManager.exists(userId) で検証し、その後で authority から実際に使う userId を再代入していた。

その結果、呼び出し元が 999@some.provider のような未作成ユーザー ID を authority に含めた場合、引数 userId が実在していれば最初の存在確認を通過し、authority 由来の未作成 userId が ComponentResolverBase#queryProvider() へ渡り得た。queryProvider() は PackageStateInternal#getUserStateOrDefault(userId) を使うため、未作成 userId に対して PackageUserStateInternal.DEFAULT が返り、パッケージがインストール済みかつ通常状態であるかのように ApplicationInfo / ProviderInfo を生成できた。

原因

根本原因は、信頼境界をまたぐ正規化と検証の順序ミスである。

・resolveContentProvider() の name は単なる authority 文字列ではなく、userId@authority 形式を含み得る。
・メソッド引数 userId は最終的な解決対象 userId とは限らない。
・それにもかかわらず、修正前は name を正規化する前の userId に対して存在確認と flags 更新を実行していた。
・正規化後の userId に対する mUserManager.exists() が抜けていた。
・後段の getUserStateOrDefault() が未登録 userId を DEFAULT 状態にフォールバックする設計と組み合わさり、未作成 userId の provider 情報生成が可能になった。

どこから特定したか

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/frameworks/base/+/02fc7472ebb27fd394caafa8b87d4daead295d70 / https://android.googlesource.com/platform/frameworks/base/+/02fc7472ebb27fd394caafa8b87d4daead295d70%5E%21/

validated.md を表示
# CVE-2025-22424 検証結果

## 結論

この CVE は `PackageManagerService` 側の `ComputerEngine#resolveContentProvider()` における userId 検証順序の不備だった。ContentProvider authority は `userId@authority` 形式で userId を含められるが、修正前コードはメソッド引数の `userId` だけを先に `mUserManager.exists(userId)` で検証し、その後で authority から実際に使う userId を再代入していた。

その結果、呼び出し元が `999@some.provider` のような未作成ユーザー ID を authority に含めた場合、引数 userId が実在していれば最初の存在確認を通過し、authority 由来の未作成 userId が `ComponentResolverBase#queryProvider()` へ渡り得た。`queryProvider()` は `PackageStateInternal#getUserStateOrDefault(userId)` を使うため、未作成 userId に対して `PackageUserStateInternal.DEFAULT` が返り、パッケージがインストール済みかつ通常状態であるかのように `ApplicationInfo` / `ProviderInfo` を生成できた。

パッチは `ContentProvider.getAuthorityWithoutUserId(name)` と `ContentProvider.getUserIdFromAuthority(name, userId)` を実行した後に `mUserManager.exists(userId)` と `updateFlagsForComponent(flags, userId)` を行うように順序を入れ替えており、実際に解決に使う userId が存在しない場合は `null` を返すようにした。

判定: **ok**。公開 AOSP ソースと差分から、脆弱な条件、データフロー、根本原因、修正内容を特定できた。

## 基本情報

- CVE: CVE-2025-22424
- Android Security Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Component: Framework
- Type: EoP
- Severity: High
- Reference: A-350456241
- Updated AOSP versions: 14, 15, 16, 16-qpr2
- 修正 commit: `02fc7472ebb27fd394caafa8b87d4daead295d70`
- 修正 commit URL: https://android.googlesource.com/platform/frameworks/base/+/02fc7472ebb27fd394caafa8b87d4daead295d70
- diff URL: https://android.googlesource.com/platform/frameworks/base/+/02fc7472ebb27fd394caafa8b87d4daead295d70%5E%21/
- 親 commit: `36a774d7239923d0ef16ae5f51b87fb132e2bbb9`
- 変更ファイル: `services/core/java/com/android/server/pm/ComputerEngine.java`

## パッチ内容

保存済み diff: `patch.diff`

修正前:

```java
if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForComponent(flags, userId);

String authorityWithoutUserId = ContentProvider.getAuthorityWithoutUserId(name);
userId = ContentProvider.getUserIdFromAuthority(name, userId);
```

修正後:

```java
String authorityWithoutUserId = ContentProvider.getAuthorityWithoutUserId(name);
userId = ContentProvider.getUserIdFromAuthority(name, userId);

if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForComponent(flags, userId);
```

変更は 4 行の移動だけだが、検証対象が「引数 userId」から「authority 解析後の実 userId」に変わるため、セキュリティ上の意味は大きい。

## 脆弱性が起きる状況

前提となる形式:

- `ContentProvider.getUserIdFromAuthority("999@media", defaultUserId)` は `999` を返す。
- `ContentProvider.getAuthorityWithoutUserId("999@media")` は `media` を返す。
- `ContentProvider.createContentUriForUser()` / `maybeAddUserId()` もこの形式を使う。

修正前の `ComputerEngine#resolveContentProvider(name, flags, userId, callingUid)` では、次の流れになる。

1. 呼び出し引数の `userId` が存在すれば `mUserManager.exists(userId)` を通過する。
2. `flags = updateFlagsForComponent(flags, userId)` も引数 userId を前提に更新される。
3. その後、`name` から `authorityWithoutUserId` と authority 埋め込み userId を取り出す。
4. `userId` が authority 由来の値に上書きされる。
5. しかし、上書き後 userId の存在確認は行われない。
6. `mComponentResolver.queryProvider(this, authorityWithoutUserId, flags, userId)` に未作成 userId が渡る。

`ComponentResolverBase#queryProvider()` は直接 authority map から provider を取り、次を実行する。

```java
final PackageUserStateInternal state = packageState.getUserStateOrDefault(userId);
ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(
        pkg, flags, state, userId, packageState);
return PackageInfoUtils.generateProviderInfo(pkg, p, flags, state, appInfo, userId,
        packageState);
```

ここで `PackageStateInternal#getUserStateOrDefault(userId)` は対象 userId の状態がない場合に `PackageUserStateInternal.DEFAULT` を返す。`PackageUserStateDefault` は `isInstalled() == true`, `isHidden() == false`, `isInstantApp() == false`, `isStopped() == false`, `isSuspended() == false` なので、未作成ユーザーであっても「通常インストール済み」の状態として扱われる。

## 影響

本来、存在しない userId に対する content provider 解決は失敗すべきである。しかし修正前は、authority に埋め込まれた userId の存在確認が抜けていたため、未作成 userId の `ProviderInfo` / `ApplicationInfo` が作られ得た。

単純な通常アプリが任意の `999@authority` を渡すだけで常に成功するわけではない。`ComputerEngine#resolveContentProvider()` は provider 解決後に cross-user grant を確認し、grant がなければ `enforceCrossUserPermission(callingUid, userId, ...)` を実行するためである。ただし、解決処理自体が未作成 userId に対して成功可能だったことにより、cross-user provider 解決や URI grant を扱う経路で、存在しないユーザーの provider が有効な対象であるかのように扱われる余地が生じる。

Android の provider/URI 権限処理では、`UriGrantsManagerService#checkAuthorityGrants()` が `GrantUri.sourceUserId == userId` と provider authority の一致を見て cross-user 権限の代替として扱う。したがって、未作成 userId を含む authority が解決可能であることは、通常の user/profile 境界の前提を崩す。Bulletin の分類どおり、これは Framework の EoP と評価される。

## 根本原因

根本原因は、信頼境界をまたぐ正規化と検証の順序ミスである。

- `resolveContentProvider()` の `name` は単なる authority 文字列ではなく、`userId@authority` 形式を含み得る。
- メソッド引数 `userId` は最終的な解決対象 userId とは限らない。
- それにもかかわらず、修正前は `name` を正規化する前の userId に対して存在確認と flags 更新を実行していた。
- 正規化後の userId に対する `mUserManager.exists()` が抜けていた。
- 後段の `getUserStateOrDefault()` が未登録 userId を DEFAULT 状態にフォールバックする設計と組み合わさり、未作成 userId の provider 情報生成が可能になった。

## 面白い点・調査メモ

- `ContextImpl.ApplicationContentResolver#acquireProvider()` は `ContentProvider.getAuthorityWithoutUserId(auth)` と `resolveUserIdFromAuthority(auth)` で authority と userId を分離してから `ActivityThread` に渡す。この通常経路だけを見ると、PM 側の再解析は冗長に見える。
- しかし `ApplicationPackageManager#resolveContentProvider()` など、authority 文字列をそのまま PM に渡せる API があり、PM 側のコメントにも「Callers of this API may not always separate the userID and authority」と明記されている。したがって PM 側での正規化後検証が必要だった。
- `ComponentResolverBase#queryProvider()` の直接 authority 解決には `mUserManager.exists(userId)` がない。一方で intent provider query の `ProviderIntentResolver#queryIntent()` や `newResult()` には userId 存在確認がある。直接 authority 解決だけは呼び出し元の事前検証に依存していた。
- `PackageUserStateDefault#isInstalled()` が true であることが、このバグの影響を大きくしている。未作成 userId の状態が「存在しない」ではなく「デフォルトの通常インストール状態」として進むため、`ApplicationInfo` 生成まで到達する。
- パッチは `Bug:401188957` を参照しているが、bulletin の reference は `A-350456241`。公開コミット上の bug ID と bulletin reference が一致していない。

## 解析に使用した主なローカル保存物

- `ComputerEngine.before.java`
- `ComputerEngine.after.java`
- `patch.diff`
- `ContentProvider.java`
- `ComponentResolverBase.java`
- `PackageStateInternal.java`
- `PackageUserStateDefault.java`
- `ContentProviderHelper.java`
- `ContextImpl.java`
- `ApplicationPackageManager.java`
- `UriGrantsManagerService.java`
- `sources_manifest.md`
004 OK

CVE-2025-22426

004-ok-ComputerEngine-CrossUser-Uri-EoP

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-365086157
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-22426 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

判定: ok。

CVE-2025-22426 は PackageManagerService の ComputerEngine.java 周辺にある横断ユーザ処理のロジックエラーだった。公開情報では「many functions of ComputerEngine.java」「access URIs across users」と説明されており、OSV の ASB-A-365086157 では resolveContentProvider、hasCrossUserPermission、getInstalledApplications、queryIntentServicesInternal、getComponentEnabledSetting に関する修正シグネチャが紐づいている。

根本原因は2つに分けられる。

1. resolveContentProvider() が userId@authority 形式を正規化する前に mUserManager.exists(userId) を実行していた。authority に埋め込まれた実 userId を取り出した後は存在確認していなかったため、未作成 userId に対して ProviderInfo / ApplicationInfo を生成できた。
2. 一部の横断ユーザ権限チェックで、検査すべき「指定 UID」と実際の Binder.getCallingUid() / checkCallingOrSelfPermission() が混同されていた。system_server 内部や代理呼び出しの文脈では、対象アプリ UID ではなく system_server 側の権限を見てしまい、横断ユーザアクセス制御が緩む。

原因

根本原因は、信頼境界をまたぐ前の正規化と主体判定が一貫していなかったこと。

・name / authority は単なる provider authority ではなく userId@authority を含み得る。
・メソッド引数 userId は最終的に解決する userId とは限らない。
・正規化後の userId を検証しないまま後段へ渡した。
・ComponentResolverBase#queryProvider() は未作成 userId を自前で拒否せず、getUserStateOrDefault() に依存していた。
・PackageUserStateDefault が「インストール済み・非停止・非hidden」のような通常状態を返すため、未作成 userId が有効な package user state のように扱われた。
・横断ユーザ権限チェックで、実際の Binder caller、代理対象 UID、package visibility 用 UID の意味が混ざっていた。

どこから特定したか

解析したコミット: ASB-A-365086157.json の ecosystem_specific.fixes と vanir_signatures を起点にした。

パッチ解析: 保存済み差分: 57eaa465cabb9a74cc57cbb16657c36ad9fc2d58.diff, 02fc7472.diff

修正前:

``java
if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForComponent(flags, userId);

String authorityWithoutUserId = ContentProvider.getAuthorityWithoutUserId(name);
userId = ContentProvider.getUserIdFromAuthority(name, userId);
`

修正後:

保存した付帯ファイル: ・ASB-A-365086157.json: OSVレコード
・02fc7472.commit.json, 02fc7472.diff
・57eaa465cabb9a74cc57cbb16657c36ad9fc2d58.commit.json, 57eaa465cabb9a74cc57cbb16657c36ad9fc2d58.diff
・d1ec2efc0b8941a0585712d5b4cec95fd9f12f17.commit.json, d1ec2efc0b8941a0585712d5b4cec95fd9f12f17.diff
・6775f07552f15f6e4b934bb9552f7a6abff8060b.commit.jso…

validated.md を表示
# CVE-2025-22426 検証結果

## 結論

判定: **ok**。

CVE-2025-22426 は `PackageManagerService` の `ComputerEngine.java` 周辺にある横断ユーザ処理のロジックエラーだった。公開情報では「many functions of ComputerEngine.java」「access URIs across users」と説明されており、OSV の `ASB-A-365086157` では `resolveContentProvider`、`hasCrossUserPermission`、`getInstalledApplications`、`queryIntentServicesInternal`、`getComponentEnabledSetting` に関する修正シグネチャが紐づいている。

根本原因は2つに分けられる。

1. `resolveContentProvider()` が `userId@authority` 形式を正規化する前に `mUserManager.exists(userId)` を実行していた。authority に埋め込まれた実 userId を取り出した後は存在確認していなかったため、未作成 userId に対して `ProviderInfo` / `ApplicationInfo` を生成できた。
2. 一部の横断ユーザ権限チェックで、検査すべき「指定 UID」と実際の `Binder.getCallingUid()` / `checkCallingOrSelfPermission()` が混同されていた。system_server 内部や代理呼び出しの文脈では、対象アプリ UID ではなく system_server 側の権限を見てしまい、横断ユーザアクセス制御が緩む。

この2系統はいずれも URI / ContentProvider / PackageManager の user boundary を壊すため、Framework EoP として説明できる。実機PoCは作成していないが、AOSPソース差分、OSVシグネチャ、NVD説明、呼び出し経路から脆弱条件と修正意図を特定できたため ok とする。

## 基本情報

- CVE: `CVE-2025-22426`
- Reference: `A-365086157`
- Component: `Framework`
- Type: `EoP`
- Severity: `High`
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://storage.googleapis.com/android-osv/ASB-A-365086157.json
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2025-22426
- Affected AOSP versions: Android 14, 15, 16, 16-qpr2
- NVD CVSS v3.1: `AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H`
- CWE: `CWE-284 Improper Access Control`

## 解析したコミット

`ASB-A-365086157.json` の `ecosystem_specific.fixes` と `vanir_signatures` を起点にした。

- `d1ec2efc0b8941a0585712d5b4cec95fd9f12f17`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/d1ec2efc0b8941a0585712d5b4cec95fd9f12f17
  - 件名: `Parse authority to separate userId and non-user parts of it`
  - 内容: `10@com.example` のような authority を `userId=10` と `authority=com.example` に分離して provider を解決する。
- `57eaa465cabb9a74cc57cbb16657c36ad9fc2d58`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/57eaa465cabb9a74cc57cbb16657c36ad9fc2d58
  - 件名: `Checking userId in com.android.server.pm.ComputerEngine#resolveContentProvider`
  - 内容: authority から取り出した実 userId に対して `mUserManager.exists(userId)` と `updateFlagsForComponent()` を行うよう順序を修正。
- `02fc7472ebb27fd394caafa8b87d4daead295d70`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/02fc7472ebb27fd394caafa8b87d4daead295d70
  - 2026-06 bulletin から直接リンクされる `57eaa465...` の cherry-pick。
- `6775f07552f15f6e4b934bb9552f7a6abff8060b`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/6775f07552f15f6e4b934bb9552f7a6abff8060b
  - 件名: `Check cross user permissions for a given UID`
  - 内容: `hasCrossUserPermission()` で引数の `callingUid` に対して `INTERACT_ACROSS_USERS(_FULL)` を確認する。加えて、public Binder API 境界では代理 UID ではなく `Binder.getCallingUid()` を使って横断ユーザチェックするよう修正。

## パッチ解析

### 1. `resolveContentProvider()` の userId 検証順序

保存済み差分: `57eaa465cabb9a74cc57cbb16657c36ad9fc2d58.diff`, `02fc7472.diff`

修正前:

```java
if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForComponent(flags, userId);

String authorityWithoutUserId = ContentProvider.getAuthorityWithoutUserId(name);
userId = ContentProvider.getUserIdFromAuthority(name, userId);
```

修正後:

```java
String authorityWithoutUserId = ContentProvider.getAuthorityWithoutUserId(name);
userId = ContentProvider.getUserIdFromAuthority(name, userId);

if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForComponent(flags, userId);
```

`ContentProvider.getUserIdFromAuthority("999@media", defaultUserId)` は `999` を返し、`getAuthorityWithoutUserId("999@media")` は `media` を返す。旧コードでは、引数 `userId` が実在していれば最初の存在確認を通過し、その後に authority 由来の `999` で上書きされても再検証されなかった。

後段の `ComponentResolverBase#queryProvider()` は直接 authority map から provider を引き、`packageState.getUserStateOrDefault(userId)` を使って `ApplicationInfo` と `ProviderInfo` を生成する。この関数自体には `mUserManager.exists(userId)` がない。

`PackageUserStateInternal.DEFAULT` は `PackageUserStateDefault` で、`isInstalled() == true`, `isHidden() == false`, `isInstantApp() == false`, `isStopped() == false`, `isSuspended() == false` を返す。つまり未作成 userId の状態が「存在しない」ではなく「通常インストール済み」に近い状態として扱われ、provider 解決が成立し得る。

### 2. 指定 UID と Binder UID の混同

保存済み差分: `6775f07552f15f6e4b934bb9552f7a6abff8060b.diff`

旧 `hasCrossUserPermission()` は、引数 `callingUid` を受け取りながら、権限確認では引数なし `hasPermission()` を呼んでいた。

```java
boolean permissionGranted = requireFullPermission ? hasPermission(
        Manifest.permission.INTERACT_ACROSS_USERS_FULL)
        : (hasPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
        || hasPermission(Manifest.permission.INTERACT_ACROSS_USERS));
```

引数なし `hasPermission()` は `mContext.checkCallingOrSelfPermission(permission)` なので、検査対象は「指定 UID」ではなく Binder 呼び出し元または system_server 自身になる。修正後は次のように `callingUid` を明示する。

```java
boolean permissionGranted = requireFullPermission ? hasPermission(
        Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingUid)
        : (hasPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingUid)
        || hasPermission(Manifest.permission.INTERACT_ACROSS_USERS, callingUid));
```

一方、`queryIntentServicesInternal()`、`getInstalledApplications()`、`getComponentEnabledSetting()` では、public Binder API 境界の横断ユーザチェックに代理対象の `callingUid` を渡していた箇所が `Binder.getCallingUid()` に置き換えられている。これは、実際に API を呼んだアプリに対して user boundary を強制するための修正である。代理対象 UID は package visibility や結果フィルタには必要だが、横断ユーザアクセス権を持つかどうかの主体ではない。

## 脆弱性が起きる状況

`resolveContentProvider` 系:

1. 低権限アプリまたは system component が `PackageManager.resolveContentProvider()` / `IPackageManager.resolveContentProvider()` に到達する。
2. authority に `userId@authority` 形式を含める。例: `999@com.example.provider`。
3. 引数側の `userId` は呼び出し元ユーザなど実在する値なので、旧コードの先頭 `mUserManager.exists(userId)` は通る。
4. その後 `ContentProvider.getUserIdFromAuthority()` で `userId=999` に上書きされる。
5. 旧コードは上書き後の `999` を存在確認しないまま `mComponentResolver.queryProvider()` に渡す。
6. `queryProvider()` は `PackageUserStateInternal.DEFAULT` にフォールバックし、未作成 userId 向けの `ProviderInfo` / `ApplicationInfo` を生成する。
7. URI grant や cross-user provider 解決の後続処理が「存在する provider」として扱えるため、本来失敗すべき横断ユーザ URI アクセスの前提が崩れる。

指定 UID/Binder UID 混同系:

1. PackageManager 内部 API には `callingUid` を引数に取り、特定 UID から見える package/provider/component 情報を返すものがある。
2. 旧コードでは横断ユーザチェックでもこの `callingUid` をそのまま使う箇所、または `hasCrossUserPermission(callingUid, ...)` 内で `checkCallingOrSelfPermission()` を使う箇所があった。
3. その結果、チェックすべき主体が「実際の Binder 呼び出し元」または「指定 UID」のどちらなのかが崩れ、system_server 経由の代理呼び出しや可視性フィルタ用 UID を使う経路で横断ユーザ権限を誤判定し得た。
4. 修正後は、public API 境界の横断ユーザ enforcement は `Binder.getCallingUid()`、指定 UID の権限有無を見る helper は `hasPermission(permission, callingUid)` に統一されている。

## 根本原因

根本原因は、信頼境界をまたぐ前の正規化と主体判定が一貫していなかったこと。

- `name` / `authority` は単なる provider authority ではなく `userId@authority` を含み得る。
- メソッド引数 `userId` は最終的に解決する userId とは限らない。
- 正規化後の userId を検証しないまま後段へ渡した。
- `ComponentResolverBase#queryProvider()` は未作成 userId を自前で拒否せず、`getUserStateOrDefault()` に依存していた。
- `PackageUserStateDefault` が「インストール済み・非停止・非hidden」のような通常状態を返すため、未作成 userId が有効な package user state のように扱われた。
- 横断ユーザ権限チェックで、実際の Binder caller、代理対象 UID、package visibility 用 UID の意味が混ざっていた。

## 面白い点・調査メモ

- 2026-06 bulletin の `CVE-2025-22424` と `CVE-2025-22426` は同じ公開リンク `02fc7472...` に向いている。OSV を見ると `CVE-2025-22426` には `6775f075...` と `d1ec2efc...` も紐づいており、bulletin の表だけでは修正範囲を過小評価しやすい。
- `d1ec2efc...` は `10@com.example` を正しく user 10 の `com.example` provider として解決する機能修正だが、その後 `57eaa465...` が「正規化後 userId の存在確認」を追加している。前者だけだとむしろ未作成 userId が後段に届く条件が明確になる。
- direct authority 解決の `ComponentResolverBase#queryProvider()` には user existence check がない。一方で intent resolver 側の provider query には `mUserManager.exists(userId)` がある。直接 provider 解決だけが呼び出し元の検証に強く依存していた。
- `PackageUserStateDefault#isInstalled()` が `true` であることが影響を大きくしている。未作成ユーザ用 state がない場合に「非インストール」へ倒れない。
- `6775f075...` の commit message は「legacy behavior維持のため、method enforcement では custom UID を `Binder.getCallingUid()` に置き換える」と説明している。これは public API の user boundary は実呼び出し元で評価し、結果の見え方だけ指定 UID でフィルタする、という境界整理になっている。

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

- `ASB-A-365086157.json`: OSVレコード
- `02fc7472.commit.json`, `02fc7472.diff`
- `57eaa465cabb9a74cc57cbb16657c36ad9fc2d58.commit.json`, `57eaa465cabb9a74cc57cbb16657c36ad9fc2d58.diff`
- `d1ec2efc0b8941a0585712d5b4cec95fd9f12f17.commit.json`, `d1ec2efc0b8941a0585712d5b4cec95fd9f12f17.diff`
- `6775f07552f15f6e4b934bb9552f7a6abff8060b.commit.json`, `6775f07552f15f6e4b934bb9552f7a6abff8060b.diff`
- `ComputerEngine_before.java`, `ComputerEngine_after.java`
- `ComputerEngine_6775_before.java`, `ComputerEngine_6775_after.java`
- `ComponentResolverBase_before.java`
- `ContentProvider.java`
- `PackageUserStateInternal.java`
- `PackageUserStateDefault.java`
- `ApplicationPackageManager.java`
- `ContentProviderHelper.java`
- `UriGrantsManagerService.java`
- `IPackageManager.aidl`
005 OK

CVE-2025-48570

005-ok-pip-stale-pinned-task-bal-confused-deputy

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14
ReferencesA-376048041
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-48570 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

判定: ok。

CVE-2025-48570 は、Framework の WM Shell / PiP 管理にある confused deputy 型の EoP だった。公開 OSV は「PipTaskOrganizer.java の複数関数で、confused deputy によりバックグラウンドから Activity を起動できる」と説明している。AOSP の修正差分を見ると、問題は SystemUI/Shell 再起動後に、既存の pinned/PiP task が PipTaskOrganizer#onTaskAppeared() に再通知されるものの、実際の PiP enter transition が続かない場合に、その task が stale なまま残ることだった。

修正は onTaskAppeared() で3秒後の復旧チェックを登録し、PiP が ENTERING_PIP に進まなければ、同じ topActivity を持つ running task を ActivityTaskManager.removeTask() で削除する。正常な PiP 遷移では listener がこの callback をキャンセルする。つまり、SystemUI再起動後の「PiPとして現れたが本物のPiP遷移に入らない task」を強制的に片付ける修正である。

原因

根本原因は、SystemUI/Shell 再起動をまたぐ PiP task の所有権と状態同期の不足である。

・PipTaskOrganizer は systemui process 内の状態機械を持つ。
・既存の pinned task は systemui 再起動後も WM 側に残り得る。
・再起動後の onTaskAppeared() は「今まさに PiP に入る task」と「再接続で通知された stale pinned task」を同じように扱っていた。
・旧コードには、後続の PiP transition state change が来ない場合に task を破棄する timeout / recovery がなかった。
・Android の BAL は可視 task や foreground process 状態をセキュリティ判断に使うため、stale task は単なる表示上の不具合ではなく、background Activity launch 制限の信頼境界を壊す confused deputy になった。

どこから特定したか

解析したコミット: ・c38e7078d853c1b22ee7d139c85b08ab669f89d1
- URL: https://android.googlesource.com/platform/frameworks/base/+/c38e7078d853c1b22ee7d139c85b08ab669f89d1
- diff: https://android.googlesource.com/platform/frameworks/base/+/c38e7078d853c1b22ee7d139c85b08ab669f89d1%5E%21/
- 件名: [RESTRICT AUTOMERGE] Remove staled pinned Task upon SystemUI reboot
- 内容: onTas…

BAL / PiP 側の根拠コード: BackgroundActivityStartController#checkBackgroundActivityStart() は、呼び出し UID に visible window がある場合や、caller process が許可状態の場合に background Activity start を許す。

保存済み: artifacts/BackgroundActivityStartController_1451.java

保存した付帯ファイル: ・artifacts/ASB-A-376048041.json: OSV JSON
・artifacts/c38e7078.commit.json, artifacts/c38e7078.diff
・artifacts/6b3066f8.commit.json, artifa…

validated.md を表示
# CVE-2025-48570 検証結果

## 結論

判定: **ok**。

CVE-2025-48570 は、Framework の WM Shell / PiP 管理にある confused deputy 型の EoP だった。公開 OSV は「`PipTaskOrganizer.java` の複数関数で、confused deputy によりバックグラウンドから Activity を起動できる」と説明している。AOSP の修正差分を見ると、問題は SystemUI/Shell 再起動後に、既存の pinned/PiP task が `PipTaskOrganizer#onTaskAppeared()` に再通知されるものの、実際の PiP enter transition が続かない場合に、その task が stale なまま残ることだった。

修正は `onTaskAppeared()` で3秒後の復旧チェックを登録し、PiP が `ENTERING_PIP` に進まなければ、同じ `topActivity` を持つ running task を `ActivityTaskManager.removeTask()` で削除する。正常な PiP 遷移では listener がこの callback をキャンセルする。つまり、SystemUI再起動後の「PiPとして現れたが本物のPiP遷移に入らない task」を強制的に片付ける修正である。

根本原因は、PiP task の lifetime を Shell/SystemUI 側の遷移状態に依存していたにもかかわらず、SystemUI再起動で state machine が失われた後に既存 pinned task を安全に再同期または削除する処理がなかったこと。Android の Background Activity Launch (BAL) 判定は、可視 task、pinned windowing mode、プロセスの可視 Activity 状態を組み合わせて Activity 起動可否を決めるため、stale pinned task が残ると本来バックグラウンド扱いにすべきアプリが、SystemUI/Shell を代理にした状態不整合で起動制限を回避できる。

## 基本情報

- CVE: `CVE-2025-48570`
- Reference: `A-376048041`
- Component: `Framework`
- Type: `EoP`
- Severity: `High`
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://osv.dev/vulnerability/ASB-A-376048041
- OSV JSON: https://storage.googleapis.com/android-osv/ASB-A-376048041.json
- Affected AOSP versions: `14`
- OSV details: `PipTaskOrganizer.java` の複数関数で confused deputy により background Activity launch が可能。追加権限・ユーザー操作は不要。

## 解析したコミット

- `c38e7078d853c1b22ee7d139c85b08ab669f89d1`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/c38e7078d853c1b22ee7d139c85b08ab669f89d1
  - diff: https://android.googlesource.com/platform/frameworks/base/+/c38e7078d853c1b22ee7d139c85b08ab669f89d1%5E%21/
  - 件名: `[RESTRICT AUTOMERGE] Remove staled pinned Task upon SystemUI reboot`
  - 内容: `onTaskAppeared()` 後、PiP transition state change が続かなければ stale pinned task を削除する。
- `6b3066f8d199b17853992fc121f85bfa9aa43136`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/6b3066f8d199b17853992fc121f85bfa9aa43136
  - diff: https://android.googlesource.com/platform/frameworks/base/+/6b3066f8d199b17853992fc121f85bfa9aa43136%5E%21/
  - 内容: `c38e7078...` の revert。理由は `b/458676344`。
- `1451fd2024faebf940f439c71c4775e603709e34`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/1451fd2024faebf940f439c71c4775e603709e34
  - diff: https://android.googlesource.com/platform/frameworks/base/+/1451fd2024faebf940f439c71c4775e603709e34%5E%21/
  - 内容: セキュリティ修正の再投入。`info.topActivity` の null を考慮し、`b/459832318` の NPE を修正。
- `c0f88bec3bf04db6a1ba3fad276dcde898de0f5e`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/c0f88bec3bf04db6a1ba3fad276dcde898de0f5e
  - OSV references に含まれる同系統の reland commit。commit metadata は保存したが、diff は通信タイムアウトで空ファイルになった。

## パッチ内容

保存済み差分:

- `artifacts/c38e7078.diff`
- `artifacts/6b3066f8.diff`
- `artifacts/1451fd20.diff`

最終修正の中心は `PipTaskOrganizer#onTaskAppeared()` に追加された次の処理である。

```java
mRemoveStaledPinnedTaskRunnable = () -> {
    final ComponentName toRemove = (info != null && info.topActivity != null)
            ? info.topActivity : null;
    if (toRemove == null) return;
    List<ActivityManager.RunningTaskInfo> tasks = ActivityTaskManager.getService()
            .getTasks(10, false, false, Display.DEFAULT_DISPLAY);
    for (ActivityManager.RunningTaskInfo task : tasks) {
        if (toRemove.equals(task.topActivity)) {
            ActivityTaskManager.getService().removeTask(task.taskId);
        }
    }
};
mMainExecutor.executeDelayed(mRemoveStaledPinnedTaskRunnable,
        CRASH_RECOVERY_CHECK_DELAY_MS);
```

コンストラクタには、正常な PiP enter transition を検出して callback をキャンセルする listener が追加された。

```java
mPipTransitionState.addOnPipTransitionStateChangedListener(
        (oldState, newState) -> {
            if (mPipTransitionState.isEnteringPip()
                    && mRemoveStaledPinnedTaskRunnable != null) {
                mMainExecutor.removeCallbacks(mRemoveStaledPinnedTaskRunnable);
                mRemoveStaledPinnedTaskRunnable = null;
            }
        });
```

この差分から、削除対象は「PiP task が現れたが、3秒以内に `ENTERING_PIP` へ進まないもの」だと分かる。正常な PiP では `onTaskAppeared()` 後に `enterPipWithAlphaAnimation()`、`scheduleAnimateResizePip()`、固定回転完了、swipe-to-home 完了などの経路から `ENTERING_PIP` / `ENTERED_PIP` へ進むため、削除 callback は実行されない。

## 脆弱性が起きる状況

成立条件は次のように整理できる。

1. 攻撃アプリが PiP 可能な Activity を持つ。
2. その Activity が pinned/PiP task として存在している状態で SystemUI/Shell が再起動する、または同等に Shell 側の `PipTaskOrganizer` state machine が失われる。
3. 再生成された `PipTaskOrganizer` は `ShellTaskOrganizer` に listener 登録し、既存 pinned task について `onTaskAppeared()` を受ける。
4. 旧コードは `mPipTransitionState` を `TASK_APPEARED` にするだけで、実際の PiP enter transition が続かない場合の cleanup をしない。
5. stale な pinned task が残り、アプリ側の Activity/task/process 状態が foreground/visible として残る、または PiP として扱うべき状態が Shell と WM/BAL の間でずれる。
6. BAL 判定は visible task や process foreground 状態を Activity 起動許可の根拠に使うため、通常なら background Activity launch として拒否される起動が許可され得る。

修正 commit の test 行にも `Run the PoC app and make sure no background Activity launch` とあり、攻撃の観測結果は「PoC app から background Activity launch ができること」だったと分かる。

## BAL / PiP 側の根拠コード

`BackgroundActivityStartController#checkBackgroundActivityStart()` は、呼び出し UID に visible window がある場合や、caller process が許可状態の場合に background Activity start を許す。

保存済み: `artifacts/BackgroundActivityStartController_1451.java`

- `mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity(callingUid)` と `mActiveUids.hasNonAppVisibleWindow(callingUid)` で visible window を見る。
- `callerApp.areBackgroundActivityStartsAllowed(appSwitchState)` が `BAL_BLOCK` でなければ起動を許す。

`WindowProcessController#areBackgroundActivityStartsAllowed()` は `BackgroundLaunchProcessController` に次を渡す。

```java
hasActivityInVisibleTask(), inPinnedWindowingMode()
```

保存済み: `artifacts/WindowProcessController_1451.java`

`BackgroundLaunchProcessController#areBackgroundActivityStartsAllowed()` は次の条件で foreground task 由来の起動を許可する。

```java
if ((isCheckingForFgsStart || !inPinnedWindow)
        && hasActivityInVisibleTask && appSwitchState != APP_SWITCH_DISALLOW) {
    return BAL_ALLOW_FOREGROUND;
}
```

保存済み: `artifacts/BackgroundLaunchProcessController_1451.java`

ここで `inPinnedWindow` が正しく true なら通常 Activity 起動は抑制される。しかし SystemUI/Shell の PiP organizer state が失われ、既存 pinned task が stale に残った状態では、PiP transition と task/process 可視状態の整合性が崩れる。今回の修正は、整合性が回復できない task を削除することで、BAL 判定が stale task を foreground/visible 根拠として使う余地を消している。

## 根本原因

根本原因は、SystemUI/Shell 再起動をまたぐ PiP task の所有権と状態同期の不足である。

- `PipTaskOrganizer` は systemui process 内の状態機械を持つ。
- 既存の pinned task は systemui 再起動後も WM 側に残り得る。
- 再起動後の `onTaskAppeared()` は「今まさに PiP に入る task」と「再接続で通知された stale pinned task」を同じように扱っていた。
- 旧コードには、後続の PiP transition state change が来ない場合に task を破棄する timeout / recovery がなかった。
- Android の BAL は可視 task や foreground process 状態をセキュリティ判断に使うため、stale task は単なる表示上の不具合ではなく、background Activity launch 制限の信頼境界を壊す confused deputy になった。

## 面白い点・調査メモ

- 修正の見た目は「SystemUI reboot recovery」だが、commit message の test は明確に PoC の background Activity launch を確認している。表示復旧ではなくセキュリティ修正である。
- `PipTransitionState.isInPip()` は `TASK_APPEARED` 以上を PiP とみなすが、修正のキャンセル条件は `isEnteringPip()`、つまり `ENTERING_PIP` のみである。`TASK_APPEARED` のまま止まる task を異常系として削除する意図が明確。
- 初回修正 `c38e7078...` は `info.topActivity` をそのまま capture していた。reland の `1451fd20...` / `c0f88bec...` では null safe に直されており、セキュリティ修正が一度 revert されてから NPE 対策付きで再投入されたことが分かる。
- `ActivityTaskManagerService#removeTask()` は `REMOVE_TASKS` 権限を要求する。通常アプリは stale task を自力で消せず、SystemUI/Shell が privileged deputy として cleanup する必要がある。
- `VisibleActivityProcessTracker#hasVisibleNotPinnedActivity()` は pinned activity を除外するため、PiP はBAL上も特別扱いされている。この特別扱いは、PiP organizer と WM state が一致していることを前提にしている。

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

- `artifacts/ASB-A-376048041.json`: OSV JSON
- `artifacts/c38e7078.commit.json`, `artifacts/c38e7078.diff`
- `artifacts/6b3066f8.commit.json`, `artifacts/6b3066f8.diff`
- `artifacts/1451fd20.commit.json`, `artifacts/1451fd20.diff`
- `artifacts/c0f88bec.commit.json`, `artifacts/c0f88bec.diff`: diff は取得失敗により空
- `artifacts/PipTaskOrganizer_c38e_before.java`, `artifacts/PipTaskOrganizer_c38e_after.java`
- `artifacts/PipTaskOrganizer_1451_before.java`, `artifacts/PipTaskOrganizer_1451_after.java`
- `artifacts/PipTransitionState_1451.java`
- `artifacts/ActivityTaskManagerService_1451.java`
- `artifacts/BackgroundActivityStartController_1451.java`
- `artifacts/BackgroundLaunchProcessController_1451.java`
- `artifacts/WindowProcessController_1451.java`
- `artifacts/VisibleActivityProcessTracker_1451.java`
- `artifacts/Task_1451.java`
- `artifacts/ActivityRecord_1451.java`
- `artifacts/ConfigurationContainer_1451.java`
- `artifacts/patch_analysis.md`
006 OK

CVE-2025-48595

006-ok-sqlite-integer-overflows

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-430889718
Advisory noteGoogle states there are indications this issue may be under limited, targeted exploitation.
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-48595 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

判定: ok

CVE-2025-48595 は Android Framework として公表されているが、公開AOSP参照ID A-430889718 の実体は Android が同梱する libsqlite3 の 3.44.3 -> 3.44.5 更新だった。パッチ差分から、SQLite内の複数箇所の整数オーバーフロー/数値切り詰めを修正しており、Androidの説明「multiple locations」「integer overflow」「local escalation of privilege」と整合する。

最も直接的にコード実行へつながる箇所は concat_ws() の結果バッファ長計算である。修正前は n += (argc-1)*nSep; の argc-1 と nSep が32bit int として乗算されてから64bit変数 n に加算されるため、大きなseparatorと多数引数で32bit整数オーバーフローが発生する。過小なサイズで sqlite3_malloc64(n+1) した後、実際の連結処理がより大きいデータを書き込むことでヒープバッファオーバーフローになり得る。修正後は n += (argc-1)*(i64)nSep; となり、乗算前に64bitへ拡張している。

原因

記載なし。

どこから特定したか

公開情報: ・Android Security Bulletin 2026-06-01 の Framework 表では CVE-2025-48595 / A-430889718 / EoP / High / 14,15,16,16-qpr2 として掲載されている。
・NVDのCVE-2025-48595説明は「multiple locations」「possible way to achieve code execution due to an integer overflow」「local escalation of privilege」「no user interaction」となっている。
・NVDではCISA KEVにも登録済みで、名称は「Android Framework Integer Overflow Vu…

パッチ解析: 差分:

``diff
・n += (argc-1)*nSep;
+ n += (argc-1)*(i64)nSep;
`

修正前の根本原因:

・n は64bit系のサイズ変数だが、右辺の (argc-1)*nSep は両方が int のため、Cの通常算術変換により32bit int で乗算される。
・その後に64bitへ代入/加算されるため、オーバーフロー後の小さい値がバッファサイズ計算に使われる。
・sqlite3_malloc64(n+1) が過小確保になり、後続の文字列連結で実データ量を書き込むとヒープ破壊になる。

関連一次情報:

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/…

validated.md を表示
# CVE-2025-48595 検証メモ

## 結論

判定: ok

CVE-2025-48595 は Android Framework として公表されているが、公開AOSP参照ID A-430889718 の実体は Android が同梱する `libsqlite3` の 3.44.3 -> 3.44.5 更新だった。パッチ差分から、SQLite内の複数箇所の整数オーバーフロー/数値切り詰めを修正しており、Androidの説明「multiple locations」「integer overflow」「local escalation of privilege」と整合する。

最も直接的にコード実行へつながる箇所は `concat_ws()` の結果バッファ長計算である。修正前は `n += (argc-1)*nSep;` の `argc-1` と `nSep` が32bit `int` として乗算されてから64bit変数 `n` に加算されるため、大きなseparatorと多数引数で32bit整数オーバーフローが発生する。過小なサイズで `sqlite3_malloc64(n+1)` した後、実際の連結処理がより大きいデータを書き込むことでヒープバッファオーバーフローになり得る。修正後は `n += (argc-1)*(i64)nSep;` となり、乗算前に64bitへ拡張している。

加えて、集約式解析の `Expr.iAgg` が `i16` であるにもかかわらず、集約項目数がその範囲を超え得る問題が修正されている。修正後は `SQLITE_LIMIT_COLUMN` を上限として「more than %d aggregate terms」を早期エラーにし、`pExpr->iAgg = (i16)k` / `(i16)i` の前に範囲内であることを保証する。これはCVE-2025-6965としても公開されている「aggregate terms could exceed the number of columns」問題と一致する。

また、`setupLookaside()` でも `sz*nBig` の32bit乗算を64bit化し、`sz` を `65528` 以下に制限している。これは `SQLITE_DBCONFIG_LOOKASIDE` のサイズ/個数計算が32bitで折り返し、lookaside領域の分割数を誤る問題を潰す修正である。

## 既存cve.mdの確認

- CVE: CVE-2025-48595
- 参照ID: A-430889718
- Component: Framework
- Type: EoP
- Severity: High
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Affected/updated AOSP versions: 14, 15, 16, 16-qpr2
- Advisory note: limited, targeted exploitation の兆候あり

## 公開情報

- Android Security Bulletin 2026-06-01 の Framework 表では CVE-2025-48595 / A-430889718 / EoP / High / 14,15,16,16-qpr2 として掲載されている。
- NVDのCVE-2025-48595説明は「multiple locations」「possible way to achieve code execution due to an integer overflow」「local escalation of privilege」「no user interaction」となっている。
- NVDではCISA KEVにも登録済みで、名称は「Android Framework Integer Overflow Vulnerability」、追加日は 2026-06-02、期限は 2026-06-05。

## AOSP参照コミット

Bulletin の A-430889718 に紐づく公開コミットは次の5件。

1. `platform/build/release` `b11607ea3ec7ab3183b558392850c842c582d2cc`
   - `RELEASE_PACKAGE_LIBSQLITE3` を `3440300` から `3440500` に変更。
   - URL: https://android.googlesource.com/platform/build/release/+/b11607ea3ec7ab3183b558392850c842c582d2cc

2. `platform/external/sqlite` `cbebed38b5798baa61d3924de8e09db9f458292c`
   - `dist/sqlite-autoconf-3440500/` に SQLite 3.44.5 ソースを追加。
   - URL: https://android.googlesource.com/platform/external/sqlite/+/cbebed38b5798baa61d3924de8e09db9f458292c

3. `platform/external/sqlite` `1612b56a5b4092f8256dfaa2096e9680d3f47f98`
   - 3.44.5追加を一度revert。理由は performance regression。
   - URL: https://android.googlesource.com/platform/external/sqlite/+/1612b56a5b4092f8256dfaa2096e9680d3f47f98

4. `platform/build/release` `9484064212935962adbd8b6f4e028f2d5179433e`
   - release flag の 3.44.5 選択をrevert。理由は performance regression。
   - URL: https://android.googlesource.com/platform/build/release/+/9484064212935962adbd8b6f4e028f2d5179433e

5. `platform/external/sqlite` `aaebce3d8fd545d05f16cc9a137f22da8cad52c8`
   - `dist/sqlite-autoconf-3440300/` ディレクトリのまま内容を 3.44.5 に差し替え。
   - 実際にAndroid側で効かせる修正コミットと判断。
   - URL: https://android.googlesource.com/platform/external/sqlite/+/aaebce3d8fd545d05f16cc9a137f22da8cad52c8

面白い点: 最初は新しい `3440500` ディレクトリを追加してフラグで切り替える形だったが、性能退行で一度revertされ、最終的に `3440300` ディレクトリ名のまま中身を3.44.5へ置換している。ディレクトリ名だけを見ると3.44.3に見えるため、バージョン判定は `README.version` / `SQLITE_VERSION` / `SQLITE_SOURCE_ID` を見る必要がある。

## パッチ解析

### 1. `concat_ws()` の32bit整数オーバーフロー

差分:

```diff
-  n += (argc-1)*nSep;
+  n += (argc-1)*(i64)nSep;
```

修正前の根本原因:

- `n` は64bit系のサイズ変数だが、右辺の `(argc-1)*nSep` は両方が `int` のため、Cの通常算術変換により32bit `int` で乗算される。
- その後に64bitへ代入/加算されるため、オーバーフロー後の小さい値がバッファサイズ計算に使われる。
- `sqlite3_malloc64(n+1)` が過小確保になり、後続の文字列連結で実データ量を書き込むとヒープ破壊になる。

関連一次情報:

- SQLite check-in `498e3f1cf57f164f`: 「concat_ws() function with an enormous separator values and many arguments」の32bit整数オーバーフローを避けるtypecast。
- NVD CVE-2025-3277: `concat_ws()` の整数オーバーフローにより切り詰められたサイズでバッファを確保し、その後の書き込みで約4GB規模のheap buffer overflowが起き得る。

### 2. aggregate terms / `Expr.iAgg` の数値切り詰め

主な差分:

```diff
+  int mxTerm = pParse->db->aLimit[SQLITE_LIMIT_COLUMN];
+  assert( mxTerm <= SMXV(i16) );
...
+  if( k>mxTerm ){
+    sqlite3ErrorMsg(pParse, "more than %d aggregate terms", mxTerm);
+    k = mxTerm;
+  }
...
+  assert( k <= SMXV(pExpr->iAgg) );
   pExpr->iAgg = (i16)k;
```

修正前の根本原因:

- `AggInfo` 側の項目数は `int` で増え得る一方、式ノード `Expr.iAgg` は `i16`。
- 集約項目が多すぎるSQLを解析すると、`pExpr->iAgg = (i16)k` または `(i16)i` でインデックスが16bitへ切り詰められる。
- 後続処理が切り詰め後の誤った集約項目インデックスを使うことで、誤ったメモリアクセス/メモリ破壊につながる。

関連一次情報:

- SQLite check-in `5508b56fd24016c13981ec280ecdd833007c9d8dd595edb295b984c2b487b5c8`: 集約項目数が最大列数を超える場合に即エラーにする修正。
- NVD CVE-2025-6965: SQLite 3.50.2より前では集約項目数が利用可能な列数を超え、memory corruptionにつながり得る。

### 3. `setupLookaside()` の32bit乗算

主な差分:

```diff
-  sqlite3_int64 szAlloc = sz*(sqlite3_int64)cnt;
+  sqlite3_int64 szAlloc;
...
+  if( sz>65528 ) sz = 65528;
+  szAlloc = (i64)sz*(i64)cnt;
...
-    nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL;
+    nSm = (szAlloc - (i64)sz*(i64)nBig)/LOOKASIDE_SMALL;
```

修正前の根本原因:

- `szAlloc` 自体は64bit計算だが、後段の `sz*nBig` は `int * int` として評価され得る。
- 大きな `sz` と `nBig` の組み合わせで32bitオーバーフローし、small slot数 `nSm` の計算が壊れる。
- lookasideメモリ領域の内部分割が誤ると、メモリアロケータとしての管理構造に不整合が出る。

## Androidでの影響整理

Android Framework のJava APIやシステムサービスは `android.database.sqlite` を通じてネイティブ `libsqlite3` を利用する。アプリが自分のDBやContentProvider経由のDB操作でSQLを到達させられるため、SQLiteのメモリ破壊はアプリプロセス内のコード実行だけでなく、権限の高いプロセスが攻撃者制御のSQL/DBを処理する構成では権限昇格に使われ得る。

今回のAndroid CVEは単一のSQLite upstream CVEをそのまま載せたものではなく、A-430889718 の修正として SQLite 3.44.5 へ差し替えたことで、複数の整数オーバーフロー系修正をAndroid Framework脆弱性として束ねているように見える。Bulletin/NVDの「multiple locations」という表現、AOSP差分の複数修正箇所、SQLite upstreamの既知CVEが互いに一致する。

## 解析に使ったファイル

- `artifacts/bulletin-2026-06-01.html`
- `artifacts/nvd-CVE-2025-48595.html`
- `artifacts/nvd-CVE-2025-3277.html`
- `artifacts/nvd-CVE-2025-6965.html`
- `artifacts/sqlite-checkin-498e3f1cf57f164f.html`
- `artifacts/sqlite-checkin-5508b56fd24016c1.html`
- `artifacts/sqlite-changes.html`
- `artifacts/commit-index.csv`
- `artifacts/commit-b11607ea.decoded.diff`
- `artifacts/commit-cbebed38.decoded.diff`
- `artifacts/commit-1612b56a.decoded.diff`
- `artifacts/commit-94840642.decoded.diff`
- `artifacts/commit-aaebce3d.decoded.diff`
- `artifacts/key-hunks-index.txt`
- `artifacts/interesting-hunks-sqlite3-orig.diff`
- `artifacts/interesting-hunks-sqlite3-android.diff`

## 最終判定理由

ok とする。理由は、公開AOSPコミットから `libsqlite3` の3.44.3から3.44.5への差分を取得でき、整数オーバーフロー修正箇所をソースコードレベルで確認できたため。特に `concat_ws()` は過小確保からヒープオーバーフローへ至る条件がNVD CVE-2025-3277の説明と一致し、集約項目数問題はNVD CVE-2025-6965およびSQLite check-inの説明と一致する。
007 OK

CVE-2025-48615

007-ok-media-button-receiver-persistence-desync

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-433250316
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-48615 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

判定: ok。

CVE-2025-48615 は Framework の MediaButtonReceiverHolder.java における Media Button Receiver 永続化処理の入力長検証不足だった。アプリが MediaSession API で指定する media button receiver の ComponentName が、Settings.Secure.MEDIA_BUTTON_RECEIVER に flattenToString() 形式で保存されるにもかかわらず、修正前はコンポーネント名の長さに上限がなかった。

根本原因は、通常アプリから到達できる MediaSession.setMediaButtonReceiver(PendingIntent) / MediaSession.setMediaButtonBroadcastReceiver(ComponentName) の入力が、system_server 内で永続化される設定値になる境界で、リソース消費を制限していなかったこと。特に SettingsState には1文字列 32768 文字の上限があり、過大な保存値では IllegalArgumentException が発生し得るが、MediaSessionService 側は永続化の成否とメモリ上の mLastMediaButtonReceiverHolder の整合性を保証していなかった。

原因

・ComponentName はアプリ由来の入力だが、flattenToString() されて system_server 管理の永続設定に保存される。
・MediaButtonReceiverHolder は永続化フォーマットのサイズ上限を持っていなかった。
・SettingsState には MAX_LENGTH_PER_STRING = 32768 と package別メモリ上限があり、過大な値は例外や保存失敗につながる。
・Settings.Secure.putString() は RemoteException だけを捕捉し、provider側の IllegalArgumentException / IllegalStateException は通常の失敗値として処理しない。
・MediaSessionService.rememberMediaButtonReceiverLocked() は Settings.Secure.putString() の戻り値を見ず、mLastMediaButtonReceiverHolder を先に更新する。
・1本目の修正後も、直接 ComponentName を受け取る setMediaButtonBroadcastReceiver() 経路が残っていた。

どこから特定したか

解析したコミット: ・a5795fc0cf1f21da88cf05ad06610d3653d1be0e
- 件名: Check length of MBR component name properties
- 変更: MediaButtonReceiverHolder.getComponentName(PendingIntent, int) で、PendingIntent から解決した target component の長さを MAX_COMPONENT_NAME_LENGTH = 1024 以下に制限。
- 保存差分: artifacts/a5795fc0.diff
・bb15e7f14f638ead9bfc57374e90f9f108f3a5e6
- 件名: MediaSession: Enforce m…

パッチ解析: 修正前の MediaButtonReceiverHolder は、media button receiver を次の形式で永続化していた。

``java
return String.join(COMPONENT_NAME_USER_ID_DELIM,
mComponentName.flattenToString(),
String.valueOf(mUserId),
String.valueOf(mComponentType));
`

保存した付帯ファイル: ・artifacts/ASB-A-433250316.json: Android OSV レコード
・artifacts/bulletin-2026-06-01.html: Android Security Bulletin
・artifact…

validated.md を表示
# CVE-2025-48615 検証結果

## 結論

判定: **ok**。

CVE-2025-48615 は Framework の `MediaButtonReceiverHolder.java` における Media Button Receiver 永続化処理の入力長検証不足だった。アプリが `MediaSession` API で指定する media button receiver の `ComponentName` が、`Settings.Secure.MEDIA_BUTTON_RECEIVER` に `flattenToString()` 形式で保存されるにもかかわらず、修正前はコンポーネント名の長さに上限がなかった。

根本原因は、通常アプリから到達できる `MediaSession.setMediaButtonReceiver(PendingIntent)` / `MediaSession.setMediaButtonBroadcastReceiver(ComponentName)` の入力が、system_server 内で永続化される設定値になる境界で、リソース消費を制限していなかったこと。特に `SettingsState` には1文字列 `32768` 文字の上限があり、過大な保存値では `IllegalArgumentException` が発生し得るが、`MediaSessionService` 側は永続化の成否とメモリ上の `mLastMediaButtonReceiverHolder` の整合性を保証していなかった。

パッチは `MAX_COMPONENT_NAME_LENGTH = 1024` を導入し、永続化される `ComponentName` の `packageName + "/" + className` 相当の長さを上限以下に制限する。公開ソース差分と OSV の説明から、脆弱性の型、影響するAPI経路、根本原因を特定できたため ok とする。

## 基本情報

- CVE: `CVE-2025-48615`
- Reference: `A-433250316`
- Component: `Framework`
- Type: `EoP`
- Severity: `High`
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://storage.googleapis.com/android-osv/ASB-A-433250316.json
- Updated AOSP versions: Android 14, 15, 16, 16-qpr2
- Bulletin links:
  - https://android.googlesource.com/platform/frameworks/base/+/a5795fc0cf1f21da88cf05ad06610d3653d1be0e
  - https://android.googlesource.com/platform/frameworks/base/+/bb15e7f14f638ead9bfc57374e90f9f108f3a5e6

OSV の詳細説明は「`getComponentName` において、resource exhaustion により永続化の desync が起き得る。その結果、追加権限なし・ユーザー操作なしで local EoP につながる」という内容だった。

## 解析したコミット

- `a5795fc0cf1f21da88cf05ad06610d3653d1be0e`
  - 件名: `Check length of MBR component name properties`
  - 変更: `MediaButtonReceiverHolder.getComponentName(PendingIntent, int)` で、PendingIntent から解決した target component の長さを `MAX_COMPONENT_NAME_LENGTH = 1024` 以下に制限。
  - 保存差分: `artifacts/a5795fc0.diff`
- `bb15e7f14f638ead9bfc57374e90f9f108f3a5e6`
  - 件名: `MediaSession: Enforce max name length on broadcast receivers too`
  - 変更: 1本目の修正が `setMediaButtonReceiver(PendingIntent)` 経路だけを見ており、`setMediaButtonBroadcastReceiver(ComponentName)` 経路が漏れていたため、`create(int userId, ComponentName broadcastReceiver)` にも同じ長さ制限を追加。
  - 保存差分: `artifacts/bb15e7f1.diff`
- OSV上のバージョン別公開コミット:
  - `9062dd861d49627405804fcc9bb50fdae3701aa2`: 17-next向けの1本目。`artifacts/9062dd86.diff`
  - `d09400d72573c2e6124ae28dd9bb68139c9598a5`: 17-next向けの2本目。`artifacts/d09400d7.diff`
  - `dc3e39c1b5fa962c6f4dfa0d5855d6c3f0c33a1f`: Android 14向けの1本目。`artifacts/dc3e39c1.diff`
  - `013bb57034ee44eb4bcaf6e808732b6f1eb780b0`: Android 14向けの2本目。`artifacts/013bb570.diff`

OSVには Android 15/16/16-qpr2 用のコミットも列挙されているが、一部は `android.googlesource.com` で404だった。公開されている差分はいずれも同じ `MediaButtonReceiverHolder.java` の長さ制限追加で、bulletin直リンク2本と意味は一致する。

## パッチ解析

修正前の `MediaButtonReceiverHolder` は、media button receiver を次の形式で永続化していた。

```java
return String.join(COMPONENT_NAME_USER_ID_DELIM,
        mComponentName.flattenToString(),
        String.valueOf(mUserId),
        String.valueOf(mComponentType));
```

これは `MediaSessionService.rememberMediaButtonReceiverLocked()` から `Settings.Secure` の `media_button_receiver` に保存される。起動時には `FullUserRecord` がこの値を読み、`MediaButtonReceiverHolder.unflattenFromString()` で復元する。

1本目の修正では、PendingIntent から receiver/activity/service の `ComponentInfo` を解決した後、次の検査を追加した。

```java
int componentNameLength =
        componentInfo.packageName.length() + componentInfo.name.length() + 1;
if (componentNameLength > MAX_COMPONENT_NAME_LENGTH) {
    continue;
}
```

2本目の修正では、このロジックを `componentNameTooLong(ComponentName)` にまとめたうえで、直接 `ComponentName` を受け取る broadcast receiver 経路にも適用した。

```java
public static MediaButtonReceiverHolder create(int userId, ComponentName broadcastReceiver) {
    if (componentNameTooLong(broadcastReceiver)) {
        throw new IllegalArgumentException("receiver name too long");
    }
    return new MediaButtonReceiverHolder(userId, null, broadcastReceiver,
            COMPONENT_TYPE_BROADCAST);
}
```

この2本目が重要で、コミットメッセージにも「前の変更は `MediaSession.setMediaButtonReceiver(PendingIntent)` だけを検査し、`MediaSession.setMediaButtonBroadcastReceiver(ComponentName)` を検査していなかった」と明記されている。

## 脆弱性が起きる状況

1. ローカルアプリが `MediaSession` を作成する。
2. アプリが `setMediaButtonReceiver(PendingIntent)` または `setMediaButtonBroadcastReceiver(ComponentName)` で、自分のパッケージに属する非常に長い receiver/component 名を指定する。
3. system_server 側の `MediaSessionRecord` が `MediaButtonReceiverHolder` を作成し、`MediaSessionService.onMediaButtonReceiverChanged()` 経由で最後の media button receiver として記憶する。
4. `rememberMediaButtonReceiverLocked()` が `mLastMediaButtonReceiverHolder.flattenToString()` を `Settings.Secure.MEDIA_BUTTON_RECEIVER` に保存する。
5. 修正前はこの保存値の長さを `MediaButtonReceiverHolder` 側で制限していないため、SettingsProvider の文字列長上限やリソース制限に到達し得る。
6. その結果、メモリ上の最後の receiver と永続化された receiver がずれ、再起動後またはセッション復元時の media button routing が意図しない古い状態を参照し得る。

Media button receiver は、セッションが停止した後や起動後にもハードウェア/システムのメディアキーイベントを配送するための Framework 管理状態である。通常アプリがこの永続状態をリソース枯渇で壊せることが、追加権限なしの local EoP と評価されたと考えられる。

## 根本原因

- `ComponentName` はアプリ由来の入力だが、`flattenToString()` されて system_server 管理の永続設定に保存される。
- `MediaButtonReceiverHolder` は永続化フォーマットのサイズ上限を持っていなかった。
- `SettingsState` には `MAX_LENGTH_PER_STRING = 32768` と package別メモリ上限があり、過大な値は例外や保存失敗につながる。
- `Settings.Secure.putString()` は `RemoteException` だけを捕捉し、provider側の `IllegalArgumentException` / `IllegalStateException` は通常の失敗値として処理しない。
- `MediaSessionService.rememberMediaButtonReceiverLocked()` は `Settings.Secure.putString()` の戻り値を見ず、`mLastMediaButtonReceiverHolder` を先に更新する。
- 1本目の修正後も、直接 `ComponentName` を受け取る `setMediaButtonBroadcastReceiver()` 経路が残っていた。

## 面白い点・調査メモ

- 1本目の commit message には `Test: Can't be tested on main as PackageManager prevents it` とある。mainline側では PackageManager が長すぎる component を防ぐ可能性があるが、対象リリースブランチでは Framework 側でも防御が必要だったことが読み取れる。
- 2本目の commit message の参照番号 `[1]` と `[2]` はどちらも `setMediaButtonBroadcastReceiver(ComponentName)` のURLになっており、おそらく `[1]` は `setMediaButtonReceiver(PendingIntent)` を指すつもりだった誤記。
- `MediaSessionRecord.setMediaButtonBroadcastReceiver()` は receiver package が session package と一致すること、component が存在することを確認している。しかし「存在するが極端に長い名前」という条件は旧コードでは拒否していなかった。
- `Settings.Secure.MEDIA_BUTTON_RECEIVER` は `Settings.java` では private secure setting に分類されており、通常アプリが直接書く設定ではない。問題は直接書き込み権限ではなく、通常API経由で system_server に過大な保存値を書かせられる点にある。

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

- `artifacts/ASB-A-433250316.json`: Android OSV レコード
- `artifacts/bulletin-2026-06-01.html`: Android Security Bulletin
- `artifacts/a5795fc0.diff`, `artifacts/a5795fc0.commit.clean.json`
- `artifacts/bb15e7f1.diff`, `artifacts/bb15e7f1.commit.clean.json`
- `artifacts/9062dd86.diff`, `artifacts/9062dd86.commit.json`
- `artifacts/d09400d7.diff`, `artifacts/d09400d7.commit.json`
- `artifacts/dc3e39c1.diff`, `artifacts/dc3e39c1.commit.json`
- `artifacts/013bb570.diff`, `artifacts/013bb570.commit.json`
- `artifacts/MediaButtonReceiverHolder.before_a5795.java`
- `artifacts/MediaButtonReceiverHolder.after_a5795.java`
- `artifacts/MediaButtonReceiverHolder.before_bb15.java`
- `artifacts/MediaButtonReceiverHolder.after_bb15.java`
- `artifacts/MediaSession.java`
- `artifacts/MediaSessionRecord.java`
- `artifacts/MediaSessionService.java`
- `artifacts/Settings.java`
- `artifacts/SettingsProvider.java`
- `artifacts/SettingsState.java`
- `artifacts/analysis-notes.md`
008 OK

CVE-2025-48649

008-ok-self-data-clear-permission-restore-eop

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-339109116
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-48649 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

判定: ok。

この CVE は、通常アプリが自分自身に対して呼べる ActivityManager.clearApplicationUserData() と、特権主体が実行する「runtime permission reset 後に default/role 由来の事前付与 permission を復元する」処理が同じ経路になっていたことによる Framework EoP だった。

修正前は、アプリが自分のデータを削除すると ActivityManagerService が「自分の UID のデータ削除なので許可」と判定し、そのまま PackageManagerService.clearApplicationUserData() へ進む。そこで PermissionManagerServiceImpl.resetRuntimePermissions() が呼ばれ、FLAG_PERMISSION_GRANTED_BY_DEFAULT または FLAG_PERMISSION_GRANTED_BY_ROLE が付いた runtime permission を再 grant していた。つまり、ユーザーが一度拒否・取り消し・固定した permission でも、default grant または role grant の履歴フラグが残っていれば、アプリ自身がデータ削除をトリガーして RUNTIME_GRANTED を復活させられる。

原因

根本原因は、同じ「アプリデータ削除」操作の中に、権限モデル上は別主体であるべき2種類の意味を混在させていたこと。

・通常アプリに許される操作: 自分自身のアプリデータを削除する。
・特権主体だけに許されるべき操作: permission reset 後に default/role/pregrant permission を復元し、ユーザー選択を再初期化する。

修正前の ActivityManagerService は自己 UID であれば前者として許可したが、後段の PackageManagerService / PermissionManagerService は常に後者まで実行した。permission reset 実装側も「なぜ reset しているのか」を受け取る引数がなく、default/role grant の復元を無条件に行っていた。

このため、ユーザーの runtime permission 選択がアプリ自身によって実質的に上書き可能になっていた。

どこから特定したか

解析した commit / diff: 主に以下を解析した。

保存した付帯ファイル: ・ASB-A-339109116.json: OSV レコード
・7b9a906980a34008cb7e3b93c5ba1d84a2cfaefc.commit.json
・7b9a906980a34008cb7e3b93c5ba1d84a2cfaefc.diff
・8dba23c13100882f37d3792b5e0b43dc061f9d16.commit.json
・8dba23c13100882f37d3792b5e0b43dc061f9d16.diff
・23da448adbb0bdfc2449009fa1c64f019c6c0c9e.commit.json
・23da448adbb0bdfc2449009fa1c64f019c6c0c9e.diff
・sources/: 8dba... の親/修正…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://storage.googleapis.com/android-osv/ASB-A-339109116.json / https://android.googlesource.com/platform/frameworks/base/+/7b9a906980a34008cb7e3b93c5ba1d84a2cfaefc / https://android.googlesource.com/platform/frameworks/base/+/8dba23c13100882f37d3792b5e0b43dc061f9d16

validated.md を表示
# CVE-2025-48649 検証結果

## 結論

判定: **ok**。

この CVE は、通常アプリが自分自身に対して呼べる `ActivityManager.clearApplicationUserData()` と、特権主体が実行する「runtime permission reset 後に default/role 由来の事前付与 permission を復元する」処理が同じ経路になっていたことによる Framework EoP だった。

修正前は、アプリが自分のデータを削除すると `ActivityManagerService` が「自分の UID のデータ削除なので許可」と判定し、そのまま `PackageManagerService.clearApplicationUserData()` へ進む。そこで `PermissionManagerServiceImpl.resetRuntimePermissions()` が呼ばれ、`FLAG_PERMISSION_GRANTED_BY_DEFAULT` または `FLAG_PERMISSION_GRANTED_BY_ROLE` が付いた runtime permission を再 grant していた。つまり、ユーザーが一度拒否・取り消し・固定した permission でも、default grant または role grant の履歴フラグが残っていれば、アプリ自身がデータ削除をトリガーして `RUNTIME_GRANTED` を復活させられる。

パッチは `restorePregrantedPermissions` / `restorePregrants` という boolean を API 経路全体に追加し、自己データ削除では `false` を渡すようにした。さらに、`restorePregrantedPermissions == true` の操作は `CLEAR_APP_USER_DATA` 権限を持つ呼び出し元だけに限定した。これにより、通常アプリは自分のデータを消すことはできるが、ユーザー選択を上書きして事前付与 permission を復元することはできなくなった。

## 基本情報

- CVE: `CVE-2025-48649`
- Reference: `A-339109116`
- Component: `Framework`
- Type: `EoP`
- Severity: `High`
- Android Security Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://storage.googleapis.com/android-osv/ASB-A-339109116.json
- OSV details: `In multiple locations, there is a possible way to reset user-selected permissions selections due to a permissions bypass.`
- Updated AOSP versions: Android 14, 15, 16, 16-qpr2

## 解析した commit / diff

主に以下を解析した。

- `7b9a906980a34008cb7e3b93c5ba1d84a2cfaefc`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/7b9a906980a34008cb7e3b93c5ba1d84a2cfaefc
  - 件名: `Apps clearing self data shouldn't get permissions restored`
  - 親: `b88956f3198d591897fd81191b71b001d12e2c19`
  - 保存diff: `7b9a906980a34008cb7e3b93c5ba1d84a2cfaefc.diff`
- `8dba23c13100882f37d3792b5e0b43dc061f9d16`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/8dba23c13100882f37d3792b5e0b43dc061f9d16
  - 件名: `Apps clearing self data shouldn't get permissions restored`
  - 親: `1938cc12684013aa9e8fa0125eb82a4ba16b48f7`
  - 保存diff: `8dba23c13100882f37d3792b5e0b43dc061f9d16.diff`
- `23da448adbb0bdfc2449009fa1c64f019c6c0c9e`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/23da448adbb0bdfc2449009fa1c64f019c6c0c9e
  - 件名: `RESTRICT AUTOMERGE Apps clearing self data shouldn't get permissions restored`
  - 親: `420be2e23e37e13ed357387a60451f4ecfadfb65`
  - 保存diff: `23da448adbb0bdfc2449009fa1c64f019c6c0c9e.diff`

OSV には `8bc8cd7f43218d5b9aeb61010a3131531795caf5`, `ab870f12f148feef86c5b5057ce3014cdd23cb84`, `e14f875f6b56dd1d599bfae46efd4b6350e2ef76` も fix として列挙されていたが、調査時点では googlesource から直接取得できなかった。取得できた3本はいずれも同じ修正意図で、ブランチ差により `PermissionManagerServiceImpl.java` の有無などが異なる。

## パッチ内容

### 1. 自己データ削除は permission restore なしに変更

修正前の `ActivityManager.clearApplicationUserData()` は、引数なしの公開APIでも hidden API と同じ `clearApplicationUserData(packageName, observer)` に流れていた。

```java
public boolean clearApplicationUserData() {
    return clearApplicationUserData(mContext.getPackageName(), null);
}
```

修正後は内部 helper に `restorePregrantedPermissions` が追加され、引数なしの公開APIは `false` を渡す。

```java
public boolean clearApplicationUserData() {
    return clearApplicationUserData(mContext.getPackageName(), null, false);
}
```

`false` の場合は新しい Binder API `clearApplicationUserDataWithoutPermissionReset()` に向かう。

### 2. permission restore を伴う操作は `CLEAR_APP_USER_DATA` 必須に変更

修正前の `ActivityManagerService` は、自分の UID の package であれば `CLEAR_APP_USER_DATA` なしで許可していた。

```java
permitted = (applicationInfo != null && applicationInfo.uid == uid)
        || checkComponentPermission(CLEAR_APP_USER_DATA, ...);
```

修正後は、自己 UID で許されるのは `restorePregrantedPermissions == false` の場合だけになった。

```java
permitted = (applicationInfo != null && applicationInfo.uid == uid
        && !restorePregrantedPermissions)
        || checkComponentPermission(CLEAR_APP_USER_DATA, ...);
```

これにより、通常アプリが自分のデータを消す経路と、Settings や system component が permission pregrant を含めてリセットする経路が分離された。

### 3. permission reset 実装に `restorePregrants` が追加

修正前の `PermissionManagerServiceImpl.resetRuntimePermissionsInternal()` は、default grant / role grant のフラグが残っている runtime permission を常に再 grant していた。

```java
if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0
        || (oldFlags & FLAG_PERMISSION_GRANTED_BY_ROLE) != 0) {
    grantRuntimePermissionInternal(packageName, permName, false,
            Process.SYSTEM_UID, userId, delayingPermCallback);
}
```

修正後は `restorePregrantedPermissions` が true の場合だけ再 grant する。

```java
if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0
        || (oldFlags & FLAG_PERMISSION_GRANTED_BY_ROLE) != 0) {
    if (restorePregrantedPermissions) {
        grantRuntimePermissionInternal(packageName, permName, false,
                Process.SYSTEM_UID, userId, delayingPermCallback);
    }
}
```

新 permission stack 側の `AppIdPermissionPolicy.kt` でも同様に、`ROLE` / `PREGRANT` フラグがある場合に `RUNTIME_GRANTED` を戻す処理が `restorePregrants` で条件化された。

```kotlin
if (isSystemOrInstalled && newFlags.hasAnyBit(PermissionFlags.ROLE or PermissionFlags.PREGRANT)) {
    if (restorePregrants) newFlags or PermissionFlags.RUNTIME_GRANTED else newFlags
}
```

## 脆弱性が起きる状況

成立条件は次の通り。

1. 対象アプリが runtime permission を要求している。
2. その permission が default grant または role grant として事前付与され得るため、permission state に `GRANTED_BY_DEFAULT` / `GRANTED_BY_ROLE`、または新stackの `PREGRANT` / `ROLE` が残っている。
3. ユーザーがその permission を拒否、取り消し、またはユーザー選択で変更する。
4. アプリが `ActivityManager.clearApplicationUserData()` を自分自身に対して呼ぶ。
5. 修正前は自己 UID のデータ削除として許可され、`PackageManagerService.clearApplicationUserDataLIF()` で `resetRuntimePermissions(pkg, userId)` が実行される。
6. `resetRuntimePermissionsInternal()` がユーザー選択フラグをクリアした後、default/role 由来の permission を再 grant する。
7. 結果として、ユーザーが選択した拒否状態がリセットされ、アプリが runtime permission を再取得できる。

ユーザー操作なしで悪用可能という OSV の説明は、アプリ自身が API を呼べばよい、という意味で説明できる。実際の攻撃ではアプリデータが消える副作用はあるが、認可境界としては「ユーザーが拒否した runtime permission をアプリ自身が復元できる」ため EoP になる。

## 根本原因

根本原因は、同じ「アプリデータ削除」操作の中に、権限モデル上は別主体であるべき2種類の意味を混在させていたこと。

- 通常アプリに許される操作: 自分自身のアプリデータを削除する。
- 特権主体だけに許されるべき操作: permission reset 後に default/role/pregrant permission を復元し、ユーザー選択を再初期化する。

修正前の `ActivityManagerService` は自己 UID であれば前者として許可したが、後段の `PackageManagerService` / `PermissionManagerService` は常に後者まで実行した。permission reset 実装側も「なぜ reset しているのか」を受け取る引数がなく、default/role grant の復元を無条件に行っていた。

このため、ユーザーの runtime permission 選択がアプリ自身によって実質的に上書き可能になっていた。

## 面白い点・調査メモ

- commit message は短いが、修正範囲は `ActivityManager`, `IActivityManager`, `IPackageManager`, `PackageManagerService`, 旧/新 permission stack にまたがる。単なる permission service の修正ではなく、Binder API の意味を分ける修正だった。
- public self API の `ActivityManager.clearApplicationUserData()` は、ドキュメント上「runtime permissions を revoke する」と書かれている。しかし旧実装では pregrant/role の場合に revoke ではなく grant 復元まで起き得た。
- hidden の `ActivityManager.clearApplicationUserData(String, observer)` と `PackageManager.clearApplicationUserData()` は従来通り privileged/system 用の挙動を維持するため、`restorePregrantedPermissions=true` が残されている。
- `ActivityManagerService` では `restorePregrantedPermissions=true` の自己 UID 呼び出しを拒否する条件が追加されている。これは Binder API を直接叩く通常アプリが `true` を指定して迂回することを防ぐために重要。
- OSV の Vanir signature は `ActivityManagerService.clearApplicationUserData`, `PackageManagerService.clearApplicationUserData`, `PermissionManagerServiceImpl.resetRuntimePermissionsInternal`, `AppIdPermissionPolicy.resetRuntimePermissions` などを指しており、今回のデータフローと一致した。

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

- `ASB-A-339109116.json`: OSV レコード
- `7b9a906980a34008cb7e3b93c5ba1d84a2cfaefc.commit.json`
- `7b9a906980a34008cb7e3b93c5ba1d84a2cfaefc.diff`
- `8dba23c13100882f37d3792b5e0b43dc061f9d16.commit.json`
- `8dba23c13100882f37d3792b5e0b43dc061f9d16.diff`
- `23da448adbb0bdfc2449009fa1c64f019c6c0c9e.commit.json`
- `23da448adbb0bdfc2449009fa1c64f019c6c0c9e.diff`
- `sources/`: `8dba...` の親/修正後から取得した主要 before/after ソース
- `sources_7b9a/`: `7b9a...` の親/修正後から取得した `PermissionManagerServiceImpl` 周辺 before/after ソース
- `artifacts/manifest.md`: 保存物、OSV fixes、commit metadata の一覧
009 OK

CVE-2025-48652

009-ok-packageinstaller-intent-install-mdm-bypass

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions15, 16, 16-qpr2
ReferencesA-452042097
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-48652 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

特定できた。CVE-2025-48652 は Android Framework の PackageInstaller における intent 経由インストールの信頼元判定ミスで、ACTION_VIEW または ACTION_INSTALL_PACKAGE で起動されたインストール要求が、呼び出し元に android.permission.INSTALL_PACKAGES があるだけで「trusted source」と扱われていた。その結果、MDM/DevicePolicyManager が設定する unknown source 系インストール制限を迂回できる。

フォルダは ok としてよい。公開AOSPソースとパッチから、脆弱な条件、根本原因、修正内容を説明できる。

原因

根本原因は、異なる意味の「信頼」を単一の isTrustedSource に混ぜたこと。

・PackageInstaller session APIを使う権限付きインストーラは、INSTALL_PACKAGES によりunknown sourceチェックをスキップしてよい。
・しかし ACTION_VIEW / ACTION_INSTALL_PACKAGE は、PackageInstaller UIに「外部ソースからAPKを開かせる」intentインストール経路であり、MDMのunknown source制限とAppOps確認の対象にすべき。
・旧実装は INSTALL_PACKAGES の有無だけで isTrustedSource=true にしていたため、intent経路まで信頼済みに昇格した。

この isTrustedSource は以下の2つを短絡していた。

どこから特定したか

解析したコミット: BulletinのA-452042097から次の2コミットへ辿った。

保存した付帯ファイル: ・artifacts/ASB-A-452042097.json
・artifacts/4dc009cd.commit.json
・artifacts/4dc009cd.diff
・artifacts/a37dfe71.commit.json
・artifacts/a37dfe71.diff
・artifacts/InstallRepository.7b9a9069.kt
・artifacts/InstallRepository.4dc009cd.kt
・artifacts/InstallRepository.a37dfe71.kt
・artifacts/InstallStart.7b9a9069.java
・artifacts/InstallStart.4dc009cd.java
・artifacts/Ins…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://osv.dev/vulnerability/ASB-A-452042097 / https://android.googlesource.com/platform/frameworks/base/+/4dc009cd724cc1cac5202737a36fd99a36817fef / https://android.googlesource.com/platform/frameworks/base/+/a37dfe713785cf6668e37b2db51ddd0117d000fd

validated.md を表示
# CVE-2025-48652 検証結果

## 結論

特定できた。CVE-2025-48652 は Android Framework の PackageInstaller における intent 経由インストールの信頼元判定ミスで、`ACTION_VIEW` または `ACTION_INSTALL_PACKAGE` で起動されたインストール要求が、呼び出し元に `android.permission.INSTALL_PACKAGES` があるだけで「trusted source」と扱われていた。その結果、MDM/DevicePolicyManager が設定する unknown source 系インストール制限を迂回できる。

フォルダは `ok` としてよい。公開AOSPソースとパッチから、脆弱な条件、根本原因、修正内容を説明できる。

## 確認したメタデータ

- CVE: CVE-2025-48652
- 参照ID: A-452042097
- Component/Subcomponent: Framework / PackageInstaller
- 種別/深刻度: EoP / High
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV URL: https://osv.dev/vulnerability/ASB-A-452042097
- OSV説明: `performPreInstallChecks` in `InstallRepository.kt` のlogic errorによりMDM policyをbypass可能。追加実行権限とユーザー操作は不要。

## 解析したコミット

BulletinのA-452042097から次の2コミットへ辿った。

- `4dc009cd724cc1cac5202737a36fd99a36817fef`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/4dc009cd724cc1cac5202737a36fd99a36817fef
  - 件名: `Reapply "[PM] Check unknown sources user restriction for intent installation"`
  - 変更ファイル: `packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java`, `packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt`
  - 内容: MDMのunknown source user restrictionをスキップしてよい条件を、PackageInstaller API経由か privileged known source に限定した。
- `a37dfe713785cf6668e37b2db51ddd0117d000fd`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/a37dfe713785cf6668e37b2db51ddd0117d000fd
  - 件名: `[PM] Check unknown sources for intent installation`
  - 変更ファイル: 同上
  - 内容: 同じ限定条件を `isTrustedSource` 自体に反映し、DevicePolicyだけでなくAppOps/`REQUEST_INSTALL_PACKAGES` 側にも効くようにした。

OSVに記録されているバックポート修正は `artifacts/fixes-index.tsv` に保存した。15/16/16-qpr2/17-next にそれぞれ2コミットずつ存在する。

## 脆弱性の発生条件

旧実装では `InstallRepository.performPreInstallChecks()` が次のように `isTrustedSource` を決めていた。

```kotlin
return isPrivilegedAndKnown || isInstallPkgPermissionGranted
```

ここで `isInstallPkgPermissionGranted` は呼び出し元UIDに `Manifest.permission.INSTALL_PACKAGES` が付与されているかだけを見る。intentのactionが `ACTION_VIEW` / `ACTION_INSTALL_PACKAGE` かどうかは見ていない。

そのため、次の条件が揃うと問題になる。

- MDM/Profile Owner/Device Owner が `UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES` または `DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY` を設定している。
- `INSTALL_PACKAGES` を持つアプリが、PackageInstaller session APIではなく `ACTION_VIEW` または `ACTION_INSTALL_PACKAGE` intentでAPKインストールUIを起動する。
- 呼び出し元が privileged app + `Intent.EXTRA_NOT_UNKNOWN_SOURCE=true` という正当な既知ソース条件ではない。

この場合、本来は「intent経由のunknown sourceインストール」としてMDM制限およびAppOps `OP_REQUEST_INSTALL_PACKAGES` を確認すべきだが、旧実装は `isTrustedSource=true` として扱う。

## 根本原因

根本原因は、異なる意味の「信頼」を単一の `isTrustedSource` に混ぜたこと。

- PackageInstaller session APIを使う権限付きインストーラは、`INSTALL_PACKAGES` によりunknown sourceチェックをスキップしてよい。
- しかし `ACTION_VIEW` / `ACTION_INSTALL_PACKAGE` は、PackageInstaller UIに「外部ソースからAPKを開かせる」intentインストール経路であり、MDMのunknown source制限とAppOps確認の対象にすべき。
- 旧実装は `INSTALL_PACKAGES` の有無だけで `isTrustedSource=true` にしていたため、intent経路まで信頼済みに昇格した。

この `isTrustedSource` は以下の2つを短絡していた。

- `getDevicePolicyRestrictions(isTrustedSource)`: trueの場合、`DISALLOW_INSTALL_APPS` だけを見て、`DISALLOW_INSTALL_UNKNOWN_SOURCES` と `DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY` を確認しない。
- `requestUserConfirmation()`: trueの場合、`handleUnknownSources()` を呼ばず、`REQUEST_INSTALL_PACKAGES` に対応するAppOpsを確認しない。

## パッチの意味

最終修正後は次の判定になった。

```kotlin
val isIntentInstall =
    Intent.ACTION_VIEW == intent.action ||
    Intent.ACTION_INSTALL_PACKAGE == intent.action

isTrustedSource =
    (!isIntentInstall && isInstallPkgPermissionGranted) || isPrivilegedAndKnown
```

これにより、`INSTALL_PACKAGES` 権限だけでunknown source制限を迂回できるのはPackageInstaller API経由の非intentインストールに限定された。intent経由では `INSTALL_PACKAGES` があっても `isTrustedSource=false` になり、MDM制限とAppOps確認が走る。

privileged app が `EXTRA_NOT_UNKNOWN_SOURCE=true` を付けるケースは、引き続き既知ソースとして扱われる。これはコメント上も意図された例外である。

## 面白い点・調査メモ

- `4dc009cd` は「Reapply」となっており、過去に `29962260bd043c197e411b690e862a318b31bae5` をrevertした後に修正して再投入したものだった。
- `4dc009cd` だけを見ると、`getDevicePolicyRestrictions()` には限定条件が入るが、`isTrustedSource` 変数自体はまだ `isPrivilegedAndKnown || isInstallPkgPermissionGranted` のままだった。このため `requestUserConfirmation()` のAppOpsスキップは残る。直後の `a37dfe71` が `isTrustedSource` そのものを修正しており、こちらまで含めて完全な修正と判断した。
- OSVのdetailsは `InstallRepository.kt` を名指ししているが、同じロジックは旧UI側の `InstallStart.java` にもあり、両方がパッチされている。
- コミットメッセージのテストは `CtsDevicePolicyManagerTestCases:MixedProfileOwnerTest#testPackageInstallUserRestrictions` と `MixedManagedProfileOwnerTest#testPackageInstallUserRestrictions`、およびPackageInstaller intent/session CTSで、MDM制限とintent/session経路の切り分けが修正対象だったことを裏付けている。

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

- `artifacts/ASB-A-452042097.json`
- `artifacts/4dc009cd.commit.json`
- `artifacts/4dc009cd.diff`
- `artifacts/a37dfe71.commit.json`
- `artifacts/a37dfe71.diff`
- `artifacts/InstallRepository.7b9a9069.kt`
- `artifacts/InstallRepository.4dc009cd.kt`
- `artifacts/InstallRepository.a37dfe71.kt`
- `artifacts/InstallStart.7b9a9069.java`
- `artifacts/InstallStart.4dc009cd.java`
- `artifacts/InstallStart.a37dfe71.java`
- `artifacts/PackageUtil.7b9a9069.kt`
- `artifacts/PackageUtil.7b9a9069.java`
- `artifacts/fixes-index.tsv`
- `artifacts/key-hunks-and-truth-table.md`

## 判定

`009-ok-packageinstaller-intent-install-mdm-bypass` にリネームする。
010 OK

CVE-2026-0009

010-ok-photopicker-single-select-confirmation-tapjacking

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions15, 16
ReferencesA-329631990
Also listed under Google Play system updatesMediaProvider.
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0009 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

特定できた。CVE-2026-0009 は Android Photo Picker/MediaProvider の単一選択モードにおける tapjacking 型 EoP である。根本原因は、selectionLimit == 1 のときに「メディア項目を選択するタップ」と「呼び出し元アプリへURIアクセスを許可してPickerを終了する確認」を同じイベントにしていたこと。ユーザーが1枚のメディアをタップした瞬間に onMediaSelectionConfirmed() が走るため、悪意ある呼び出し元がPhoto Picker上の特定タイルへのタップを誘導/誤認させると、追加の確認なしにそのメディアURIへのアクセスを得られる。

フォルダは ok としてよい。公開AOSP差分とOSV説明から、脆弱な状態遷移、修正内容、根本原因を説明できる。

原因

根本原因は、単一選択の状態機械が「選択」と「確定」を分離していなかったこと。

multi-selectではselection barの確認操作が必要で、ユーザーは選択状態を見てから確定する。一方、single-selectでは利便性のために selection.flow の変化を最終同意として扱っていた。これにより、tapjacking耐性上重要な「タップされた対象を表示し、別操作で確定する」という境界が消えていた。

修正後は以下のように境界が戻された。

・MainActivity.listenForSelectionIfSingleSelect() を削除し、選択だけでは終了しない。
・MediaGrid.kt で単一選択でも選択済み表示を出す。
・SelectionBarFeature.kt を単一選択activity modeでも有効化する。
・SelectionImpl.toggle() で単一選択時に既存選択を新しい項目へ置換できるようにする。
・Previewからの確定は Event.MediaSelectionConfirmed に分離する。

どこから特定したか

解析したコミット: BulletinのA-329631990から次の3コミットへ辿った。

保存した付帯ファイル: ・artifacts/patch-analysis-notes.md
・artifacts/reconstructed-vulnerability.md
・artifacts/SHA256SUMS.txt

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://osv.dev/vulnerability/ASB-A-329631990 / https://www.originhq.com/research/patch-diffing-pipeline / https://android.googlesource.com/platform/packages/providers/MediaProvider/+/61808742c17acb107221fa5f0ce998532dbc0bed

validated.md を表示
# CVE-2026-0009 検証結果

## 結論

特定できた。CVE-2026-0009 は Android Photo Picker/MediaProvider の単一選択モードにおける tapjacking 型 EoP である。根本原因は、`selectionLimit == 1` のときに「メディア項目を選択するタップ」と「呼び出し元アプリへURIアクセスを許可してPickerを終了する確認」を同じイベントにしていたこと。ユーザーが1枚のメディアをタップした瞬間に `onMediaSelectionConfirmed()` が走るため、悪意ある呼び出し元がPhoto Picker上の特定タイルへのタップを誘導/誤認させると、追加の確認なしにそのメディアURIへのアクセスを得られる。

フォルダは `ok` としてよい。公開AOSP差分とOSV説明から、脆弱な状態遷移、修正内容、根本原因を説明できる。

## 確認したメタデータ

- CVE: CVE-2026-0009
- 参照ID: A-329631990
- Component/Subcomponent: Framework / MediaProvider, Photo Picker
- 種別/深刻度: EoP / High
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Bulletin上の対象: Android 15, 16
- Google Play system updates: MediaProvider
- OSV URL: https://osv.dev/vulnerability/ASB-A-329631990
- OSV説明: `multiple locations` のlogic errorによりtapjackingが可能。追加実行権限は不要で、local EoPにつながる。
- 参考にしたpatch-diffing記事: https://www.originhq.com/research/patch-diffing-pipeline

## 解析したコミット

BulletinのA-329631990から次の3コミットへ辿った。

- `61808742c17acb107221fa5f0ce998532dbc0bed`
  - URL: https://android.googlesource.com/platform/packages/providers/MediaProvider/+/61808742c17acb107221fa5f0ce998532dbc0bed
  - 件名: `Revert^2 "Fix: add confirmation step in single select mode."`
  - Bug: `329631990`
  - 変更ファイル: `MainActivity.kt`, `MediaGrid.kt`, `SelectionImpl.kt`, `SelectionBar.kt`, `SelectionBarFeature.kt`, tests
  - 内容: 単一選択時に選択フローを監視して即 `onMediaSelectionConfirmed()` する処理を削除し、単一選択でも選択状態表示とselection barを有効化した。
- `8a710e8508880a2af058ad93b58b4fe5e770be57`
  - URL: https://android.googlesource.com/platform/packages/providers/MediaProvider/+/8a710e8508880a2af058ad93b58b4fe5e770be57
  - 件名: `Fix select button in preview for single-select`
  - 内容: プレビュー画面の単一選択ボタンから `MediaSelectionConfirmed` イベントを発火し、`MainActivity` がそれを受けて確定するようにした。
- `f04605de9b68a9301e9ca59b7335cb1978cac792`
  - URL: https://android.googlesource.com/platform/packages/providers/MediaProvider/+/f04605de9b68a9301e9ca59b7335cb1978cac792
  - 件名: `feat(selection): Add size method to Selection interface`
  - 内容: `Selection.size()` を追加。主に単一選択フローとテストの補助変更。

OSVには 17-next/15/16 のブランチ別修正コミットも列挙されている。詳細は `artifacts/patch-analysis-notes.md` に保存した。

## 脆弱性の発生条件

旧実装では、Photo Pickerを単一選択で起動した場合に `MainActivity` が `listenForSelectionIfSingleSelect()` を登録していた。このcollectorは `selection.flow` を監視し、選択集合のサイズが1になった時点で `onMediaSelectionConfirmed()` を呼ぶ。

このため、次の条件で問題になる。

- 攻撃者アプリがPhoto Pickerを呼び出す。
- Pickerは `MediaStore.ACTION_PICK_IMAGES` などの単一選択、つまり `selectionLimit == 1` で動作する。
- ユーザーがPhoto Picker内のメディアタイルを1回タップする。
- そのタップが攻撃者のUI誘導、重なり、誤認などによりユーザーの明確な確定意思と切り離されている。

本来Photo Pickerはメディアアクセス権限の委譲UIなので、選択されたURIを呼び出し元へ返す前にユーザーの明示的な確認境界が必要である。しかし旧実装では単一選択だけ、最初の選択タップがそのまま確定になっていた。

## 根本原因

根本原因は、単一選択の状態機械が「選択」と「確定」を分離していなかったこと。

multi-selectではselection barの確認操作が必要で、ユーザーは選択状態を見てから確定する。一方、single-selectでは利便性のために `selection.flow` の変化を最終同意として扱っていた。これにより、tapjacking耐性上重要な「タップされた対象を表示し、別操作で確定する」という境界が消えていた。

修正後は以下のように境界が戻された。

- `MainActivity.listenForSelectionIfSingleSelect()` を削除し、選択だけでは終了しない。
- `MediaGrid.kt` で単一選択でも選択済み表示を出す。
- `SelectionBarFeature.kt` を単一選択activity modeでも有効化する。
- `SelectionImpl.toggle()` で単一選択時に既存選択を新しい項目へ置換できるようにする。
- Previewからの確定は `Event.MediaSelectionConfirmed` に分離する。

## 面白い点・調査メモ

- Bulletin上はFrameworkのHigh EoPだが、Google Play system updatesではMediaProviderに列挙されており、実体はMainline Photo Pickerの修正だった。
- `61808742c17a` は `Revert^2` で、以前 `c5d89a70...` がrevertされ、CTS修正後に再投入された履歴が見える。セキュリティ修正そのものは「add confirmation step in single select mode」というUX変更として表現されている。
- OSVの「multiple locations」は、1箇所の権限チェックではなく、UI/状態管理/preview/selection barをまとめて直す必要があったことを示している。
- OSV本文には「User interaction is not needed」とある一方で、detailsはtapjackingと説明している。今回の差分からは、攻撃者アプリがPhoto Pickerを起動し、単一選択の最初のタップをそのまま権限委譲に変える問題として再構成できる。つまり、ユーザーの通常操作を確認なしで最終同意扱いにすることが本質で、独立した二度目の確認操作は不要だった、という意味で読むのが自然。
- `8a710e850888` はCVE番号のBug IDではなく `449079350` だが、`61808742c17a` の直後に単一選択previewの確定不能回帰を直している。セキュリティ境界を「選択後に明示確定」へ変えたことで、preview側にも明示的な確定イベントが必要になったと判断した。
- ローカルshellから `android.googlesource.com` への `curl`/`git clone` はタイムアウトまたは接続リセットになったため、生diffファイルは保存できなかった。ブラウザ経由でGitiles diffを確認し、主要hunkとURLを `artifacts/patch-analysis-notes.md` に残した。

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

- `artifacts/patch-analysis-notes.md`
- `artifacts/reconstructed-vulnerability.md`
- `artifacts/SHA256SUMS.txt`

## 判定

`010-ok-photopicker-single-select-confirmation-tapjacking` にリネームする。
011 OK

CVE-2026-0046

011-ok-letterbox-trusted-system-window-tapjacking

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16
ReferencesA-443272513
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0046 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

CVE-2026-0046は、Framework WindowManagerのletterbox入力ウィンドウの所有者設定ミスに起因するtapjacking型EoPである。根本原因は、アプリを囲うletterboxが WindowManagerService.MY_UID でInputDispatcherへ登録され、既存の遮蔽タッチ防御が信頼システムウィンドウ扱いにより回避されることだった。修正はletterboxの ownerPid/ownerUid を対象アプリのsession由来に変更し、既存のInputDispatcherのUID境界・遮蔽判定を正しく働かせるものだった。

原因

根本原因は、WindowManagerがletterboxの入力用 InputWindowHandle に誤ったセキュリティ主体を設定していたこと。

修正前の Letterbox.InputInterceptor は、letterboxが特定アプリを囲むためのUIであるにもかかわらず、入力ウィンドウの ownerPid/ownerUid を WindowManagerService.MY_PID/MY_UID にしていた。これによりInputDispatcherのタッチ遮蔽判定で、letterboxが「アプリ由来の遮蔽物」ではなく「信頼されたシステムウィンドウ」に近い扱いになった。

InputDispatcher側では canBeObscuredBy() が次の条件で遮蔽物扱いを除外する。

・対象ウィンドウと遮蔽物候補のtokenが同じ。
・遮蔽物候補が不可視。
・遮蔽物候補がalpha 0かつnot touchable。
・ownerUid が同じ。コメント上も「同じUID内にはsecurity boundaryがない」としている。
・遮蔽物候補が TRUSTED_OVERLAY。
・displayが違う。

どこから特定したか

パッチ差分: Letterbox.java の InputInterceptor 初期化で、letterbox用 InputWindowHandle の所有者が変更された。

修正前:

``java
mWindowHandle.ownerPid = WindowManagerService.MY_PID;
mWindowHandle.ownerUid = WindowManagerService.MY_UID;
`

修正後:

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/frameworks/base/+/678475b0c23cd3edc527b0b21e42fbafc028ee1a

validated.md を表示
# CVE-2026-0046 検証結果

## 判定

ok: ソースコード差分から脆弱性の根本原因と悪用条件を特定できた。

タイトル案: `letterbox-trusted-system-window-tapjacking`

## 基本情報

- CVE: CVE-2026-0046
- Android Bug ID: A-443272513
- Component: Framework
- 種別: EoP
- Severity: High
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Bulletin上の対象: Android 14, 15, 16
- 公開パッチ: https://android.googlesource.com/platform/frameworks/base/+/678475b0c23cd3edc527b0b21e42fbafc028ee1a
- Commit: `678475b0c23cd3edc527b0b21e42fbafc028ee1a`
- Parent: `02fc7472ebb27fd394caafa8b87d4daead295d70`
- 変更ファイル: `services/core/java/com/android/server/wm/Letterbox.java`

## 解析に使った資料

- `artifacts/commit_678475b0.txt`: Gitilesから取得したコミット本文。
- `artifacts/Letterbox.before.java`: 親コミット版の `Letterbox.java`。
- `artifacts/Letterbox.after.java`: 修正コミット版の `Letterbox.java`。
- `artifacts/Letterbox.before_after.diff`: 親版と修正版のローカルunified diff。
- `artifacts/678475b0.diff`: 上記diffのコピー。Gitilesの `.diff` 直取得は公開URLで `NOT_FOUND` になったため、保存済みbefore/afterから再生成した。
- `artifacts/InputDispatcher.main.cpp`: `frameworks/native` の `InputDispatcher.cpp`。遮蔽タッチ判定の根拠確認用。
- `artifacts/bulletin-2026-06-01.html`: Android Security Bulletin保存版。
- `artifacts/origin-patch-diffing-pipeline.html`: 参考にしたpatch diffing pipeline記事の保存版。
- `artifacts/SHA256SUMS.txt`: 保存成果物のSHA-256。

## パッチ差分

`Letterbox.java` の `InputInterceptor` 初期化で、letterbox用 `InputWindowHandle` の所有者が変更された。

修正前:

```java
mWindowHandle.ownerPid = WindowManagerService.MY_PID;
mWindowHandle.ownerUid = WindowManagerService.MY_UID;
```

修正後:

```java
// Set owner to the app's UID to prevent tapjacking. This ensures the letterbox is not
// treated as a trusted system window for input security checks, which could be used
// to bypass obscured touch logic.
mWindowHandle.ownerPid = win.mSession.mPid;
mWindowHandle.ownerUid = win.mSession.mUid;
```

つまり、letterboxの入力ウィンドウを system_server 所有ではなく、囲っているアプリのプロセス/UID所有としてInputDispatcherへ渡す変更である。

## 脆弱性の内容

これは、画面向き変更やアスペクト比調整時に表示されるletterboxの黒帯が、入力セキュリティ上「system UID所有の信頼できるウィンドウ」として扱われていたことによるタップジャッキングである。

攻撃/問題条件は次の通り。

1. あるアプリがletterbox表示され、黒帯領域が前面に存在する。
2. ユーザーのタッチがletterboxの黒帯から「滑る」または外れる形で、下層にいる別アクティビティ/別ウィンドウへ到達する。
3. 下層のアプリから見ると、本来は別ウィンドウに覆われている状態なので、Androidの遮蔽タッチ防御によりdropまたはobscured扱いになるべきである。
4. しかし修正前のletterboxは `WindowManagerService.MY_UID`、つまりsystem UID所有として登録されていた。
5. InputDispatcherの遮蔽判定では、同一UIDのウィンドウやtrusted overlayは遮蔽物として扱われない。また、system由来の信頼ウィンドウは通常の未信頼overlayと同じ扱いにならない。
6. その結果、ユーザーが実際には下層UIを視認できない状態でも、タッチが下層アプリへ届き、tapjacking防御を回避できる。

コミット本文も同じ内容を説明しており、「Touch can slip out of the black bar of a Letterbox」「bottom layer of other activities」「Letterbox window is considered trusted system windows」と明記している。

## 根本原因

根本原因は、WindowManagerがletterboxの入力用 `InputWindowHandle` に誤ったセキュリティ主体を設定していたこと。

修正前の `Letterbox.InputInterceptor` は、letterboxが特定アプリを囲むためのUIであるにもかかわらず、入力ウィンドウの `ownerPid/ownerUid` を `WindowManagerService.MY_PID/MY_UID` にしていた。これによりInputDispatcherのタッチ遮蔽判定で、letterboxが「アプリ由来の遮蔽物」ではなく「信頼されたシステムウィンドウ」に近い扱いになった。

InputDispatcher側では `canBeObscuredBy()` が次の条件で遮蔽物扱いを除外する。

- 対象ウィンドウと遮蔽物候補のtokenが同じ。
- 遮蔽物候補が不可視。
- 遮蔽物候補がalpha 0かつnot touchable。
- `ownerUid` が同じ。コメント上も「同じUID内にはsecurity boundaryがない」としている。
- 遮蔽物候補が `TRUSTED_OVERLAY`。
- displayが違う。

その後、`computeTouchOcclusionInfoLocked()` が `BLOCK_UNTRUSTED` または不透明度しきい値超過を計算し、`isTouchTrustedLocked()` が未信頼タッチをdropする。`ownerUid` が誤ってsystem側になっていると、この防御の前提である「誰のウィンドウが誰を覆っているか」が崩れる。

修正はletterboxの所有者を `win.mSession.mPid` / `win.mSession.mUid` に変更するだけで、letterboxを囲われているアプリと同じ主体として扱わせる。これにより、下層の別UIDアプリへタッチが届こうとした場合、letterboxは遮蔽物として評価され、既存のobscured/untrusted touch logicが機能する。

## 面白い点・調査メモ

- パッチは1ファイル、実質2行の主体変更だけだが、セキュリティ境界はInputDispatcher側のUID比較に依存しているため影響が大きい。
- `Letterbox.java` には `Flags.scrollingFromLetterbox()` が有効な場合に `TYPE_APPLICATION_OVERLAY` と `InputConfig.SPY` を使い、input surfaceへ `setTrustedOverlay(..., true)` する経路もある。この経路はspy windowがtrusted overlayであることをInputDispatcherが要求するための実装に見える。今回の根本原因は、通常のletterbox入力ウィンドウ所有者がsystem_serverだった点。
- コミットの `Test: Manual` から、自動CTS/ユニットテストではなく再現手順ベースで検証された修正と思われる。
- Bulletin上ではFrameworkのHigh EoPだが、コミット本文では「remote escalation of privilege」ではなくtapjackingとして説明されている。攻撃者アプリが画面状態や下層UI配置を誘導し、ユーザー操作を見えないUIへ通すタイプの権限昇格と解釈した。

## 再現シナリオの推定

完全なPoCは作成していないが、コードとコミット本文から成立条件は説明できる。

- 攻撃者がletterbox表示されるアプリ/Activity、またはletterbox状態を誘導できるUI遷移を用意する。
- 画面回転、固定向き、互換モード、アスペクト比差などにより黒帯letterboxが表示される。
- 黒帯に見える領域の背後、またはタッチが滑って到達する位置に、別アプリの権限付与・確認・設定変更などの重要操作UIがある。
- ユーザーは黒帯または攻撃者が意図した見かけのUIを触ったつもりだが、実際のタッチは下層の別Activityへ届く。
- 修正前はletterboxがsystem UID所有のため遮蔽タッチ防御が正しく発火せず、下層UIが操作される。
- 修正後はletterboxが囲っているアプリのUIDとして登録されるため、別UIDの下層ウィンドウに対する遮蔽物として扱われ、未信頼タッチのdrop/obscured判定が機能する。

## 結論

CVE-2026-0046は、Framework WindowManagerのletterbox入力ウィンドウの所有者設定ミスに起因するtapjacking型EoPである。根本原因は、アプリを囲うletterboxが `WindowManagerService.MY_UID` でInputDispatcherへ登録され、既存の遮蔽タッチ防御が信頼システムウィンドウ扱いにより回避されることだった。修正はletterboxの `ownerPid/ownerUid` を対象アプリのsession由来に変更し、既存のInputDispatcherのUID境界・遮蔽判定を正しく働かせるものだった。
012 OK

CVE-2026-0048

012-ok-tapjacking-overlay-exit-animation

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-463364410
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0048 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

ok: ソースコード差分と OSV 詳細から、脆弱性の発生条件、根本原因、修正内容を特定できた。

タイトル案: tapjacking-overlay-exit-animation

原因

根本原因は、overlay を強制的に隠す security policy と、WindowManager の既存 animation 状態の扱いが衝突していたこと。

WindowStateAnimator.applyAnimationLocked(int transit, boolean isEntrance) は、すでに同じ entrance/exit 種別の animation が走っている場合、既存 animation を残して true を返す。

``java
if (mWin.isAnimating() && mAnimationIsEntrance == isEntrance) {
return true;
}
`

どこから特定したか

パッチ差分: 修正は services/core/java/com/android/server/wm/WindowState.java の hide(boolean doAnimation, boolean requestAnim) に入っている。

修正前:

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://osv.dev/vulnerability/ASB-A-463364410 / https://android.googlesource.com/platform/frameworks/base/+/36a774d7239923d0ef16ae5f51b87fb132e2bbb9

validated.md を表示
# CVE-2026-0048 検証結果

## 判定

ok: ソースコード差分と OSV 詳細から、脆弱性の発生条件、根本原因、修正内容を特定できた。

タイトル案: `tapjacking-overlay-exit-animation`

## 基本情報

- CVE: CVE-2026-0048
- Android Bug ID / OSV: A-463364410 / ASB-A-463364410
- Component: Framework
- Type / Severity: EoP / High
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://osv.dev/vulnerability/ASB-A-463364410
- OSV details: `WindowState.java` の `hide` で、tapjacking/overlay attack によりユーザーをだまして permission approval を行わせる可能性がある。追加権限不要、user interaction 不要と説明されている。

## 解析に使った主な資料

- `artifacts/ASB-A-463364410.json`
- `artifacts/bulletin-2026-06-01.html`
- `artifacts/36a774d7.commit.json`
- `artifacts/36a774d7.diff`
- `artifacts/WindowState.before.java`
- `artifacts/WindowState.after.java`
- `artifacts/WindowStateAnimator.after.java`
- `artifacts/WindowManagerService.after.java`
- `artifacts/WindowManager.after.java`
- `artifacts/fix-commits.tsv`
- `artifacts/fetch-notes.txt`

主解析 commit:

- https://android.googlesource.com/platform/frameworks/base/+/36a774d7239923d0ef16ae5f51b87fb132e2bbb9
- parent: `4518f78f8b34510a1329c60dc5e0b018f015a6e3`
- message: `Hide non system overlay window immediately if it is animating exit`

OSV に載っていたブランチ別 fix URL:

- 17-next: `0246ce8a4eafb042885ae212cf503285b4cd91c6`
- 15: `628b977e0ed69724c9d525d085a56d4c5240b735`
- 16: `e0fc0b9962498477378d18d7799c1339b0bdf1e5`
- 16-qpr2: `0bd3fadc1852775b9c87e6836ca56b175b179a38`
- 14: `6ca1d6b26237d3f1ae0dac23e5f4bb487b23bf93`

## パッチ差分

修正は `services/core/java/com/android/server/wm/WindowState.java` の `hide(boolean doAnimation, boolean requestAnim)` に入っている。

修正前:

```java
boolean hide(boolean doAnimation, boolean requestAnim) {
    if (doAnimation) {
        if (!mToken.okToAnimate()) {
            doAnimation = false;
        }
    }
    boolean current =
            doAnimation ? mLegacyPolicyVisibilityAfterAnim : isLegacyPolicyVisibility();
    ...
    if (doAnimation) {
        if (!mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false /* isEntrance */)) {
            doAnimation = false;
        }
    }
    mLegacyPolicyVisibilityAfterAnim = false;
    ...
    if (!doAnimation) {
        clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
        if (mSurfaceControl != null) {
            getPendingTransaction().hide(mSurfaceControl);
        }
    }
}
```

修正後:

```java
if (doAnimation) {
    if (!mToken.okToAnimate()) {
        doAnimation = false;
    }
    if (mForceHideNonSystemOverlayWindow || mHiddenWhileSuspended
            || !mAppOpVisibility || mPermanentlyHidden) {
        if (isAnimating()) {
            if (mAnimatingExit) {
                // Hide immediately if the window is playing an exit animation.
                doAnimation = false;
            }
            cancelAnimation();
        }
    }
}
```

ポイントは、policy/app-op/overlay 強制 hide のときに既存 animation を取り消し、特に exit animation 中なら `doAnimation = false` にして `LEGACY_POLICY_VISIBILITY` と `SurfaceControl` を即時 hide する点。

## 呼び出し経路

保護対象の window は `SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS` を持つ。この flag は `WindowManager.LayoutParams` で「TYPE_TOAST または SYSTEM_ALERT_WINDOW app-op が必要な application process の window を、この window が visible の間 hide する」と説明されている。

`WindowManagerService.updateNonSystemOverlayWindowsVisibilityIfNeeded(WindowState win, boolean surfaceShown)` は、保護対象 window が表示されると `mHidingNonSystemOverlayWindows` に登録し、状態が変わったときに全 window へ `setForceHideNonSystemOverlayWindowIfNeeded(shouldHideNonSystemOverlayWindow(w))` を呼ぶ。

`WindowState.setForceHideNonSystemOverlayWindowIfNeeded(true)` は、内部 system window ではない `TYPE_APPLICATION_OVERLAY` / system alert / toast 系 window に対して `mForceHideNonSystemOverlayWindow = true` を設定し、`hide(true, true)` を呼ぶ。

したがって、権限確認 UI など overlay を隠すべき system/trusted UI が表示された瞬間、既存 overlay は `WindowState.hide(true, true)` 経由で隠されるべきである。

## 根本原因

根本原因は、overlay を強制的に隠す security policy と、WindowManager の既存 animation 状態の扱いが衝突していたこと。

`WindowStateAnimator.applyAnimationLocked(int transit, boolean isEntrance)` は、すでに同じ entrance/exit 種別の animation が走っている場合、既存 animation を残して `true` を返す。

```java
if (mWin.isAnimating() && mAnimationIsEntrance == isEntrance) {
    return true;
}
```

攻撃側 overlay が長い exit animation 中にあると、保護対象 UI 表示によって `hide(true, true)` が呼ばれても、`applyAnimationLocked(TRANSIT_EXIT, false)` は新しい hide animation を開始せず、既存 exit animation をそのまま残す。`hide()` 側は `doAnimation == true` のまま進むため、`LEGACY_POLICY_VISIBILITY` の clear と `SurfaceControl.hide()` は即時実行されず、animation 完了時の `onExitAnimationDone()` まで延期される。

その結果、overlay を「今すぐ消す」べき security-sensitive なタイミングで、overlay surface が画面上に残り続ける。長い exit animation を使えば、この猶予を攻撃者が伸ばせる。

## 脆弱性の内容

攻撃シナリオ:

1. 攻撃アプリが `TYPE_APPLICATION_OVERLAY` など非システム overlay window を表示する。
2. 攻撃アプリが overlay window の削除または非表示で長い exit animation を走らせ、`mAnimatingExit == true` かつ `isAnimating() == true` の状態を作る。
3. その状態で、権限承認 UI など `SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS` を使う保護対象 window が表示される。
4. WindowManager は overlay に `setForceHideNonSystemOverlayWindowIfNeeded(true)` を呼ぶが、修正前は exit animation 中の overlay を即時 hide できない。
5. overlay が permission dialog 等の上に残り、視覚的誘導や tapjacking に使える。

EoP とされる理由は、ユーザーが本来見えるべき permission approval UI を overlay で誤認させられ、攻撃アプリに権限を与える可能性があるため。これは OSV の「trick the user into approving permissions due to a tapjacking/overlay attack」という説明とも一致する。

## 修正の意味

修正後の `hide()` は、以下の policy hide 条件で既存 animation をキャンセルする。

- `mForceHideNonSystemOverlayWindow`
- `mHiddenWhileSuspended`
- `!mAppOpVisibility`
- `mPermanentlyHidden`

さらに `mAnimatingExit` 中なら `doAnimation = false` にするため、その後の処理で即時に policy visibility が落ち、`SurfaceControl` も hide される。

これにより「overlay を隠すべき保護対象 window が表示されたのに、攻撃者制御の exit animation が終わるまで overlay が残る」という遅延が消える。

## テストから分かること

17-next の `0246ce8a.diff` には単体テスト `testForceHideExitingOverlayWindow` が追加されていた。

テストは `TYPE_APPLICATION_OVERLAY` window に `Animation_Dialog` を設定し、`mAnimatingExit = true` にして `TRANSIT_EXIT` animation を開始する。その後 `setForceHideNonSystemOverlayWindowIfNeeded(true)` を呼び、`isAnimating()` と `isVisibleByPolicy()` が両方 false になることを確認している。

これは今回の根本原因を直接表すテストで、修正前なら「まだ animating」「policy visible のまま」になり得る箇所である。

## 面白い点・調査メモ

- commit message は「hide operation will wait for the previous exit animation to be finished, which could be a long duration」と明記しており、攻撃者が長い exit animation duration を使う余地が問題の中心だった。
- 同じ `setForceHideNonSystemOverlayWindowIfNeeded` 周辺には過去に CVE-2024-34741 もあり、lock screen / screensaver 上の message content 表示に関する問題だった。今回は同じ overlay 強制 hide 機構だが、`hide()` と exit animation の race/遅延が tapjacking に繋がる別問題。
- `WindowStateAnimator.applyAnimationLocked()` の「同じ種別の animation がすでにあるならそのまま true」は通常の animation 重複回避としては自然だが、security policy hide では「true だから後で消える」と扱うと危険になる。
- `mHiddenWhileSuspended`, `!mAppOpVisibility`, `mPermanentlyHidden` も同じ即時 hide 対象に追加されているため、修正は overlay tapjacking だけでなく、policy/app-op で非表示にすべき window が animation によって残る一般問題も潰している。

## 取得失敗・制限

- `../binaries/frameworks_base_36a774d7` への AOSP clone/fetch はネットワーク遅延と切断で中断した。解析には Gitiles から個別取得した source/diff を使用した。
- `WindowSurfaceController.after.java` は該当 commit の Gitiles パスで 404 だったため空ファイルになっている。今回の根本原因解析には不要。
- `628b977e`, `e0fc0b99`, `0bd3fadc` の `^!` diff endpoint はこの実行では 404 だった。OSV JSON の fix URL は保存済み。`0246ce8a` と `6ca1d6b2` の diff は取得でき、同等の `hide()` 修正を確認した。
013 OK

CVE-2026-0055

013-ok-packageinstaller-volumeuuid-path-traversal

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-460779368
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0055 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

判定: ok

CVE-2026-0055 は、Package Installer のセッション作成処理で SessionParams.volumeUuid を UUID として検証しないまま、インストール用ステージングディレクトリのパス生成に使用していた脆弱性である。pm install-create --force-uuid ../../../data のような値を渡すと、修正前は volumeUuid がそのまま /mnt/expand/<volumeUuid>/... に連結され、.. を含むパストラバーサル入力が PackageInstallerService の内部状態とステージングパスに到達した。

パッチは INSTALL_FORCE_VOLUME_UUID の分岐で StorageManager.convert(params.volumeUuid) を呼び、null、primary_physical、system、FAT 形式 XXXX-YYYY、標準 UUID 以外を IllegalArgumentException で拒否する。これにより、../../../data のような非 UUID 文字列が後段のパス生成や永続化済みセッションに入らない。

原因

根本原因は、volumeUuid が「ストレージボリュームの識別子」という型付きデータとして扱われるべきなのに、String として受け取られ、INSTALL_FORCE_VOLUME_UUID 指定時に妥当性検証されないままパス生成に使われていたこと。

関連する修正前コードの流れは以下。

どこから特定したか

パッチ差分: 修正対象は services/core/java/com/android/server/pm/PackageInstallerService.java のみ。

修正前は、呼び出し元が INSTALL_FORCE_VOLUME_UUID を指定している場合、params.installFlags |= PackageManager.INSTALL_INTERNAL; を設定するだけで、params.volumeUuid の形式検証がなかった。

修正後は同じ分岐に以下が追加された。

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/frameworks/base/+/62ec466efd801a253a1134011bf9c0e83f1bfb1d

validated.md を表示
# CVE-2026-0055 パッチ解析結果

## 結論

判定: ok

CVE-2026-0055 は、Package Installer のセッション作成処理で `SessionParams.volumeUuid` を UUID として検証しないまま、インストール用ステージングディレクトリのパス生成に使用していた脆弱性である。`pm install-create --force-uuid ../../../data` のような値を渡すと、修正前は `volumeUuid` がそのまま `/mnt/expand/<volumeUuid>/...` に連結され、`..` を含むパストラバーサル入力が `PackageInstallerService` の内部状態とステージングパスに到達した。

パッチは `INSTALL_FORCE_VOLUME_UUID` の分岐で `StorageManager.convert(params.volumeUuid)` を呼び、`null`、`primary_physical`、`system`、FAT 形式 `XXXX-YYYY`、標準 UUID 以外を `IllegalArgumentException` で拒否する。これにより、`../../../data` のような非 UUID 文字列が後段のパス生成や永続化済みセッションに入らない。

## 確認した基本情報

- CVE: CVE-2026-0055
- Android Bug ID / Reference: A-460779368
- 追加でコミット本文に出る Bug: 393614518
- Component: Framework
- Type: EoP
- Severity: High
- Subcomponent 推定: Package Installer / PackageInstallerService
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- AOSP commit: https://android.googlesource.com/platform/frameworks/base/+/62ec466efd801a253a1134011bf9c0e83f1bfb1d
- Commit title: `Add StorageManager.convert() check earlier in the stack so the command fails early instead of crashing system later.`

## 解析に使った保存ファイル

- `commit_62ec466efd801a253a1134011bf9c0e83f1bfb1d.txt`: Gitiles のコミット本文
- `diff_62ec466efd801a253a1134011bf9c0e83f1bfb1d.patch`: Gitiles のパッチ差分
- `PackageInstallerService_before.java`: 親コミット `a8f3c0ccb472eb9c1b553ce832d374bae9d5a8aa` の対象ファイル
- `PackageInstallerService_after.java`: 修正コミット後の対象ファイル
- `PackageManagerShellCommand_after.java`: `--force-uuid` 入力経路確認用
- `PackageInstaller_after.java`: `SessionParams.volumeUuid` 確認用
- `Environment_after.java`: `volumeUuid` からデータディレクトリを作る処理確認用
- `StorageManager_after.java`: `StorageManager.convert()` の許容形式確認用
- `PackageInstallerSession_before.java`, `PackageInstallerSession_after.java`: セッション永続化と `volumeUuid` の保持確認用
- `path_calculation_examples.txt`: 問題入力で生成されるパスの計算結果
- `bulletin_CVE-2026-0055_excerpt.html`: Bulletin の該当行抜粋
- `android-security-bulletin-2026-06-01.html`: Bulletin の保存コピー

## パッチ差分

修正対象は `services/core/java/com/android/server/pm/PackageInstallerService.java` のみ。

修正前は、呼び出し元が `INSTALL_FORCE_VOLUME_UUID` を指定している場合、`params.installFlags |= PackageManager.INSTALL_INTERNAL;` を設定するだけで、`params.volumeUuid` の形式検証がなかった。

修正後は同じ分岐に以下が追加された。

```java
// Check if volumeUuid value is valid, else fail.
try {
    StorageManager.convert(params.volumeUuid);
} catch (IllegalArgumentException e) {
    throw new IllegalArgumentException("Invalid volumeUuid value in session "
            + "params: "
            + params.volumeUuid);
}
```

コミット本文には、修正後の想定エラーとして次が記録されている。

```text
java.lang.IllegalArgumentException: Invalid volumeUuid value in session params: ../../../data
    at com.android.server.pm.PackageInstallerService.createSessionInternal(...)
```

## 入力経路

`PackageManagerShellCommand` の `install-create` 系オプションには `--force-uuid` があり、この値はそのまま `SessionParams.volumeUuid` に入る。

```java
case "--force-uuid":
    sessionParams.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID;
    sessionParams.volumeUuid = getNextArg();
    if ("internal".equals(sessionParams.volumeUuid)) {
        sessionParams.volumeUuid = null;
    }
    break;
```

したがって、修正前の最小再現入力は次の形になる。

```sh
pm install-create --force-uuid ../../../data -S 1
```

この入力はコミット本文にもテスト時のエラー値として残っている。

## 根本原因

根本原因は、`volumeUuid` が「ストレージボリュームの識別子」という型付きデータとして扱われるべきなのに、`String` として受け取られ、`INSTALL_FORCE_VOLUME_UUID` 指定時に妥当性検証されないままパス生成に使われていたこと。

関連する修正前コードの流れは以下。

1. `--force-uuid` または Binder API 経由で `params.volumeUuid` を指定する。
2. `PackageInstallerService.createSessionInternal()` は `INSTALL_FORCE_VOLUME_UUID` 分岐で `INSTALL_INTERNAL` を立てるだけで、`volumeUuid` を検証しない。
3. 非 multi-package セッションでは `buildSessionDir(sessionId, params)` が呼ばれる。
4. 非 staged では `Environment.getDataAppDirectory(params.volumeUuid)`、staged/APEX では `Environment.getDataStagingDirectory(params.volumeUuid)` が使われる。
5. `Environment.getDataDirectory(volumeUuid)` は空でない `volumeUuid` を `new File("/mnt/expand/" + volumeUuid)` で扱う。

このため、`volumeUuid = "../../../data"` のような値は、UUID ではないにもかかわらず `/mnt/expand/../../../data/...` のようなパスに変換される。

## パス計算

`path_calculation_examples.txt` に保存した計算結果:

```text
../../../data => non-staged /data/app/vmdl123.tmp | staged /data/app-staging/session_123
../../data => non-staged /data/app/vmdl123.tmp | staged /data/app-staging/session_123
.. => non-staged /mnt/app/vmdl123.tmp | staged /mnt/app-staging/session_123
../../../data/system => non-staged /data/system/app/vmdl123.tmp | staged /data/system/app-staging/session_123
aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee => non-staged /mnt/expand/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/app/vmdl123.tmp | staged /mnt/expand/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/app-staging/session_123
```

面白い点として、コミット本文の `../../../data` は単にクラッシュ用の不正 UUID というだけでなく、`Environment` の実装上は `/data/app` または `/data/app-staging` に正規化される。さらに `../../../data/system` のような値なら `/data/system/app/...` 方向へずれる。実際に作成できるかは親ディレクトリの存在、権限、SELinux ラベル復元に依存するが、Package Installer が system_server 文脈でパスを組み立てる前にこの入力を拒否すべきだった。

## 影響評価

Bulletin 上の分類は Framework / EoP / High。公開パッチだけから断定できる範囲では、攻撃者が `volumeUuid` に `..` を含む任意文字列を指定し、Package Installer のセッション作成処理に意図外のストレージ識別子を保持させ、ステージングディレクトリの解決先を `/mnt/expand/<UUID>` 以外へずらせる問題である。

コミット本文は「後で system が crash する代わりに早期に失敗させる」と説明している。これは、不正な `volumeUuid` がセッション内に残った後、後段の storage/package install 処理で UUID 変換やパス操作に到達して system_server 側例外・不整合を起こしていたことを示す。EoP としての本質は、通常のインストール API 入力が、UUID として検証されないまま privileged なファイルシステムパス生成・セッション永続化に使われる trust-boundary failure と判断する。

ただし、公開情報だけでは、最終的に任意ファイル作成、既存ディレクトリ利用、system_server crash、またはインストール先制御のどれが Android Security Team の EoP 判定の直接条件だったかまでは非公開 Bug 依存である。今回の ok 判定は、脆弱な入力、根本原因、修正点、発生条件を AOSP ソースコードと公式コミットで説明できるため。

## 修正の妥当性

`StorageManager.convert()` は次のみを受理する。

- `null`、つまり internal storage
- `primary_physical`
- `system`
- FAT volume identifier 形式 `XXXX-YYYY`
- `UUID.fromString()` が受理する標準 UUID

`../../../data` のような値は `UUID.fromString()` で `IllegalArgumentException` になるため、`PackageInstallerService.createSessionInternal()` の早い段階で拒否される。後段の `Environment.getDataDirectory(volumeUuid)` に到達しなくなるため、パストラバーサル入力を根元で遮断している。

## 残メモ

- `PackageInstallerSession` は `params.volumeUuid` を `install_sessions.xml` に `volumeUuid` 属性として保存・復元する。修正前に不正値を持つセッションが作られると、再起動後も不正値が残り得る。
- `INSTALL_FORCE_VOLUME_UUID` 分岐は、通常の自動解決分岐 `InstallLocationUtils.resolveInstallVolume()` を通らない。ここが検証抜けの発生点だった。
- `fitsOnInternal()` は `INSTALL_INTERNAL` が最初から立っている分岐では呼ばれるが、`INSTALL_FORCE_VOLUME_UUID` 分岐では呼ばれない。今回のパッチは容量チェックではなく、明確に `volumeUuid` の形式検証を追加している。
- Pixel 固有のバイナリ解析は不要。対象は AOSP Framework の Java ソース修正で完結している。
014 OK

CVE-2026-0061

014-ok-windowstate-overlay-surface-policy-bypass

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-452010556
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0061 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

ok: ソースコード差分と OSV 詳細から、脆弱性の発生条件と根本原因を特定できた。

原因

修正前の WindowState.hide() / checkPolicyVisibilityChange() は policy hidden にするとき、主に mWinAnimator.hide(...) を呼んでいた。

WindowStateAnimator.createSurfaceLocked() を見ると、mWinAnimator.mSurfaceControl は mWin.mSurfaceControl、つまり WindowState.mSurfaceControl の子として作られる。WindowStateAnimator.hide() はこの子 surface に対して transaction.hide(mSurfaceControl) するだけで、親である WindowState.mSurfaceControl は隠していなかった。

どこから特定したか

保存した付帯ファイル: ・artifacts/ASB-A-452010556.json
・artifacts/4518f78f.commit.json
・artifacts/4518f78f.diff
・artifacts/e58fd9cd11e400235ac480b4fba6a20f8161ff9b.diff
・artifacts/47589e30fe8bd9b8884758985bd23fb25b83a8fe.diff
・artifacts/WindowState.before.java
・artifacts/WindowState.after.java
・artifacts/WindowStateTests.before.java
・artifacts/WindowStateTests.after.java
・artifac…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://storage.googleapis.com/android-osv/ASB-A-452010556.json / https://android.googlesource.com/platform/frameworks/base/+/4518f78f8b34510a1329c60dc5e0b018f015a6e3

validated.md を表示
# CVE-2026-0061 検証結果

## 判定

ok: ソースコード差分と OSV 詳細から、脆弱性の発生条件と根本原因を特定できた。

## 基本情報

- CVE: CVE-2026-0061
- Android bug: A-452010556
- Component: Framework
- Type / Severity: EoP / High
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://storage.googleapis.com/android-osv/ASB-A-452010556.json
- 代表公開 fix: https://android.googlesource.com/platform/frameworks/base/+/4518f78f8b34510a1329c60dc5e0b018f015a6e3
- 対象ファイル: `platform/frameworks/base/services/core/java/com/android/server/wm/WindowState.java`

## 脆弱性の内容

`WindowState.java` の policy visibility 制御が、実際に攻撃者クライアントから再表示可能な ViewRootImpl/VRI 側 surface に依存していたため、非システム overlay を隠すべき場面で overlay が画面上に残る、または再表示される可能性があった。

攻撃シナリオは tapjacking/overlay attack。悪意あるアプリが overlay window を表示しておき、権限付与 UI など `SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS` を持つ敏感な window が表示されるタイミングで、WMS 側の「overlay を隠した」という論理状態をすり抜けて VRI surface を再表示する。ユーザーは権限 UI の上に重なった攻撃者 overlay に誘導され、意図しない permission accept を行わされ得る。結果としてローカル権限昇格になる。

OSV の details も「`WindowState.java` の複数関数で、tapjacking/overlay attack によりユーザーを permission accept に誘導できる」としている。なお OSV 文面は「user interaction is not needed」とも書いているが、同じ details 内で「trick a user into accepting a permission」と説明しており、実態は権限 UI 上の overlay/tapjacking 問題として読むのが自然。

## 根本原因

修正前の `WindowState.hide()` / `checkPolicyVisibilityChange()` は policy hidden にするとき、主に `mWinAnimator.hide(...)` を呼んでいた。

`WindowStateAnimator.createSurfaceLocked()` を見ると、`mWinAnimator.mSurfaceControl` は `mWin.mSurfaceControl`、つまり `WindowState.mSurfaceControl` の子として作られる。`WindowStateAnimator.hide()` はこの子 surface に対して `transaction.hide(mSurfaceControl)` するだけで、親である `WindowState.mSurfaceControl` は隠していなかった。

一方、fix commit の説明は「client side can access the ViewRootImpl surface and changes its visibility」と明記している。つまり、policy hide をクライアント側/VRI 側 surface にかけても、攻撃者クライアントがその surface visibility を操作できるため、WMS の overlay 抑止ポリシーの信頼境界として不適切だった。

根本原因は、セキュリティポリシーである policy visibility を attacker-controlled に近い client/VRI surface に適用し、server-owned な `WindowState.mSurfaceControl` に適用していなかったこと。

## パッチ内容

代表 commit `4518f78f8b34510a1329c60dc5e0b018f015a6e3` は `WindowState.java` の 3 箇所に `mSurfaceControl` の show/hide を追加している。

- `checkPolicyVisibilityChange()`: `!isVisibleByPolicy()` になったとき、`mWinAnimator.hide(...)` に加えて `getPendingTransaction().hide(mSurfaceControl)` を実行。
- `show()`: policy visibility を戻すとき、`getPendingTransaction().show(mSurfaceControl)` を実行。
- `hide()`: 即時 hide で `LEGACY_POLICY_VISIBILITY` を落とした後、`getPendingTransaction().hide(mSurfaceControl)` を実行。

追加テスト `WindowStateTests#testIsOnScreen_hiddenByPolicy` も、`window.hide(false, false)` 後に `mTransaction.hide(window.mSurfaceControl)` が呼ばれること、`window.show(false, false)` 後に `mTransaction.show(window.mSurfaceControl)` が呼ばれることを検証している。

Android 14 の公開 diff `e58fd9cd11e400235ac480b4fba6a20f8161ff9b.diff` も同じ 3 箇所の修正。17-next の `47589e30fe8bd9b8884758985bd23fb25b83a8fe.diff` では `!WindowManager.useClientSurface()` 条件付きだが、同じく server-side `WindowState.mSurfaceControl` を policy show/hide の対象にしている。

## 面白い点・調査メモ

- commit message の再現メモが具体的だった: 「overlay window を表示し、VRI surface を表示し続ける loop を回し、Settings を起動すると overlay が見えてはいけない」。これは攻撃者が policy hide 後に VRI surface を再表示する状況そのもの。
- 修正前でも `WindowState.isOnScreen()` は `isVisibleByPolicy()` を見るため false になり得る。つまり WMS の内部論理状態は「隠れている」なのに、実描画 surface は client 側の操作で再表示可能というズレが問題だった。
- `setForceHideNonSystemOverlayWindowIfNeeded()` は `mForceHideNonSystemOverlayWindow` をセットして `hide(true, true)` / `show(true, true)` を呼ぶ。権限 UI などが `SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS` を使うと、この経路で非システム overlay の policy visibility が変わる。
- OSV に載っている Android 15/16/16-qpr2 の branch fix commit は、この実行時点では Gitiles で 404 だった。代表 fix と Android 14/17-next diff は取得でき、修正内容は一致している。

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

- `artifacts/ASB-A-452010556.json`
- `artifacts/4518f78f.commit.json`
- `artifacts/4518f78f.diff`
- `artifacts/e58fd9cd11e400235ac480b4fba6a20f8161ff9b.diff`
- `artifacts/47589e30fe8bd9b8884758985bd23fb25b83a8fe.diff`
- `artifacts/WindowState.before.java`
- `artifacts/WindowState.after.java`
- `artifacts/WindowStateTests.before.java`
- `artifacts/WindowStateTests.after.java`
- `artifacts/WindowStateAnimator.java`
- `artifacts/ViewRootImpl.java`
- `artifacts/bulletin-2026-06-01.html`
- `artifacts/analysis-notes.md`
015 OK

CVE-2026-0076

015-ok-androidfw-xml-attribute-size-oob-read

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-470115162
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0076 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

CVE-2026-0076は、libandroidfw のbinary XML start element検証において、属性1要素のサイズ attributeSize が ResXMLTree_attribute の最小サイズ以上であることを確認していなかった境界チェック不備である。細工されたXMLが attributeSize を小さく設定すると、旧 validateNode() は合計サイズチェックを通してしまい、後続の属性アクセサが固定長の ResXMLTree_attribute としてノード範囲外を読む。

修正は attributeSize < sizeof(ResXMLTree_attribute) を BAD_TYPE として拒否することで、属性配列のstrideと実際の読み取りサイズを一致させ、OOB readを防ぐものだった。

原因

根本原因は、入力フォーマット上のstrideである ResXMLTree_attrExt::attributeSize と、実装が読み取る実体サイズ sizeof(ResXMLTree_attribute) の整合性を検証していなかったこと。

旧 validateNode() は「申告された属性配列の合計サイズがノード範囲内か」だけを確認した。これは attributeSize が正しい最小要素サイズ以上である場合にだけ十分な検証になる。attributeSize が小さい場合、合計サイズ検証は通る一方で、各属性アクセサは ResXMLTree_attribute の固定レイアウトを前提に ns、name、rawValue、typedValue を読むため、後続属性の読み取りがノード末尾を越える。

修正は attributeSize < sizeof(ResXMLTree_attribute) を明示的に拒否し、既存の attributeStart + attributeSize * attributeCount 検証を意味のある境界チェックに戻している。

どこから特定したか

パッチ差分: 修正は ResXMLTree::validateNode() のSTART_ELEMENT検証に、属性1要素の最小サイズ検証を追加するものだった。

修正前:

``cpp
const size_t attrSize = ((size_t)dtohs(attrExt->attributeSize))
* dtohs(attrExt->attributeCount);
if ((dtohs(attrExt->attributeStart)+attrSize) <= (size-headerSize)) {
return NO_ERROR;
}
`

修正後:

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/frameworks/base/+/a91d16a02b51b7a5652031e485508eee655dff47 / https://android.googlesource.com/platform/frameworks/base/+/4d869cd4de74f1dccf30e729bd9caabc3b397e7a

validated.md を表示
# CVE-2026-0076 検証結果

## 判定

ok: 公開ソースコード差分、OSV詳細、追加テストから、脆弱性の発生条件と根本原因を特定できた。

タイトル案: `androidfw-xml-attribute-size-oob-read`

## 基本情報

- CVE: CVE-2026-0076
- Android Bug ID: A-470115162
- Component: Framework
- 種別: EoP
- Severity: High
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Bulletin上の対象: Android 14, 15, 16, 16-qpr2
- ASB公開パッチ: https://android.googlesource.com/platform/frameworks/base/+/a91d16a02b51b7a5652031e485508eee655dff47
- upstream相当パッチ: https://android.googlesource.com/platform/frameworks/base/+/4d869cd4de74f1dccf30e729bd9caabc3b397e7a
- 変更ファイル:
  - `libs/androidfw/ResourceTypes.cpp`
  - `libs/androidfw/tests/ResourceTypes_test.cpp`

## 解析に使った資料

- `artifacts/ASB-A-470115162.json`: Android OSVのCVE詳細。`validateNode` のincorrect bounds checkによるout-of-bounds read、local EoPと明記。
- `artifacts/commit_a91d16a0.txt`: ASBからリンクされた公開コミット本文。
- `artifacts/a91d16a0.diff`: ASBリンク先コミットのGitiles diff。
- `artifacts/commit_4d869cd4.txt`: upstream相当の元コミット本文。
- `artifacts/commit_9b483563.txt`: Android 14向けcherry-pickコミット本文。
- `artifacts/ResourceTypes.before.cpp`: 親コミット `66c209d1f65f07c06907b33b352c5409520b61c5` の `ResourceTypes.cpp`。
- `artifacts/ResourceTypes.after.cpp`: 修正コミット `a91d16a02b51b7a5652031e485508eee655dff47` の `ResourceTypes.cpp`。
- `artifacts/ResourceTypes.before_after.diff`: before/afterから生成したローカルdiff。
- `artifacts/ResourceTypes.h`: `ResXMLTree_attrExt` / `ResXMLTree_attribute` の構造体定義確認用。
- `artifacts/ResourceTypes_test.after.cpp`: 追加回帰テスト確認用。
- `artifacts/attribute_size_oob_notes.md`: 境界外読み取りが起きるサイズ計算メモ。
- `artifacts/bulletin-2026-06-01.html`: Android Security Bulletin保存版。
- `artifacts/origin-patch-diffing-pipeline.html`: 参考にしたpatch diffing pipeline記事の保存版。
- `artifacts/SHA256SUMS.txt`: 保存成果物のSHA-256。

## パッチ差分

修正は `ResXMLTree::validateNode()` のSTART_ELEMENT検証に、属性1要素の最小サイズ検証を追加するものだった。

修正前:

```cpp
const size_t attrSize = ((size_t)dtohs(attrExt->attributeSize))
    * dtohs(attrExt->attributeCount);
if ((dtohs(attrExt->attributeStart)+attrSize) <= (size-headerSize)) {
    return NO_ERROR;
}
```

修正後:

```cpp
if (dtohs(attrExt->attributeSize) < sizeof(ResXMLTree_attribute)) {
    ALOGW("Bad XML block: attribute size %d is smaller than min expected %d\n",
          int(dtohs(attrExt->attributeSize)), int(sizeof(ResXMLTree_attribute)));
    return BAD_TYPE;
}
const size_t attrSize = ((size_t)dtohs(attrExt->attributeSize))
    * dtohs(attrExt->attributeCount);
if ((dtohs(attrExt->attributeStart)+attrSize) <= (size-headerSize)) {
    return NO_ERROR;
}
```

追加テスト `ResXMLTree_ValidateNode_SmallAttributeSize` は、`attributeSize = sizeof(ResXMLTree_attribute) - 1` の不正なXML start elementを作り、`ResXMLTree::setTo()` が `BAD_TYPE` を返すことを確認している。

## 脆弱性の内容

Androidのbinary XML parserである `libandroidfw` の `ResXMLTree::validateNode()` が、XML start elementの属性配列を検証するときに、`attributeSize * attributeCount` という合計サイズだけを検証していた。ところが、実際の属性アクセサ群は各属性を `ResXMLTree_attribute` 構造体として扱い、少なくとも `sizeof(ResXMLTree_attribute)` バイトを読む。

`ResXMLTree_attrExt::attributeSize` は属性配列のstrideとして使われる。旧コードではこの値が `sizeof(ResXMLTree_attribute)` より小さくても、合計サイズがノード内に収まるなら妥当なXMLとして受け入れていた。

例:

- `sizeof(ResXMLTree_attrExt) = 20`
- `sizeof(ResXMLTree_attribute) = 20`
- `attributeStart = 20`
- `attributeSize = 10`
- `attributeCount = 2`
- `size - headerSize = 40`

旧検証では `20 + 10 * 2 <= 40` なので通る。しかし `getAttributeNameID()`、`getAttributeData()`、`getAttributeValue()` などは、2個目の属性を `tag + 20 + 10 * 1`、つまりoffset 30から始まる20バイト構造体として読む。ノード内にある属性領域はoffset 40までなので、2個目の属性読み取りは最大10バイト分ノード外を読む。

OSV詳細もこの結論と一致しており、「`validateNode` のincorrect bounds checkによりout of bounds readが可能で、追加権限なし・ユーザー操作なしでlocal EoPにつながる」としている。

## 根本原因

根本原因は、入力フォーマット上のstrideである `ResXMLTree_attrExt::attributeSize` と、実装が読み取る実体サイズ `sizeof(ResXMLTree_attribute)` の整合性を検証していなかったこと。

旧 `validateNode()` は「申告された属性配列の合計サイズがノード範囲内か」だけを確認した。これは `attributeSize` が正しい最小要素サイズ以上である場合にだけ十分な検証になる。`attributeSize` が小さい場合、合計サイズ検証は通る一方で、各属性アクセサは `ResXMLTree_attribute` の固定レイアウトを前提に `ns`、`name`、`rawValue`、`typedValue` を読むため、後続属性の読み取りがノード末尾を越える。

修正は `attributeSize < sizeof(ResXMLTree_attribute)` を明示的に拒否し、既存の `attributeStart + attributeSize * attributeCount` 検証を意味のある境界チェックに戻している。

## 攻撃面・影響の整理

攻撃入力は、細工されたbinary XMLを含むAPK/リソースと考えられる。`libandroidfw` の `ResXMLTree` はAndroid framework側でXMLリソース、特にAPK内のbinary XMLを処理する基盤であり、PackageManagerやAssetManager経由で権限の高いプロセスが攻撃者提供のAPK/リソースを解析する経路がある。

公開パッチだけでは、OOB read後にどの上位パーサ状態をどのように制御してEoPへつなげるかまでは示されていない。ただし、脆弱な読み取りプリミティブ自体はソース上で明確に説明できる。Android OSVはこれをlocal EoP、no additional execution privileges、user interaction not neededとして分類している。

## 面白い点・調査メモ

- コミット本文が非常に直接的で、旧コードが「単一要素サイズと要素数の積」だけを検証し、「単一要素サイズには下限がある」ことを保証していなかった、と説明している。
- 追加テストは `attributeCount=1` かつ `attributeSize=19` を拒否するテストで、単体ではノード外読み取りを直接発生させる最小例ではない。実際のOOB read条件は、`attributeCount > 1` などにより後続属性の20バイト読み取りが申告領域外へはみ出すケースとして説明できる。
- `ResXMLTree_attribute` は `ns`、`name`、`rawValue`、`typedValue` からなる20バイト構造体で、`typedValue` はoffset 12から8バイト。`getAttributeValue()` はこの8バイトを `copyFrom_dtoh()` するため、末尾不足時にまとまった境界外readになり得る。
- OSVのaffectedには `17-next`、`15`、`16`、`16-qpr2`、`14` のfix URLが載っている。ただし調査時点で `ca02a1c2`、`10ae6120`、`7f88e052` のGitiles直URLは404だった。ASB公開リンク先 `a91d16a0`、upstream相当 `4d869cd4`、Android 14向け `9b483563` は取得できた。
- ASB上はFramework High EoPだが、修正箇所はJava frameworkではなく `frameworks/base/libs/androidfw` のnative C++ resource parserである。

## 結論

CVE-2026-0076は、`libandroidfw` のbinary XML start element検証において、属性1要素のサイズ `attributeSize` が `ResXMLTree_attribute` の最小サイズ以上であることを確認していなかった境界チェック不備である。細工されたXMLが `attributeSize` を小さく設定すると、旧 `validateNode()` は合計サイズチェックを通してしまい、後続の属性アクセサが固定長の `ResXMLTree_attribute` としてノード範囲外を読む。

修正は `attributeSize < sizeof(ResXMLTree_attribute)` を `BAD_TYPE` として拒否することで、属性配列のstrideと実際の読み取りサイズを一致させ、OOB readを防ぐものだった。
016 OK

CVE-2026-0077

016-ok-resumeConfigurationDispatch-bal-eop

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions16-qpr2
ReferencesA-467082881
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0077 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

CVE-2026-0077 は Framework の ActivityRecord.resumeConfigurationDispatch() における background activity launch (BAL) 制限の迂回です。構成変更の dispatch pause を解除する経路で、不可視・停止中の Activity に対する可視性チェックを行わずに updateReportedConfigurationAndSend() を呼び、条件次第で relaunchActivityLocked() に到達して Activity relaunch transaction を発行できることが根本原因です。

このため、バックグラウンド側の Activity が構成変更を契機に再起動され、通常の foreground launch/BAL 判定を通らずに lifecycle が進む可能性があります。OSV の説明も「resumeConfigurationDispatch の logic error により background application launch が可能」と一致します。

判定: ok。公開 fix commit 本体は 2026-06-23 時点で Gitiles 404 でしたが、OSV が対象関数・ファイル・fix commit を明示しており、公開 AOSP ソース上で脆弱な制御フローと根本原因を特定できました。

原因

根本原因は、構成変更 dispatch の再開処理が ensureActivityConfiguration(false) と同じ安全条件を共有していなかったことです。

ensureActivityConfiguration(false) は不可視 Activity を skip するのに、resumeConfigurationDispatch() は同じ updateReportedConfigurationAndSend() を直接呼び、不可視 Activity の relaunch を許します。つまり「configuration relaunch は表示対象 Activity に限る」という不変条件が、pause/resume 用の別経路に複製されていなかった、または共通化されていなかったことがバグです。

どこから特定したか

解析したソース: 保存済みファイル:

・artifacts/ActivityRecord.android16-qpr2-release.full.java
・artifacts/ActivityRecord.android-16.0.0_r4.full.java
・artifacts/ActivityRecord.android16-qpr1-release.full.java
・artifacts/key-code-excerpts.txt
・artifacts/ActivityRecord.qpr1_vs_qpr2.diff
・artifacts/reconstructed_visibility_guard.diff

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://storage.googleapis.com/android-osv/ASB-A-467082881.json / https://android.googlesource.com/platform/frameworks/base/+/2e95632ce2f16f42a0b0d8c08ddffad49d952b44` / https://android.googlesource.com/platform/frameworks/base/+/407d0fcb459d11b1574e1ebe6ccc297a9d00c6b6`

validated.md を表示
# CVE-2026-0077 検証結果

## 結論

CVE-2026-0077 は Framework の `ActivityRecord.resumeConfigurationDispatch()` における background activity launch (BAL) 制限の迂回です。構成変更の dispatch pause を解除する経路で、不可視・停止中の Activity に対する可視性チェックを行わずに `updateReportedConfigurationAndSend()` を呼び、条件次第で `relaunchActivityLocked()` に到達して Activity relaunch transaction を発行できることが根本原因です。

このため、バックグラウンド側の Activity が構成変更を契機に再起動され、通常の foreground launch/BAL 判定を通らずに lifecycle が進む可能性があります。OSV の説明も「`resumeConfigurationDispatch` の logic error により background application launch が可能」と一致します。

判定: ok。公開 fix commit 本体は 2026-06-23 時点で Gitiles 404 でしたが、OSV が対象関数・ファイル・fix commit を明示しており、公開 AOSP ソース上で脆弱な制御フローと根本原因を特定できました。

## 入口情報

- CVE: CVE-2026-0077
- 参照 ID: A-467082881
- Component: Framework
- Type: EoP
- Severity: High
- Updated AOSP versions: 16-qpr2
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV JSON: https://storage.googleapis.com/android-osv/ASB-A-467082881.json

## OSV から得たパッチ情報

`ASB-A-467082881.json` には以下が記録されています。

- detail: `ActivityRecord.java` の `resumeConfigurationDispatch` で BAL が可能なロジックエラー。
- package: `platform/frameworks/base`
- 16-qpr2 fix: `https://android.googlesource.com/platform/frameworks/base/+/2e95632ce2f16f42a0b0d8c08ddffad49d952b44`
- 17-next fix: `https://android.googlesource.com/platform/frameworks/base/+/407d0fcb459d11b1574e1ebe6ccc297a9d00c6b6`
- Vanir signature target: `services/core/java/com/android/server/wm/ActivityRecord.java`

ただし、上記 2 commit は調査時点で Gitiles から 404 を返しました。HTTP 応答は `artifacts/gitiles-2e95632ce2f16f42-http.txt` と `artifacts/gitiles-407d0fcb459d-http.txt` に保存しています。

## 解析したソース

保存済みファイル:

- `artifacts/ActivityRecord.android16-qpr2-release.full.java`
- `artifacts/ActivityRecord.android-16.0.0_r4.full.java`
- `artifacts/ActivityRecord.android16-qpr1-release.full.java`
- `artifacts/key-code-excerpts.txt`
- `artifacts/ActivityRecord.qpr1_vs_qpr2.diff`
- `artifacts/reconstructed_visibility_guard.diff`

`android16-qpr2-release` と `android-16.0.0_r4` の `ActivityRecord.java` は `resumeConfigurationDispatch()` 周辺が同一で、公開 branch には OSV の fix commit がまだ見えませんでした。よって公開ソースを修正前コードとして解析しました。

## 脆弱な制御フロー

`resumeConfigurationDispatch()` は pause count を戻した後、display/config が変わっていれば child window へ config を dispatch し、最後に直接 `updateReportedConfigurationAndSend()` を呼びます。

重要なのは、この関数には以下のような不可視 Activity ガードが存在しない点です。

```java
if (mState == STOPPING || mState == STOPPED || !shouldBeVisible()) {
    ...
}
```

一方、通常経路の `ensureActivityConfiguration(false)` にはこのガードがあります。

```java
if (!ignoreVisibility && (mState == STOPPING || mState == STOPPED || !shouldBeVisible())) {
    ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check invisible: %s", this);
    return true;
}
```

つまり、通常の構成確認では不可視・停止中 Activity の relaunch を避ける設計なのに、pause/resume 経路だけがその設計を迂回します。

`updateReportedConfigurationAndSend()` は config 差分を計算し、アプリが処理できない差分なら `shouldRelaunchLocked()` が true になり、`relaunchActivityLocked(preserveWindow, changes)` を呼びます。この直前には不可視 Activity の relaunch を想定したログ分岐も存在します。

`relaunchActivityLocked()` は `ActivityRelaunchItem` と lifecycle item を client process に schedule します。`andResume` が true なら `ResumeActivityItem`、そうでなければ `PauseActivityItem` が送られます。これによりバックグラウンド Activity でも構成変更由来の relaunch transaction が発行されます。

## 攻撃条件の整理

攻撃に必要な状態は次の通りです。

- 対象 Activity の configuration dispatch が pause されている。
- その Activity が foreground 可視ではない、または `STOPPING` / `STOPPED` 相当になっている。
- pause 中に display / bounds / orientation / screen size など、Activity が manifest の `configChanges` で処理しない構成差分が発生する。
- `resumeConfigurationDispatch()` が呼ばれ、可視性チェックなしで `updateReportedConfigurationAndSend()` に入る。
- `shouldRelaunchLocked()` が true となり `relaunchActivityLocked()` が実行される。

この経路は明示的な Activity start API の BAL gate ではなく、ActivityTaskManager / WindowManager の内部 configuration relaunch 経路です。そのため「background application launch due to logic error」という OSV の説明と合います。

## 根本原因

根本原因は、構成変更 dispatch の再開処理が `ensureActivityConfiguration(false)` と同じ安全条件を共有していなかったことです。

`ensureActivityConfiguration(false)` は不可視 Activity を skip するのに、`resumeConfigurationDispatch()` は同じ `updateReportedConfigurationAndSend()` を直接呼び、不可視 Activity の relaunch を許します。つまり「configuration relaunch は表示対象 Activity に限る」という不変条件が、pause/resume 用の別経路に複製されていなかった、または共通化されていなかったことがバグです。

推定される修正は `resumeConfigurationDispatch()` 側にも `mState == STOPPING || mState == STOPPED || !shouldBeVisible()` 相当のガードを追加し、不可視 Activity では `updateReportedConfigurationAndSend()` に入らないようにするものです。推定パッチは `artifacts/reconstructed_visibility_guard.diff` に保存しました。

## 面白い点・調査メモ

- Bulletin の CVE 行には `A-467082881` の公開 commit link がありませんでしたが、OSV JSON には fix commit と関数名まで含まれていました。
- OSV JSON の `modified` は `2026-06-22T15:18:41Z` で、調査日の 2026-06-23 時点でも fix commit URL は 404 でした。公開 branch と OSV metadata の反映タイミングに差がある可能性があります。
- `resumeConfigurationDispatch()` は WindowContainer transaction / transition 処理中の一時停止解除で呼ばれるため、通常の Activity start 監査だけを見ても見落としやすい経路です。
- `updateReportedConfigurationAndSend()` には「invisible activity を relaunch する」ログが残っており、開発者もこの挙動自体は把握していたように見えます。ただし BAL の観点では不可視 Activity の relaunch が危険な副作用になっていました。

## 参照・成果物

- `cve.md`: 初期 advisory 情報。
- `ASB-A-467082881.json`: Android OSV の CVE 詳細。
- `artifacts/bulletin-2026-06-01.html`: Android Security Bulletin 保存版。
- `artifacts/origin-patch-diffing-pipeline.html`: 指定された patch diffing pipeline 記事の保存版。
- `artifacts/key-code-excerpts.txt`: 解析に使った主要コード抜粋。
- `artifacts/reconstructed_visibility_guard.diff`: OSV 情報と公開ソースから推定した修正箇所。
- `artifacts/gitiles-2e95632ce2f16f42-http.txt`: 16-qpr2 fix commit URL の 404 応答。
- `artifacts/gitiles-407d0fcb459d-http.txt`: 17-next fix commit URL の 404 応答。
017 OK

CVE-2026-0078

017-ok-global-proxy-persistence-desync

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-445418705
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0078 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

OK。AOSP の公開修正コミットとテスト差分から、脆弱なコード位置、入力条件、修正内容、根本原因を特定できた。

原因

根本原因は、Device Policy として永続化される globalProxySpec / globalProxyExclusionList が、他のポリシー文字列と同じ PolicySizeVerifier の最大長制約を適用されていなかったこと。

setGlobalProxy() は入力を受け取ったあと、永続化可能性を確認する前に ActiveAdmin の状態を更新していた。つまり、入力検証の責任境界が Binder/API 入力側ではなく保存処理側に暗黙化しており、保存できないサイズの文字列が管理状態に入ってしまう設計になっていた。

どこから特定したか

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/frameworks/base/+/50cbf4422ac8e930c522642f5dce0724581a6aa9

validated.md を表示
# CVE-2026-0078 検証結果

## 判定

OK。AOSP の公開修正コミットとテスト差分から、脆弱なコード位置、入力条件、修正内容、根本原因を特定できた。

## 基本情報

- CVE: CVE-2026-0078
- 参照 ID: A-445418705
- Component: Framework
- 種別/深刻度: EoP / High
- 影響バージョン: Android 14, 15, 16, 16-qpr2
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- 公開修正コミット: https://android.googlesource.com/platform/frameworks/base/+/50cbf4422ac8e930c522642f5dce0724581a6aa9
- 保存した patch: `artifacts/50cbf4422ac8e930c522642f5dce0724581a6aa9.patch`
- 解析メモ: `artifacts/analysis-notes.md`

## 修正内容

修正対象は `frameworks/base` の `DevicePolicyManagerService.setGlobalProxy()`。

脆弱版では、`proxySpec != null` の分岐で `proxySpec` と `exclusionList` のサイズを検証せず、そのまま以下の管理状態へ格納していた。

- `admin.specifiesGlobalProxy = true`
- `admin.globalProxySpec = proxySpec`
- `admin.globalProxyExclusionList = exclusionList`

修正後は、これらのフィールドを更新する直前に次の検証が追加された。

```java
PolicySizeVerifier.enforceMaxStringLength(proxySpec, "proxySpec");
if (exclusionList != null) {
    PolicySizeVerifier.enforceMaxStringLength(exclusionList, "exclusionList");
}
```

同時に追加されたテスト `testSetGlobalProxy_tooLongStrings()` は、65536 文字の ASCII 文字列を使い、長すぎる `proxySpec` と長すぎる `exclusionList` の両方で `IllegalArgumentException` が投げられることを確認している。テスト内コメントによると、`PolicySizeVerifier` は `ModifiedUtf8.countBytes()` で長さを測り、上限は 65535 UTF bytes。

## 脆弱性の内容

`DevicePolicyManagerService.setGlobalProxy()` が、グローバルプロキシ設定用の文字列に対して、Device Policy の永続化で必要な最大長検証を行っていなかった。

そのため、Device Owner / 対応 Device Admin が `setGlobalProxy()` に 65535 Modified UTF-8 bytes を超える `proxySpec` または `exclusionList` を渡すと、`system_server` 内の `ActiveAdmin` ランタイム状態にはその値が受理される一方、Device Policy の XML 永続化・再読み込み側とは整合しない状態を作れる。公開 CVE 説明でいう "desync in persistence" はこの不整合を指す。

この不整合により、再起動や DPM 状態の保存/復元をまたいで、管理ポリシーの実効状態と永続状態がずれ、ローカル権限昇格につながる。必要な攻撃入力は特権 API のバイパスではなく、正規に `setGlobalProxy()` を呼べる管理主体からの過大な文字列である。ユーザー操作は不要。

## 根本原因

根本原因は、Device Policy として永続化される `globalProxySpec` / `globalProxyExclusionList` が、他のポリシー文字列と同じ `PolicySizeVerifier` の最大長制約を適用されていなかったこと。

`setGlobalProxy()` は入力を受け取ったあと、永続化可能性を確認する前に `ActiveAdmin` の状態を更新していた。つまり、入力検証の責任境界が Binder/API 入力側ではなく保存処理側に暗黙化しており、保存できないサイズの文字列が管理状態に入ってしまう設計になっていた。

## 面白い点・調査メモ

- patch は 3 ファイルだけで、実質的な修正は `DevicePolicyManagerService.java` の 4 行のみ。
- テスト用 `device_admin_sample.xml` に `<set-global-proxy />` が追加されており、再現にはこの Device Admin policy が必要だったことが分かる。
- 修正コミットのメッセージ自体が `Validate max proxy string length for proxySpec and exclusionList using PolicySizeVerifier.` で、問題が「形式」ではなく「永続化可能な最大サイズ」の欠落だったことを強く示している。
- ローカルの `../binaries/frameworks_base_36a774d7` には対象コミットがなく、対象コミットの `git fetch` は完了しなかったため、Gitiles から直接取得した patch を一次根拠として保存した。
018 OK

CVE-2026-0087

018-ok-app-links-wildcard-domain-boundary

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-483142784
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0087 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

脆弱性を特定できた。CVE-2026-0087 は Android Framework の App Links / Domain Verification におけるワイルドカードドメイン照合の境界チェック不備である。

*.xyz.com のような検証済みワイルドカードドメインを、脆弱な実装は xyz.com という単なる suffix として host.endsWith() で比較していた。そのため、本来は xyz.com または abc.xyz.com だけが一致すべきところ、abcxyz.com のような無関係なドメインも「検証済み wildcard に一致」と判定され、該当パッケージがそのドメインの App Links owner として扱われ得た。

これはリンク解決時に承認済みアプリへ絞り込む DomainVerificationService.filterToApprovedApp() / approvalLevelForDomain() の判断に影響するため、攻撃者アプリが Web リンクの解決先として不当に選ばれる EoP と評価できる。

原因

根本原因は、ワイルドカードドメインの意味を「ラベル境界を持つ DNS サブドメイン」ではなく「文字列 suffix」として実装したこと。

具体的には *.example.com から example.com を取り出し、先頭側にドットがあるかを確認せず host.endsWith("example.com") を使った。DNS 名のラベル境界を考慮するなら、一致条件は host == "example.com" または host が .example.com で終わることに限定する必要がある。

どこから特定したか

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/frameworks/base/+/2e3d71d027b090e6466b96995678e38b22ba3fe1 / https://google.com/...`

validated.md を表示
# CVE-2026-0087 検証結果

## 結論

脆弱性を特定できた。CVE-2026-0087 は Android Framework の App Links / Domain Verification におけるワイルドカードドメイン照合の境界チェック不備である。

`*.xyz.com` のような検証済みワイルドカードドメインを、脆弱な実装は `xyz.com` という単なる suffix として `host.endsWith()` で比較していた。そのため、本来は `xyz.com` または `abc.xyz.com` だけが一致すべきところ、`abcxyz.com` のような無関係なドメインも「検証済み wildcard に一致」と判定され、該当パッケージがそのドメインの App Links owner として扱われ得た。

これはリンク解決時に承認済みアプリへ絞り込む `DomainVerificationService.filterToApprovedApp()` / `approvalLevelForDomain()` の判断に影響するため、攻撃者アプリが Web リンクの解決先として不当に選ばれる EoP と評価できる。

## Bulletin 情報

- CVE: `CVE-2026-0087`
- 参照 ID: `A-483142784`
- Component: `Framework`
- Subcomponent: bulletin 上は明示なし。コード上の該当領域は PackageManager の Domain Verification / App Links。
- Type / Severity: `EoP`, `High`
- Updated AOSP versions: `14, 15, 16, 16-qpr2`
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01

## パッチ

- Repository: `platform/frameworks/base`
- Commit: `2e3d71d027b090e6466b96995678e38b22ba3fe1`
- Commit URL: https://android.googlesource.com/platform/frameworks/base/+/2e3d71d027b090e6466b96995678e38b22ba3fe1
- Parent: `40c30bb5613ee94403723b37d0d6c58197d3d1b4`
- 変更ファイル:
  - `services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java`
  - `services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt`

保存済み証跡:

- `artifacts/2e3d71d0.commit.json`
- `artifacts/2e3d71d0.diff`
- `artifacts/DomainVerificationService.before.java`
- `artifacts/DomainVerificationService.after.java`
- `artifacts/DomainVerificationPackageTest.before.kt`
- `artifacts/DomainVerificationPackageTest.after.kt`
- `artifacts/DomainVerificationCollector.before.java`
- `artifacts/IntentFilter.before.java`
- `artifacts/bulletin-2026-06-01.html`
- `artifacts/origin-patch-diffing-pipeline.html`
- `artifacts/wildcard-matching-truth-table.md`
- `artifacts/analysis-notes.md`

## 差分解析

脆弱な実装では、検証済み状態 `STATE_SUCCESS` 等のドメイン一覧 `stateMap` を走査し、wildcard domain について次の条件で一致判定していた。

```java
domain.startsWith("*.") && host.endsWith(domain.substring(2))
```

`domain = "*.xyz.com"` のとき `domain.substring(2)` は `xyz.com` になる。したがって `host = "abcxyz.com"` も `endsWith("xyz.com")` を満たしてしまう。

修正後は次の条件になった。

```java
domain.startsWith("*.")
        && (host.endsWith(domain.substring(1))
            || host.equals(domain.substring(2)))
```

`domain.substring(1)` は `.xyz.com` なので、サブドメインの場合はドット境界込みで `endsWith(".xyz.com")` を要求する。apex/root の `xyz.com` だけは `host.equals("xyz.com")` で明示的に許可する。

追加テスト `testWildcardDomain()` は、`*.xyz.com` を検証済みにしたうえで以下を確認している。

- `abcxyz.com`: owner なし
- `abc.xyz.com`: `PKG_ONE` が owner
- `xyz.com`: `PKG_ONE` が owner

## 脆弱性が起きる状況

攻撃者が自分の管理するドメインを使って、アプリの manifest に wildcard App Links を宣言し、その wildcard domain が Domain Verification で成功した状態を作る。

例:

- 攻撃者が `gle.com` を管理する
- 攻撃者アプリが `android:autoVerify="true"` の App Links intent-filter に `android:host="*.gle.com"` を宣言する
- Android 側で `*.gle.com` が verified state になる
- 被害対象リンクが `https://google.com/...` のように `gle.com` で終わる

脆弱な実装では `google.com.endsWith("gle.com") == true` なので、攻撃者アプリは `google.com` の verified owner と誤判定され得る。修正後は `google.com.endsWith(".gle.com") == false` かつ `google.com.equals("gle.com") == false` なので拒否される。

この問題はドメイン検証そのものの成否というより、「検証済み wildcard domain を任意 host に適用する承認判定」のバグである。`DomainVerificationCollector` は `(\*\.)?` を含むドメインパターンを受け入れており、`android:autoVerify="true"`、`ACTION_VIEW`、`BROWSABLE`、`DEFAULT`、HTTP/HTTPS の intent-filter から検証対象ドメインを収集する。つまり wildcard App Links 自体は正規の入力で、壊れていたのは照合時の suffix 境界である。

## 根本原因

根本原因は、ワイルドカードドメインの意味を「ラベル境界を持つ DNS サブドメイン」ではなく「文字列 suffix」として実装したこと。

具体的には `*.example.com` から `example.com` を取り出し、先頭側にドットがあるかを確認せず `host.endsWith("example.com")` を使った。DNS 名のラベル境界を考慮するなら、一致条件は `host == "example.com"` または `host` が `.example.com` で終わることに限定する必要がある。

## 調査中に分かったこと

- patch commit message 自体が、`*.xyz.com` が `abcxyz.com` に一致することを明示している。
- 新規テストは `getOwnersForDomain()` を直接使っている。これは単なる UI 表示バグではなく、Domain Owner 判定そのものの問題である。
- `DomainVerificationService.before.java` の後続にある user selection wildcard 分岐には、同じ `host.endsWith(domain.substring(2))` パターンが残っている。ただし今回の patch とテストが修正しているのは verified wildcard 分岐であり、CVE-2026-0087 の本体は自動検証済み App Links owner 判定の不備と判断した。
- `IntentFilter.AuthorityEntry.match()` にも wildcard host の suffix-only 照合があるが、今回の修正対象ではない。IntentFilter は「フィルタにマッチする候補 Activity を集める」段階、DomainVerificationService は「候補のうち承認済み owner を選ぶ」段階であり、CVE の修正は後者に入っている。

## 判定

`ok` とする。公開 AOSP ソースコードとパッチ差分から、脆弱な条件式、悪用可能な入力、リンク解決への影響、修正後の正しい境界条件を説明できる。
019 OK

CVE-2026-0089

019-ok-developer-verification-experiment-permission-bypass

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions16-qpr2
ReferencesA-485397908
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0089 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

CVE-2026-0089 / A-485397908 は、PackageInstallerService の developer verification 実験用APIに対する権限チェック漏れによる Framework の権限昇格です。脆弱なAPIは IPackageInstaller Binderインターフェース上の以下2つです。

``aidl
void addDeveloperVerificationExperiment(String packageName, int verificationPolicy, in int[] results);
void clearDeveloperVerificationExperiment(String packagename);
`

修正前は、この2メソッドにAIDLの @EnforcePermission も、PackageInstallerService 側の Binder.getCallingUid() による手動チェックもありませんでした。そのため通常アプリUIDからでも、将来のインストール時に使われる developer verification の「実験結果」をパッケージ名単位で注入できる状態でした。

これは source-level diff とOSVの署名対象から特定できたため、判定は ok` です。

原因

根本原因は、system_server内の PackageInstallerService が提供するテスト用状態変更APIを、Binder境界で認可せず公開していたことです。

IPackageInstaller.aidl の周辺APIには @PermissionManuallyEnforced、@EnforcePermission("DEVELOPER_VERIFICATION_AGENT")、@EnforcePermission("SET_DEVELOPER_VERIFICATION_USER_RESPONSE") が付いています。一方で問題の2メソッドには権限アノテーションがありませんでした。修正前のサーバ側実装も、呼び出し元UIDを検証せずに mDeveloperVerifierController.addExperiment(...) / clearExperiment(...) へ渡していました。

どこから特定したか

確認した公開情報: ・Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
・OSV JSON: https://storage.googleapis.com/android-osv/ASB-A-485397908.json
・Component: Framework
・Type: EoP
・Severity: High
・Updated AOSP versions: 16-qpr2
・Reference: A-485397908
・OSV details: PackageInstallerService.java の複数関数で missing permission check により unverified apps をinstal…

パッチ差分の要点: addDeveloperVerificationExperiment には以下が追加されました。

``java
final int callerUid = Binder.getCallingUid();
if (!PackageManagerServiceUtils.isRootOrShell(callerUid)) {
throw new SecurityException("Not allowed to add developer verification experiment");
}
`

clearDeveloperVerificationExperiment にも同様に以下が追加されました。

保存した付帯ファイル: ・artifacts/ASB-A-485397908.json: Android OSV JSON
・ar…

validated.md を表示
# CVE-2026-0089 検証結果

## 結論

`CVE-2026-0089 / A-485397908` は、`PackageInstallerService` の developer verification 実験用APIに対する権限チェック漏れによる Framework の権限昇格です。脆弱なAPIは `IPackageInstaller` Binderインターフェース上の以下2つです。

```aidl
void addDeveloperVerificationExperiment(String packageName, int verificationPolicy, in int[] results);
void clearDeveloperVerificationExperiment(String packagename);
```

修正前は、この2メソッドにAIDLの `@EnforcePermission` も、`PackageInstallerService` 側の `Binder.getCallingUid()` による手動チェックもありませんでした。そのため通常アプリUIDからでも、将来のインストール時に使われる developer verification の「実験結果」をパッケージ名単位で注入できる状態でした。

これは source-level diff とOSVの署名対象から特定できたため、判定は `ok` です。

## 確認した公開情報

- Bulletin: `https://source.android.com/docs/security/bulletin/2026/2026-06-01`
- OSV JSON: `https://storage.googleapis.com/android-osv/ASB-A-485397908.json`
- Component: Framework
- Type: EoP
- Severity: High
- Updated AOSP versions: `16-qpr2`
- Reference: `A-485397908`
- OSV details: `PackageInstallerService.java` の複数関数で missing permission check により unverified apps をinstall可能

## 修正コミット

OSVは `16-qpr2` 向けfixとして以下を列挙しています。

- `3671a41bb57ffd2e8c0c267cdc0469bec05062b8`
- `1f7c25b7e1f12a579b2815819257f9d86bf2e95d`

ただし、解析時点ではどちらも public Gitiles でHTTP 404でした。取得結果は `artifacts/16-qpr2-fetch-status.tsv` に保存しています。

同じOSV内で `17-next` 向けとして公開されている同等修正は取得でき、Vanir signature の対象関数も `16-qpr2` と一致しています。

- `1459299f9d3e5da1254a4653be4ac3defec20759`
  - `Check caller for addDeveloperVerificationExperiment`
  - `BUG: 485397908`
  - `Test: sts-tradefed run sts-dynamic-develop -m StsHostTestCases -t android.security.sts.Bug_485397908#testBug_485397908`
- `c15dea2dc3bb0ebeefeb59eb74290ac9fa918bf8`
  - `Check caller for clearDeveloperVerificationExperiment`
  - `BUG: 485397908`
  - 同じSTSテストを参照

raw diffは以下に保存しました。

- `artifacts/addDeveloperVerificationExperiment.patch`
- `artifacts/clearDeveloperVerificationExperiment.patch`

## パッチ差分の要点

`addDeveloperVerificationExperiment` には以下が追加されました。

```java
final int callerUid = Binder.getCallingUid();
if (!PackageManagerServiceUtils.isRootOrShell(callerUid)) {
    throw new SecurityException("Not allowed to add developer verification experiment");
}
```

`clearDeveloperVerificationExperiment` にも同様に以下が追加されました。

```java
final int callerUid = Binder.getCallingUid();
if (!PackageManagerServiceUtils.isRootOrShell(callerUid)) {
    throw new SecurityException("Not allowed to clear developer verification experiment");
}
```

コミットメッセージも `Caller must be shell or root.` と明記しています。つまり、本来このAPIは `pm set-developer-verification-result` / `pm clear-developer-verification-result` のようなshell・テスト用途だけに許可されるべきものでした。

## 根本原因

根本原因は、system_server内の `PackageInstallerService` が提供するテスト用状態変更APIを、Binder境界で認可せず公開していたことです。

`IPackageInstaller.aidl` の周辺APIには `@PermissionManuallyEnforced`、`@EnforcePermission("DEVELOPER_VERIFICATION_AGENT")`、`@EnforcePermission("SET_DEVELOPER_VERIFICATION_USER_RESPONSE")` が付いています。一方で問題の2メソッドには権限アノテーションがありませんでした。修正前のサーバ側実装も、呼び出し元UIDを検証せずに `mDeveloperVerifierController.addExperiment(...)` / `clearExperiment(...)` へ渡していました。

## 脆弱性が起きる状況

攻撃者は、通常アプリから `IPackageInstaller` Binderに到達し、対象パッケージ名に対して developer verification experiment を設定します。設定値に「検証成功」を含めると、そのパッケージの次回インストール時に通常の developer verifier service 経路ではなくローカル実験経路が使われ、検証がテスト理由でバイパスされた扱いになります。

このため、developer verification が本来なら拒否、警告、ユーザー確認、または失敗扱いにするインストールについて、攻撃者が事前に成功結果を注入して「未検証アプリのインストール」を通せます。追加権限やユーザー操作なしで成立するので、bulletinの EoP / High と整合します。

`clearDeveloperVerificationExperiment` は単体では主なバイパス手段ではありませんが、同じテスト用状態を任意UIDから消せるため、同じ認可境界の欠落として修正されています。

## 面白い点・調査メモ

- Bulletin上の `CVE-2026-0089` 行は参照IDがリンク化されておらず、修正コミットは直接載っていませんでした。OSV JSONからfix URLとVanir signatureを取得する必要がありました。
- `16-qpr2` のfix URLはOSVに載っているものの、public Gitilesでは404でした。一方、`17-next` の同等コミットは公開されており、署名対象関数・追加コードが同一です。
- AIDLでは近接する developer-verification APIだけ権限注釈があり、問題の実験用APIだけ注釈が抜けていました。実装差分が4行ずつしかないため、典型的な「テスト用フックを公開Binderへ置いたが権限境界を忘れた」パターンです。
- コミット本文のSTSテスト名は `android.security.sts.Bug_485397908#testBug_485397908` で、脆弱性の再現が「root/shell以外から呼ぶと拒否されるべき」という形式でテスト化されたと推測できます。

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

- `artifacts/ASB-A-485397908.json`: Android OSV JSON
- `artifacts/bulletin-2026-06-01.html`: Android Security Bulletin
- `artifacts/1459299f9d3e5da1254a4653be4ac3defec20759.commit.json`: add側修正コミット情報
- `artifacts/c15dea2dc3bb0ebeefeb59eb74290ac9fa918bf8.commit.json`: clear側修正コミット情報
- `artifacts/addDeveloperVerificationExperiment.patch`: add側raw diff
- `artifacts/clearDeveloperVerificationExperiment.patch`: clear側raw diff
- `artifacts/IPackageInstaller.developer_verification_excerpt.txt`: AIDL抜粋
- `artifacts/16-qpr2-fetch-status.tsv`: 16-qpr2 fix URLの取得結果
- `artifacts/analysis-notes.md`: 解析メモ
- `artifacts/SHA256SUMS.txt`: 付帯ファイルのハッシュ
020 OK

CVE-2026-0091

020-ok-remote-transition-appthread-leak-eop

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-438742644
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0091 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

CVE-2026-0091 は、Framework の Shell Transitions / RemoteTransition 周辺で、アニメーションdelegateを表す IApplicationThread Binder capability を TransitionRequestInfo 経由で WM Core の外へ出していた問題だったと判断した。修正後は、delegateを Transition.mRemoteDelegate として system_server 内の Transition に保持し、Shell 側は IApplicationThread ではなく transition token だけを ActivityTaskManagerService.setRunningRemoteTransitionDelegate() に返す。

脆弱性の本質は「リモート遷移を動かすアプリプロセスを表す強いBinder参照を、Shellに通知する要求データへ混ぜていたこと」にある。IApplicationThread は単なる識別子ではなく、アプリのメインスレッドへ system_server が各種ライフサイクル操作を配送するための権限付きBinderインターフェースなので、不要なプロセス境界へ渡すべきではない。

判定: ok。公開AOSPコミットで修正箇所と意図が確認でき、脆弱性が起きる状況を説明できる。

原因

根本原因は、信頼境界の設計ミス。WM Core内部でだけ必要な IApplicationThread capabilityを、Shellとのプロトコルである TransitionRequestInfo / RemoteTransition に混ぜてしまった。

より具体的には、priority boostのために必要だったのは「このtransitionに紐づくdelegateプロセスを実行中扱いにする」という状態更新だけだった。それにもかかわらず、実装はdelegateを表す強いBinder参照をShellへ渡し、Shellから再投入させる「plumbing」になっていた。このため、capability leakとdelegate mismatchの余地が生じていた。

どこから特定したか

解析したパッチ: ・Commit: 40c30bb5613ee94403723b37d0d6c58197d3d1b4
・URL: https://android.googlesource.com/platform/frameworks/base/+/40c30bb5613ee94403723b37d0d6c58197d3d1b4
・Parent: 50cbf4422ac8e930c522642f5dce0724581a6aa9
・Subject: Map animation delegate to the transition instead of plumbing it
・Test: atest ActivityManagerTest#testActivityManager_stripsAppThreadFromRemote…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01` / https://android.googlesource.com/platform/frameworks/base/+/40c30bb5613ee94403723b37d0d6c58197d3d1b4`

validated.md を表示
# CVE-2026-0091 検証結果

## 結論

`CVE-2026-0091` は、Framework の Shell Transitions / RemoteTransition 周辺で、アニメーションdelegateを表す `IApplicationThread` Binder capability を `TransitionRequestInfo` 経由で WM Core の外へ出していた問題だったと判断した。修正後は、delegateを `Transition.mRemoteDelegate` として system_server 内の `Transition` に保持し、Shell 側は `IApplicationThread` ではなく transition token だけを `ActivityTaskManagerService.setRunningRemoteTransitionDelegate()` に返す。

脆弱性の本質は「リモート遷移を動かすアプリプロセスを表す強いBinder参照を、Shellに通知する要求データへ混ぜていたこと」にある。`IApplicationThread` は単なる識別子ではなく、アプリのメインスレッドへ system_server が各種ライフサイクル操作を配送するための権限付きBinderインターフェースなので、不要なプロセス境界へ渡すべきではない。

判定: **ok**。公開AOSPコミットで修正箇所と意図が確認でき、脆弱性が起きる状況を説明できる。

## cve.md から確認した情報

- CVE: `CVE-2026-0091`
- 参照ID: `A-438742644`
- Component: `Framework`
- Subcomponent: Android Security Bulletin上は個別subcomponentなし。差分上の実体は WindowManager Shell Transitions / ActivityTaskManager / RemoteTransition。
- Type / Severity: `EoP`, `High`
- Bulletin URL: `https://source.android.com/docs/security/bulletin/2026/2026-06-01`
- 対象AOSP版: 14, 15, 16, 16-qpr2

## 解析したパッチ

- Commit: `40c30bb5613ee94403723b37d0d6c58197d3d1b4`
- URL: `https://android.googlesource.com/platform/frameworks/base/+/40c30bb5613ee94403723b37d0d6c58197d3d1b4`
- Parent: `50cbf4422ac8e930c522642f5dce0724581a6aa9`
- Subject: `Map animation delegate to the transition instead of plumbing it`
- Test: `atest ActivityManagerTest#testActivityManager_stripsAppThreadFromRemoteTransition`
- 詳細メモ: `artifacts/patch_diff_relevant.md`

コミットメッセージは、従来はanimation delegateをWMへ入れたあと `Request` 経由でWM外へ戻し、priority boost時に再びWMへ入れていた、と説明している。修正はdelegateをWM内のtransitionへ記録し、Shellはboost通知時にtransition tokenだけを渡す設計へ変えている。

## 修正前の挙動

修正前は `TransitionController.requestStartTransition()` が `TransitionRequestInfo` を作る際に、`RemoteTransition` をそのまま渡していた。`RemoteTransition` には `IRemoteTransition` だけでなく `IApplicationThread appThread` も入る。

そのため、Shellへ送られる `TransitionRequestInfo` に、リモートアニメーションを実行するアプリの `IApplicationThread` が含まれていた。Shell側はその `appThread` を取り出して、`ActivityTaskManagerService.setRunningRemoteTransitionDelegate(IApplicationThread delegate)` に渡し、対象プロセスをremote transition実行中として扱わせていた。

問題点は、`IApplicationThread` がプロセス識別用の無害な値ではないこと。これはアプリプロセスの `ApplicationThread` Binderであり、system_serverがアプリへ lifecycle / receiver / service / configuration 等の命令を配送するための能力を持つ。RemoteTransition通知という目的に対して、このcapabilityをShellへ配送する必要はなかった。

## 修正後の挙動

修正後は `TransitionController` が以下のように動く。

- 元の `remoteTransition.getAppThread()` は `transition.mRemoteDelegate` に保存する。
- Shellへ渡す `TransitionRequestInfo` には、`new RemoteTransition(remoteTransition.getRemoteTransition(), remoteTransition.getDebugName())` を入れる。
- つまり `appThread` を除去した `RemoteTransition` だけをShellへ送る。
- `IActivityTaskManager.setRunningRemoteTransitionDelegate()` の引数は `IApplicationThread` から `IBinder transition` に変わる。
- `ActivityTaskManagerService` は `Transition.fromBinder(transitionToken)` でserver-side transitionを引き、そこから `transition.mRemoteDelegate` を取り出す。

この変更により、Shellは「どのアプリの `IApplicationThread` をboostするか」を指定できない。Shellが通知するのは「どのtransitionが実行中か」だけで、delegate解決はsystem_server内の状態に閉じる。

## 根本原因

根本原因は、信頼境界の設計ミス。WM Core内部でだけ必要な `IApplicationThread` capabilityを、Shellとのプロトコルである `TransitionRequestInfo` / `RemoteTransition` に混ぜてしまった。

より具体的には、priority boostのために必要だったのは「このtransitionに紐づくdelegateプロセスを実行中扱いにする」という状態更新だけだった。それにもかかわらず、実装はdelegateを表す強いBinder参照をShellへ渡し、Shellから再投入させる「plumbing」になっていた。このため、capability leakとdelegate mismatchの余地が生じていた。

## 脆弱性が起きる状況

攻撃面は、`RemoteTransition` を伴うactivity/task transitionが発生し、WMがShellへ `TransitionRequestInfo` を送る経路。たとえば `ActivityOptions` や split/recents 系のremote transitionで、Shellがtransition requestを処理する。

修正前はこのrequest中の `RemoteTransition` に `appThread` が残るため、Shell側またはShell経由でrequest内容を扱うコードが、アプリの `IApplicationThread` Binder capabilityを観測・保持・誤用できる状態だった。CVEのEoP評価は、このBinder capabilityが本来system_serverの内部管理対象で、外部コンポーネントへ渡ることでアプリプロセス操作の権限境界が崩れる点に由来すると見ている。

完全なPoCは作成していないが、修正テスト名 `testActivityManager_stripsAppThreadFromRemoteTransition` と差分から、セキュリティ不変条件は「Shellへ送る `TransitionRequestInfo.remoteTransition.appThread` はnullでなければならない」と読み取れる。

## 面白い点・調査メモ

- パッチは単純な権限チェック追加ではなく、API形状を `IApplicationThread` 受け渡しからtransition token受け渡しへ変えている。これはcapabilityを渡さない設計修正で、根本対策になっている。
- `WindowContainerTransaction.setAnimationDelegate()` が追加されている。recents launchのように通常の `RemoteTransition` だけではdelegateを伝えられない経路では、WCT hierarchy opとしてWM内にdelegateを記録する。
- 既存の `RemotePlayer.reportRunning(IApplicationThread)` 自体は残っているが、呼び出し元が任意にdelegateを指定する構造ではなく、server-side `Transition` から導出する構造へ変わった。
- Shell側の複数箇所が `Transitions.setRunningRemoteTransitionDelegate(remote.getAppThread())` から `Transitions.setRunningRemoteTransitionDelegate(transition)` へ変わっており、修正意図が一貫している。
- `curl` / `git ls-remote` によるandroid.googlesource.com直接取得はローカルshellから `Recv failure: Connection reset by peer` で失敗したため、Gitiles HTMLで確認した差分を `artifacts/patch_diff_relevant.md` に保存した。

## 付帯ファイル

- `artifacts/patch_diff_relevant.md`: 主要差分の抜粋と意味
- `artifacts/references.txt`: 解析に使ったURL、commit、取得時の注意
- `artifacts/acquisition_log.txt`: 取得コマンド、失敗したraw取得、fallback方法
- `artifacts/40c30bb5613ee94403723b37d0d6c58197d3d1b4.diff`: 取得を試みたがローカルネットワークで0バイトになったraw diff
- `artifacts/40c30bb5613ee94403723b37d0d6c58197d3d1b4.json`: 取得を試みたがローカルネットワークで0バイトになったcommit JSON
021 OK

CVE-2026-0100

021-ok-loadedarsc-package-id-oob-write

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-484973621
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0100 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

脆弱性を特定できた。CVE-2026-0100 は Android Framework の libs/androidfw における、resources.arsc の RES_TABLE_PACKAGE_TYPE package ID 検証不備である。

ResTable_package::id はファイル形式上 uint32_t だが、Android の resource ID は 0xPPTTEEEE 形式で package ID に 8 bit しか割り当てていない。未修正の LoadedPackage::Load() は header->id を範囲確認せず loaded_package->package_id_ に保存していた。その後 AssetManager2::BuildDynamicRefTable() がこの値を 256 要素の package_ids_ 配列の index として使うため、id = 256 以上の malformed ARSC により heap out-of-bounds read/write が起き得る。

修正は LoadedPackage::Load() で package_id > 255 を拒否するもの。追加テストも id = 256 の ARSC を作成し、ロード失敗を期待している。

原因

根本原因は、ファイル形式の ResTable_package::id が 32-bit であることと、実行時 resource ID / package lookup table が 8-bit package ID を前提にしていることの境界で、入力値の範囲検証が抜けていたこと。

既存コードは type ID については type_id_offset > 255 や type_spec->id + offset > 255 を検証していたが、package ID については同等の検証がなかった。そのため uint32_t の不正値が int package_id_ として保持され、std::array<uint8_t, 256> の index に使われた。

どこから特定したか

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://storage.googleapis.com/android-osv/ASB-A-484973621.json` / https://android.googlesource.com/platform/frameworks/base/+/ca855338abcfd12831122437d9d01ede37539bd5 / https://android.googlesource.com/platform/frameworks/base/+/50d18b36c708a7332eedecd88bc5e2cb2323b958

validated.md を表示
# CVE-2026-0100 検証結果

## 結論

脆弱性を特定できた。CVE-2026-0100 は Android Framework の `libs/androidfw` における、`resources.arsc` の `RES_TABLE_PACKAGE_TYPE` package ID 検証不備である。

`ResTable_package::id` はファイル形式上 `uint32_t` だが、Android の resource ID は `0xPPTTEEEE` 形式で package ID に 8 bit しか割り当てていない。未修正の `LoadedPackage::Load()` は `header->id` を範囲確認せず `loaded_package->package_id_` に保存していた。その後 `AssetManager2::BuildDynamicRefTable()` がこの値を 256 要素の `package_ids_` 配列の index として使うため、`id = 256` 以上の malformed ARSC により heap out-of-bounds read/write が起き得る。

修正は `LoadedPackage::Load()` で `package_id > 255` を拒否するもの。追加テストも `id = 256` の ARSC を作成し、ロード失敗を期待している。

## Bulletin 情報

- CVE: `CVE-2026-0100`
- 参照 ID: `A-484973621`
- Component: `Framework`
- Subcomponent: bulletin 上は明示なし。コード上の該当領域は `libs/androidfw` の ARSC/resource table parser。
- Type / Severity: `EoP`, `High`
- Updated AOSP versions: `14, 15, 16, 16-qpr2`
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: `https://storage.googleapis.com/android-osv/ASB-A-484973621.json`

OSV details は `LoadedArsc.cpp` の `Load` で heap buffer overflow による out-of-bounds write があり、追加権限なし・ユーザー操作なしでローカル権限昇格につながり得る、と説明している。

## パッチ

- Repository: `platform/frameworks/base`
- 公開参照 commit: `ca855338abcfd12831122437d9d01ede37539bd5`
- Commit URL: https://android.googlesource.com/platform/frameworks/base/+/ca855338abcfd12831122437d9d01ede37539bd5
- 取得できた同一修正 commit: `50d18b36c708a7332eedecd88bc5e2cb2323b958`
- Commit URL: https://android.googlesource.com/platform/frameworks/base/+/50d18b36c708a7332eedecd88bc5e2cb2323b958
- 変更ファイル:
  - `libs/androidfw/LoadedArsc.cpp`
  - `libs/androidfw/tests/LoadedArsc_test.cpp`

OSV の affected entries にはブランチ別 fixes として `50d18b36...`, `93ca69c4...`, `1a2ac700...`, `a3658d71...`, `ce1e718d...` が記録されている。`50d18b36...` は公開取得できた。`93ca69c4...`, `1a2ac700...`, `a3658d71...`, `ce1e718d...` はこの環境から googlesource で 404 だったが、OSV の Vanir signature は同じ `LoadedPackage::Load` / `LoadedArsc.cpp` を指している。OSV references の `ca855338...` は公開取得でき、差分は同じ範囲チェックである。

保存済み証跡:

- `artifacts/ASB-A-484973621.json`
- `artifacts/bulletin-2026-06-01.html`
- `artifacts/origin-patch-diffing-pipeline.html`
- `artifacts/ca855338abcf.commit.json`
- `artifacts/ca855338abcf.diff`
- `artifacts/50d18b36c708.commit.json`
- `artifacts/50d18b36c708.diff`
- `artifacts/LoadedArsc.before.cpp`
- `artifacts/LoadedArsc.after.cpp`
- `artifacts/LoadedArsc.before.h`
- `artifacts/AssetManager2.before.cpp`
- `artifacts/AssetManager2.before.h`
- `artifacts/ResourceTypes.before.h`
- `artifacts/ResourceTypes.before.cpp`
- `artifacts/*key-excerpts.txt`
- `artifacts/analysis-notes.md`
- `artifacts/SHA256SUMS.txt`

## 差分解析

未修正コード:

```cpp
loaded_package->package_id_ = dtohl(header->id);
```

修正後:

```cpp
const uint32_t package_id = dtohl(header->id);
if (package_id > std::numeric_limits<uint8_t>::max()) {
  LOG(ERROR) << "RES_TABLE_PACKAGE_TYPE package id is out of valid range";
  return {};
}

loaded_package->package_id_ = static_cast<int>(package_id);
```

追加テスト `LoadArscWithInvalidPackageId` は、`ResTable_header` と `ResTable_package` だけを持つ最小の ARSC 風データを作り、`data.package_header.id = htodl(256)` を設定する。修正後は `LoadedArsc::Load(&data, sizeof(data))` が null を返す。

## 脆弱性が起きる状況

攻撃者が malformed APK / resource container を用意し、`resources.arsc` 内の `RES_TABLE_PACKAGE_TYPE` chunk に `id = 256` 以上を設定する。

未修正の `LoadedPackage::Load()` はこの値を正常な package ID として保持する。package ID は後で `AssetManager2::BuildDynamicRefTable()` に渡る。非 dynamic package では次のように処理される。

```cpp
package_id = package->GetPackageId();
uint8_t idx = package_ids_[package_id];
if (idx == 0xff) {
  package_ids_[package_id] = idx = static_cast<uint8_t>(package_groups_.size());
  ...
}
```

一方、`package_ids_` は次の 256 要素配列である。

```cpp
std::array<uint8_t, std::numeric_limits<uint8_t>::max() + 1> package_ids_ = {};
```

したがって `package_id == 256` で index が 1 つ範囲外になり、`package_id > 256` ならさらに外側になる。上のコードは範囲外 read だけでなく、未登録 package の場合に `package_ids_[package_id] = ...` で範囲外 write を行う。OSV の heap buffer overflow / out-of-bounds write はこの経路で説明できる。

このバグは ARSC parsing の早い段階で起きるため、攻撃アプリに特別な権限は不要で、ユーザー操作も不要と評価されている。Framework が APK/resource をロード・解析するだけで malformed package ID が後段の 8-bit 前提の配列に到達する。

## 根本原因

根本原因は、ファイル形式の `ResTable_package::id` が 32-bit であることと、実行時 resource ID / package lookup table が 8-bit package ID を前提にしていることの境界で、入力値の範囲検証が抜けていたこと。

既存コードは type ID については `type_id_offset > 255` や `type_spec->id + offset > 255` を検証していたが、package ID については同等の検証がなかった。そのため `uint32_t` の不正値が `int package_id_` として保持され、`std::array<uint8_t, 256>` の index に使われた。

## 調査中に分かったこと

- commit message は「`RES_TABLE_PACKAGE_TYPE` の package ID は 32-bit だが、resource ID は package ID に 8 bit しか割り当てない」と明記している。これは今回の根本原因そのもの。
- 追加テストの最小悪性値は `256`。これは `uint8_t::max() + 1` で、`package_ids_[256]` がちょうど 1 要素 OOB になる。
- `LoadedPackage::iterator::operator*()` も `make_resid(loadedPackage_->package_id_, ...)` を呼ぶため、不正 package ID は resource ID 生成にも流れ得る。ただし heap OOB write として最も直接的に説明できる sink は `AssetManager2::BuildDynamicRefTable()` の `package_ids_[package_id]`。
- `RES_TABLE_LIBRARY_TYPE` 内の dynamic package mapping には `packageId >= 256` のチェックが既にあった。今回抜けていたのは package chunk 自体の `header->id`。
- `OSV references` の `ca855338...` は cherrypick で、message に `Cherrypick-From: ...1a2ac700...` とある。公開で取得できた `50d18b36...` と差分内容は同じ。

## 判定

`ok` とする。公開 AOSP ソースコードとパッチ差分から、脆弱な入力値、範囲検証漏れ、out-of-bounds write の sink、修正条件、追加テストまで説明できる。
022 OK

CVE-2026-28577

022-ok-toast-window-token-reuse-tapjacking

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-389950114
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-28577 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

CVE-2026-28577 は、Android Framework の WindowManagerService.addWindow() における TYPE_TOAST window token の再利用チェック不備である。

Android O 以降の app-rendered custom toast は token 必須で、NotificationManagerService が toast ごとに TYPE_TOAST の WindowToken を作成し、アプリの toast callback に渡す。設計上、この token は 1 個の toast window だけを持つ前提だった。

しかし修正前の WMS は、既存 token が TYPE_TOAST 型であることは確認していたものの、その token が既に window を持っているかを確認していなかった。既存の重複防止 DisplayContent.canAddToastWindowForUid() は UID 単位の制限なので、同じ token を別 UID から使うと迂回できる。結果として、1 つの toast token に複数の toast overlay window を追加でき、toast のキュー制御、時間制限、token 寿命モデルを崩して tapjacking/overlay 攻撃につながる。

原因

根本原因は、toast token のセキュリティ境界を UID 単位の重複チェックで代替していたこと。

TYPE_TOAST の token は「この token に 1 つだけ toast window を追加できる」という capability に近い意味を持つ。しかし修正前の WindowManagerService.addWindow() は、token type が TYPE_TOAST であることしか検証せず、token が既に消費済みかどうかを検証しなかった。

一方、既存の canAddToastWindowForUid() は「同じ UID が複数 toast を同時表示しない」ための互換性/DoS 制限であり、「同じ token を複数 window に使わせない」ための認可チェックではない。異なる UID で同じ token を使うケースが抜け、token の one-shot/one-window 前提が破れた。

どこから特定したか

保存した付帯ファイル: ・artifacts/ASB-A-389950114.json
・artifacts/bulletin-2026-06-01.html
・artifacts/origin-patch-diffing-pipeline.html
・artifacts/d9ad94e6.commit.json
・artifacts/d9ad94e6.diff
・artifacts/WindowManagerService.before.java
・artifacts/WindowManagerService.after.java
・artifacts/WindowManagerServiceTests.before.java
・artifacts/WindowManagerServiceTests.after.java
・art…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://storage.googleapis.com/android-osv/ASB-A-389950114.json / https://android.googlesource.com/platform/frameworks/base/+/d9ad94e69f4e810afbe983a31e4efae1b34a53c6

validated.md を表示
# CVE-2026-28577 検証結果

## 判定

ok: ソースコード差分、追加テスト、Toast/NotificationManagerService の実装から、脆弱性の発生条件と根本原因を特定できた。

## 基本情報

- CVE: `CVE-2026-28577`
- Android bug / 参照 ID: `A-389950114`
- Component: `Framework`
- Subcomponent: bulletin 上は明示なし。コード上は WindowManager / Toast window 管理。
- Type / Severity: `EoP` / `High`
- Updated AOSP versions: `14, 15, 16, 16-qpr2`
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://storage.googleapis.com/android-osv/ASB-A-389950114.json
- OSV details: `WindowManagerService.java` の `addWindow` における tapjacking/overlay attack。

## 結論

CVE-2026-28577 は、Android Framework の `WindowManagerService.addWindow()` における `TYPE_TOAST` window token の再利用チェック不備である。

Android O 以降の app-rendered custom toast は token 必須で、NotificationManagerService が toast ごとに `TYPE_TOAST` の `WindowToken` を作成し、アプリの toast callback に渡す。設計上、この token は 1 個の toast window だけを持つ前提だった。

しかし修正前の WMS は、既存 token が `TYPE_TOAST` 型であることは確認していたものの、その token が既に window を持っているかを確認していなかった。既存の重複防止 `DisplayContent.canAddToastWindowForUid()` は UID 単位の制限なので、同じ token を別 UID から使うと迂回できる。結果として、1 つの toast token に複数の toast overlay window を追加でき、toast のキュー制御、時間制限、token 寿命モデルを崩して tapjacking/overlay 攻撃につながる。

## パッチ

OSV に記載された branch fix hash は以下だが、2026-06-23 時点で Gitiles から直接取得すると 404 だった。

- Android 14: `17371594baff69a8ff477391955892c4f4826e9e`
- Android 15: `fd23e57220d587660cbe175d6b465cbc2aec222c`
- Android 16: `55aea98481db15689b390c54cae99c409281343f`
- Android 16-qpr2: `69ace6d38b365847d80653750f26b204adf6e663`
- 17-next: `352e98e9ed8ab9a0c63a499665b09d2ab2769f7e`

公開 Gitiles では、同じ `Bug: 389950114` を持ち、`Cherrypick-From: ...55aea98481db15689b390c54cae99c409281343f` と明記された代表 commit を確認できた。

- Repository: `platform/frameworks/base`
- Public commit: `d9ad94e69f4e810afbe983a31e4efae1b34a53c6`
- Commit URL: https://android.googlesource.com/platform/frameworks/base/+/d9ad94e69f4e810afbe983a31e4efae1b34a53c6
- Parent: `ca855338abcfd12831122437d9d01ede37539bd5`
- Subject: `Block adding toast windows to non-empty tokens.`
- Test: `atest WindowManagerServiceTests`
- 変更ファイル:
  - `services/core/java/com/android/server/wm/WindowManagerService.java`
  - `services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java`

修正内容は `WindowManagerService.addWindow()` の `TYPE_TOAST` 処理に以下を追加するもの。

```java
if (addToastWindowRequiresToken && !token.isEmpty()) {
    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
```

`WindowToken.isEmpty()` は `mChildren.isEmpty()` なので、既に window がぶら下がっている toast token への追加を拒否する。

## 脆弱な処理

修正前の `addWindow()` は、既存 token がある `TYPE_TOAST` について次の検証を行っていた。

- Android O 以降相当の app では `doesAddToastWindowRequireToken()` が true になる。
- token の window type が `TYPE_TOAST` でなければ拒否する。
- `DisplayContent.canAddToastWindowForUid(callingUid)` で同一 UID の同時 toast を制限する。

問題は、最後のチェックが UID 単位であり、token 単位ではなかったこと。`canAddToastWindowForUid()` は focused window を例外にしつつ、同じ UID の `TYPE_TOAST` が既に存在するかを見るだけで、同じ `WindowToken` に child が存在するかは見ない。

追加テスト `testAddToastWindow_singleWindowPerToken()` はこの迂回を直接表している。UID 1234 で同じ token に最初の toast window を追加し、その後 UID 1235 で同じ token に 2 つ目の toast window を追加する。テストコメントにも、2 つ目は `canAddToastWindowForUid` を迂回するため別 UID にしている、と書かれている。修正後は 2 つ目が `ADD_BAD_APP_TOKEN` で拒否される。

## 脆弱性が起きる状況

通常の custom toast 経路は以下の通り。

1. アプリが `Toast.show()` で NotificationManagerService に toast を enqueue する。
2. `NotificationManagerService.enqueueToast()` が toast ごとに `new Binder()` で `windowToken` を作る。
3. NMS が `mWindowManagerInternal.addWindowToken(windowToken, TYPE_TOAST, displayId, ...)` で WMS に `TYPE_TOAST` token を登録する。
4. `CustomToastRecord.show()` が app callback `ITransientNotification.show(windowToken)` を呼ぶ。
5. app 側 `Toast.TN.handleShow()` が `ToastPresenter.show()` を呼ぶ。
6. `ToastPresenter.adjustLayoutParams()` が `params.type = TYPE_TOAST`、`params.token = windowToken`、`hideTimeoutMilliseconds` を設定し、`WindowManager.addView()` する。

この token は「この toast のために発行された一時的な window token」であり、token ごとに 1 つの toast window だけが追加される前提で NMS のキュー制御・duration timeout・token cleanup が動く。

修正前は、同じ `TYPE_TOAST` token を使って別 UID から 2 つ目の toast window を追加した場合、WMS は token 非空を検出しない。UID が違えば `canAddToastWindowForUid()` の「同一 UID の同時 toast」制限にも引っかからない。そのため、本来 1 toast の寿命に束縛されるべき overlay window を複数追加できる。

OSV/NVD はこれを `addWindow` の tapjacking/overlay attack と説明している。Toast window は通常のアプリ権限で使える overlay 系 window で、画面上の UI に重ねて表示できる。token の単一 window 制約が破れると、NMS が想定する表示数・表示時間・cleanup と WMS 上の実 window 集合がずれ、権限ダイアログ等への視覚的誘導に使える overlay を成立させ得る。

## 根本原因

根本原因は、toast token のセキュリティ境界を UID 単位の重複チェックで代替していたこと。

`TYPE_TOAST` の token は「この token に 1 つだけ toast window を追加できる」という capability に近い意味を持つ。しかし修正前の `WindowManagerService.addWindow()` は、token type が `TYPE_TOAST` であることしか検証せず、token が既に消費済みかどうかを検証しなかった。

一方、既存の `canAddToastWindowForUid()` は「同じ UID が複数 toast を同時表示しない」ための互換性/DoS 制限であり、「同じ token を複数 window に使わせない」ための認可チェックではない。異なる UID で同じ token を使うケースが抜け、token の one-shot/one-window 前提が破れた。

## 調査中に分かったこと

- OSV の exact fix hash は Gitiles で 404 だったが、公開 commit `d9ad94e6...` が同じ bug ID と `Cherrypick-From: 55aea984...` を持っており、修正内容と追加テストを確認できた。
- commit message は「`TYPE_TOAST` の `WindowToken` は 1 つの toast window だけを許すので、非空 token への追加をブロックする」と明言している。
- 追加テストは、2 つ目の toast window を別 UID にして `canAddToastWindowForUid` を迂回する、とコメントしている。つまり問題は UID レート/重複制限そのものではなく、token 単位の消費済みチェック欠落である。
- `NotificationManagerService` は toast enqueue ごとに `windowToken` を新規作成し、`ToastRecord.windowToken` として保持する。token cleanup は NMS の duration/kill timeout と連動しているため、WMS 側で同じ token に複数 child を許すと、NMS の 1 record = 1 window 前提が崩れる。
- Android 14 の OSV signature には `Session.java` も含まれているが、公開代表パッチでは `WindowManagerService.java` とテストのみが変更されていた。脆弱性の本体は `addWindow()` の token 非空チェック欠落と判断した。

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

- `artifacts/ASB-A-389950114.json`
- `artifacts/bulletin-2026-06-01.html`
- `artifacts/origin-patch-diffing-pipeline.html`
- `artifacts/d9ad94e6.commit.json`
- `artifacts/d9ad94e6.diff`
- `artifacts/WindowManagerService.before.java`
- `artifacts/WindowManagerService.after.java`
- `artifacts/WindowManagerServiceTests.before.java`
- `artifacts/WindowManagerServiceTests.after.java`
- `artifacts/WindowToken.java`
- `artifacts/DisplayContent.java`
- `artifacts/NotificationManagerService.java`
- `artifacts/Toast.java`
- `artifacts/ToastPresenter.java`
- `artifacts/ToastRecord.java`
- `artifacts/CustomToastRecord.java`
- `artifacts/analysis-notes.md`
023 OK

CVE-2026-28580

023-ok-notification-channel-vibration-persistence-desync

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeEoP
SeverityHigh
Updated AOSP versions16, 16-qpr2
ReferencesA-481967442
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-28580 is listed in the Android Security Bulletin as a High severity EoP issue in Framework.

特定した具体的な脆弱性

CVE-2026-28580 / A-481967442 は、NotificationChannel の VibrationEffect を Parcel 経由で受け取る経路と XML 永続化経路でサイズ検証が一致していなかったことによる、通知チャネル設定の persistence desync です。

脆弱性は特定できました。修正対象は AOSP platform/frameworks/base の core/java/android/app/NotificationChannel.java で、根本原因は「XMLに永続化する値の上限を、実際のXML文字列長ではなく Parcel の残りバイト数で近似判定していた」こと、および writeXml() 側で vibration_effect 属性を書き出す直前に上限を再確認していなかったことです。

原因

根本原因は、同じ VibrationEffect に対して複数のシリアライズ表現を混同したことです。

・setVibrationEffect() は XML文字列長を正確に測って拒否していた。
・NotificationChannel(Parcel in) は XML文字列長ではなく Parcel の残りサイズで過大判定していた。
・writeXml() は実際に XML に書く直前の長さ制限を持っていなかった。

その結果、Binder/Parcel では受理されるが XML persistence では同じ意味で保存・復元できない NotificationChannel が作れていました。

どこから特定したか

確認した公開情報: ・Bulletin: Android Security Bulletin 2026-06-01
・Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
・CVE: CVE-2026-28580
・Reference: A-481967442
・Component/Subcomponent: Framework
・Type/Severity: EoP / High
・OSV: https://api.osv.dev/v1/vulns/ASB-A-481967442
・Public fix: https://android.googlesource.com/platform/frameworks/base/+…

パッチ解析: 修正コミット 80828212c3187adf56fc2a25d2d24001c5209937 は主に NotificationChannel.java を変更しています。

解析時に確認した決め手は次の3点です。

保存した付帯ファイル: ・artifacts/bulletin-2026-06-01.html: Android Security Bulletin本文
・artifacts/ASB-A-481967442.json: OSV/ASB JSON
・artifacts/80828212.commit.txt: 修正コミット本文
・artifacts/80828212.diff: 修正コミット差分
・artifacts/NotificationChannel.before_80828212.java: 親コミット側 Notification…

validated.md を表示
# CVE-2026-28580 検証結果

## 結論

`CVE-2026-28580 / A-481967442` は、`NotificationChannel` の `VibrationEffect` を Parcel 経由で受け取る経路と XML 永続化経路でサイズ検証が一致していなかったことによる、通知チャネル設定の persistence desync です。

脆弱性は特定できました。修正対象は AOSP `platform/frameworks/base` の `core/java/android/app/NotificationChannel.java` で、根本原因は「XMLに永続化する値の上限を、実際のXML文字列長ではなく Parcel の残りバイト数で近似判定していた」こと、および `writeXml()` 側で `vibration_effect` 属性を書き出す直前に上限を再確認していなかったことです。

## 確認した公開情報

- Bulletin: Android Security Bulletin 2026-06-01
- Bulletin URL: `https://source.android.com/docs/security/bulletin/2026/2026-06-01`
- CVE: `CVE-2026-28580`
- Reference: `A-481967442`
- Component/Subcomponent: `Framework`
- Type/Severity: `EoP / High`
- OSV: `https://api.osv.dev/v1/vulns/ASB-A-481967442`
- Public fix: `https://android.googlesource.com/platform/frameworks/base/+/80828212c3187adf56fc2a25d2d24001c5209937`
- Commit title: `Skip serialization of huge vibration effects in NotificationChannel`

OSV の説明は「multiple functions に incorrect bounds check があり、persistence desync による local escalation of privilege」となっており、差分内容と一致します。

## パッチ解析

修正コミット `80828212c3187adf56fc2a25d2d24001c5209937` は主に `NotificationChannel.java` を変更しています。

解析時に確認した決め手は次の3点です。

- `artifacts/NotificationChannel.before_80828212.java` の `NotificationChannel(Parcel in)` は `in.dataAvail()` を使って `largeEffect` を判定していた。
- `artifacts/NotificationChannel.before_80828212.java` の `writeXml()` は `ATT_VIBRATION_EFFECT` を長さ検査なしで書いていた。
- `artifacts/NotificationChannel.after_80828212.java` の `writeXml()` は `vibrationToString()` 済みの実文字列長を `MAX_SERIALIZED_VIBRATION_LENGTH` と比較してから書くようになった。

脆弱版の `NotificationChannel(Parcel in)` では、`VibrationEffect` を読み込む前に次のような近似判定をしていました。

```java
largeEffect = (in.dataAvail() > MAX_SERIALIZED_VIBRATION_LENGTH);
```

その後、`largeEffect` の場合だけ `cropToLengthOrNull(MAX_VIBRATION_LENGTH)` を試し、切り詰め不能なら `mVibrationEffect` を `null` にしていました。しかし `dataAvail()` は Parcel 上の残りサイズであり、XML化した `vibration_effect` 属性の文字列長ではありません。Parcel 表現が小さくても XML 表現が `MAX_SERIALIZED_VIBRATION_LENGTH` を超える、またはその逆のケースがあり得ます。

さらに脆弱版の `writeXml()` は、`mVibrationEffect` が存在し、同等の `mVibrationPattern` がない場合に、長さを確認せずに `ATT_VIBRATION_EFFECT` を書いていました。

```java
out.attribute(null, ATT_VIBRATION_EFFECT, vibrationToString(getVibrationEffect()));
```

修正版では、Parcel 復元時の `dataAvail()` による「XMLサイズ推定」をやめ、復元時は軽い trimming だけを行います。正確な制限は XML 書き出し直前に移されました。

```java
String serializedVibrationEffect = vibrationToString(getVibrationEffect());
if (serializedVibrationEffect.length() <= MAX_SERIALIZED_VIBRATION_LENGTH) {
    out.attribute(null, ATT_VIBRATION_EFFECT, serializedVibrationEffect);
}
```

これにより、永続化される値そのものの長さを永続化境界で検証するようになっています。

## 脆弱性が起きる状況

攻撃者アプリは通常の `setVibrationEffect()` APIを素直に使うと、巨大で切り詰め不能な effect は `getTrimmedVibrationEffect()` によって拒否されます。しかし実際の権限境界は、アプリプロセスから system_server の notification service へ渡る Binder/Parcelable 境界です。

悪意あるローカルアプリが手作りの Binder transaction / Parcel を使い、通常setterの検証を通らない `NotificationChannel` を system_server に渡すと、system_server 側の `NotificationChannel(Parcel in)` がその値を復元します。脆弱版ではこの復元時チェックが Parcel サイズによる近似だったため、XML永続化では扱えない `mVibrationEffect` をメモリ上のチャネル状態として受け入れ得ました。

通知チャネルは作成後にアプリから自由に変更できない永続設定です。`PreferencesHelper` でも、ユーザー変更時には `USER_LOCKED_VIBRATION` などを立て、通常の更新経路と永続化を前提に状態を管理しています。にもかかわらず、メモリ上のチャネル状態と、XMLバックアップ/復元または再起動後のチャネル状態が異なると、アプリは通常のチャネル更新権限を通らずに通知チャネルの振動挙動を変化させられます。これが OSV のいう local EoP です。

修正後テスト `testVibrationEffect_tooLongForSerialization_droppedWhenWritingXml` はこの状態を直接モデル化しています。テストは repeating waveform effect を作り、reflection で `mVibrationEffect` に直接代入して setter を迂回します。その後、Parcel round-trip では effect が残る一方、XML backup/restore 後は `getVibrationEffect() == null` になることを確認します。これは「通常setterを通らない不正な内部状態が Binder/Parcelable 境界で入る」という攻撃モデルの単体テスト上の再現です。

## 根本原因

根本原因は、同じ `VibrationEffect` に対して複数のシリアライズ表現を混同したことです。

- `setVibrationEffect()` は XML文字列長を正確に測って拒否していた。
- `NotificationChannel(Parcel in)` は XML文字列長ではなく Parcel の残りサイズで過大判定していた。
- `writeXml()` は実際に XML に書く直前の長さ制限を持っていなかった。

その結果、Binder/Parcel では受理されるが XML persistence では同じ意味で保存・復元できない `NotificationChannel` が作れていました。

## 面白い点・調査メモ

- 修正コミットのテストは `Field mVibrationEffect` への reflection を使って setter の検証を意図的に迂回しています。これはPoCそのものではなく、Binder/Parcelable境界で不正な内部状態が入った場合を単体テスト内で再現するためのショートカットです。
- 既存の `getTrimmedVibrationEffect()` は実際に `vibrationToString()` を呼び、`MAX_SERIALIZED_VIBRATION_LENGTH` を超えたら `null` を返すため、通常APIの入力検証は比較的正確でした。問題はその正確な検証がすべての入力経路と永続化経路に置かれていなかった点です。
- パッチは「Parcel復元時に厳密検査する」のではなく、「Parcel復元時は安価に扱い、XML永続化時に正確に落とす」方向です。コミットメッセージにも、unparceling時の厳密検査は性能影響が大きいと書かれています。
- `MAX_VIBRATION_LENGTH` は waveform timings の要素数上限、`MAX_SERIALIZED_VIBRATION_LENGTH` は XML文字列長上限であり、同じ「大きさ」でも測っている対象が違います。この違いがバグの本質です。
- 旧コードには「vibration effect は Parcel の最後に置く必要がある」というコメントがありました。`dataAvail()` が「残り全体のバイト数」しか見られないためで、この設計自体が特定フィールドのXML永続化サイズ検査として脆いことを示しています。修正後はこの制約コメントも削除されています。
- パッチは `dumpDebug()` の `record.put(ATT_VIBRATION_EFFECT, vibrationToString(getVibrationEffect()))` には手を入れていません。永続化境界ではないため、CVEの修正点は XML `writeXml()` に絞られています。

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

- `artifacts/bulletin-2026-06-01.html`: Android Security Bulletin本文
- `artifacts/ASB-A-481967442.json`: OSV/ASB JSON
- `artifacts/80828212.commit.txt`: 修正コミット本文
- `artifacts/80828212.diff`: 修正コミット差分
- `artifacts/NotificationChannel.before_80828212.java`: 親コミット側 `NotificationChannel.java`
- `artifacts/NotificationChannel.after_80828212.java`: 修正後 `NotificationChannel.java`
- `artifacts/NotificationChannel.before_after_80828212.diff`: 前後差分
- `artifacts/NotificationChannelTest.before_80828212.java`: 親コミット側テスト
- `artifacts/NotificationChannelTest.after_80828212.java`: 修正後テスト
- `artifacts/NotificationChannelTest.before_after_80828212.diff`: テスト差分
- `artifacts/PreferencesHelper.android-16.0.0_r2.java`: 通知チャネル作成・更新・ロック処理の確認用
- `artifacts/origin-patch-diffing-pipeline.html`: 参照された OriginHQ のパッチ解析パイプライン記事
- `artifacts/analysis-notes.md`: 解析メモ
- `artifacts/SHA256SUMS.txt`: 取得・生成ファイルのSHA-256

## 判定

`ok` とします。公開修正コミット、OSV の説明、前後ソース、追加テストから、脆弱性の対象コード、発生条件、根本原因、修正方針をソースコードベースで説明できました。
024 OK

CVE-2026-0016

024-ok-credentialmanager-cross-user-settings-id

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeID
SeverityHigh
Updated AOSP versions16, 16-qpr2
ReferencesA-460933604
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0016 is listed in the Android Security Bulletin as a High severity ID issue in Framework.

特定した具体的な脆弱性

CVE-2026-0016 / A-460933604 は、Android Framework の Credential Manager におけるマルチユーザー処理の不整合による情報漏えいです。脆弱性は特定できました。判定は ok です。

直接の根本原因は、CredentialManagerService.updateProvidersWhenServiceRemoved() が引数で受け取った対象ユーザー userId ではなく、UserHandle.myUserId() を使って Settings.Secure.CREDENTIAL_SERVICE_PRIMARY と Settings.Secure.CREDENTIAL_SERVICE を読み書きしていたことです。system_server でこのコードが動くため、UserHandle.myUserId() は通常 user 0 になり、別ユーザーの credential provider 削除処理が user 0 の secure settings を上書きし得ます。

原因

記載なし。

どこから特定したか

確認した公開情報: ・Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
・OSV: https://storage.googleapis.com/android-osv/ASB-A-460933604.json
・CVE: CVE-2026-0016
・参照 ID: A-460933604
・Component / Subcomponent: Framework
・Type: ID
・Severity: High
・OSV details: updateProvidersWhenServiceRemoved で permissions bypass により users を跨いで settings を override でき、lo…

解析した commit / diff: ・10b748dbc3488c8deb232f47b923c93d8ab01371
- URL: https://android.googlesource.com/platform/frameworks/base/+/10b748dbc3488c8deb232f47b923c93d8ab01371
- 保存: artifacts/commit-10b748dbc3488c8deb232f47b923c93d8ab01371.diff
- 代表的な公開 cherry-pick。CredentialManagerService と AbstractMasterSystemService の実効修正を確認。
・a631806c7aef2d0adf40793883957956aaada357
- UR…

パッチ差分…

validated.md を表示
# CVE-2026-0016 検証結果

## 結論

CVE-2026-0016 / A-460933604 は、Android Framework の Credential Manager におけるマルチユーザー処理の不整合による情報漏えいです。脆弱性は特定できました。判定は `ok` です。

直接の根本原因は、`CredentialManagerService.updateProvidersWhenServiceRemoved()` が引数で受け取った対象ユーザー `userId` ではなく、`UserHandle.myUserId()` を使って `Settings.Secure.CREDENTIAL_SERVICE_PRIMARY` と `Settings.Secure.CREDENTIAL_SERVICE` を読み書きしていたことです。system_server でこのコードが動くため、`UserHandle.myUserId()` は通常 user 0 になり、別ユーザーの credential provider 削除処理が user 0 の secure settings を上書きし得ます。

加えて、`AbstractMasterSystemService.removeInvalidCachedServicesLocked()` が `visitServicesLocked()` で全ユーザーの cached service を走査し、package name だけで対象判定していました。修正前は `s.getUserId() == userId` を確認していなかったため、あるユーザーの package update / service invalidation が別ユーザーの cached service に波及し、上記の誤った settings 書き込み経路を起動できる状態でした。

## 確認した公開情報

- Bulletin: `https://source.android.com/docs/security/bulletin/2026/2026-06-01`
- OSV: `https://storage.googleapis.com/android-osv/ASB-A-460933604.json`
- CVE: `CVE-2026-0016`
- 参照 ID: `A-460933604`
- Component / Subcomponent: `Framework`
- Type: `ID`
- Severity: `High`
- OSV details: `updateProvidersWhenServiceRemoved` で permissions bypass により users を跨いで settings を override でき、local information disclosure につながる、と記載。

## 解析した commit / diff

- `10b748dbc3488c8deb232f47b923c93d8ab01371`
  - URL: `https://android.googlesource.com/platform/frameworks/base/+/10b748dbc3488c8deb232f47b923c93d8ab01371`
  - 保存: `artifacts/commit-10b748dbc3488c8deb232f47b923c93d8ab01371.diff`
  - 代表的な公開 cherry-pick。`CredentialManagerService` と `AbstractMasterSystemService` の実効修正を確認。
- `a631806c7aef2d0adf40793883957956aaada357`
  - URL: `https://android.googlesource.com/platform/frameworks/base/+/a631806c7aef2d0adf40793883957956aaada357`
  - 保存: `artifacts/commit-a631806c7aef2d0adf40793883957956aaada357.diff`
  - 17-next 側の修正。`Flags.multiUserFixEnabled()` で userId 修正を gated rollout している。
- `ffdfa5c70fcaeabb63ef0ec41c33acd2466316dd`
  - URL: `https://android.googlesource.com/platform/frameworks/base/+/ffdfa5c70fcaeabb63ef0ec41c33acd2466316dd`
  - 保存: `artifacts/commit-ffdfa5c70fcaeabb63ef0ec41c33acd2466316dd.diff`
  - テストから multi-user flag 参照を削除する後続 commit。

OSV は `8458cfc84b460c37a9936f40f80dc960419b51b6`, `67619d9eb580710bc82a2bbf95677d41476c6bef`, `ce3708dbb0316d93ebb441f416d3cd1945f7221c`, `509569d8352076426523cd7c01891880c0a90307` も branch-specific fix として列挙しています。検証時に `?format=TEXT` で直接取得を試みましたが 404 でした。取得時の headers は `artifacts/fetched/` に保存しています。

## パッチ差分から見える脆弱箇所

### CredentialManagerService

修正前の `updateProvidersWhenServiceRemoved(SettingsWrapper, ComponentName, int userId)` は、冒頭で primary providers を `userId` から読んでいます。

- 修正前保存ファイル: `artifacts/CredentialManagerService-163acedb9164acf6320391fd5afe12aeadcf14d7.java`
- 修正後保存ファイル: `artifacts/CredentialManagerService-10b748dbc3488c8deb232f47b923c93d8ab01371.java`

問題はその後です。修正前は以下の操作で `UserHandle.myUserId()` を使っていました。

- `Settings.Secure.CREDENTIAL_SERVICE_PRIMARY` の filtered 値を書き戻す。
- `Settings.Secure.CREDENTIAL_SERVICE` を読む。
- `Settings.Secure.CREDENTIAL_SERVICE` の filtered 値を書き戻す。

修正後はこれらがすべて引数の `userId` に置換されています。つまり、この CVE の直接修正は「対象ユーザーを最後まで保持して settings を読む/書く」ことです。

### AbstractMasterSystemService

修正前の `removeInvalidCachedServicesLocked(String[] validServices, String packageName, int userId)` は、全 cached service を `visitServicesLocked()` で走査し、`serviceComponentName.getPackageName().equals(packageName)` だけで対象にしていました。

修正後は `int serviceUserId = s.getUserId();` を追加し、条件が `serviceUserId == userId && packageName一致` になっています。これにより、package update event の対象ユーザーと異なるユーザーの cached service を処理しなくなります。

## 想定される脆弱性の成立条件

1. Credential provider が複数ユーザー環境で使われている。
2. user 0 と user 10 など、複数ユーザーに同じ provider package、または同名 package の cached service / settings が存在する。
3. 片方のユーザーで package update / service removal / invalidation 相当のイベントが発生する。
4. 修正前の `AbstractMasterSystemService` が package name だけで cached service を選び、別ユーザーの service removal 処理を呼び得る。
5. 修正前の `CredentialManagerService` が target `userId` ではなく `UserHandle.myUserId()` で secure settings を読み書きする。
6. 結果として、別ユーザー由来の provider 削除結果が user 0 の `CREDENTIAL_SERVICE_PRIMARY` / `CREDENTIAL_SERVICE` に反映される。

この settings は credential provider の有効化・primary provider 選択状態を表すため、ユーザー境界を越えた provider 設定状態の改変・露出につながります。OSV の `local information disclosure`、`no additional execution privileges`、`user interaction is not needed` という説明と整合します。

## テスト差分で確認できる意図

追加テスト `updateProvidersWhenServiceRemoved_multiUser_otherUserUnchanged` は、user 0 と user 10 の credential provider settings を別々に設定し、user 10 の service removal を実行した後、user 0 の `CREDENTIAL_SERVICE_PRIMARY` と `CREDENTIAL_SERVICE` が変化しないことを確認しています。

これは、このバグが単なる NullPointerException や DoS ではなく、「service removal 時に他ユーザーの credential settings を触らない」ことを保証する修正であることを示しています。

## 面白い点・調査メモ

- OSV の public details がかなり具体的で、`updateProvidersWhenServiceRemoved` と cross-user settings override まで明記されていました。パッチ diff と完全に一致します。
- 最初の修正 `a631806...` では `Flags.multiUserFixEnabled()` による分岐が入っており、旧挙動と新挙動が同じ関数内に残っていました。その後の代表 patch `10b748...` では直接 `userId` を使う実装になっています。
- `AbstractMasterSystemService` 側の修正がないと、`CredentialManagerService` 側だけ直しても「余計な別ユーザー service removal 処理」は走り得ます。したがって根本修正は、呼び出し元の userId フィルタと、呼び出し先の settings userId の両方です。
- Pixel 固有のバイナリ解析は不要でした。対象は AOSP Framework で、ソース diff から原因と修正を直接確認できました。

## 保存した artifact

- `artifacts/ASB-A-460933604.json`: Android OSV entry
- `artifacts/bulletin-2026-06-01.html`: Android Security Bulletin 保存版
- `artifacts/commit-10b748dbc3488c8deb232f47b923c93d8ab01371.diff`
- `artifacts/commit-a631806c7aef2d0adf40793883957956aaada357.diff`
- `artifacts/commit-ffdfa5c70fcaeabb63ef0ec41c33acd2466316dd.diff`
- `artifacts/CredentialManagerService-163acedb9164acf6320391fd5afe12aeadcf14d7.java`: 修正前代表
- `artifacts/CredentialManagerService-10b748dbc3488c8deb232f47b923c93d8ab01371.java`: 修正後代表
- `artifacts/AbstractMasterSystemService-163acedb9164acf6320391fd5afe12aeadcf14d7.java`: 修正前代表
- `artifacts/AbstractMasterSystemService-10b748dbc3488c8deb232f47b923c93d8ab01371.java`: 修正後代表
- `artifacts/fetched/`: 再取得した OSV、bulletin、OriginHQ 記事、Gitiles commit text、取得失敗 headers
- `artifacts/fetched/SHA256SUMS.txt`: 再取得 artifact の SHA-256
- `artifacts/analysis-notes.md`: 解析メモ

## 判定

`ok`: 公開 AOSP ソースコード差分と OSV details により、脆弱性の発生箇所、根本原因、成立条件、修正内容を具体的に説明できました。
025 OK

CVE-2026-0036

025-ok-malformed-split-enter-tapjacking

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeID
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-405392600
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0036 is listed in the Android Security Bulletin as a High severity ID issue in Framework.

特定した具体的な脆弱性

特定できた。CVE-2026-0036 は AOSP Framework の StageCoordinator.startAnimation() 周辺にある split-screen enter transition の状態不整合で、2 つの task 起動が同じ transition に畳まれ、後続 task が adjacent launch だった場合に、split enter が StageCoordinator の管理下に入らず、片側 stage だけが表示・残留し得る tapjacking/overlay 問題だった。

根本原因は、transition request の handler 解決が trigger task に強く依存している一方で、batched transition では trigger task が「adjacent launch された split 側 task」ではなく先に起動された task になることがあり、split enter として扱うべき transition を split handler が管理できなかったこと。古い startAnimation() は split が非アクティブなら即 false を返すだけで、片側だけ stage に入った malformed enter transition を検出・修復していなかった。

原因

根本原因は、split enter transition の完全性を handleRequest() の trigger task だけに依存して判定していたことと、startAnimation() 側に「split 非アクティブだが transition 内には split stage の opening task がある」という矛盾状態を修復するガードがなかったこと。

より具体的には、handleRequest() は request.getTriggerTask() から getStageOfTask(triggerTask) を計算して handler を決める。batched transition で trigger が先行 task を指すと、後続の adjacent launch task が split stage に関係していても StageCoordinator が enter split として握れない。その後、古い startAnimation() は !isSplitActive() で即 return するため、片側 task の stage reparent が取り残される。

どこから特定したか

解析したパッチ: ・mainline: 3be8f7ff61baa3a98320de393a94735aecc6e77c
- URL: https://android.googlesource.com/platform/frameworks/base/+/3be8f7ff61baa3a98320de393a94735aecc6e77c
- 保存: artifacts/commit-3be8f7ff61baa3a98320de393a94735aecc6e77c.diff
・public cherry-pick: 04814cb8a86e78a6c9ae9c061c491f36e5c552f9
- URL: https://android.googlesource.com/platform/frameworks/ba…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://storage.googleapis.com/android-osv/ASB-A-405392600.json / https://android.googlesource.com/platform/frameworks/base/+/3be8f7ff61baa3a98320de393a94735aecc6e77c / https://android.googlesource.com/platform/frameworks/base/+/04814cb8a86e78a6c9ae9c061c491f36e5c552f9

validated.md を表示
# CVE-2026-0036 / A-405392600 検証結果

## 結論

特定できた。CVE-2026-0036 は AOSP Framework の `StageCoordinator.startAnimation()` 周辺にある split-screen enter transition の状態不整合で、2 つの task 起動が同じ transition に畳まれ、後続 task が adjacent launch だった場合に、split enter が `StageCoordinator` の管理下に入らず、片側 stage だけが表示・残留し得る tapjacking/overlay 問題だった。

根本原因は、transition request の handler 解決が trigger task に強く依存している一方で、batched transition では trigger task が「adjacent launch された split 側 task」ではなく先に起動された task になることがあり、split enter として扱うべき transition を split handler が管理できなかったこと。古い `startAnimation()` は split が非アクティブなら即 `false` を返すだけで、片側だけ stage に入った malformed enter transition を検出・修復していなかった。

## 基本情報

- CVE: CVE-2026-0036
- Android bug/reference: A-405392600
- Component: Framework
- Type: ID
- Severity: High
- Subcomponent/file: `platform/frameworks/base`, `libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java`
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://storage.googleapis.com/android-osv/ASB-A-405392600.json

## 解析したパッチ

- mainline: `3be8f7ff61baa3a98320de393a94735aecc6e77c`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/3be8f7ff61baa3a98320de393a94735aecc6e77c
  - 保存: `artifacts/commit-3be8f7ff61baa3a98320de393a94735aecc6e77c.diff`
- public cherry-pick: `04814cb8a86e78a6c9ae9c061c491f36e5c552f9`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/04814cb8a86e78a6c9ae9c061c491f36e5c552f9
  - 保存: `artifacts/commit-04814cb8a86e78a6c9ae9c061c491f36e5c552f9.diff`
  - commit message 上で `260c1e81ccaee07cac1bc8de20187f44f343f09d` からの cherry-pick と記載されている。
- Android 14 backport: `f60c7771358ce3e5b84e4fe1f57f6f41da985841`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/f60c7771358ce3e5b84e4fe1f57f6f41da985841
  - 保存: `artifacts/commit-f60c7771358ce3e5b84e4fe1f57f6f41da985841.diff`
- OSV に載っていた `260c1e81...`, `8e2cb82...`, `6d8942...` は、この実行では android.googlesource.com から直接取得すると 404 だった。0 バイトの取得結果も `artifacts/` に残している。

## 脆弱性の発生条件

修正 commit message は次の発生条件を説明している。

1. 2 つの task がほぼ連続して起動される。
2. 後者の起動が adjacent launch である。
3. 2 つの起動が同じ transition に入る。
4. transition request の trigger task が後者の adjacent task ではなく、最初に起動された task になる。
5. `StageCoordinator` がその transition の handler として解決されず、enter transition が default transition handler に落ちる。
6. default handler は adjacent task だけを通常表示し、split pair としての整合性を作らない。

この結果、split-screen 用 stage に片側 task だけが入った malformed enter transition になり、攻撃者が overlay/tapjacking 的な画面状態を作れる。Bulletin 上の分類は ID だが、OSV の details は "tapjacking/overlay attack" および "local escalation of privilege" と書いており、公開メタデータ上は影響分類に揺れがある。

## パッチ内容

修正前の `StageCoordinator.startAnimation()` は、pending split transition でない場合に housekeeping を行う入口を持っていたが、split がアクティブでなければ即座に処理を諦めていた。

```java
if (!isSplitActive()) return false;
```

修正後は、この早期 return の前に malformed enter transition を検査する。

```java
if (!isSplitActive()) {
    final WindowContainerTransaction wct =
            SplitTransitionUtils.handleMalformedEnterTransition(info,
                    (taskInfo) -> getStageOfTask(taskInfo));
    if (wct != null) {
        mTransitions.startTransition(TRANSIT_CLOSE, wct, null);
    }
    return false;
}
```

新規追加された `SplitTransitionUtils.handleMalformedEnterTransition()` は、transition 内の opening task を走査し、それぞれが属する `StageTaskListener` を解決する。split enter として成立するには少なくとも 2 つの stage が必要だが、opening な split task が存在するのに parent stage が 1 つ以下なら malformed と判定する。

malformed と判定した場合、該当 task token を `null` parent、つまり TaskDisplayArea に reparent し、`TRANSIT_CLOSE` の cleanup transition を開始する。これにより、片側 stage だけが残った状態で default handler に描画されることを防ぐ。

## 根本原因

根本原因は、split enter transition の完全性を `handleRequest()` の trigger task だけに依存して判定していたことと、`startAnimation()` 側に「split 非アクティブだが transition 内には split stage の opening task がある」という矛盾状態を修復するガードがなかったこと。

より具体的には、`handleRequest()` は `request.getTriggerTask()` から `getStageOfTask(triggerTask)` を計算して handler を決める。batched transition で trigger が先行 task を指すと、後続の adjacent launch task が split stage に関係していても `StageCoordinator` が enter split として握れない。その後、古い `startAnimation()` は `!isSplitActive()` で即 return するため、片側 task の stage reparent が取り残される。

## 検証メモ

- `artifacts/StageCoordinator.before-04814.java:3098` 付近で修正前の早期 return を確認した。
- `artifacts/StageCoordinator.after-04814.java:3104` 付近で修正後の malformed transition 検出と `TRANSIT_CLOSE` cleanup を確認した。
- `artifacts/SplitTransitionUtils.java:41` 以降で、opening task の stage 数が 1 以下なら malformed とみなし、`WindowContainerTransaction.reparent(token, null, true)` する処理を確認した。
- `artifacts/SplitTransitionUtilsTests.java:90` 以降に、1 stage の opening transition は `assertNotNull(wct)`、2 stage の opening transition は `assertNull(wct)` という単体テストが追加されている。
- Android 14 backport では `StageTaskListener` を `public` にする差分もある。これは新規 helper が `common.split` package から `splitscreen` package の class を参照するための backport 上の都合で、脆弱性の本体ではない。

## 付帯ファイル

- `artifacts/ASB-A-405392600.json`: OSV JSON
- `artifacts/bulletin-2026-06-01.html`: Android Security Bulletin
- `artifacts/origin-patch-diffing-pipeline.html`: 参照した patch-diffing pipeline 記事
- `artifacts/commit-*.json`: Gitiles commit metadata
- `artifacts/commit-*.diff`: Gitiles diff
- `artifacts/StageCoordinator.before-*.java`, `artifacts/StageCoordinator.after-*.java`: 主要ブランチの前後ソース
- `artifacts/SplitTransitionUtils.java`: 新規 helper
- `artifacts/SplitTransitionUtilsTests.java`: 追加テスト
- `artifacts/SHA256SUMS.txt`: 保存物の SHA-256
- `artifacts/analysis-notes.md`: 調査ログとメモ

## 判定

`ok` と判定する。公開ソース差分、OSV の関数シグネチャ、commit message、追加テストがすべて `StageCoordinator.startAnimation()` の malformed split enter transition 修復を指しており、脆弱性が起きる状態と修正理由を説明できる。

026 OK

CVE-2026-0056

026-ok-ResStringPool-styleCount-oob-read

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeID
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-462431486
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0056 is listed in the Android Security Bulletin as a High severity ID issue in Framework.

特定した具体的な脆弱性

ok。AOSP の公開ソース差分から脆弱箇所、修正内容、根本原因を特定できた。

CVE-2026-0056 は platform/frameworks/base の libs/androidfw/ResourceTypes.cpp、具体的には ResStringPool::setTo() における ResStringPool_header.styleCount の境界検証不足による out-of-bounds read である。悪意ある APK / resources.arsc などに含まれる StringPool chunk の styleCount を実際の style offset 配列数より大きく偽装すると、旧コードは chunk 内の stringsStart より手前に styleCount * sizeof(uint32_t) 分の style offset 配列が収まっていることを確認しないまま受理していた。

その結果、setTo() の endian 変換ループ、または後続の styleAt(idx) で、StringPool chunk の style offset 配列外を uint32_t の style offset として読む可能性があった。Android の公開説明どおり、影響はローカル情報漏えい、追加権限不要、ユーザー操作不要。

原因

根本原因は、可変長配列の個数フィールド ResStringPool_header.styleCount を信頼しながら、対応する可変長領域の終端を検証していなかったこと。

より具体的には、mEntryStyles の開始位置チェックはあったが、styleCount 個の uint32_t が stringsStart までの領域に収まるという構造的不変条件を確認していなかった。また styleCount * sizeof(uint32_t) の乗算オーバーフローも明示的に拒否していなかった。

修正後は以下の 2 段階で拒否する。

1. styleCount > UINT32_MAX / 4 を拒否し、乗算オーバーフローを防ぐ
2. styleOffsetsStart + styleCount * 4 > stringsStart 相当の条件を拒否し、style offset 配列が文字列データ開始位置を越えないことを保証する

どこから特定したか

参照した公開情報: ・Android Security Bulletin 2026-06-01: https://source.android.com/docs/security/bulletin/2026/2026-06-01
・公開修正コミット: https://android.googlesource.com/platform/frameworks/base/+/d5a52f737cabce3d9a58e8c23f6201ea658287ac
・OSV: https://osv.dev/vulnerability/ASB-A-462431486
・OSV JSON: https://storage.googleapis.com/android-osv/ASB-A-462431486.json
・NVD: https://n…

取得・保存した付帯ファイル: ・patch-d5a52f737cabce3d9a58e8c23f6201ea658287ac.diff: 公開修正コミットの差分
・ResourceTypes.cpp.before: 親コミット dc3785a739bc197b6d71fa57ff798423fa51cb6b の修正前 ResourceTypes.cpp
・ResourceTypes.cpp.after: 修正コミット d5a52f737cabce3d9a58e8c23f6201ea658287ac の修正後 ResourceTypes.cpp
・ResourceTypes.h.after: ResStringPool_header の構造体定義確認用
・ResourceTypes_test.cpp.added: 追加された回帰テスト
・A…

パッチ差分の要点:…

validated.md を表示
# CVE-2026-0056 検証メモ

## 結論

`ok`。AOSP の公開ソース差分から脆弱箇所、修正内容、根本原因を特定できた。

CVE-2026-0056 は `platform/frameworks/base` の `libs/androidfw/ResourceTypes.cpp`、具体的には `ResStringPool::setTo()` における `ResStringPool_header.styleCount` の境界検証不足による out-of-bounds read である。悪意ある APK / resources.arsc などに含まれる StringPool chunk の `styleCount` を実際の style offset 配列数より大きく偽装すると、旧コードは chunk 内の `stringsStart` より手前に `styleCount * sizeof(uint32_t)` 分の style offset 配列が収まっていることを確認しないまま受理していた。

その結果、`setTo()` の endian 変換ループ、または後続の `styleAt(idx)` で、StringPool chunk の style offset 配列外を `uint32_t` の style offset として読む可能性があった。Android の公開説明どおり、影響はローカル情報漏えい、追加権限不要、ユーザー操作不要。

## 基本情報

- CVE: `CVE-2026-0056`
- Android bug: `A-462431486`
- Component: `Framework`
- Type: `ID`
- Severity: `High`
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Bulletin 上の対象: Android 14, 15, 16, 16-qpr2
- 対象パッケージ: `platform/frameworks/base`
- 対象関数: `libs/androidfw/ResourceTypes.cpp` の `ResStringPool::setTo`

## 参照した公開情報

- Android Security Bulletin 2026-06-01: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- 公開修正コミット: https://android.googlesource.com/platform/frameworks/base/+/d5a52f737cabce3d9a58e8c23f6201ea658287ac
- OSV: https://osv.dev/vulnerability/ASB-A-462431486
- OSV JSON: https://storage.googleapis.com/android-osv/ASB-A-462431486.json
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-0056

NVD/OSV の説明は「`ResourceTypes.cpp` の `setTo` に incorrect bounds check があり out-of-bounds read から local information disclosure につながる」という内容で、今回のパッチ解析結果と一致する。

## 取得・保存した付帯ファイル

- `patch-d5a52f737cabce3d9a58e8c23f6201ea658287ac.diff`: 公開修正コミットの差分
- `ResourceTypes.cpp.before`: 親コミット `dc3785a739bc197b6d71fa57ff798423fa51cb6b` の修正前 `ResourceTypes.cpp`
- `ResourceTypes.cpp.after`: 修正コミット `d5a52f737cabce3d9a58e8c23f6201ea658287ac` の修正後 `ResourceTypes.cpp`
- `ResourceTypes.h.after`: `ResStringPool_header` の構造体定義確認用
- `ResourceTypes_test.cpp.added`: 追加された回帰テスト
- `ASB-A-462431486.osv.json`, `ASB-A-462431486.osv.pretty.json`: OSV の機械可読情報
- `old-setTo-style-validation-lines.txt`: 旧コードの該当行抜粋
- `new-setTo-style-validation-lines.txt`: 新コードの該当行抜粋
- `ResStringPool_header-layout-lines.txt`: StringPool header レイアウト抜粋
- `added-test-lines.txt`: 追加テスト抜粋
- `fix-commits-summary.txt`: 公開・OSV 上で確認した修正コミットの要約

Pixel 固有のバイナリ解析は不要だった。今回の CVE は AOSP `platform/frameworks/base` の公開ソース修正で根本原因まで追える。

## パッチ差分の要点

修正コミット:

```text
d5a52f737cabce3d9a58e8c23f6201ea658287ac
Validate ResStringPool_header.styleCount
Bug: 462431486
Test: atest libandroidfw_tests
Test: Manual: An APK with invalid styleCount failed to install
```

主要差分は `ResStringPool::setTo()` の `styleCount > 0` 処理に以下の検証を追加した点。

```cpp
if (mHeader->styleCount >
    std::numeric_limits<decltype(mHeader->styleCount)>::max() / sizeof(uint32_t)) {
  ALOGW("Bad string block: potential integer overflow when finding style entries\n");
  return (mError = BAD_TYPE);
}

const size_t styleOffsetsStart =
    mEntryStyles.convert<uint8_t>() - mHeader.convert<uint8_t>();
if (mHeader->styleCount * sizeof(uint32_t) > (mHeader->stringsStart - styleOffsetsStart)) {
  ALOGW("Bad string block: style offsets extend past style data start\n");
  return (mError = BAD_TYPE);
}
```

また `libs/androidfw/tests/ResourceTypes_test.cpp` が追加され、次の 2 ケースが `BAD_TYPE` になることを検証している。

- `styleCount = UINT32_MAX`: `styleCount * sizeof(uint32_t)` のオーバーフロー懸念
- 実際は style offset が 1 個しかない StringPool に対して `styleCount = 2`: style offset 配列が `stringsStart` を越える

## 脆弱な旧コード

`ResStringPool_header` の仕様上、`styleCount != 0` の場合、string offset 配列の直後に `styleCount` 個の `uint32_t` style offset 配列があり、その後に文字列データ、さらに `stylesStart` から style span データが置かれる。

旧コードでは以下だけを確認していた。

- `mEntryStyles = mEntries + mHeader->stringCount` が整数オーバーフローで戻っていないこと
- `mEntryStyles` の開始位置が入力サイズを越えていないこと
- `stylesStart` が `header.size` 未満であること

しかし、肝心の「`mEntryStyles` から `styleCount * 4` bytes の style offset 配列全体が `stringsStart` より前に収まること」は検証していなかった。

問題のある旧コードの流れ:

```cpp
if (mHeader->styleCount > 0) {
    mEntryStyles = mEntries + mHeader->stringCount;
    if (mEntryStyles < mEntries) { ... }

    if ((mEntryStyles.convert<uint8_t>() - mHeader.convert<uint8_t>()) > (int)size) {
        ...
    }
    mStyles = data.offset(mHeader->stylesStart).convert<uint32_t>();
    if (mHeader->stylesStart >= mHeader->header.size) {
        ...
    }
    mStylePoolSize =
        (mHeader->header.size-mHeader->stylesStart)/sizeof(uint32_t);

    if (notDeviceEndian) {
        uint32_t* e = const_cast<uint32_t*>(mEntryStyles.unsafe_ptr());
        for (i=0; i<mHeader->styleCount; i++) {
            e[i] = dtohl(e[i]);
        }
    }
    ...
}
```

`styleCount` が偽装されると、`e[i]` が実際の style offset 配列外を読む。通常の little-endian Android 端末では `notDeviceEndian` は false になりやすいが、同じ不正な `styleCount` は `styleAt(idx)` の `idx < mHeader->styleCount` 判定にも使われるため、後続の API 呼び出しで `mEntryStyles + idx` が配列外を style offset として読む経路が残る。

`styleAt()` 側の旧コード:

```cpp
if (mError == NO_ERROR && idx < mHeader->styleCount) {
    auto offPtr = mEntryStyles + idx;
    ...
    const uint32_t off = ((offPtr.value())/sizeof(uint32_t));
    if (off < mStylePoolSize) {
        return (mStyles+off).convert<ResStringPool_span>();
    }
}
```

`setTo()` が不正な header を `NO_ERROR` として受理してしまうことが根本で、`styleAt()` は header の `styleCount` を信頼してしまう。

## 脆弱性が起きる状況

攻撃者が malformed APK / resource table を用意し、StringPool chunk を次のような不整合状態にする。

1. `stringCount > 0`
2. `styleCount > 0`
3. 実際に存在する style offset 配列数よりも `styleCount` を大きくする
4. `mEntryStyles` の開始位置自体は chunk/input 内に置く
5. `stylesStart` も `header.size` 未満に置く
6. ただし `mEntryStyles + styleCount * 4` が `stringsStart` を越えるようにする

旧 `setTo()` は 4 と 5 だけで満足し、6 を拒否しない。これにより style offset 配列の後ろにある文字列データや chunk 後続領域を、style offset 配列の一部として読みうる。

追加テスト `ResStringPool_HeaderStyleCountExceedsStyleOffsetCount` はこの状況を最小化している。正常な style 1 個の StringPool を生成した後、header の `styleCount` だけを `2` に改変し、修正後 `setTo()` が `BAD_TYPE` を返すことを確認している。

## 根本原因

根本原因は、可変長配列の個数フィールド `ResStringPool_header.styleCount` を信頼しながら、対応する可変長領域の終端を検証していなかったこと。

より具体的には、`mEntryStyles` の開始位置チェックはあったが、`styleCount` 個の `uint32_t` が `stringsStart` までの領域に収まるという構造的不変条件を確認していなかった。また `styleCount * sizeof(uint32_t)` の乗算オーバーフローも明示的に拒否していなかった。

修正後は以下の 2 段階で拒否する。

1. `styleCount > UINT32_MAX / 4` を拒否し、乗算オーバーフローを防ぐ
2. `styleOffsetsStart + styleCount * 4 > stringsStart` 相当の条件を拒否し、style offset 配列が文字列データ開始位置を越えないことを保証する

## 面白い点・調査メモ

- コミットメッセージの manual test は「invalid styleCount の APK が install に失敗する」だった。つまり、攻撃入力は APK の resource table として到達可能だったと見てよい。
- 修正は `styleCount` の妥当性だけに限定されており、`styleAt()` 自体の防御強化ではない。設計としては `setTo()` で不正な StringPool をロード時に拒否し、以後の accessor は header を信頼する形を維持している。
- 追加テストは実ファイルを手で構築せず、`StringPool::FlattenUtf8()` で正常な StringPool を作ってから header の `styleCount` だけを改変している。差分がこの CVE の本質、つまり「他フィールドは正常でも `styleCount` だけで壊せる」ことをよく示している。
- CVE レコードの CWE は NVD 側で `CWE-120` が付いているが、実態は C/C++ の古典的コピー先 overflow ではなく、resource chunk 内の可変長配列境界の検証漏れによる OOB read と見るのが正確。

## 判定

ソースコード、公開コミット、追加テスト、OSV/NVD の説明が一致しているため、脆弱性を特定できたと判断する。

推奨フォルダ名:

`026-ok-ResStringPool-styleCount-oob-read`
027 OK

CVE-2026-28586

027-ok-appops-suspended-note-start-bypass

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeID
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-477935679
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-28586 is listed in the Android Security Bulletin as a High severity ID issue in Framework.

特定した具体的な脆弱性

・判定: ok
・脆弱性: suspended app に対する AppOps の制限が checkOp 系だけに適用され、noteOp / startOp 系の実行経路では適用されていなかった。
・根本原因: AppOpsService が同じ AppOp 判定を複数の入口 (checkOperation、checkAudioOperation、noteOperationUnchecked、startOperationUnchecked、startOperationDryRun) に分散して実装しており、suspend 状態を確認する isOpRestrictedDueToSuspend() が note / start の内部入口に欠落していた。
・影響: suspended package であっても、OP_RECORD_AUDIO、OP_CAMERA、OP_VIBRATE、OP_PLAY_AUDIO など suspend 時に拒否すべき AppOp を noteOp / startOp 経由で MODE_ALLOWED として進められる可能性があった。AppOps はカメラ、マイク、音声再生などプライバシー関連リソースの使用許可ゲートとして使われるため、Android bulletin 上の分類は ID (Information Disclosure) / High。

原因

根本原因は「suspend による AppOps 制限」が AppOps の共通ポリシーとして一元化されず、複数の操作入口に個別実装されていたこと。

パッチ前にも isOpRestrictedDueToSuspend() 自体は存在し、checkOperation 系では呼ばれていた。つまり suspend 制限の設計がなかったのではなく、note / start という実際のリソース使用に近い入口へ同じ制限を適用し忘れた実装漏れだった。

どこから特定したか

参照情報: ・CVE: CVE-2026-28586
・Android bug / reference ID: A-477935679
・Component: Framework
・Type: ID
・Severity: High
・Updated AOSP versions: 14, 15, 16, 16-qpr2
・Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
・AOSP commit: https://android.googlesource.com/platform/frameworks/base/+/9bef8bf1eee45a434e10c40e61acaeb2f90e10ad
・Commit: 9bef…

保存した証跡ファイル: ・commit_9bef8bf1.txt: commit metadata と commit message
・commit_9bef8bf1.diff: Gitiles から取得した公式 raw diff (^!/?format=TEXT)
・gitiles_commit_diff_page.txt: 上記 raw diff 取得結果
・AppOpsService_before.java: parent commit の AppOpsService.java
・AppOpsService_after.java: fixed commit の AppOpsService.java
・AppOpsService_before_after.diff: before/after からローカル生成した diff
・S…

URL: https://sour…

validated.md を表示
# CVE-2026-28586 検証結果

## 結論

- 判定: ok
- 脆弱性: suspended app に対する AppOps の制限が `checkOp` 系だけに適用され、`noteOp` / `startOp` 系の実行経路では適用されていなかった。
- 根本原因: `AppOpsService` が同じ AppOp 判定を複数の入口 (`checkOperation`、`checkAudioOperation`、`noteOperationUnchecked`、`startOperationUnchecked`、`startOperationDryRun`) に分散して実装しており、suspend 状態を確認する `isOpRestrictedDueToSuspend()` が `note` / `start` の内部入口に欠落していた。
- 影響: suspended package であっても、`OP_RECORD_AUDIO`、`OP_CAMERA`、`OP_VIBRATE`、`OP_PLAY_AUDIO` など suspend 時に拒否すべき AppOp を `noteOp` / `startOp` 経由で `MODE_ALLOWED` として進められる可能性があった。AppOps はカメラ、マイク、音声再生などプライバシー関連リソースの使用許可ゲートとして使われるため、Android bulletin 上の分類は ID (Information Disclosure) / High。

## 参照情報

- CVE: CVE-2026-28586
- Android bug / reference ID: A-477935679
- Component: Framework
- Type: ID
- Severity: High
- Updated AOSP versions: 14, 15, 16, 16-qpr2
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- AOSP commit: https://android.googlesource.com/platform/frameworks/base/+/9bef8bf1eee45a434e10c40e61acaeb2f90e10ad
- Commit: `9bef8bf1eee45a434e10c40e61acaeb2f90e10ad`
- Parent: `a38e8de8dac3052b6b65aea5689a363832a257cd`
- Change-Id: `Ifeac8cebdec2fb8d6129ecfdf18b4413303b62f4`

## パッチ内容

commit message は問題をかなり明示している。

> Suspended apps could previously bypass AppOps restrictions by using the startOp and noteOp code paths, as these did not check the package suspended state.

修正対象は `platform/frameworks/base` の以下 2 ファイル。

- `services/core/java/com/android/server/appop/AppOpsService.java`
- `services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java`

`AppOpsService.java` では `noteOperationUnchecked()`、`startOperationUnchecked()`、`startOperationDryRun()` に以下のチェックが追加された。

```java
if (isOpRestrictedDueToSuspend(code, packageName, uid)) {
    return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
            packageName);
}
```

このチェックは既存の `verifyAndGetBypass()` 後、実際に op 状態を取得・開始・記録する前に置かれている。つまり不正な package/uid の検証を通した後、suspended package なら AppOps の通常状態に関係なく `MODE_IGNORED` で拒否する。

また `OPS_RESTRICTED_ON_SUSPEND` に `OP_RESERVED_FOR_TESTING` が追加された。これは本番の保護対象追加というより、テストで直接制御しやすい op を使うための変更と読める。既存の保護対象は `OP_RECORD_AUDIO`、`OP_CAMERA`、`OP_VIBRATE`、`OP_PLAY_AUDIO` だった。

## 脆弱性が起きる状況

1. ある package が `PackageManager.setPackagesSuspended()` などにより suspended 状態になる。
2. `AppOpsService` は suspend 時に特定の op を拒否する設計で、`checkOperation()` / `checkAudioOperation()` では `isOpRestrictedDueToSuspend()` により `MODE_IGNORED` を返していた。
3. しかしパッチ前の `noteOperationUnchecked()`、`startOperationUnchecked()`、`startOperationDryRun()` には同じ suspend チェックがなかった。
4. そのため、呼び出し側またはシステムサービスが `checkOp` ではなく `noteOp` / `startOp` によって AppOps 判定を行う経路では、suspended package でも通常の uid/package mode 判定に進んでしまう。
5. op の通常 mode が allowed/default allowed であれば、suspend されているにもかかわらず対象 op が許可される。

`startOperationDryRun()` も修正されている点が重要。proxy operation では、proxy 側を開始する前に proxied app が start 可能かを dry-run で確認するため、この経路にも suspend チェックが必要だった。

## 根本原因

根本原因は「suspend による AppOps 制限」が AppOps の共通ポリシーとして一元化されず、複数の操作入口に個別実装されていたこと。

パッチ前にも `isOpRestrictedDueToSuspend()` 自体は存在し、`checkOperation` 系では呼ばれていた。つまり suspend 制限の設計がなかったのではなく、`note` / `start` という実際のリソース使用に近い入口へ同じ制限を適用し忘れた実装漏れだった。

## テスト差分から分かること

`SuspendPackagesTest` は、従来 `checkOperation()` だけを確認していた。パッチ後は同じ suspended package に対して以下をすべて `MODE_IGNORED` と期待する。

- `checkOperation(...)`
- `noteOperation(...)`
- `startOperation(...)`

テスト対象 op は以下に変更された。

- `OP_RESERVED_FOR_TESTING`
- `OP_VIBRATE`
- `OP_PLAY_AUDIO`

commit message によると、以前の microphone/camera op 依存は「直接変更できない」ためやめている。これはテスト容易性のためのリファクタであり、実脆弱性の本質は `note` / `start` 経路の suspend チェック欠落にある。

## 面白い点・調査メモ

- Bulletin の Type は ID だが、commit message では「AppOps restrictions bypass」と表現されている。AppOps の対象にカメラ・マイクが含まれるため、許可バイパスの結果が情報漏えいに分類されたと判断できる。
- `checkOperation()` には既に suspend チェックがあったため、単純な `checkOp` ベースの検証だけでは脆弱性を見落とす。今回の修正テストが `check`、`note`、`start` を分けて確認するようになったのは、このバグの本質を反映している。
- `startOperation()` の public path には `OP_RECORD_AUDIO` / `OP_CAMERA` の foreground チェックのために `checkOperation()` を呼ぶ特別処理もあるが、すべての suspend restricted op や proxy/dry-run 経路を覆うには不十分だった。そのため内部の `startOperationUnchecked()` と `startOperationDryRun()` に直接チェックを追加している。
- Pixel 固有バイナリ解析は不要だった。AOSP Framework の公開 commit で原因と修正内容が特定できた。

## 保存した証跡ファイル

- `commit_9bef8bf1.txt`: commit metadata と commit message
- `commit_9bef8bf1.diff`: Gitiles から取得した公式 raw diff (`^!/?format=TEXT`)
- `gitiles_commit_diff_page.txt`: 上記 raw diff 取得結果
- `AppOpsService_before.java`: parent commit の `AppOpsService.java`
- `AppOpsService_after.java`: fixed commit の `AppOpsService.java`
- `AppOpsService_before_after.diff`: before/after からローカル生成した diff
- `SuspendPackagesTest_before.java`: parent commit の `SuspendPackagesTest.java`
- `SuspendPackagesTest_after.java`: fixed commit の `SuspendPackagesTest.java`
- `SuspendPackagesTest_before_after.diff`: before/after からローカル生成した test diff

## 実行・取得コマンド

```sh
curl -L --fail 'https://android.googlesource.com/platform/frameworks/base/+/9bef8bf1eee45a434e10c40e61acaeb2f90e10ad?format=TEXT' | base64 --decode > commit_9bef8bf1.txt
curl -L --fail 'https://android.googlesource.com/platform/frameworks/base/+/9bef8bf1eee45a434e10c40e61acaeb2f90e10ad%5E%21/?format=TEXT' | base64 --decode > gitiles_commit_diff_page.txt
cp gitiles_commit_diff_page.txt commit_9bef8bf1.diff
curl -L --fail 'https://android.googlesource.com/platform/frameworks/base/+/a38e8de8dac3052b6b65aea5689a363832a257cd/services/core/java/com/android/server/appop/AppOpsService.java?format=TEXT' | base64 --decode > AppOpsService_before.java
curl -L --fail 'https://android.googlesource.com/platform/frameworks/base/+/9bef8bf1eee45a434e10c40e61acaeb2f90e10ad/services/core/java/com/android/server/appop/AppOpsService.java?format=TEXT' | base64 --decode > AppOpsService_after.java
curl -L --fail 'https://android.googlesource.com/platform/frameworks/base/+/a38e8de8dac3052b6b65aea5689a363832a257cd/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java?format=TEXT' | base64 --decode > SuspendPackagesTest_before.java
curl -L --fail 'https://android.googlesource.com/platform/frameworks/base/+/9bef8bf1eee45a434e10c40e61acaeb2f90e10ad/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java?format=TEXT' | base64 --decode > SuspendPackagesTest_after.java
diff -u AppOpsService_before.java AppOpsService_after.java > AppOpsService_before_after.diff
diff -u SuspendPackagesTest_before.java SuspendPackagesTest_after.java > SuspendPackagesTest_before_after.diff
```

## 最終判定理由

公開 AOSP commit の commit message が `Bug: 477935679` と CVE 参照に一致し、修正差分が `noteOp` / `startOp` 経路に suspend チェックを追加している。テストも suspended package に対して `checkOperation` だけでなく `noteOperation` / `startOperation` が `MODE_IGNORED` になることを明示している。したがって、脆弱性条件、根本原因、修正内容をソースコードから特定できたため `ok` とする。
028 OK

CVE-2025-32348

028-ok-pip-pinned-window-background-activity-launch

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeDoS
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-406880479
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-32348 is listed in the Android Security Bulletin as a High severity DoS issue in Framework.

特定した具体的な脆弱性

判定: ok

CVE-2025-32348 は、Android Framework の Background Activity Launch (BAL) 判定で、Picture-in-Picture などの pinned window を通常の可視Activity/foreground taskと同等に扱っていたため、pinned window を持つアプリが本来許可されないバックグラウンドActivity起動を許可され得る脆弱性だった。

根本原因は認可条件の粒度不足。BALの「可視ActivityがあるUID」「foreground taskにActivityがあるプロセス」という例外が、WINDOWING_MODE_PINNED のActivityを除外していなかった。pinned window はユーザー前面に小さく表示されていても、通常の前面Activityと同じように任意のActivity起動権限を与えるべきではない。

原因

BAL例外が「可視であること」を過大評価していたこと。hasVisibleActivity() と hasActivityInVisibleTask() が、pinned/PIPという特殊なwindowing modeを区別せず、通常の可視Activityと同じ認可材料にしていた。

正しい境界は「ユーザーが通常の前面Activityとして操作している、non-pinnedな可視Activityを持つか」であり、pinned window はBAL許可の根拠から除外されるべきだった。

どこから特定したか

公開情報との差異メモ: Android bulletin の Framework 表では DoS / High として掲載されている。一方、NVD/GitHub/Mondoo 側のCVE説明は「possible background activity launch due to a missing permission check」「local escalation of privilege」としており、CVSSも AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H になっている。パッチ内容からも、実態はBAL認可バイパスであり、ユーザー操作なしのActivity前面化による権限境界/UX境界の破壊と見るのが自然。DoS分類はAndroid bulletin側の分類だが、CVE説明はEoP寄り。

解析したURL / commit / 付帯ファイル: ・Bulletin保存: artifacts/bulletin-2026-06-01.html
・NVD JSON保存: artifacts/nvd-CVE-2025-32348.json
・Commit一覧: artifacts/commit-summary.tsv
・各commitのGitiles JSON/diff:
- https://android.googlesource.com/platform/frameworks/base/+/b96d7a515e9e9c8e2e8351232c2b7cc502074a37
- https://android.googlesource.com/platform/frameworks/base/+/c879fb5561f221534bf9d13d58b…

パッチ解析:…

validated.md を表示
# CVE-2025-32348 検証結果

## 結論

判定: ok

CVE-2025-32348 は、Android Framework の Background Activity Launch (BAL) 判定で、Picture-in-Picture などの pinned window を通常の可視Activity/foreground taskと同等に扱っていたため、pinned window を持つアプリが本来許可されないバックグラウンドActivity起動を許可され得る脆弱性だった。

根本原因は認可条件の粒度不足。BALの「可視ActivityがあるUID」「foreground taskにActivityがあるプロセス」という例外が、`WINDOWING_MODE_PINNED` のActivityを除外していなかった。pinned window はユーザー前面に小さく表示されていても、通常の前面Activityと同じように任意のActivity起動権限を与えるべきではない。

## cve.md から確認した情報

- CVE: CVE-2025-32348
- Bulletin: Android Security Bulletin 2026-06-01
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Component: Framework
- Type: DoS
- Severity: High
- Updated AOSP versions: 14, 15, 16, 16-qpr2
- Reference: A-406880479

## 公開情報との差異メモ

Android bulletin の Framework 表では `DoS / High` として掲載されている。一方、NVD/GitHub/Mondoo 側のCVE説明は「possible background activity launch due to a missing permission check」「local escalation of privilege」としており、CVSSも `AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H` になっている。パッチ内容からも、実態はBAL認可バイパスであり、ユーザー操作なしのActivity前面化による権限境界/UX境界の破壊と見るのが自然。DoS分類はAndroid bulletin側の分類だが、CVE説明はEoP寄り。

## 解析したURL / commit / 付帯ファイル

- Bulletin保存: `artifacts/bulletin-2026-06-01.html`
- NVD JSON保存: `artifacts/nvd-CVE-2025-32348.json`
- Commit一覧: `artifacts/commit-summary.tsv`
- 各commitのGitiles JSON/diff:
  - https://android.googlesource.com/platform/frameworks/base/+/b96d7a515e9e9c8e2e8351232c2b7cc502074a37
  - https://android.googlesource.com/platform/frameworks/base/+/c879fb5561f221534bf9d13d58b497b8b20516ab
  - https://android.googlesource.com/platform/frameworks/base/+/7dd276c1cf343d034480ac5c8cc646f6da2a89d6
  - https://android.googlesource.com/platform/frameworks/base/+/a9caac794459dfad602b7fe17f190db441e05443
  - https://android.googlesource.com/platform/frameworks/base/+/4d488a6a05abacba0859fff475e3b00c46d79e01
  - https://android.googlesource.com/platform/frameworks/base/+/bc34b284c508cc5ffaa27b153acdeb896c3eb9ca
  - https://android.googlesource.com/platform/frameworks/base/+/6ed9e0385c8b8e81b222d0e7d929c642cf50951a

## パッチ解析

主修正は `b96d7a515e9e9c8e2e8351232c2b7cc502074a37` の "Ignore pinned Windows"。commit messageにも「Pinned windows (e.g. PIP windows) should not enable BAL.」と書かれている。

変更点:

- `BackgroundActivityStartController.BalState` に `mCallingUidHasVisibleNotPinnedActivity` と `mRealCallingUidHasVisibleNotPinnedActivity` を追加。
- 旧コードは `mCallingUidHasVisibleActivity` / `mRealCallingUidHasVisibleActivity` だけで `BAL_ALLOW_VISIBLE_WINDOW` を返していた。
- 新コードは `hasVisibleNotPinnedActivity(uid)` の結果がtrueの場合だけ `BAL_ALLOW_VISIBLE_WINDOW` を返す。
- `VisibleActivityProcessTracker` に `hasVisibleNotPinnedActivity(int uid)` を追加し、`wpc -> !wpc.inPinnedWindowingMode()` を満たす可視プロセスだけを一致させる。
- `WindowProcessController` から `BackgroundLaunchProcessController.areBackgroundActivityStartsAllowed()` へ `inPinnedWindowingMode()` を渡すように変更。
- `BackgroundLaunchProcessController` の「foreground taskにActivityがあるので許可」分岐は、通常のBALでは `!inPinnedWindow` を要求するようになった。ただし foreground service start チェックでは `isCheckingForFgsStart` の場合に従来の許可を残している。

テスト差分も脆弱条件を直接示している:

- `testCaller_appHasVisibleWindow` は、可視Activityがあっても non-pinned でなければ `BAL_BLOCK` を期待するように変更。
- `testRealCaller_appHasVisibleWindow` も同様に `BAL_BLOCK` へ変更。
- `testCaller_appHasVisiblePinnedWindow` / `testRealCaller_appHasNotPinnedVisibleWindow` が追加され、non-pinned可視Activityがある場合だけ `BAL_ALLOW_VISIBLE_WINDOW` を確認。
- `BackgroundLaunchProcessControllerTests.testForegroundTaskBlockedIfPinned` が追加され、pinned windowのみでは foreground task 例外が `BAL_BLOCK` になることを確認。
- `VisibleActivityProcessTrackerTests.testVisiblePinnedActivity` が追加され、pinned Activity は `hasVisibleActivity()` ではtrueでも `hasVisibleNotPinnedActivity()` ではfalseになることを確認。

## 脆弱性が起きる状況

1. 攻撃アプリがPicture-in-Picture等で pinned window を表示する。
2. pinned window は小さい常時表示UIであり、通常の前面Activityと違ってユーザーの現在操作中アプリを所有しているわけではない。
3. 旧実装では、そのpinned Activityが `VisibleActivityProcessTracker` 上の「可視Activity」として扱われ、`BackgroundActivityStartController` では `BAL_ALLOW_VISIBLE_WINDOW`、`BackgroundLaunchProcessController` では `BAL_ALLOW_FOREGROUND` の根拠になり得た。
4. その結果、攻撃アプリがバックグラウンド状態からActivity起動制限を回避し、全画面Activityを前面に出せる可能性があった。
5. これはユーザー操作なしで現在の操作を奪うため、Android bulletin上のDoS分類としては画面占有/操作妨害に該当し得る。同時に、NVDの説明どおり、BALという認可境界を回避するlocal EoP的な性質も持つ。

## 根本原因

BAL例外が「可視であること」を過大評価していたこと。`hasVisibleActivity()` と `hasActivityInVisibleTask()` が、pinned/PIPという特殊なwindowing modeを区別せず、通常の可視Activityと同じ認可材料にしていた。

正しい境界は「ユーザーが通常の前面Activityとして操作している、non-pinnedな可視Activityを持つか」であり、pinned window はBAL許可の根拠から除外されるべきだった。

## 面白い点 / 調査メモ

- Bulletinには7件のリンクがあるが、すべてが脆弱性修正本体ではない。`c879...` / `bc34...` / `4d488...` はテストの引数不整合を直すリリースブランチ向け修正とrevert/roll-forward。`7dd...` は一度のrevert。最終的に `a9ca...` の consolidated fix がロールフォワードしている。
- `a9ca...` のcommit messageには `ag/32704936`, `ag/35782210`, `ag/36195227`, `ag/36359572` と複数の社内変更が統合されたことが示される。`7dd...` では「app compat issue」を理由に一度revertされており、pinned windowをBALから外す変更は互換性影響があったと分かる。
- `6ed9...` は `use_visible_requested_for_process_tracker` flag削除で、可視Activity追跡の条件を `ACTIVITY_STATE_FLAG_IS_VISIBLE` に寄せる変更。CVE本体の pinned window 除外ではないが、同じ可視Activity追跡面の整理としてbulletin行に含まれている。
- テスト変数名に `mInPinnedWindoMode` というtypoが残っている。セキュリティロジックには影響しないが、cherry-pick由来の細かい痕跡として残っている。

## 検証

- 公開bulletin HTMLを保存し、CVE行が A-406880479 と7件のframeworks/base commitへリンクしていることを確認した。
- Gitilesから各commitのJSONと `^!` diffを保存した。
- 主修正diffを読み、BAL許可判定が pinned window を除外するよう変わったことを確認した。
- 実機/atestは未実行。AOSP全体のビルド環境はこの作業ディレクトリに揃っていないため、検証は公開ソース差分とテスト差分の静的解析に基づく。
029 OK

CVE-2026-0018

029-ok-a11y-qs-tile-service-validation-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeDoS
SeverityHigh
Updated AOSP versions15, 16, 16-qpr2
ReferencesA-449392803
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0018 is listed in the Android Security Bulletin as a High severity DoS issue in Framework.

特定した具体的な脆弱性

このCVEは特定できた。Android Framework の AccessibilityManagerService が、アクセシビリティサービス/ショートカットのメタデータに書かれた Quick Settings TileService 名を十分に検証せず、内部状態と SystemUI の QS タイル追加/削除経路へ渡していたことによる DoS である。

根本原因は AccessibilityUserState.updateTileServiceMapForAccessibilityServiceLocked() と updateTileServiceMapForAccessibilityActivityLocked() が、getTileServiceName() から得た文字列を同一パッケージ内の ComponentName として組み立て、そのコンポーネントが本当に有効な TileService かを確認せず mA11yServiceToTileService / mA11yActivityToTileService に登録していた点。

修正後は、AccessibilityTileUtils.getValidA11yTileServices() が追加され、以下を満たすものだけを内部マップへ登録するようになった。

・TileService.ACTION_QS_TILE で解決できる
・ServiceInfo が存在する
・exported=true
・android.permission.BIND_QUICK_SETTINGS_TILE で保護されている
・component enabled state と manifest 上の enabled 状態から見て有効

原因

記載なし。

どこから特定したか

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/frameworks/base/+/7783a5265907eb5a4f14287d81ac4ab1249053a0

validated.md を表示
# CVE-2026-0018 パッチ解析結果

## 結論

このCVEは特定できた。Android Framework の AccessibilityManagerService が、アクセシビリティサービス/ショートカットのメタデータに書かれた Quick Settings TileService 名を十分に検証せず、内部状態と SystemUI の QS タイル追加/削除経路へ渡していたことによる DoS である。

根本原因は `AccessibilityUserState.updateTileServiceMapForAccessibilityServiceLocked()` と `updateTileServiceMapForAccessibilityActivityLocked()` が、`getTileServiceName()` から得た文字列を同一パッケージ内の `ComponentName` として組み立て、そのコンポーネントが本当に有効な `TileService` かを確認せず `mA11yServiceToTileService` / `mA11yActivityToTileService` に登録していた点。

修正後は、`AccessibilityTileUtils.getValidA11yTileServices()` が追加され、以下を満たすものだけを内部マップへ登録するようになった。

- `TileService.ACTION_QS_TILE` で解決できる
- `ServiceInfo` が存在する
- `exported=true`
- `android.permission.BIND_QUICK_SETTINGS_TILE` で保護されている
- component enabled state と manifest 上の enabled 状態から見て有効

## 対象情報

- CVE: CVE-2026-0018
- Bulletin: Android Security Bulletin, 2026-06-01
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Component: Framework
- Type: DoS
- Severity: High
- Reference: A-449392803
- 公開修正コミット: https://android.googlesource.com/platform/frameworks/base/+/7783a5265907eb5a4f14287d81ac4ab1249053a0
- Commit: `7783a5265907eb5a4f14287d81ac4ab1249053a0`
- Parent: `e770e9f0234158f4631c7147b64a1d70e0843d0b`
- Commit title: `Sanitize a11y qs shortcut tile service name before using it`

## 影響する実装

脆弱な実装では、アクセシビリティサービスの `AccessibilityServiceInfo.getTileServiceName()` またはアクセシビリティショートカットの `AccessibilityShortcutInfo.getTileServiceName()` から得たクラス名を、次のようにそのまま `ComponentName` にしていた。

- `pre/AccessibilityUserState.java`
  - `updateTileServiceMapForAccessibilityServiceLocked()`
  - `updateTileServiceMapForAccessibilityActivityLocked()`

問題のある処理は「同じパッケージのこのクラス名なら QS TileService だろう」という仮定だけで、実在性、`ACTION_QS_TILE` への解決、exported、`BIND_QUICK_SETTINGS_TILE`、enabled を確認していなかった。

このマップは次の経路で利用される。

- `AccessibilityManagerService.notifyQuickSettingsTilesChanged()`
- `AccessibilityManagerService.updateAccessibilityShortcutTargetsLocked(... QUICK_SETTINGS ...)`
- `AccessibilityManagerService.removeShortcutTargetForUnboundServiceLocked()`
- `AccessibilityManagerService.updateA11yTileServicesInQuickSettingsPanel()`
- `AccessibilityManagerService.getA11yFeatureToTileMapInternal()`

特に `updateA11yTileServicesInQuickSettingsPanel()` は、マップに入った TileService component を `StatusBarManagerInternal.addQsTileToFrontOrEnd()` / `removeQsTile()` に渡す。`StatusBarManagerService` の通常のアプリ向け `requestAddTile()` には TileService 妥当性検証があるが、Accessibility 経由の内部呼び出しでは修正前に同等の検証がなかった。

## 想定される攻撃/再現条件

攻撃者はアクセシビリティサービス、またはアクセシビリティショートカットを持つアプリを用意し、メタデータの `tileService` 相当の属性に不正なクラス名を指定する。

成立する不正入力の例:

- 実在しない TileService クラス名
- `TileService.ACTION_QS_TILE` で解決できない service
- `exported=false` の service
- `android.permission.BIND_QUICK_SETTINGS_TILE` で保護されていない service
- disabled な service

ユーザー切り替え、パッケージ変更、アクセシビリティ設定更新などで AMS がインストール済み a11y service/shortcut を再読込すると、修正前はこの不正 component が a11y feature -> tile service map に入る。その後、QS shortcut target の更新や QS panel 反映で SystemUI/StatusBar 側へ不正な TileService component が渡される。結果として QS タイル処理の整合性が崩れ、SystemUI 側のクラッシュ/再起動や関連 UI 処理停止につながる DoS と判断できる。

このCVEが DoS であり権限昇格ではない理由は、修正が権限境界の拡張ではなく、SystemUI/StatusBar に渡す component の妥当性検証と内部マップ汚染の防止に集中しているため。

## 修正内容

主な変更点:

- `AccessibilityTileUtils.java` を新規追加。
- `getValidA11yTileServices()` で、a11y service/shortcut に紐付く TileService component を PackageManagerInternal で検証。
- `AccessibilityUserState` の tile map 更新処理を、検証済み `Set<ComponentName>` に含まれるものだけ登録する形へ変更。
- `AccessibilityManagerService` は user switch、package changed、package update finished の各経路で、`mLock` を取る前に `getValidA11yTileServices()` を実行するよう変更。
- service/shortcut 情報が変わらない場合でも tile map を再構築するよう変更。コメントによると、初期ロードや package changed 時に PackageManager が TileService を解決できないことがあるため、常に再構築して stale map を避ける意図がある。

面白い点:

- commit message は「Sanitize a11y qs shortcut tile service name」と書いているが、実際の修正は文字列サニタイズではなく PackageManager での semantic validation。
- `StatusBarManagerService.requestAddTile()` には既に `isComponentValidTileService()` が存在した。つまり通常の TileService 追加APIでは検証していたが、Accessibility shortcut 連携用の内部経路だけ同等チェックが欠けていた。
- 修正では PackageManager 呼び出しを AMS の `mLock` 外へ移している。commit message にも、PackageManager 呼び出し中に AccessibilityManagerService が長時間ロックを保持することを避けるとある。CVEの直接原因は不正 component の信頼だが、ロック粒度も同時に改善されている。

## テストから分かること

追加された `AccessibilityTileUtilsTest` は、以下を明示的に拒否する。

- `pm == null`
- service/shortcut list が null/empty
- tileServiceName が null
- TileService が存在しない
- exported されていない
- permission が `BIND_QUICK_SETTINGS_TILE` ではない
- disabled

また、enabled state が `COMPONENT_ENABLED_STATE_DEFAULT` の場合は manifest の `ServiceInfo.enabled` を採用する。これは `StatusBarManagerService` 側にあった既存の考え方と整合する。

## 解析に使った付帯ファイル

- `cve.md`: 初期メタ情報
- `commit_7783a5265907.json`: Gitiles commit metadata
- `commit_7783a5265907_patch_base64.txt`: Gitiles TEXT形式のpatch
- `7783a5265907_full.patch`: decoded full patch
- `pre/AccessibilityManagerService.java`: parent commit の対象ファイル
- `post/AccessibilityManagerService.java`: fixed commit の対象ファイル
- `pre/AccessibilityUserState.java`: parent commit の対象ファイル
- `post/AccessibilityUserState.java`: fixed commit の対象ファイル
- `post/AccessibilityTileUtils.java`: 追加された検証ロジック
- `post/AccessibilityTileUtilsTest.java`: 追加された検証テスト
- `AccessibilityManagerService_pre_post.diff`: pre/post 差分
- `AccessibilityUserState_pre_post.diff`: pre/post 差分
- `systemui/StatusBarManagerService_pre.java`: StatusBarManagerInternal/通常 requestAddTile 検証経路の確認
- `systemui/CommandQueue_pre.java`: SystemUI command queue への QS tile add/remove 伝搬確認
- `systemui/QSHostAdapter_pre.kt`: QS host 側で ComponentName から TileSpec を作る経路の確認
- `systemui/qs_pipeline_tree.txt`: QS pipeline 周辺ファイル確認ログ

Pixel 固有バイナリは使っていない。今回の参照IDは公開AOSP `platform/frameworks/base` のソースパッチに直接解決でき、根本原因と修正内容をソースコードで確認できたため。

## 判定

`ok`。公開AOSPコミット、pre/post差分、追加テストから、脆弱性の発生条件、根本原因、修正意図をソースコード上で説明できる。
030 OK

CVE-2026-0069

030-ok-packageinstaller-pkcs7-signature-resource-exhaustion-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeDoS
SeverityHigh
Updated AOSP versions14
ReferencesA-480126173
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0069 is listed in the Android Security Bulletin as a High severity DoS issue in Framework.

特定した具体的な脆弱性

OK。ソースコード差分と呼び出し経路から脆弱性を特定できた。

この CVE は、アプリが PackageInstaller.Session#setChecksums() 経由で渡せる PKCS#7 detached signature の byte[] にサイズ上限がなく、system_server 側で ApkChecksums.verifySignature() がそれをそのまま sun.security.pkcs.PKCS7 に投入して ASN.1/証明書/SignerInfo を展開していたため、細工した大きな署名入力で system_server のメモリまたは CPU を消費させられるローカル DoS だった。

原因

根本原因は、system_server 内で処理する外部入力 signature に対し、PKCS#7 パーサへ渡す前のサイズ制限・リソース制限がなかったこと。

修正前の ApkChecksums.verifySignature() は、checksum を ByteArrayOutputStream に直列化した後、次を直接実行していた。

``java
PKCS7 pkcs7 = new PKCS7(signature);
`

どこから特定したか

パッチ差分の要点: Android 14 修正 a3ca193de2c8b789b59c9bfb7af529b9472da538 では services/core/java/com/android/server/pm/ApkChecksums.java に以下が追加された。

``java
private static final int MAX_SIGNATURE_SIZE_BYTES = 35 * 1024;
`

そして verifySignature(Checksum[] checksums, byte[] signature) の冒頭に以下が追加された。

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://osv.dev/vulnerability/ASB-A-480126173 / https://android.googlesource.com/platform/frameworks/base/+/a3ca193de2c8b789b59c9bfb7af529b9472da538 / https://android.googlesource.com/platform/frameworks/base/+/7250d76a8a2d501af62081d88545c301d43106a4

validated.md を表示
# CVE-2026-0069 / A-480126173 検証結果

## 判定

OK。ソースコード差分と呼び出し経路から脆弱性を特定できた。

この CVE は、アプリが `PackageInstaller.Session#setChecksums()` 経由で渡せる PKCS#7 detached signature の `byte[]` にサイズ上限がなく、system_server 側で `ApkChecksums.verifySignature()` がそれをそのまま `sun.security.pkcs.PKCS7` に投入して ASN.1/証明書/SignerInfo を展開していたため、細工した大きな署名入力で system_server のメモリまたは CPU を消費させられるローカル DoS だった。

## 元情報

- CVE: CVE-2026-0069
- Android bug / reference: A-480126173
- Component: Framework
- Type: DoS
- Severity: High
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://osv.dev/vulnerability/ASB-A-480126173
- OSV details: `In verifySignature of ApkChecksums.java, there is a possible way to cause a crash due to resource exhaustion. This could lead to local denial of service with no additional execution privileges needed. User interaction is not needed for exploitation.`
- 対象 AOSP version: Android 14
- Security patch level: 2026-06-01

## 修正コミット

- Android 14 修正: https://android.googlesource.com/platform/frameworks/base/+/a3ca193de2c8b789b59c9bfb7af529b9472da538
- 元コミット / 17-next: https://android.googlesource.com/platform/frameworks/base/+/7250d76a8a2d501af62081d88545c301d43106a4
- Android 14 parent: `d13e0e732fba5097cea9bdde935c67f6148853ad`
- Commit message: `Verify incoming signature.`
- Commit bug IDs: `Bug: 307288067`, `Bug: 480126173`
- Test: `atest ChecksumsTest`
- Change-Id: `Iea181bfa387f64ec58f8245b096010c3a1f48adf`

保存した主な証跡:

- `artifacts/ASB-A-480126173.json`: Android OSV JSON
- `artifacts/osv-summary.json`: OSV の要約
- `artifacts/a3ca193de2c8b789b59c9bfb7af529b9472da538.patch`: Android 14 修正差分
- `artifacts/a3ca193de2c8b789b59c9bfb7af529b9472da538.commit.decoded.txt`: Android 14 commit metadata
- `artifacts/7250d76a8a2d501af62081d88545c301d43106a4.patch`: 17-next 修正差分
- `artifacts/ApkChecksums_parent.java`, `artifacts/ApkChecksums_fixed.java`: 修正前後の対象ファイル
- `artifacts/PackageInstallerSession_parent.java`, `artifacts/PackageInstallerSession_fixed.java`: 修正前後の呼び出し元
- `artifacts/PackageInstaller_api_parent.java`: public API 側の `PackageInstaller.Session#setChecksums`
- `artifacts/IPackageInstallerSession_parent.aidl`: binder interface
- `artifacts/PKCS7.java`: Android 14 libcore の `sun.security.pkcs.PKCS7`
- `artifacts/SHA256SUMS.txt`: 取得物の SHA256

## パッチ差分の要点

Android 14 修正 `a3ca193de2c8b789b59c9bfb7af529b9472da538` では `services/core/java/com/android/server/pm/ApkChecksums.java` に以下が追加された。

```java
private static final int MAX_SIGNATURE_SIZE_BYTES = 35 * 1024;
```

そして `verifySignature(Checksum[] checksums, byte[] signature)` の冒頭に以下が追加された。

```java
if (signature == null || signature.length > MAX_SIGNATURE_SIZE_BYTES) {
    throw new SignatureException("Invalid signature");
}
```

`PackageInstallerSession.java` 側は例外メッセージに `e.getMessage()` を含めるだけで、セキュリティ上の本体は `ApkChecksums.verifySignature()` のサイズ制限である。

## 攻撃経路

public API の `PackageInstaller.Session#setChecksums(String name, List<Checksum> checksums, byte[] signature)` は deprecated だが存在しており、JavaDoc は `signature` を `DER PKCS#7 detached signature bytes over binary serialized checksums` と説明している。内部では `IPackageInstallerSession.setChecksums(String name, in Checksum[] checksums, in byte[] signature)` で system_server の `PackageInstallerSession.setChecksums()` に渡る。

修正前の `PackageInstallerSession.setChecksums()` は、`signature != null && signature.length != 0` の場合、所有者チェックより前に `ApkChecksums.verifySignature(checksums, signature)` を呼んでいた。呼び出し元 UID と installer package の整合性は `AppOpsManager.checkPackage()` で確認されるが、通常のインストーラセッション所有アプリが自身のセッションに対してこの API を呼ぶだけで到達でき、OSV の通り追加権限やユーザー操作は不要とみられる。

重要な点として、この DoS は「署名が正しく検証される」必要がない。問題は検証結果に到達する前の PKCS#7 パースにあるため、攻撃者は大きい、または ASN.1 構造として高コストな `signature` を渡せばよい。

## 根本原因

根本原因は、system_server 内で処理する外部入力 `signature` に対し、PKCS#7 パーサへ渡す前のサイズ制限・リソース制限がなかったこと。

修正前の `ApkChecksums.verifySignature()` は、checksum を `ByteArrayOutputStream` に直列化した後、次を直接実行していた。

```java
PKCS7 pkcs7 = new PKCS7(signature);
```

Android 14 libcore の `PKCS7(byte[])` は `DerInputStream derin = new DerInputStream(bytes); parse(derin);` を実行する。`parseSignedData()` では digestAlgorithm set、certificate set、CRL set、signerInfos set を `DerValue[]` や `X509Certificate[]` / `SignerInfo[]` として展開し、証明書については `CertificateFactory.generateCertificate()` も呼ぶ。つまり、`byte[] signature` のサイズと ASN.1 要素数に比例して system_server のヒープ・CPU を消費する。

修正後は 35 KiB を超える署名を `PKCS7` に渡す前に `SignatureException("Invalid signature")` で拒否する。PKCS#7 detached signature は checksum 群への署名と証明書チェーンを含む用途なので、35 KiB は通常用途を許容しつつ resource exhaustion を止めるための実用的な上限として追加されたものと読める。

## 影響

- 影響プロセス: package manager / system_server
- 影響種別: local denial of service
- 権限: 追加権限不要
- ユーザー操作: 不要
- 攻撃の成立条件: アプリが package installer session を作成し、`setChecksums()` に空でない `checksums` と巨大または高コストな PKCS#7 DER 風 `signature` を渡す。
- 失敗時挙動: 修正前は `PKCS7` パース中に system_server のリソースを消費し、クラッシュまたは応答不能を引き起こし得る。修正後は 35 KiB 超の署名が即時に `IllegalArgumentException("Can't verify signature: Invalid signature", ...)` へ変換され、重いパースに入らない。

## 疑似 PoC

実機での最小形は次の流れになる。

1. `PackageInstaller` で通常の install session を作成する。
2. `openWrite()` で APK ファイル名を session に登録する。
3. `Checksum` を 1 個以上作る。
4. `byte[] signature = new byte[900 * 1024]` など binder transaction 上限内で大きな DER/PKCS#7 風データを作る。
5. `session.setChecksums(apkName, checksums, signature)` を繰り返す。

修正前は system_server が `new PKCS7(signature)` に入り、入力サイズや内部 set の展開でリソースを消費する。修正後は `signature.length > 35 * 1024` の時点で拒否されるため、この経路の DoS は成立しない。

## 調査中のメモ

- OSV の Vanir signature は `ApkChecksums.verifySignature` と `PackageInstallerSession.setChecksums` をターゲットにしており、diff 解析結果と一致した。
- `PackageInstaller.Session#setChecksums()` は deprecated だが、古い installer-provided checksums 互換のために残っている。deprecated API でも system_server がパースする外部入力であるため、リソース上限が必要だった。
- `PackageInstallerSession.setChecksums()` は `assertCallerIsOwnerOrRoot()` より前に署名検証を行う。直前に `appOps.checkPackage(Binder.getCallingUid(), installerPackageName)` はあるため任意 UID が任意セッションを叩けるわけではないが、攻撃者自身が所有する installer session で十分に到達可能である。
- `storeDigestsForFile()` でも保存済み signature を再度 `verifySignature()` するため、修正前に一度受理された巨大 signature は commit 処理時にも再パースされる可能性があった。

## 取得・解析コマンドの概要

```sh
curl -L -o artifacts/ASB-A-480126173.json https://storage.googleapis.com/android-osv/ASB-A-480126173.json
curl -L 'https://android.googlesource.com/platform/frameworks/base/+/a3ca193de2c8b789b59c9bfb7af529b9472da538%5E%21/?format=TEXT' | base64 -D > artifacts/a3ca193de2c8b789b59c9bfb7af529b9472da538.patch
curl -L 'https://android.googlesource.com/platform/frameworks/base/+/7250d76a8a2d501af62081d88545c301d43106a4%5E%21/?format=TEXT' | base64 -D > artifacts/7250d76a8a2d501af62081d88545c301d43106a4.patch
curl -L 'https://android.googlesource.com/platform/frameworks/base/+/d13e0e732fba5097cea9bdde935c67f6148853ad/services/core/java/com/android/server/pm/ApkChecksums.java?format=TEXT' | base64 -D > artifacts/ApkChecksums_parent.java
curl -L 'https://android.googlesource.com/platform/frameworks/base/+/a3ca193de2c8b789b59c9bfb7af529b9472da538/services/core/java/com/android/server/pm/ApkChecksums.java?format=TEXT' | base64 -D > artifacts/ApkChecksums_fixed.java
curl -L 'https://android.googlesource.com/platform/libcore/+/android14-release/ojluni/src/main/java/sun/security/pkcs/PKCS7.java?format=TEXT' | base64 -D > artifacts/PKCS7.java
sha256sum artifacts/* > artifacts/SHA256SUMS.txt
```
031 OK

CVE-2026-0070

031-ok-dpm-critical-app-hidden-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeDoS
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-438186009
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0070 is listed in the Android Security Bulletin as a High severity DoS issue in Framework.

特定した具体的な脆弱性

このCVEは特定できた。Android Framework の DevicePolicyManagerService#setApplicationHidden() が、管理アプリによるアプリ非表示ポリシーの対象として、端末/プロファイルの起動や基本動作に必要な重要パッケージを拒否していなかったことによる DoS である。

根本原因は、修正前の setApplicationHidden() が policy_exempt_apps / vendor_policy_exempt_apps だけを免除リストとして扱い、com.android.nfc、com.android.settings、com.android.providers.settings のような setApplicationHidden 専用に保護すべき基盤パッケージを非表示にできた点。コミットメッセージにも「work profile でこれらを隠すと boot failure の原因になり得る」と明記されている。

修正後は application_hidden_policy_exempt_apps という専用リソース配列が追加され、setApplicationHidden() が通常の policy exempt apps に加えてこの配列も確認する。該当パッケージの場合はポリシーを書き込まず false を返す。

原因

根本原因は、DPM の「ポリシー上無効化してはいけないアプリ」のモデルが、setApplicationHidden() の危険性に対して不足していたこと。

既存の policy_exempt_apps は lock task や suspension など複数のポリシーに使われる汎用免除リストだった。修正前の setApplicationHidden() はこれだけを見ていたが、AOSP のデフォルト policy_exempt_apps は空であり、setApplicationHidden() 固有に保護すべき critical apps が存在しなかった。

修正で汎用の policy_exempt_apps に3パッケージを足さず、application_hidden_policy_exempt_apps を新設している点が面白い。policy_exempt_apps に入れると lock task 許可や suspension 判定など他のDPMポリシーにも副作用が出るため、アプリ非表示ポリシーだけに限定して保護する設計にしたと読める。

どこから特定したか

修正差分の要点: 変更ファイルは3つ。

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/frameworks/base/+/dc3785a739bc197b6d71fa57ff798423fa51cb6b

validated.md を表示
# CVE-2026-0070 パッチ解析結果

## 結論

このCVEは特定できた。Android Framework の `DevicePolicyManagerService#setApplicationHidden()` が、管理アプリによるアプリ非表示ポリシーの対象として、端末/プロファイルの起動や基本動作に必要な重要パッケージを拒否していなかったことによる DoS である。

根本原因は、修正前の `setApplicationHidden()` が `policy_exempt_apps` / `vendor_policy_exempt_apps` だけを免除リストとして扱い、`com.android.nfc`、`com.android.settings`、`com.android.providers.settings` のような `setApplicationHidden` 専用に保護すべき基盤パッケージを非表示にできた点。コミットメッセージにも「work profile でこれらを隠すと boot failure の原因になり得る」と明記されている。

修正後は `application_hidden_policy_exempt_apps` という専用リソース配列が追加され、`setApplicationHidden()` が通常の policy exempt apps に加えてこの配列も確認する。該当パッケージの場合はポリシーを書き込まず `false` を返す。

## 対象情報

- CVE: CVE-2026-0070
- Bulletin: Android Security Bulletin, 2026-06-01
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Component: Framework
- Type: DoS
- Severity: High
- Updated AOSP versions: 14, 15, 16, 16-qpr2
- Reference: A-438186009
- 公開修正コミット: https://android.googlesource.com/platform/frameworks/base/+/dc3785a739bc197b6d71fa57ff798423fa51cb6b
- Commit: `dc3785a739bc197b6d71fa57ff798423fa51cb6b`
- Parent: `4abc0b8da1e97accf0213fd228f663f0fc6176a4`
- Commit title: `Don't allow hiding critical apps.`
- Change-Id: `I2ade10f20636fe8dfe875f4827e5e97d734bf8a1`

## 修正差分の要点

変更ファイルは3つ。

- `core/res/res/values/policy_exempt_apps.xml`
  - `application_hidden_policy_exempt_apps` を新規追加。
  - 初期値として `com.android.nfc`、`com.android.settings`、`com.android.providers.settings` を登録。
- `core/res/res/values/symbols.xml`
  - Javaから参照できるよう `application_hidden_policy_exempt_apps` の symbol を追加。
- `services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java`
  - `isPackageExemptFromHiding()` を追加。
  - `setApplicationHidden()` の免除判定を `exemptApps.contains(packageName) || isPackageExemptFromHiding(packageName)` に変更。
  - `dumpsys` 用のリソース出力にも新配列を追加。

修正前の重要部分:

```java
List<String> exemptApps = listPolicyExemptAppsUnchecked(mContext);
if (exemptApps.contains(packageName)) {
    return false;
}
...
mDevicePolicyEngine.setLocalPolicy(
        PolicyDefinition.APPLICATION_HIDDEN(packageName),
        admin,
        new BooleanPolicyValue(hidden),
        userId);
```

修正後:

```java
List<String> exemptApps = listPolicyExemptAppsUnchecked(mContext);
if (exemptApps.contains(packageName) || isPackageExemptFromHiding(packageName)) {
    return false;
}
```

## 脆弱性の発生条件

`DevicePolicyManager#setApplicationHidden()` は、device owner、profile owner、または `DELEGATION_PACKAGE_ACCESS` を委任されたアプリが呼び出せる管理APIである。APIドキュメント上も「hidden にされたパッケージは利用不可になるが、データとAPKファイルは残る」と説明されている。

修正前は、managed profile / work profile の profile owner が、プロファイル内の全アプリを列挙して `setApplicationHidden(..., true)` を呼ぶような処理を行った場合、次の基盤パッケージも非表示にできた。

- `com.android.providers.settings`
- `com.android.settings`
- `com.android.nfc`

特に `com.android.providers.settings` は Android の設定値を提供する基盤パッケージであり、これをプロファイル内で不可用にすると、プロファイル起動時やシステムサービス初期化時の前提が崩れる。コミットメッセージのとおり、work profile が boot failure に至り得る。攻撃/事故シナリオとしては、悪意ある、または不具合のある DPC が managed profile で「全アプリを隠す」ポリシーを実行し、重要パッケージまで不可用にしてしまうケースが該当する。

## 根本原因

根本原因は、DPM の「ポリシー上無効化してはいけないアプリ」のモデルが、`setApplicationHidden()` の危険性に対して不足していたこと。

既存の `policy_exempt_apps` は lock task や suspension など複数のポリシーに使われる汎用免除リストだった。修正前の `setApplicationHidden()` はこれだけを見ていたが、AOSP のデフォルト `policy_exempt_apps` は空であり、`setApplicationHidden()` 固有に保護すべき critical apps が存在しなかった。

修正で汎用の `policy_exempt_apps` に3パッケージを足さず、`application_hidden_policy_exempt_apps` を新設している点が面白い。`policy_exempt_apps` に入れると lock task 許可や suspension 判定など他のDPMポリシーにも副作用が出るため、アプリ非表示ポリシーだけに限定して保護する設計にしたと読める。

## なぜDoSか

この修正は権限境界の拡張や情報漏えい防止ではなく、管理APIによって重要システム/プロファイル構成要素を不可用にできることを防いでいる。結果として発生する影響は、work profile の起動失敗、管理対象プロファイルの利用不能、関連サービス/UIの継続的な失敗であり、DoS分類と整合する。

## 調査中に分かったこと

- ASB上の参照ID `A-438186009` は公開AOSPコミット `dc3785a739bc197b6d71fa57ff798423fa51cb6b` に直接リンクされていた。
- コミットメッセージのテストは `atest CtsDevicePolicyManagerTestCases:com.android.cts.devicepolicy.ManagedProfileTest#testHideAllApps`。公開コミットにはCTSテスト差分は含まれていなかったが、テスト名からも「managed profileで全アプリを隠す」ケースが再現条件だったと分かる。
- `DELEGATION_PACKAGE_ACCESS` は `isApplicationHidden`、`setApplicationHidden`、`isPackageSuspended`、`setPackagesSuspended` へのアクセスを与える委任スコープで、DPC本体だけでなく委任先アプリ経由でも到達し得る。
- `setApplicationHidden()` は `mDevicePolicyEngine.setLocalPolicy(PolicyDefinition.APPLICATION_HIDDEN(packageName), ...)` にポリシーを書き込む。preでは critical app 判定がこの書き込み前に存在しなかった。
- Pixel固有バイナリ解析は実施していない。今回の参照IDは公開AOSPのソースパッチに解決でき、pre/post差分だけで根本原因と修正意図を確認できた。

## 解析に使った付帯ファイル

- `cve.md`: 初期メタ情報。
- `artifacts/android_security_bulletin_2026-06-01.html`: ASB保存。
- `artifacts/asb_CVE-2026-0070_excerpt.txt`: ASB該当行抜粋。
- `artifacts/commit_dc3785a739bc.json`: Gitiles commit metadata。
- `artifacts/commit_dc3785a739bc_patch_base64.txt`: Gitiles TEXT形式patch。
- `artifacts/dc3785a739bc_full.patch`: decoded full patch。
- `pre/DevicePolicyManagerService.java`: parent commit の対象ファイル。
- `post/DevicePolicyManagerService.java`: fixed commit の対象ファイル。
- `pre/policy_exempt_apps.xml`, `post/policy_exempt_apps.xml`: 免除リソースのpre/post。
- `pre/symbols.xml`, `post/symbols.xml`: Java symbolのpre/post。
- `artifacts/DevicePolicyManagerService_pre_post.diff`: DPMサービス差分。
- `artifacts/policy_exempt_apps_pre_post.diff`: 免除リソース差分。
- `artifacts/symbols_pre_post.diff`: symbols差分。
- `artifacts/DevicePolicyManager_api_post.java`: `DevicePolicyManager#setApplicationHidden()` と delegation scope のAPI説明確認用。
- `artifacts/IDevicePolicyManager_post.aidl`: Binder API確認用。
- `artifacts/ManagedProfileTest_main.java`: 公開CTS側の確認用。該当テスト名そのものはこの取得版には見つからなかった。

## 判定

`ok`。公開AOSPコミット、pre/post差分、APIドキュメント、コミットメッセージから、脆弱性の発生条件、根本原因、修正内容をソースコードで説明できる。
032 OK

CVE-2026-28578

032-ok-packagepolicy-package-name-length-dpm-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentFramework
TypeDoS
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-475228205
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-28578 is listed in the Android Security Bulletin as a High severity DoS issue in Framework.

特定した具体的な脆弱性

脆弱性は特定できた。DevicePolicyManagerService.java の3つの PackagePolicy setter が、PackagePolicy に含まれる package name の長さを検証しないまま ActiveAdmin に反映し、device_policies.xml へ永続化しようとしていた。修正は各 setter で package name を PolicySizeVerifier.MAX_PACKAGE_NAME_LENGTH、つまり 223 文字以下に制限するもの。

これは Android / NVD / OSV が説明する「DevicePolicyManagerService.java の複数関数における improper input validation による persistence desync、local DoS」と一致する。

原因

根本原因は、PackagePolicy が「package name集合を保持する型」であるにもかかわらず、型の生成時にも、DevicePolicyManagerService の受け口でも、package name として成立する長さを検証していなかったこと。

PackagePolicy.java のコンストラクタは policy type が BLOCKLIST / ALLOWLIST_AND_SYSTEM / ALLOWLIST のいずれかであることだけを確認し、packageNames の要素長は確認しない。そのため profile owner / device owner など、該当DPM APIを呼べるローカル主体は、実在しないほど長い package name を含む PackagePolicy を作って渡せた。

どこから特定したか

解析したcommit / URL: ・Bulletin掲載の公開fix:
- https://android.googlesource.com/platform/frameworks/base/+/48c17df8bdc45e4175a33978791957d460388b72
- 親commit: 80828212c3187adf56fc2a25d2d24001c5209937
・OSVに掲載されていた同系統fix:
- 4914d6e98bd25e620867650e0e431df3ad23a886
- 36421c7d97b00d05fd0be4c7050c3bee59058ad8
- 04023137da055ba8a7054d9772b5fdb36cb19ddb
- bb3184f1df179ce052b37c…

パッチ差分: 修正対象は services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java の以下3関数。

・setManagedProfileCallerIdAccessPolicy(PackagePolicy policy)
・setManagedProfileContactsAccessPolicy(PackagePolicy policy)
・setCredentialManagerPolicy(PackagePolicy policy)

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://api.osv.dev/…

validated.md を表示
# CVE-2026-28578 検証結果

## 結論

脆弱性は特定できた。`DevicePolicyManagerService.java` の3つの `PackagePolicy` setter が、`PackagePolicy` に含まれる package name の長さを検証しないまま `ActiveAdmin` に反映し、`device_policies.xml` へ永続化しようとしていた。修正は各 setter で package name を `PolicySizeVerifier.MAX_PACKAGE_NAME_LENGTH`、つまり 223 文字以下に制限するもの。

これは Android / NVD / OSV が説明する「`DevicePolicyManagerService.java` の複数関数における improper input validation による persistence desync、local DoS」と一致する。

## 基本情報

- CVE: CVE-2026-28578
- Android bug ID: A-475228205
- Component: Framework
- Type: DoS
- Severity: High
- 影響バージョン: Android 14, 15, 16, 16-qpr2
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://api.osv.dev/v1/vulns/ASB-A-475228205
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-28578

## 解析したcommit / URL

- Bulletin掲載の公開fix:
  - https://android.googlesource.com/platform/frameworks/base/+/48c17df8bdc45e4175a33978791957d460388b72
  - 親commit: `80828212c3187adf56fc2a25d2d24001c5209937`
- OSVに掲載されていた同系統fix:
  - `4914d6e98bd25e620867650e0e431df3ad23a886`
  - `36421c7d97b00d05fd0be4c7050c3bee59058ad8`
  - `04023137da055ba8a7054d9772b5fdb36cb19ddb`
  - `bb3184f1df179ce052b37c9ad50e98ae5fed67fa`
  - `f344abfad1799fb6b16de99f43be955994f957ae`
- 手元で取得できた公開差分:
  - `commit_48c17df8_full.patch`
  - `commit_4914d6e9_full.patch`
  - `DevicePolicyManagerService_parent_fixed.diff`

一部のOSV掲載commitはGitiles上で直接 `NOT_FOUND` になったため、取得できた公開commitとOSVのVanir signatureを使って対象関数を確認した。

## パッチ差分

修正対象は `services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java` の以下3関数。

- `setManagedProfileCallerIdAccessPolicy(PackagePolicy policy)`
- `setManagedProfileContactsAccessPolicy(PackagePolicy policy)`
- `setCredentialManagerPolicy(PackagePolicy policy)`

修正前は、これらの関数が caller 権限を確認した後、`PackagePolicy` をそのまま `ActiveAdmin` に代入して `saveSettingsLocked()` していた。

修正後は、各 setter の先頭で以下を追加している。

```java
if (policy != null) {
    enforcePackagePolicyPackageNamesLength(policy);
}
```

追加された helper は以下。

```java
private void enforcePackagePolicyPackageNamesLength(@NonNull PackagePolicy policy) {
    for (String pkg : policy.getPackageNames()) {
        if (pkg == null) {
            continue;
        }
        PolicySizeVerifier.enforceMaxPackageNameLength(pkg);
    }
}
```

`PolicySizeVerifier.enforceMaxPackageNameLength()` は `pkg.length() <= 223` を要求する。コメント上、この 223 は `FrameworkParsingPackageUtils#MAX_FILE_NAME_SIZE` 由来で、Android package name がディレクトリ名などにも使われることを前提にした上限。

## 根本原因

根本原因は、`PackagePolicy` が「package name集合を保持する型」であるにもかかわらず、型の生成時にも、DevicePolicyManagerService の受け口でも、package name として成立する長さを検証していなかったこと。

`PackagePolicy.java` のコンストラクタは policy type が `BLOCKLIST` / `ALLOWLIST_AND_SYSTEM` / `ALLOWLIST` のいずれかであることだけを確認し、`packageNames` の要素長は確認しない。そのため profile owner / device owner など、該当DPM APIを呼べるローカル主体は、実在しないほど長い package name を含む `PackagePolicy` を作って渡せた。

## 脆弱性が起きる状況

攻撃主体は該当APIを呼べるローカル管理主体。

- managed profile の profile owner:
  - `setManagedProfileCallerIdAccessPolicy()`
  - `setManagedProfileContactsAccessPolicy()`
- managed profile の profile owner、default device owner、または `MANAGE_PROFILE_AND_DEVICE_OWNERS` 保持者:
  - `setCredentialManagerPolicy()`

修正前の処理は以下の流れになる。

1. 攻撃主体が 223 文字を超える package name を含む `PackagePolicy` を作る。
2. 上記 setter に渡す。
3. `DevicePolicyManagerService` が `ActiveAdmin` の `mManagedProfileCallerIdAccess` / `mManagedProfileContactsAccess` / `mCredentialManagerPolicy` に未検証の値を保存する。
4. `saveSettingsLocked()` が `DevicePolicyData.store()` を呼び、`ActiveAdmin.writePackagePolicy()` が `device_policies.xml` に package list を保存する。
5. 実行時のDPM状態と永続化されたDPM状態の間で、Androidの package name 上限に反する値を含む状態が成立し、CVE説明にある persistence desync に至る。

DoSとしての実害は、DPMが管理する caller ID / contacts access / credential manager policy の状態が永続化境界で破綻し、管理ポリシーの適用・復元・後続の照会が意図しない状態になること。特に credential manager policy はユーザが利用可能な credential provider を制御するため、壊れた policy を設定されると credential manager 機能の利用不能につながる。

## 周辺コードで確認したこと

- `ActiveAdmin.writePackagePolicy()` は `PackagePolicy.getPackageNames()` を `package-policy-packages` としてXMLへ書く。
- `ActiveAdmin.readPackagePolicy()` はXMLから package list を読み、再び `new PackagePolicy(policy, packageNames)` するが、ここでも package name 長は検証されない。
- `DevicePolicyData.store()` は `ActiveAdmin.writeToXml()` を通じて全admin policyを `device_policies.xml` に保存する。
- `DevicePolicyData.load()` はadmin読み込み時の `RuntimeException` を捕捉して当該adminの読み込み失敗として扱うため、永続化済みpolicyが壊れるとDPMの管理状態欠落につながり得る。
- 同じ `DevicePolicyManagerService` 内の別API、例えば `setPermittedAccessibilityServices()` は既に package list に `PolicySizeVerifier.enforceMaxPackageNameLength()` を適用していた。今回の3つの `PackagePolicy` setter が検証漏れだった。

## 解析時のメモ

- パッチは非常に小さいが、修正位置が3つのsetterに限定されているため、CVE対象関数は明確。
- `PackagePolicy` 自体に検証を入れず、DPMS setter側で検証している。既存の `PackagePolicy` 生成・読み戻し互換性を壊さず、外部入力境界だけを塞ぐ意図と見られる。
- `null` package name は helper 内で無視される。`PackagePolicy` の `ArraySet<String>` 自体はnullを技術的には保持できるため、今回の修正範囲は「長さ」だけ。
- OSVの `vanir_signatures` も対象関数として `setManagedProfileCallerIdAccessPolicy`、`setManagedProfileContactsAccessPolicy`、`setCredentialManagerPolicy` を指しており、差分解析結果と一致した。

## 付帯ファイル

- `commit_48c17df8_metadata.txt`: commit metadata
- `commit_48c17df8_full.patch`: Bulletin公開fixのGitiles差分
- `commit_4914d6e9_full.patch`: OSV掲載fixの同一差分
- `DevicePolicyManagerService_parent_80828212.java`: 修正前ソース
- `DevicePolicyManagerService_fixed_48c17df8.java`: 修正後ソース
- `DevicePolicyManagerService_parent_fixed.diff`: 修正前後diff
- `ActiveAdmin_48c17df8.java`: `PackagePolicy` のXML保存・読み戻し確認用
- `DevicePolicyData_48c17df8.java`: `device_policies.xml` 保存・読み込み確認用
- `DevicePolicyManager_48c17df8.java`: 公開API権限・説明確認用
- `PackagePolicy_48c17df8.java`: `PackagePolicy` コンストラクタ確認用
- `PolicySizeVerifier_48c17df8.java`: package name 長上限確認用
- `osv_ASB-A-475228205.json`: OSV JSON
- `repro_scenario.md`: PoC形と処理フローのメモ

## 判定

`ok`。公開AOSPソースとパッチ差分から、未検証の `PackagePolicy` package name がDPM永続化状態に入り込むこと、修正がその入力境界にpackage name長検証を追加していることを確認できた。

033 OK

CVE-2026-0043

033-ok-dng-sdk-ubsan-overflow-exception

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityCritical
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-453649377
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0043 is listed in the Android Security Bulletin as a Critical severity EoP issue in System.

特定した具体的な脆弱性

CVE-2026-0043 は、Android の System コンポーネントに含まれる DNG/RAW 画像デコード経路 (external/dng_sdk + Skia SkRawCodec) に対する整数オーバーフロー系の問題だったと判断する。

公開パッチは、個別の演算箇所を1つずつ修正するものではなく、libdng_sdk を signed/unsigned integer overflow の UBSan 計測付きでビルドしつつ、従来の ubsan-minimal によるプロセス abort をやめ、UBSan の overflow handler を C++ 例外に置き換えるものだった。Skia 側の DNG デコーダは catch (...) で DNG SDK 例外や未知例外を画像デコード失敗に変換しているため、攻撃者制御のDNG入力で整数オーバーフローに到達しても、プロセス全体を落としたり、オーバーフロー後の不正状態で処理を継続したりせず、kInvalidInput / kIncompleteInput 等として失敗する。

したがって根本原因は、DNG SDK が外部入力由来の寸法、タイル数、オフセット、byte count、opcode table などを多数の整数演算に流し込む構造である一方、すべての演算が SafeUint32* / SafeInt32* で覆われていなかったこと、および検出時のエラー処理が Android の画像デコードAPIのエラー境界に統合されず、UBSan runtime の abort に依存していたこと。

原因

根本原因は2層ある。

1. 入力検証不足: DNG/TIFFの可変長・多次元メタデータから計算されるサイズ、位置、タイル数、バッファ長の整数演算が多く、一部は安全演算ヘルパーで保護されていなかった。
2. エラー境界の不一致: DNG SDK と Skia は C++ 例外で失敗を伝搬する設計なのに、整数オーバーフロー検出だけが ubsan-minimal のabortに落ちていた。結果として、画像デコード失敗として扱うべき malformed input がプロセス全体の異常終了または未定義動作に接続されていた。

面白い点として、今回のパッチは dng_sdk の脆弱な算術箇所を直接直していない。むしろ、広範囲の整数オーバーフローを一括で検出し、既存の例外ベースの失敗処理へ接続する「ランタイム方針の修正」だった。これは同じコミットが複数のDNG CVEに使われている理由でもある。

どこから特定したか

解析対象のパッチ: 対象コミット:

``text
74a5a91d169a341db58d57e0bf018d0a8b784cce
Replace ubsan-minimal with throw
Author: John Reck <jreck@google.com>
Committer: Android Build Coastguard Worker
Bug: 470966846
Bug: 467994860
Bug: 467994310
Bug: 461790658
Bug: 456471487
Bug: 453649377
Bug: 449728942
Test: atest ImageDecoderTest#testInterestingDngs
`

取得・保存した付帯ファイル: ・artifacts/bulletin-2026-06-01.html: Android Security Bulletin保存版
・artifacts/74a5a91d169a341db58d57e0bf018d0a8b784cce.json: Gitiles commit JSON
・artifacts/74a5a91d169a341db58d57e0bf018d0a8b784cce.patch: Gitiles ^! パッチ
・artifacts/git_show_74a5a91.txt: git show --stat --format=fuller
・artifacts/git_show_74a5a91.patch: ローカルgitで取得した対象パッチ
・artifacts/Android.bp.b…

URL: https://source.android.com/docs/security…

validated.md を表示
# CVE-2026-0043 検証メモ

## 結論

`CVE-2026-0043` は、Android の System コンポーネントに含まれる DNG/RAW 画像デコード経路 (`external/dng_sdk` + Skia `SkRawCodec`) に対する整数オーバーフロー系の問題だったと判断する。

公開パッチは、個別の演算箇所を1つずつ修正するものではなく、`libdng_sdk` を signed/unsigned integer overflow の UBSan 計測付きでビルドしつつ、従来の `ubsan-minimal` によるプロセス abort をやめ、UBSan の overflow handler を C++ 例外に置き換えるものだった。Skia 側の DNG デコーダは `catch (...)` で DNG SDK 例外や未知例外を画像デコード失敗に変換しているため、攻撃者制御のDNG入力で整数オーバーフローに到達しても、プロセス全体を落としたり、オーバーフロー後の不正状態で処理を継続したりせず、`kInvalidInput` / `kIncompleteInput` 等として失敗する。

したがって根本原因は、DNG SDK が外部入力由来の寸法、タイル数、オフセット、byte count、opcode table などを多数の整数演算に流し込む構造である一方、すべての演算が `SafeUint32*` / `SafeInt32*` で覆われていなかったこと、および検出時のエラー処理が Android の画像デコードAPIのエラー境界に統合されず、UBSan runtime の abort に依存していたこと。

## 基本情報

- CVE: `CVE-2026-0043`
- Android bug: `A-453649377`
- Component: `System`
- Type: `EoP`
- Severity: `Critical`
- Updated AOSP versions: `14, 15, 16, 16-qpr2`
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- 公開修正コミット: https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce

## 解析対象のパッチ

対象コミット:

```text
74a5a91d169a341db58d57e0bf018d0a8b784cce
Replace ubsan-minimal with throw
Author: John Reck <jreck@google.com>
Committer: Android Build Coastguard Worker
Bug: 470966846
Bug: 467994860
Bug: 467994310
Bug: 461790658
Bug: 456471487
Bug: 453649377
Bug: 449728942
Test: atest ImageDecoderTest#testInterestingDngs
```

このコミットは `A-453649377` だけでなく、同じ2026年6月Bulletin内の複数の `external/dng_sdk` CVEにも使われている。Bulletin上では `CVE-2026-0043` が `EoP/Critical`、同じコミットに紐づく `CVE-2026-0039` から `CVE-2026-0080` の多くが `DoS/Critical` として列挙されていた。つまり、公開パッチは複数の内部クラッシュ/オーバーフロー入力をまとめて安全な失敗に変換する修正で、Bug IDごとのPoCやDNGタグ値は公開されていない。

差分の主要点:

```diff
 sanitize: {
+    // disable ubsan_minimal runtime so that we can inject our own
+    // that converts ubsan errors into C++ exceptions.
+    never: true,
 }

 cflags: [
     "-DqDNGValidate=0",
+    "-fsanitize=signed-integer-overflow,unsigned-integer-overflow",
+    "-fno-sanitize-link-runtime",
 ]

+srcs: [
+    "ubsan-replacement/ubsan_throwing_runtime.cpp"
+]
```

追加された `ubsan_throwing_runtime.cpp`:

```cpp
INTERFACE void __ubsan_handle_add_overflow() {
    throw std::runtime_error("ubsan: add-overflow");
}

INTERFACE void __ubsan_handle_sub_overflow() {
    throw std::runtime_error("ubsan: sub-overflow");
}

INTERFACE void __ubsan_handle_mul_overflow() {
    throw std::runtime_error("ubsan: mul-overflow");
}

INTERFACE void __ubsan_handle_negate_overflow() {
    throw std::runtime_error("ubsan: negate-overflow");
}

INTERFACE void __ubsan_handle_divrem_overflow() {
    throw std::runtime_error("ubsan: divrem-overflow");
}
```

## 呼び出し経路

Skia の `Android.bp` では `skia_deps` が `libdng_sdk` をリンクしている。

```text
cc_defaults {
    name: "skia_deps",
    shared_libs: [
        "libdng_sdk",
        "libjpeg",
        "libpiex",
        ...
    ],
}
```

Skia側のRAW/DNGデコード経路は `src/codec/SkRawCodec.cpp`。DNG/TIFFヘッダを確認した後、`SkDngImage::NewFromStream()` を作り、DNG SDK の `dng_info::Parse`, `dng_negative::Parse`, `ReadStage1Image`, `BuildStage2Image`, `BuildStage3Image`, `dng_render::Render` へ進む。

重要なのは、Skia側が広い例外境界を持っていること。

- `SkDngImage::readDng()` は `catch (...) { return false; }`
- `SkDngImage::render()` は `catch (...) { return nullptr; }`
- `SkRawCodec::onGetPixels()` は `image->Get()` の失敗を `kIncompleteInput` に変換
- `SkDngHost::PerformAreaTask()` は worker 内の未知例外を `dng_error_unknown` に変換し、最終的に `Throw_dng_error()` で呼び出し元に戻す

このため、UBSan handler が abort ではなく C++ 例外を投げるようになると、DNG SDK 内の未保護の整数オーバーフローはプロセス停止ではなく画像デコード失敗として処理される。

## 脆弱性の状況

攻撃者は、DNG/TIFF構造を持つ画像ファイルをアプリ、メディア処理、画像プレビュー、共有/添付/サムネイル生成などの画像デコード経路に渡す。ファイル内の以下のような値がDNG SDK内の演算に入る。

- `ImageWidth` / `ImageLength`
- `TileWidth` / `TileLength`
- strip/tile offset と byte count
- samples per pixel、bits per sample、plane数
- DNG opcode list の area、pitch、table count
- CFA pattern、mosaic、resampling、rendering時の中間バッファサイズ

DNG SDKには `SafeUint32Mult`, `SafeUint32Add`, `SafeInt32Add` などの安全演算が多数ある一方、コード全体には生の演算も残っている。今回のパッチは `signed-integer-overflow,unsigned-integer-overflow` を `libdng_sdk` に対して有効化し、そうした未保護の演算に到達した場合に UBSan が検出できるようにしている。

修正前は Android の `ubsan-minimal` runtime が使われ、コミットメッセージにもある通り UBSan エラー時に hard abort していた。修正後は `__ubsan_handle_*_overflow` が `std::runtime_error` を投げるため、Skia/DNGの既存 `catch (...)` により `Invalid input` として閉じられる。

## 根本原因

根本原因は2層ある。

1. 入力検証不足: DNG/TIFFの可変長・多次元メタデータから計算されるサイズ、位置、タイル数、バッファ長の整数演算が多く、一部は安全演算ヘルパーで保護されていなかった。
2. エラー境界の不一致: DNG SDK と Skia は C++ 例外で失敗を伝搬する設計なのに、整数オーバーフロー検出だけが `ubsan-minimal` のabortに落ちていた。結果として、画像デコード失敗として扱うべき malformed input がプロセス全体の異常終了または未定義動作に接続されていた。

面白い点として、今回のパッチは `dng_sdk` の脆弱な算術箇所を直接直していない。むしろ、広範囲の整数オーバーフローを一括で検出し、既存の例外ベースの失敗処理へ接続する「ランタイム方針の修正」だった。これは同じコミットが複数のDNG CVEに使われている理由でもある。

## EoPとしての評価

Bulletinでは `CVE-2026-0043` は `System / EoP / Critical` とされている。ただし公開情報だけでは、`A-453649377` 固有のDNG入力、到達した関数、権限昇格の最終効果は確認できなかった。

ソースから確実に言えるのは、攻撃者制御のDNGが Android の画像デコード経路で `libdng_sdk` に到達し、整数オーバーフローを発生させ得ること、および修正前はその異常が画像デコードAPIの通常の失敗値ではなく `ubsan-minimal` のabort/未定義動作側に出ていたこと。AndroidのBulletin分類がEoPであるため、内部Bugでは単なる自アプリクラッシュではなく、System側の高権限処理経路での影響が確認されていたと考えるのが自然。

## 取得・保存した付帯ファイル

- `artifacts/bulletin-2026-06-01.html`: Android Security Bulletin保存版
- `artifacts/74a5a91d169a341db58d57e0bf018d0a8b784cce.json`: Gitiles commit JSON
- `artifacts/74a5a91d169a341db58d57e0bf018d0a8b784cce.patch`: Gitiles `^!` パッチ
- `artifacts/git_show_74a5a91.txt`: `git show --stat --format=fuller`
- `artifacts/git_show_74a5a91.patch`: ローカルgitで取得した対象パッチ
- `artifacts/Android.bp.before`: 親コミット `47cd326e0c8f19cc367663b31d95c03584198fa4` の `Android.bp`
- `artifacts/Android.bp.after`: 修正コミットの `Android.bp`
- `artifacts/ubsan_throwing_runtime.cpp`: 追加されたUBSan置換runtime
- `artifacts/dng_sdk.git/`: `external/dng_sdk` のローカルclone、HEADは `74a5a91d169a341db58d57e0bf018d0a8b784cce`
- `artifacts/skia_Android.bp`: Skiaのビルド定義。`libdng_sdk` リンク確認に使用
- `artifacts/SkRawCodec.cpp`, `artifacts/SkRawCodec.h`: Skia RAW/DNGデコード経路
- `artifacts/SkCodec.h`: `SkCodec::Result` の失敗値確認
- `artifacts/dng_sdk_key_search.txt`: `dng_sdk` 内の overflow、安全演算、例外、catch の検索結果
- `artifacts/git_log_453649377.txt`: `A-453649377` を含む `dng_sdk` ログ検索

## 再現・検証コマンド

```sh
curl -L 'https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce%5E%21/?format=TEXT' | base64 -d > artifacts/74a5a91d169a341db58d57e0bf018d0a8b784cce.patch

curl -L 'https://android.googlesource.com/platform/external/dng_sdk/+/47cd326e0c8f19cc367663b31d95c03584198fa4/Android.bp?format=TEXT' | base64 -d > artifacts/Android.bp.before
curl -L 'https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce/Android.bp?format=TEXT' | base64 -d > artifacts/Android.bp.after
diff -u artifacts/Android.bp.before artifacts/Android.bp.after

git clone --no-checkout https://android.googlesource.com/platform/external/dng_sdk artifacts/dng_sdk.git
git -C artifacts/dng_sdk.git checkout 74a5a91d169a341db58d57e0bf018d0a8b784cce
git -C artifacts/dng_sdk.git show --stat --format=fuller 74a5a91d169a341db58d57e0bf018d0a8b784cce

rg -n 'dng_exception|catch \(\.\.\.\)|std::runtime_error|__ubsan|signed-integer-overflow|unsigned-integer-overflow|SafeUint|SafeInt|ThrowOverflow' artifacts/dng_sdk.git/source artifacts/dng_sdk.git/ubsan-replacement artifacts/dng_sdk.git/Android.bp
```

## 判定

`ok`

理由: CVE固有の内部PoCは公開されていないが、公開ソースコードと公開パッチから、攻撃面、修正内容、例外処理境界、根本原因を説明できる。修正が個別演算ではなく `libdng_sdk` 全体の UBSan overflow runtime を abort から C++ 例外に置き換えるものであることも確認できた。
034 OK

CVE-2026-0097

034-ok-le-passkey-pairing-approval-bypass

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityCritical
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-446114623
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0097 is listed in the Android Security Bulletin as a Critical severity EoP issue in System.

特定した具体的な脆弱性

脆弱性は特定できた。CVE-2026-0097 / A-446114623 は、Android Bluetooth の LE Secure Connections Passkey Display / Key Notification ペアリングで、ユーザー承認を待たずにSMPの鍵生成・認証完了側が進んでしまうロジック不整合である。近接したBLEデバイスが、ユーザー操作なしにLEペアリングの承認相当をバイパスできる可能性があるため、ASBでは System / EoP / Critical とされている。

原因

根本原因は、LE Secure Connections Passkey Display / Key Notificationの状態機械で、SMPの暗号プロトコル進行とBTIF/UIのユーザー承認結果が単一の同期条件で結合されていなかったこと。

具体的には次の2点。

・smp_process_stk がユーザー承認状態を確認せず、STK生成後に即座に SMP_KEY_READY_EVT を送っていた。
・btif_dm_ble_passkey_notif_evt がLEペアリング用の pairing_cb.is_le_only / is_le_nc を初期化しておらず、UI応答の配送先がLE SMPではなくBR/EDR側になり得た。

修正は、approved と confirmed の2条件が揃うまで鍵Readyイベントを出さない設計に変え、さらにBTIF側のLEフラグ初期化とタイムアウトキャンセルを追加している。

どこから特定したか

パッチ差分から見える修正内容: system/btif/src/btif_dm.cc の btif_dm_ble_passkey_notif_evt に次が追加された。

``cpp
pairing_cb.is_le_only = true;
pairing_cb.is_le_nc = false;
`

修正前はこのLE Passkey Notification経路で pairing_cb.is_le_only が初期化されていなかった。btif_dm_ssp_reply は pairing_cb.is_le_only を見て、LEなら BTA_DmBleSecurityGrant、BR/EDRなら BTA_DmConfirm に返答を流す。つまり修正前は、LEペアリングの承認/拒否がSMP側へ正しく届かない可能性があった。

保存した主な付帯ファイル: ・artifacts/source-urls.txt: URL、commit、取得ファイル一覧
・artifacts/patch-analysis-notes.md: パッチ解析メモ
・artifacts/diff-ce76f82.patch: 統合バックポート差分
・artifacts/gitiles/ce76f82-full.patch: Gitilesから取得した統合バックポート差分
・artifacts/gitiles/android14-57541dad.patch: Android 14向け差分
・artifacts/pre-smp_api.cc, artifacts/post-smp_api.cc
・artifacts/pre-smp_keys.cc, artifacts/post-smp_ke…

URL: https://…

validated.md を表示
# CVE-2026-0097 検証結果

## 結論

脆弱性は特定できた。CVE-2026-0097 / A-446114623 は、Android Bluetooth の LE Secure Connections Passkey Display / Key Notification ペアリングで、ユーザー承認を待たずにSMPの鍵生成・認証完了側が進んでしまうロジック不整合である。近接したBLEデバイスが、ユーザー操作なしにLEペアリングの承認相当をバイパスできる可能性があるため、ASBでは System / EoP / Critical とされている。

## 確認した基本情報

- CVE: CVE-2026-0097
- 参照ID: A-446114623
- Bulletin: Android Security Bulletin
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Component: System
- 実際の修正対象: `platform/packages/modules/Bluetooth`
- 種別/深刻度: EoP / Critical
- 対象バージョン: Android 14, 15, 16, 16-qpr2, 17-next
- ASB/OSV詳細: `artifacts/ASB-A-446114623.json`

ASB JSONには「LEデバイスのペアリングで、ロジックエラーによりユーザー操作をバイパスできる可能性」とあり、攻撃条件は remote proximal/adjacent、追加権限不要、ユーザー操作不要と記載されている。

## 主要パッチ

主に確認したパッチは以下。

- 統合バックポート: `ce76f82dac2a8e0e247ca9c838bda57fb9a27b04`
- mainline相当:
  - `b9ddeb3bc5b0524090266d3b7a46e36358ff889e`
  - `4a6f8f383285a2c5a7f17e7e48cb4cdeff9718f2`
  - `e9d39624fdb8f7bda9a780ca8b5856ff6f536da8`
  - `8d9bb12908e875776866414c6fcfaa7ccacd3224`
- Android 14: `57541dad9e1f98f445bd5d25742a96c3f203db6f`

URLと保存ファイルは `artifacts/source-urls.txt` にまとめた。Android 15/16/16-qpr2のfix URLは `ASB-A-446114623.json` に存在するが、今回のGitiles `^!` 直接取得ではHTTP 404だったため、保存済みJSONを証跡としている。

## パッチ差分から見える修正内容

### 1. LE Passkey通知をLEペアリングとして正しく初期化

`system/btif/src/btif_dm.cc` の `btif_dm_ble_passkey_notif_evt` に次が追加された。

```cpp
pairing_cb.is_le_only = true;
pairing_cb.is_le_nc = false;
```

修正前はこのLE Passkey Notification経路で `pairing_cb.is_le_only` が初期化されていなかった。`btif_dm_ssp_reply` は `pairing_cb.is_le_only` を見て、LEなら `BTA_DmBleSecurityGrant`、BR/EDRなら `BTA_DmConfirm` に返答を流す。つまり修正前は、LEペアリングの承認/拒否がSMP側へ正しく届かない可能性があった。

### 2. SMPに「ユーザー承認済み」と「相手側確認済み」の同期点を追加

`system/stack/smp/smp_int.h` に次の状態が追加された。

```cpp
struct {
  bool approved;
  bool confirmed;
} passkey_display_state;
```

`system/stack/smp/smp_api.cc` の `SMP_SecurityGrant` は、修正後に `SMP_MODEL_SEC_CONN_PASSKEY_DISP` と `SMP_MODEL_KEY_NOTIF` を特別扱いする。ユーザーが承認した場合は `approved = true` を立て、相手側確認も済んでいれば `SMP_KEY_READY_EVT` を発火する。拒否された場合は `SMP_AUTH_CMPL_EVT` / `SMP_PAIR_AUTH_FAIL` で失敗させる。

修正前の `SMP_SecurityGrant` は、主に `SMP_MODEL_SEC_CONN_JUSTWORKS` と `SMP_MODEL_ENCRYPTION_ONLY` の同意ダイアログを扱うだけで、Passkey Display / Key Notificationをユーザー承認で止める処理がなかった。

### 3. STK生成完了をユーザー承認まで止める

`system/stack/smp/smp_keys.cc` の `smp_process_stk` は、修正前はSTKをマスクした後に無条件で `SMP_KEY_READY_EVT` を送っていた。

修正後は、association modelが `SMP_MODEL_SEC_CONN_PASSKEY_DISP` または `SMP_MODEL_KEY_NOTIF` の場合、生成済みキーを `smp_cb.tk` に保持し、`passkey_display_state.confirmed = true` を立てる。まだ `approved` でなければその場でreturnし、ユーザー承認後にだけ `SMP_KEY_READY_EVT` を送る。

この差分が脆弱性の中核である。修正前は「SMP暗号処理が完了した」ことと「ユーザーがペアリングを承認した」ことが同じゲートで同期されていなかった。

### 4. タイムアウト時にLE SMPペアリングをキャンセル

`system/stack/btm/btm_sec.cc` の `btm_sec_pairing_timeout` では、`BTM_PAIR_STATE_WAIT_AUTH_COMPLETE` かつ `BTM_PAIR_FLAGS_LE_ACTIVE` の場合に `SMP_PairCancel` を呼ぶようになった。承認待ちで止める設計にした結果、タイムアウト時にSMP側も明示的に中止する必要がある。

## 脆弱性が起きる状況

近接した攻撃者がBLEデバイスとしてAndroid端末とLE Secure ConnectionsのPasskey Display / Key Notification系ペアリングを進める。脆弱な実装では、UI/アプリの承認が成功していなくても、SMPのSTK生成完了経路が `SMP_KEY_READY_EVT` を送って認証・暗号化・ボンディング側へ進み得る。また一部経路ではBTIFの `is_le_only` 未初期化により、ユーザー応答がLE SMPへ届かない。

結果として、ユーザーがペアリングを承認していない、または承認操作をしていない状況でも、攻撃者のBLEデバイスがペアリング済み/信頼済みデバイスとして扱われる可能性がある。これは「ユーザー操作による許可」を前提に保護されるBluetooth権限境界を越えるため、近接リモートEoPとして扱われる。

## 根本原因

根本原因は、LE Secure Connections Passkey Display / Key Notificationの状態機械で、SMPの暗号プロトコル進行とBTIF/UIのユーザー承認結果が単一の同期条件で結合されていなかったこと。

具体的には次の2点。

- `smp_process_stk` がユーザー承認状態を確認せず、STK生成後に即座に `SMP_KEY_READY_EVT` を送っていた。
- `btif_dm_ble_passkey_notif_evt` がLEペアリング用の `pairing_cb.is_le_only` / `is_le_nc` を初期化しておらず、UI応答の配送先がLE SMPではなくBR/EDR側になり得た。

修正は、`approved` と `confirmed` の2条件が揃うまで鍵Readyイベントを出さない設計に変え、さらにBTIF側のLEフラグ初期化とタイムアウトキャンセルを追加している。

## 調査中に分かったこと・メモ

- 公開分類は `System` だが、実体はBluetooth Mainline moduleのSMP/BTIF修正だった。
- `ce76f82...` は「Handle LE Secure Connections Passkey Display/Notification」という統合バックポートで、コメント上は複数CLのcombined backport。
- mainlineでは一度 `com.android.bluetooth.flags.passkey_entry_pairing_approval` で保護を導入し、後続の `8d9bb...` でフラグを削除して常時有効化している。
- Android 14向けパッチも同じ構造で、古いログマクロ/型名に合わせた差分になっている。
- Pixel固有バイナリ解析は不要だった。AOSPソースとGitiles差分だけで、脆弱性の発生条件、根本原因、修正意図を説明できる。

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

- `artifacts/source-urls.txt`: URL、commit、取得ファイル一覧
- `artifacts/patch-analysis-notes.md`: パッチ解析メモ
- `artifacts/diff-ce76f82.patch`: 統合バックポート差分
- `artifacts/gitiles/ce76f82-full.patch`: Gitilesから取得した統合バックポート差分
- `artifacts/gitiles/android14-57541dad.patch`: Android 14向け差分
- `artifacts/pre-smp_api.cc`, `artifacts/post-smp_api.cc`
- `artifacts/pre-smp_keys.cc`, `artifacts/post-smp_keys.cc`
- `artifacts/pre-btm_sec.cc`, `artifacts/post-btm_sec.cc`
- `artifacts/gitiles/pre-btif_dm.cc`, `artifacts/gitiles/pre-smp_int.h`, `artifacts/gitiles/post-smp_int.h`

## 判定

OK。ソースコード差分から、ユーザー承認バイパスが起きる状態遷移と根本原因を特定できた。
035 OK

CVE-2026-21352

035-ok-dng-sdk-refcounted-block-maptable-oob-write-eop

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityCritical
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-483693973
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-21352 is listed in the Android Security Bulletin as a Critical severity EoP issue in System.

特定した具体的な脆弱性

ok - ソースコード差分から、DNG SDK内のメモリ破壊につながる根本原因を特定できた。

CVE-2026-21352 は Android の platform/external/dng_sdk に取り込まれた Adobe DNG SDK 1.7.1 build 2471 更新に含まれる、System / EoP / Critical の脆弱性。Android/OSV は「multiple locations の memory corruption」と説明しており、Adobe APSB26-23 では CVE-2026-21352 を Out-of-bounds Write (CWE-787)、影響を arbitrary code execution としている。

公開AOSPコミット b0d9d2a8d1003176df7d0e8ab565ae40d64b1ec1 は Bug: 483693973 と Bug: 483697751 を同時に含むSDK更新で、CVE-2026-21352 と CVE-2026-21353 が同じコミットにリンクされている。CVEごとのprivate upstream修正は公開されていないが、CVE-2026-21352 はAdobe側のCWE-787分類とOSVのVanir署名から、dng_ref_counted_block::Allocate の過小確保、および dng_opcode_MapTable の境界ミスを含むメモリ破壊修正群と判断できる。

原因

根本原因は、DNG SDKが外部入力由来のサイズ、count、black level、画像処理tableを内部メモリ表現へ変換する境界で、加算overflowとtable境界を十分に検証していなかったこと。

特に重要な不変条件は次の2つ。

・dng_ref_counted_block は header + logical size の物理確保サイズを必要とするが、修正前はその加算がwrapしないことを確認していなかった。
・MapTable は fCount 個の入力値から65536エントリのlookup tableを作るが、最後の有効要素は fCount - 1 であるにもかかわらず、修正前は fCount を参照していた。

結果として、細工されたDNG/RAW入力により、DNG SDKを使うAndroid側の画像処理プロセスでheap corruptionまたは不正table参照が発生し得る。Android bulletinではこれをSystem componentのCritical EoPとして扱っている。

どこから特定したか

パッチ解析: 修正前:

``cpp
fBuffer = malloc (size + sizeof (header));
...
new (fBuffer) header (size);
`

修正後:

`cpp
size_t mallocSize = size + sizeof (header);

if (mallocSize <= size)
ThrowOverflow ();

fBuffer = malloc (mallocSize);
`

保存した付帯ファイル: ・artifacts/android-security-bulletin-2026-06-01.html: Android Security Bulletin保存版。
・artifacts/adobe-apsb26-23.html: Adobe DNG SDK advisory保存版。
・artifacts/osv-ASB-A-483693973.json: Android OSV JSON。
・artifacts/b0d9d2a8_commit.json: Gitiles commit JSON。
・artifacts/b0d9d2a8_update_dng_sdk_1.7.1_2471.diff: 公開コミット全差分。
・artifacts/b0d9d2a8_dng_ref_counted_block.d…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/external/dng_sdk/+/b0d9d2a8d1003176…

validated.md を表示
# CVE-2026-21352 検証結果

## 判定

ok - ソースコード差分から、DNG SDK内のメモリ破壊につながる根本原因を特定できた。

CVE-2026-21352 は Android の `platform/external/dng_sdk` に取り込まれた Adobe DNG SDK 1.7.1 build 2471 更新に含まれる、System / EoP / Critical の脆弱性。Android/OSV は「multiple locations の memory corruption」と説明しており、Adobe APSB26-23 では CVE-2026-21352 を `Out-of-bounds Write (CWE-787)`、影響を arbitrary code execution としている。

公開AOSPコミット `b0d9d2a8d1003176df7d0e8ab565ae40d64b1ec1` は `Bug: 483693973` と `Bug: 483697751` を同時に含むSDK更新で、CVE-2026-21352 と CVE-2026-21353 が同じコミットにリンクされている。CVEごとのprivate upstream修正は公開されていないが、CVE-2026-21352 はAdobe側のCWE-787分類とOSVのVanir署名から、`dng_ref_counted_block::Allocate` の過小確保、および `dng_opcode_MapTable` の境界ミスを含むメモリ破壊修正群と判断できる。

## 確認したメタ情報

- CVE: CVE-2026-21352
- Android 参照ID: A-483693973
- Component/Subcomponent: System / `platform/external/dng_sdk`
- Type/Severity: EoP / Critical
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- 公開fix commit: `b0d9d2a8d1003176df7d0e8ab565ae40d64b1ec1`
- Gitiles: https://android.googlesource.com/platform/external/dng_sdk/+/b0d9d2a8d1003176df7d0e8ab565ae40d64b1ec1
- OSV: https://osv.dev/vulnerability/ASB-A-483693973
- Adobe APSB26-23: https://helpx.adobe.com/security/products/dng-sdk/apsb26-23.html

## パッチ解析

### 1. `dng_ref_counted_block::Allocate` の過小確保

修正前:

```cpp
fBuffer = malloc (size + sizeof (header));
...
new (fBuffer) header (size);
```

修正後:

```cpp
size_t mallocSize = size + sizeof (header);

if (mallocSize <= size)
    ThrowOverflow ();

fBuffer = malloc (mallocSize);
```

`dng_ref_counted_block` は先頭に `header` を置き、`Buffer()` は `fBuffer + sizeof(header)` を返す。呼び出し側は論理サイズ `size` バイトを書ける前提でこのポインタを使う。修正前は `size + sizeof(header)` の加算がwrapする場合を検査していないため、実際には `header + size` 未満の小さい領域を `malloc` し、その領域にplacement-newでheaderを書き、さらに呼び出し元が論理サイズ分を書き込む構造になっていた。

これは典型的な allocation-size overflow からの heap out-of-bounds write で、AdobeのCWE-787分類と一致する。`size` はDNG/RAWメタデータ由来の各種 table/string/list buffer などから到達し得る `uint32` 論理サイズで、特に32-bit `size_t` 環境や互換ABIでは `size + header` が小さい値へwrapする。

### 2. `dng_opcode_MapTable::ReplicateLastEntry` の境界ミス

修正前:

```cpp
for (uint32 index = 0; index < fCount; index++)
    table [index] = stream.Get_uint16 ();

ReplicateLastEntry ();

...
uint16 lastEntry = table [fCount];

for (uint32 index = fCount; index < 0x10000; index++)
    table [index] = lastEntry;
```

修正後:

```cpp
uint16 lastEntry = table [fCount - 1];
```

`fCount` は入力DNG opcode内に存在する有効なtable entry数であり、直前の読み込みで初期化される範囲は `table[0]` から `table[fCount - 1]` まで。最後の値を残りの65536エントリへ複製する意図なら、参照すべき値は `table[fCount - 1]` である。

修正前は `table[fCount]` を読むため、`fCount < 0x10000` では未初期化の次要素を複製し、`fCount == 0x10000` では確保済み65536要素の1つ外を読む。これ自体は直接にはOOB read/未初期化readだが、生成されたfull-size lookup tableは後続のpixel処理で全画素に適用されるため、SDK更新内のメモリ破壊修正群の一部としてVanir署名に含まれている。

### 3. `dng_opcode_MapTable::Prepare` の境界条件

同じファイルでは以下も修正されている。

```cpp
- real64 srcScale = 65535.0 / (65535.0 - blackLevel);
+ real64 srcScale = (blackLevel < 65535) ? 65535.0 / (65535.0 - blackLevel) : 0.0;
```

`blackLevel == 65535` の場合、修正前はゼロ除算で `srcScale` が無限大になり、その後 `Round_uint32(x)` を `srcTable[...]` の添字として使う。これもtrustedでない画像メタデータから計算された値が65536エントリのtable境界を壊す問題で、`MapTable` 周辺の根本原因は「DNG opcode由来のcount/black levelを内部65536テーブルの不変条件へ落とす際の境界検証不足」だった。

## 根本原因

根本原因は、DNG SDKが外部入力由来のサイズ、count、black level、画像処理tableを内部メモリ表現へ変換する境界で、加算overflowとtable境界を十分に検証していなかったこと。

特に重要な不変条件は次の2つ。

- `dng_ref_counted_block` は `header + logical size` の物理確保サイズを必要とするが、修正前はその加算がwrapしないことを確認していなかった。
- `MapTable` は `fCount` 個の入力値から65536エントリのlookup tableを作るが、最後の有効要素は `fCount - 1` であるにもかかわらず、修正前は `fCount` を参照していた。

結果として、細工されたDNG/RAW入力により、DNG SDKを使うAndroid側の画像処理プロセスでheap corruptionまたは不正table参照が発生し得る。Android bulletinではこれをSystem componentのCritical EoPとして扱っている。

## 悪用条件と影響

攻撃者は悪意あるDNG/RAWファイルを用意し、Android上のDNG SDK処理経路に読み込ませる。Adobeの汎用advisoryではローカル・ユーザー操作ありのarbitrary code executionとしているが、Android OSVでは追加権限なし・ユーザー操作不要のremote code execution相当の説明も付いている。Androidのbulletin分類はSystem EoPなので、実際の影響はDNG SDKを呼び出すシステム側処理の権限コンテキストに依存する。

`dng_ref_counted_block::Allocate` の場合、wrapで過小確保されたheap blockにheaderまたは後続データを書き込むため、heap metadataや隣接objectの破壊に到達する。`MapTable` の場合、細工された `fCount` や `blackLevel` によって65536エントリtableの境界外/未初期化値が使われ、後続の画像処理結果やtable lookupの整合性が崩れる。

## 調査メモ

- `cve.md` で確認した通り、対象は CVE-2026-21352 / A-483693973 / System EoP Critical / bulletin 2026-06-01。
- Android bulletinの表では CVE-2026-21352 と CVE-2026-21353 が同じ `b0d9d2a8` コミットにリンクされている。
- `b0d9d2a8` のcommit messageも `Bug: 483693973` と `Bug: 483697751` を併記している。公開差分からprivateなCVE別修正commitの分離はできない。
- 近隣の `036-ok-dng-jxl-integer-overflow-eop` は CVE-2026-21353 / A-483697751 を `dng_jxl.cpp` のCWE-190として解析している。035ではAdobe側でCWE-787とされるCVE-2026-21352に合わせ、`dng_ref_counted_block` と `dng_misc_opcodes` を主対象にした。
- OSVのVanir署名には `dng_ref_counted_block::Allocate`、`dng_opcode_MapTable::ReplicateLastEntry`、`dng_opcode_MapTable::Prepare`、`dng_jxl.cpp` などがまとめて含まれる。これはDNG SDK 1.7.1 build 2410 -> 2471更新が複数のメモリ安全修正を1コミットで取り込んだため。
- `dng_ref_counted_block` の修正は小さいが、`malloc(size + sizeof(header))` のような「確保サイズだけがwrapし、論理サイズは大きいまま残る」形なので、CWE-787として最も直接的に説明できる。

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

- `artifacts/android-security-bulletin-2026-06-01.html`: Android Security Bulletin保存版。
- `artifacts/adobe-apsb26-23.html`: Adobe DNG SDK advisory保存版。
- `artifacts/osv-ASB-A-483693973.json`: Android OSV JSON。
- `artifacts/b0d9d2a8_commit.json`: Gitiles commit JSON。
- `artifacts/b0d9d2a8_update_dng_sdk_1.7.1_2471.diff`: 公開コミット全差分。
- `artifacts/b0d9d2a8_dng_ref_counted_block.diff`: `dng_ref_counted_block::Allocate` の抽出差分。
- `artifacts/b0d9d2a8_dng_misc_opcodes.diff`: `dng_opcode_MapTable` の抽出差分。
- `artifacts/dng_ref_counted_block_before.cpp` / `.h`: 修正前ソース。
- `artifacts/dng_misc_opcodes_before.cpp`: 修正前ソース。
- `artifacts/dng_memory_before.cpp`: allocator/`dng_memory_block` 周辺の修正前ソース。
- `artifacts/SHA256SUMS`: 保存ファイルのSHA-256。
036 OK

CVE-2026-21353

036-ok-dng-jxl-integer-overflow-eop

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityCritical
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-483697751
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-21353 is listed in the Android Security Bulletin as a Critical severity EoP issue in System.

特定した具体的な脆弱性

ok - ソースコード差分から脆弱性の種類、到達条件、根本原因を特定できた。

この CVE は AOSP の platform/external/dng_sdk に取り込まれた Adobe DNG SDK 1.7.1 build 2471 更新のうち、source/dng_jxl.cpp の複数箇所にあった整数オーバーフロー/切り詰めを修正したもの。Android bulletin では System / EoP / Critical、参照 ID は A-483697751。OSV の説明も「dng_jxl.cpp の複数関数で integer overflow による memory corruption があり、追加権限なしの local EoP」となっている。

原因

根本原因は、JXL/DNG の untrusted な寸法・座標値を size_t / uint32 / uint64 から DNG SDK 内部の int32 座標・stride モデルへ変換する境界で、範囲検証と safe arithmetic が不足していたこと。

単一の off-by-one ではなく、以下が重なっていた。

どこから特定したか

保存した付帯ファイル: ・osv-ASB-A-483697751.json: Android OSV の該当 JSON。
・b0d9d2a8_commit.json: Gitiles commit JSON。
・b0d9d2a8_log_context.json: Gitiles log context。
・b0d9d2a8_update_dng_sdk_1.7.1_2471.diff: 公開コミットの全差分。
・b0d9d2a8_dng_jxl_integer_overflow.diff: dng_jxl.cpp の整数オーバーフロー関連抽出差分。
・dng_jxl_before.cpp: 修正前 dng_jxl.cpp。
・dng_jxl_after.cpp: 修正後 dng_jxl.cpp。
・Android.bp.at_b0…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/external/dng_sdk/+/b0d9d2a8d1003176df7d0e8ab565ae40d64b1ec1 / https://osv.dev/vulnerability/ASB-A-483697751 / https://helpx.adobe.com/security/products/dng-sdk/apsb26-23.html

validated.md を表示
# CVE-2026-21353 検証結果

## 判定

ok - ソースコード差分から脆弱性の種類、到達条件、根本原因を特定できた。

この CVE は AOSP の `platform/external/dng_sdk` に取り込まれた Adobe DNG SDK 1.7.1 build 2471 更新のうち、`source/dng_jxl.cpp` の複数箇所にあった整数オーバーフロー/切り詰めを修正したもの。Android bulletin では System / EoP / Critical、参照 ID は `A-483697751`。OSV の説明も「`dng_jxl.cpp` の複数関数で integer overflow による memory corruption があり、追加権限なしの local EoP」となっている。

## 確認したメタ情報

- CVE: CVE-2026-21353
- Android 参照 ID: A-483697751
- Component: System
- Type: EoP
- Severity: Critical
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- 公開 fix commit: `b0d9d2a8d1003176df7d0e8ab565ae40d64b1ec1`
- Gitiles: https://android.googlesource.com/platform/external/dng_sdk/+/b0d9d2a8d1003176df7d0e8ab565ae40d64b1ec1
- OSV: https://osv.dev/vulnerability/ASB-A-483697751
- Adobe APSB26-23: https://helpx.adobe.com/security/products/dng-sdk/apsb26-23.html

Adobe 側では CVE-2026-21353 は DNG SDK 1.7.1 build 2410 以前の `Integer Overflow or Wraparound (CWE-190)`、影響は arbitrary code execution、修正版は 1.7.1 build 2471 とされている。Android 側は同じ SDK 更新を System EoP として扱っている。

## パッチの要点

公開コミット `b0d9d2a8` は SDK 更新全体で、同じコミットに `Bug: 483697751` と `Bug: 483693973` が併記されている。OSV 上も CVE-2026-21352 と CVE-2026-21353 は同じ fix commit/Vanir 署名群を持つが、CVE-2026-21353 の説明は `dng_jxl.cpp` の integer overflow なので、以下の差分を主対象にした。

保存した抽出差分: `b0d9d2a8_dng_jxl_integer_overflow.diff`

主な修正:

- `jxl_memory_block`: `allocator.Malloc(160u + bytesNeeded)` を `size_t mallocSize = (size_t)(160u + bytesNeeded)` に分け、`mallocSize <= bytesNeeded` の場合に `ThrowOverflow()` するよう修正。`Malloc` 失敗時の null check も追加。
- `jxl_image_chunk_reader::get_color_channel_data_at`: `size_t` の `xpos/ypos/xsize/ysize` を `int32` に無条件キャストしていた箇所に `0x7fffffff` 上限チェックを追加。`ypos + ysize` と `xpos + xsize` を `SafeInt32Add` に変更。`fRowStep` 計算を `SafeUint32Mult` から `SafeInt32Mult` に変更。
- `jxl_buffer_chunk_reader::get_color_channel_data_at`: 同様に座標上限チェック、`SafeInt32Add`、`SafeInt32Mult` を追加。
- `EncodeJXL_Common`: preview frame 用 buffer の `fRowStep` と `previewBytesNeeded` を生の `int32`/`uint32` 乗算から `SafeInt32Mult` / `SafeUint32Mult` に変更。ただし該当ブロックは `#if 0` で無効化されており、直接の主到達点ではなく防御的修正と見る。
- `dng_jxl_decoder::Decode`: `basicInfo.xsize/ysize <= 0x7fffffff` を要求し、JXL 画像寸法を `dng_point` の `int32` 領域へ入れる前に拒否。`buffer.fRowStep`、`wholeBuffer.fRowStep`、`bytesNeeded` を safe arithmetic に変更。full-image path の `JxlDecoderImageOutBufferSize` も `uint32` 切り詰め前に `<= 0xffffffff` を要求。

## 脆弱性の内容

JXL/DNG の画像寸法、チャンク座標、チャネル数、pixel size から `dng_pixel_buffer` の矩形、stride、必要バイト数を組み立てる際、修正前は複数箇所で整数の範囲が破綻していた。

特に危険なのは decode path の以下の流れ。

1. `JxlDecoderGetBasicInfo` から得た `basicInfo.xsize/ysize` を、修正前は上限確認なしに `dng_point size` へ代入していた。
2. `dng_point` / `dng_rect` / `dng_pixel_buffer` 側の座標・stride は `int32` ベースであり、`0x7fffffff` を超える JXL 寸法は負値化または不整合な値になる。
3. 修正前の `buffer.fRowStep = buffer.fColStep * size.h` と `wholeBuffer.fRowStep = wholeBuffer.fPlaneStep * totalPlanes` は通常の `int32` 乗算で、オーバーフロー後の値が stride として残る。
4. `bytesNeeded` は `uint64(rowStep) * height * pixelSize` だが、ここで 64-bit 化される時点では `rowStep` が既に壊れている。つまり「本来必要な全画像 buffer サイズ」ではなく、オーバーフロー後の stride から算出したサイズで `jxl_memory_block` が確保される。
5. その後、libjxl の callback から `dng_jxl_decoder_callback_func` が呼ばれ、`cbData.fWholeBuffer.CopyArea(...)` によりデコード済み pixel が `fWholeBuffer` にコピーされる。矩形/stride/確保サイズの整合が崩れているため、過小確保 buffer への out-of-bounds write または不正なメモリアクセスにつながる。

`get_color_channel_data_at` 系も同じ設計ミスで、libjxl に渡す streaming input reader が受け取る `size_t` 座標を `int32` に直接落としてから `dng_pixel_buffer` を作っていた。`xpos + xsize` / `ypos + ysize` が wrap したり、`SafeUint32Mult` に負の幅が渡って unsigned として解釈されたりすると、確保サイズと実コピー範囲がずれる。

`jxl_memory_block` の `160u + bytesNeeded` も根本原因の一部。2GB 超の allocation では `dng_memory_block` ではなく raw `Malloc` を使うが、修正前は alignment/header 余白の `160` を足す計算を overflow check せずに `Malloc` に渡していた。`bytesNeeded` が `size_t` の限界付近、または 32-bit `size_t` 環境で切り詰められる値の場合、実際より小さい領域が確保され得る。

## 根本原因

根本原因は、JXL/DNG の untrusted な寸法・座標値を `size_t` / `uint32` / `uint64` から DNG SDK 内部の `int32` 座標・stride モデルへ変換する境界で、範囲検証と safe arithmetic が不足していたこと。

単一の off-by-one ではなく、以下が重なっていた。

- `size_t` の座標を `int32` に narrowing cast する前の上限チェックがない。
- `int32` の `x + width` / `y + height` / `planes * width` を通常の加算・乗算で計算している。
- `rowStep` が壊れた後に `uint64` へ拡張して allocation size を計算しており、64-bit 化が安全化として機能していない。
- `uint32` allocation API に渡す直前の `size_t`/`uint64` 切り詰めチェックが不足している。
- `libdng_sdk` は Android.bp 上で signed/unsigned integer overflow sanitizer を使っているが、明示的な narrowing cast や「オーバーフロー後の値を合法な別型に入れる」設計ミスまでは API 境界の不変条件として保証できない。

## 悪用条件と影響

攻撃者が巨大または境界値付近の JXL/DNG メタデータ、画像寸法、tile/chunk 座標を持つファイルを入力させると、DNG SDK の JXL decode/streaming path で stride/矩形/確保サイズが矛盾する。結果として DNG SDK を使ってファイルを処理するプロセス内で memory corruption が起こり得る。

Adobe の汎用 SDK advisory では「被害者が悪意あるファイルを開く」local user interaction 型の arbitrary code execution と説明される。一方 Android bulletin/OSV では System component の Critical EoP とされており、Android では `libdng_sdk` を呼ぶシステム側処理の権限コンテキストでメモリ破壊が起きるため、追加権限なしの local escalation と評価されたと考える。

## 調査メモ

- Android bulletin の表では CVE-2026-21352 と CVE-2026-21353 が同じ Gitiles 参照にリンクされている。
- `b0d9d2a8` の commit message には `Bug: 483697751` と `Bug: 483693973` が併記され、`Cherrypick-From` は private Googleplex review 2 件。公開 AOSP からは CVE ごとの private 原因 commit の分離は見えない。
- OSV JSON でも 21352/21353 は同じ Vanir 署名群を共有している。CVE 名だけで差分を機械的に一対一対応させるより、CVE description の「integer overflow」と一致する `dng_jxl.cpp` の safe arithmetic 化を抽出する必要があった。
- `EncodeJXL_Common` の preview frame 修正は `#if 0` 内で、現行ビルドでは直接 reachable ではない。SDK 更新として将来有効化時の同種バグも潰している。
- `README.version` は古い 1.4.0 のままだが、`source/dng_flags.h` の build string は 2410 から 2471 に更新されている。実際の修正版判定は `dng_flags.h` 側を見るべき。

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

- `osv-ASB-A-483697751.json`: Android OSV の該当 JSON。
- `b0d9d2a8_commit.json`: Gitiles commit JSON。
- `b0d9d2a8_log_context.json`: Gitiles log context。
- `b0d9d2a8_update_dng_sdk_1.7.1_2471.diff`: 公開コミットの全差分。
- `b0d9d2a8_dng_jxl_integer_overflow.diff`: `dng_jxl.cpp` の整数オーバーフロー関連抽出差分。
- `dng_jxl_before.cpp`: 修正前 `dng_jxl.cpp`。
- `dng_jxl_after.cpp`: 修正後 `dng_jxl.cpp`。
- `Android.bp.at_b0d9d2a8`: 修正コミット時点の Android.bp。
- `README.version.at_b0d9d2a8`: 修正コミット時点の README.version。

## ファイルハッシュ

```text
be805560014949d80b1d75532d75bfde9fcc39ff492671719779cb3bb331c32b  Android.bp.at_b0d9d2a8
e1180750782d144f35aea3aba3b2c7787271d831138f4b680da71e5494b23380  README.version.at_b0d9d2a8
ce3dd7f24f5369726b8130e5a2f8a11bd6df453e4582e1078a01df46bb2ba7ed  b0d9d2a8_commit.json
fe5d6d559b6721ed8cf57baf823436ff1e5f4c2adff6bd80dd91ffd8ef7a9ef6  b0d9d2a8_dng_jxl_integer_overflow.diff
d2fa0f78d697e6277b22ca31d5233d17ad7f957aa8d348bcd083542d89e82508  b0d9d2a8_log_context.json
b6a6c0f346980d3d3b84a4bce85c2a7aa5930f276a04be2c635fe81df52b8bd6  b0d9d2a8_update_dng_sdk_1.7.1_2471.diff
f6d6d97914b798087df3dbeb661247c74400c17769e6251d736459fd97690ca6  dng_jxl_after.cpp
a07047ff56aff83cce52209fc555e5b44eda4318e5aa56f0f830e4f632f816f7  dng_jxl_before.cpp
6868ad69e75fb8612fd895ef49b978213f22a33b1c38c3f877226aa8daed8537  osv-ASB-A-483697751.json
```
037 OK

CVE-2025-64505

037-ok-libpng-png-do-quantize-oob-read

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeDoS
SeverityCritical
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-463980379
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-64505 is listed in the Android Security Bulletin as a Critical severity DoS issue in System.

特定した具体的な脆弱性

判定: ok

CVE-2025-64505 は Android 2026-06-01 bulletin では System / DoS / Critical、参照 ID は A-463980379 として掲載されている。実体は AOSP の platform/external/libpng に取り込まれた libpng upstream 脆弱性で、png_do_quantize() が壊れた indexed PNG のパレットインデックスを検査前に quantize_index の添字として使うことによる heap buffer over-read だった。

根本原因は、png_set_quantize() が quantize_index を num_palette バイトで確保していた一方、後段の png_do_quantize() は PNG のピクセル値を 0..255 の外部入力として扱い、*sp = quantize_lookup[*sp]; で範囲チェックなしに読む設計不整合である。PLTE が小さい PNG、例えば 2 色だけの PLTE にピクセル値 255 を含めると、quantize_index[255] を読む。

原因

記載なし。

どこから特定したか

パッチ解析: Android bulletin の CVE 行には libpng の 6 コミットがリンクされているが、Bug: 463980379 に直接対応するのは次の 2 本だった。

保存した主な付帯ファイル: ・artifacts/libpng_commit_log.pretty.json: AOSP commit log
・artifacts/3f148ea688b5dc631c51699947ce5dd3654a5eb0.diff: AOSP memory leak/refactor diff
・artifacts/93147074acc1bebdda8316d9a891a5d4d122ca80.diff: AOSP OOB read fix diff
・artifacts/upstream-6a528eb5.diff: upstream CVE-2025-64505 fix diff
・artifacts/pngrtran.3f148ea688b5dc631c51699947ce5dd3654a5eb0.c:…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://nvd.nist.gov/vuln/detail/CVE-2025-64505 / https://github.com/pnggroup/libpng/security/advisories/GHSA-4952-h5wq-4m42 / https://github.com/pnggroup/libpng/commit/6a528eb5fd0dd7f6de1c39d30de0e41473431c37

validated.md を表示
# CVE-2025-64505 解析結果

## 結論

判定: ok

CVE-2025-64505 は Android 2026-06-01 bulletin では `System / DoS / Critical`、参照 ID は `A-463980379` として掲載されている。実体は AOSP の `platform/external/libpng` に取り込まれた libpng upstream 脆弱性で、`png_do_quantize()` が壊れた indexed PNG のパレットインデックスを検査前に `quantize_index` の添字として使うことによる heap buffer over-read だった。

根本原因は、`png_set_quantize()` が `quantize_index` を `num_palette` バイトで確保していた一方、後段の `png_do_quantize()` は PNG のピクセル値を 0..255 の外部入力として扱い、`*sp = quantize_lookup[*sp];` で範囲チェックなしに読む設計不整合である。PLTE が小さい PNG、例えば 2 色だけの PLTE にピクセル値 255 を含めると、`quantize_index[255]` を読む。

## 対象情報

- CVE: CVE-2025-64505
- Android reference: A-463980379
- Android component/type/severity: System / DoS / Critical
- Android bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Android bulletin 更新: 2026-06-03 に AOSP links が追加されたと記載
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2025-64505
- GitHub advisory: https://github.com/pnggroup/libpng/security/advisories/GHSA-4952-h5wq-4m42
- upstream fix: https://github.com/pnggroup/libpng/commit/6a528eb5fd0dd7f6de1c39d30de0e41473431c37
- AOSP fix: https://android.googlesource.com/platform/external/libpng/+/93147074acc1bebdda8316d9a891a5d4d122ca80

## パッチ解析

Android bulletin の CVE 行には libpng の 6 コミットがリンクされているが、`Bug: 463980379` に直接対応するのは次の 2 本だった。

- `3f148ea688b5dc631c51699947ce5dd3654a5eb0`: `png_set_quantize()` の再呼び出し時に既存 `quantize_index` を解放し、`quantize_sort` を `png_struct` メンバではなくローカル配列にするメモリリーク修正。
- `93147074acc1bebdda8316d9a891a5d4d122ca80`: `png_do_quantize()` の OOB read 修正。`quantize_index` の確保サイズを `num_palette` から `PNG_MAX_PALETTE_LENGTH`、つまり 256 バイトへ変更。

脆弱版の要点:

```c
png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
    (png_alloc_size_t)num_palette);
for (i = 0; i < num_palette; i++)
   png_ptr->quantize_index[i] = (png_byte)i;

...

*sp = quantize_lookup[*sp];
```

修正版の要点:

```c
png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
    PNG_MAX_PALETTE_LENGTH);
for (i = 0; i < PNG_MAX_PALETTE_LENGTH; i++)
   png_ptr->quantize_index[i] = (png_byte)i;
```

`png_do_check_palette_indexes()` による invalid palette index 検査は `png_do_quantize()` より後に呼ばれるため、この検査では OOB read を防げない。したがって、修正は「検査を前倒しする」のではなく、壊れたインデックス 0..255 のどれで読まれても配列内に収まるよう `quantize_index` を 256 要素に広げる方針になっている。

## 脆弱性が起きる条件

1. アプリケーションまたは Android の画像処理経路が libpng の read transform で `png_set_quantize()` を有効にする。
2. 入力 PNG が indexed-color PNG で、PLTE のエントリ数 `num_palette` が 256 より小さい。
3. IDAT 内のピクセル値に `num_palette` 以上の値が含まれる。これは PNG としては malformed palette index。
4. `png_read_row()` などで read transformation が走ると、`png_do_quantize()` が `quantize_lookup[*sp]` を実行し、`*sp >= num_palette` の場合に `quantize_index` の範囲外を読む。

影響は heap buffer over-read。クラッシュによる DoS が主で、ヒープ上の隣接データの読み取りにより情報漏えいの可能性もある。upstream は CVSS 6.1 / Moderate としているが、Android bulletin では System DoS Critical として扱われている。

## 再現検証

付帯ファイルとして以下を作成した。

- `artifacts/repro_cve_2025_64505.c`: `png_set_quantize()` を呼んで 1 行読む再現プログラム
- `artifacts/make_malformed_palette_png.py`: PLTE 2 色、ピクセル値 255 の 1x1 malformed indexed PNG を生成
- `artifacts/malformed_palette_index_255.png`: 生成した検証入力
- `artifacts/libpng-1.6.50/`: upstream v1.6.50、脆弱版
- `artifacts/libpng-1.6.51/`: upstream v1.6.51、修正版
- `artifacts/repro-1.6.50.err`: ASan でのクラッシュログ
- `artifacts/repro-1.6.51.out`: 修正版での実行結果

実行条件:

```sh
CC=clang CFLAGS='-fsanitize=address -fno-omit-frame-pointer -g -O1' \
  LDFLAGS='-fsanitize=address' ./configure --disable-shared --enable-static \
  --disable-tools --disable-tests
make -j
clang -fsanitize=address -fno-omit-frame-pointer -g -O1 \
  -I libpng-1.6.50 repro_cve_2025_64505.c libpng-1.6.50/.libs/libpng16.a \
  -lz -lm -o repro-1.6.50
```

結果:

- v1.6.50: `ERROR: AddressSanitizer: heap-buffer-overflow`、`READ of size 1`、スタックは `png_do_read_transformations -> png_read_row -> main`。呼び出し箇所は `pngrtran.c:5013` の `png_do_quantize(...)`。
- v1.6.51: 同じ malformed PNG と同じ再現プログラムで `decoded first byte: 255` と出て正常終了。

この比較により、ソース差分で特定した修正が実際に OOB read を止めることを確認した。

## 調査時のメモ

- Android bulletin の CVE 行に並ぶ 6 本の libpng コミットは、CVE-2025-64505 だけでなく CVE-2025-64506、CVE-2025-64720、CVE-2025-65018 相当の修正も同じ並びに含んでいる。`Bug:` 行で `463980379` を確認して切り分ける必要があった。
- GitHub advisory と NVD の説明には `palette_lookup` の bounds と書かれているが、実際のパッチと再現経路で範囲外参照されるのは `png_ptr->quantize_index`、`png_do_quantize()` の引数名では `quantize_lookup` である。RGB/RGBA を palette 化する `palette_lookup` 経路ではなく、palette 入力の再量子化経路が本件の中心。
- `3f148ea...` のメモリリーク修正も同じ Android bug ID に紐づくが、Critical DoS としての本質は `93147074...` の OOB read 修正で説明できる。
- 最初に `cmake` でビルド検証しようとしたが、この環境には `cmake` が無かったため、libpng 同梱の `configure`/`make` で検証した。

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

- `artifacts/libpng_commit_log.pretty.json`: AOSP commit log
- `artifacts/3f148ea688b5dc631c51699947ce5dd3654a5eb0.diff`: AOSP memory leak/refactor diff
- `artifacts/93147074acc1bebdda8316d9a891a5d4d122ca80.diff`: AOSP OOB read fix diff
- `artifacts/upstream-6a528eb5.diff`: upstream CVE-2025-64505 fix diff
- `artifacts/pngrtran.3f148ea688b5dc631c51699947ce5dd3654a5eb0.c`: 修正直前相当の AOSP `pngrtran.c`
- `artifacts/pngrtran.93147074acc1bebdda8316d9a891a5d4d122ca80.c`: OOB read 修正後の AOSP `pngrtran.c`
- `artifacts/configure-1.6.50.log`, `artifacts/build-1.6.50.log`
- `artifacts/configure-1.6.51.log`, `artifacts/build-1.6.51.log`
- `artifacts/repro-1.6.50.err`, `artifacts/repro-1.6.51.out`
038 OK

CVE-2026-0039

038-ok-dng-sdk-ubsan-overflow-hard-abort-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeDoS
SeverityCritical
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-470966846
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0039 is listed in the Android Security Bulletin as a Critical severity DoS issue in System.

特定した具体的な脆弱性

ok: 脆弱性の根本原因をソースコード差分で特定できた。

このCVEは platform/external/dng_sdk の libdng_sdk が、DNG/RAW画像デコード中の整数overflowを UBSan minimal runtime のハードabortとして処理していたため、細工されたDNG入力でデコード元プロセスをクラッシュさせられる DoS だった。修正は整数overflow自体を1箇所ずつ直すものではなく、libdng_sdk のUBSan handlerを独自実装に差し替え、overflow検出をabortではなくC++例外に変換するものだった。

原因

根本原因は、信頼できないDNG/RAWファイル由来の値で到達可能な整数算術overflowを、ライブラリ内の通常エラーとして扱わず、UBSan minimalのプロセスabortに任せていたこと。

より具体的には以下の組み合わせ。

・libdng_sdk-defaults で signed/unsigned integer overflow sanitizer が有効。
・libdng_sdk はC++例外を有効化しており、DNG SDK/Skia側は不正入力を例外で回復する設計。
・しかしUBSan minimal runtimeは例外を投げず、overflow検出時にhard abortする。
・DNGのmetadata、寸法、tile、opcode、render処理などは攻撃者制御入力から多数の整数計算に到達する。
・そのため、DNG SDK内のoverflowがメモリ破壊に進む前でも、検出された瞬間にプロセスDoSになる。

どこから特定したか

パッチ差分の要点: 修正前の libdng_sdk は libdng_sdk-defaults を継承しており、defaults側で以下の sanitizer が有効だった。

``bp
sanitize: {
misc_undefined: [
"unsigned-integer-overflow",
"signed-integer-overflow",
],
},
`

修正前の libdng_sdk 自体は以下だけだった。

`bp
cflags: ["-DqDNGValidate=0"],
`

保存した証跡: ・artifacts/android-security-bulletin-2026-06-01.html: Android Security Bulletin保存版
・artifacts/bulletin-grep-CVE-2026-0039.txt: bulletin上のCVE行抜粋
・artifacts/osv-ASB-A-470966846.json: 対象CVEのAndroid OSV
・artifacts/osv-ASB-A-*.json: 同じcommit messageに出る関連CVEのOSV
・artifacts/74a5a91_commit_full.txt: commit metadata/stat
・artifacts/74a5a91.patch: 対象commitのpatch
・art…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/plat…

validated.md を表示
# CVE-2026-0039 検証結果

## 判定

ok: 脆弱性の根本原因をソースコード差分で特定できた。

このCVEは `platform/external/dng_sdk` の `libdng_sdk` が、DNG/RAW画像デコード中の整数overflowを UBSan minimal runtime のハードabortとして処理していたため、細工されたDNG入力でデコード元プロセスをクラッシュさせられる DoS だった。修正は整数overflow自体を1箇所ずつ直すものではなく、`libdng_sdk` のUBSan handlerを独自実装に差し替え、overflow検出をabortではなくC++例外に変換するものだった。

## 基本情報

- CVE: CVE-2026-0039
- Android Bug ID: A-470966846
- Component: System
- Type: DoS
- Severity: Critical
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Bulletin上の修正リンク: https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce
- OSV: https://storage.googleapis.com/android-osv/ASB-A-470966846.json
- 対象AOSP versions: 14, 15, 16, 16-qpr2

## 参照した修正

主に以下のAOSP commitを解析した。

- `74a5a91d169a341db58d57e0bf018d0a8b784cce`
- Subject: `Replace ubsan-minimal with throw`
- Parent: `47cd326e0c8f19cc367663b31d95c03584198fa4`
- AuthorDate: 2026-01-09
- CommitDate: 2026-04-09
- 変更ファイル:
  - `Android.bp`
  - `OWNERS`
  - `ubsan-replacement/ubsan_throwing_runtime.cpp`

OSV上のブランチ別fixは以下。

- 17-next: `81ded662eee07fcbb830e6b6c83d1a3d85227ceb`
- 15: `475c8cce973f56488cc9f37d00cf0a4069f0e4fe`
- 16: `1337d2e14a412ec81a4a32f6251063091922a9e9`
- 16-qpr2: `690688f3b522dc80de007d5c3ac8b8ce61da8870`
- 14: `7f197e818cbb7b5bc7b9ee5017a36a23650c29de`

ローカルgitでは `81ded...` と `7f197...` が取得済みで、どちらも同じ `Replace ubsan-minimal with throw` 系の修正だった。ほかのブランチfixはOSVには記載されているが、現在のローカルmirrorにはobjectが無かった。

## パッチ差分の要点

修正前の `libdng_sdk` は `libdng_sdk-defaults` を継承しており、defaults側で以下の sanitizer が有効だった。

```bp
sanitize: {
    misc_undefined: [
        "unsigned-integer-overflow",
        "signed-integer-overflow",
    ],
},
```

修正前の `libdng_sdk` 自体は以下だけだった。

```bp
cflags: ["-DqDNGValidate=0"],
```

修正後は `libdng_sdk` に対してSoongのsanitizer runtime注入を止め、明示的に整数overflow instrumentationだけを有効化し、runtimeはリンクしない構成になった。

```bp
sanitize: {
    never: true,
},

cflags: [
    "-DqDNGValidate=0",
    "-fsanitize=signed-integer-overflow,unsigned-integer-overflow",
    "-fno-sanitize-link-runtime",
],

srcs: [
    "ubsan-replacement/ubsan_throwing_runtime.cpp"
],
```

追加された `ubsan-replacement/ubsan_throwing_runtime.cpp` は、UBSanのoverflow handlerをすべてC++例外に変換する。

```cpp
INTERFACE void __ubsan_handle_add_overflow() {
    throw std::runtime_error("ubsan: add-overflow");
}

INTERFACE void __ubsan_handle_sub_overflow() {
    throw std::runtime_error("ubsan: sub-overflow");
}

INTERFACE void __ubsan_handle_mul_overflow() {
    throw std::runtime_error("ubsan: mul-overflow");
}

INTERFACE void __ubsan_handle_negate_overflow() {
    throw std::runtime_error("ubsan: negate-overflow");
}

INTERFACE void __ubsan_handle_divrem_overflow() {
    throw std::runtime_error("ubsan: divrem-overflow");
}
```

commit messageにも「C++ exceptions are enabled in this library」「ubsan errors than a hard abort」とあり、修正意図は明確に「UBSan検出時のhard abortを例外に置換する」ことだった。

## 脆弱性が起きる状況

`libdng_sdk` はAndroidのSkia RAW/DNG codec経由で使われる。保存した `SkRawCodec.cpp` では、DNG入力に対して以下の流れになる。

1. `SkRawCodec::MakeFromStream()` がPIEX previewで処理できないRAW/DNGを `SkDngImage::NewFromStream()` に渡す。
2. `SkDngImage::readDng()` が `dng_info::Parse/PostParse`、`dng_negative::Parse/PostParse` を実行する。
3. `SkRawCodec::onGetPixels()` が `SkDngImage::render()` を呼び、`ReadStage1Image`、`BuildStage2Image`、`BuildStage3Image`、`dng_render::Render()` を実行する。

Skia側はDNG SDKが例外を投げる前提で作られている。`readDng()` と `render()` は `catch (...)` で失敗を捕捉し、`false` / `nullptr` を返す。`onGetPixels()` は `nullptr` を `kInvalidInput` に変換する。

つまり本来の失敗経路は「不正なDNG入力 -> 例外 -> 画像デコード失敗」だが、未修正では整数overflowだけがUBSan minimal runtimeによりプロセスabortになる。`catch (...)` では `abort()` は捕捉できないため、細工されたDNGを画像デコードさせるだけで、デコードを行ったプロセスを落とせる。

OSVの説明もこの理解と一致する。

> In multiple functions of ubsan_throwing_runtime.cpp, there is a possible persistent denial of service due to an integer overflow. This could lead to remote denial of service with no additional execution privileges needed. User interaction is not needed for exploitation.

ここで `ubsan_throwing_runtime.cpp` は修正後に追加されたファイル名なので、OSVの表現は「修正シグネチャの場所」を指しており、実際の入力到達点はDNG SDK内の複数のparse/render系算術処理と見るべき。

## 根本原因

根本原因は、信頼できないDNG/RAWファイル由来の値で到達可能な整数算術overflowを、ライブラリ内の通常エラーとして扱わず、UBSan minimalのプロセスabortに任せていたこと。

より具体的には以下の組み合わせ。

- `libdng_sdk-defaults` で signed/unsigned integer overflow sanitizer が有効。
- `libdng_sdk` はC++例外を有効化しており、DNG SDK/Skia側は不正入力を例外で回復する設計。
- しかしUBSan minimal runtimeは例外を投げず、overflow検出時にhard abortする。
- DNGのmetadata、寸法、tile、opcode、render処理などは攻撃者制御入力から多数の整数計算に到達する。
- そのため、DNG SDK内のoverflowがメモリ破壊に進む前でも、検出された瞬間にプロセスDoSになる。

修正は sanitizer instrumentation 自体を外さず、`-fsanitize=signed-integer-overflow,unsigned-integer-overflow` を維持している。そのうえで `-fno-sanitize-link-runtime` と独自 `__ubsan_handle_*_overflow` により、検出結果をC++例外に変換する。これは「overflowを見逃す」のではなく、「overflowを通常のデコード失敗として安全に処理する」修正である。

## 面白い点・調査メモ

- 同じ `74a5a91...` commit messageには A-470966846 以外にも `467994860`, `467994310`, `461790658`, `456471487`, `453649377`, `449728942` が列挙されていた。
- これらはそれぞれ CVE-2026-0040, CVE-2026-0041, CVE-2026-0051, CVE-2026-0042, CVE-2026-0043, CVE-2026-0044 に対応しており、OSV上の説明はいずれも `ubsan_throwing_runtime.cpp` を指している。
- つまりこのcommitは、個別のDNG入力バグを1つずつ直すパッチというより、DNG SDK全体で「UBSan検出をプロセスクラッシュにしない」ための共通修正だった。
- `SkRawCodec` 側はすでに `catch (...)` を広く置いており、パッチ後の `std::runtime_error` も捕捉される。既存の呼び出し側設計を活かすためのruntime差し替えになっている。
- OSVの `vanir_signatures` はこのCVEでは0件だった。変更がビルド設定とUBSan handler追加であり、脆弱な算術式そのものの行シグネチャでは表現しづらいことが理由と思われる。

## 保存した証跡

- `artifacts/android-security-bulletin-2026-06-01.html`: Android Security Bulletin保存版
- `artifacts/bulletin-grep-CVE-2026-0039.txt`: bulletin上のCVE行抜粋
- `artifacts/osv-ASB-A-470966846.json`: 対象CVEのAndroid OSV
- `artifacts/osv-ASB-A-*.json`: 同じcommit messageに出る関連CVEのOSV
- `artifacts/74a5a91_commit_full.txt`: commit metadata/stat
- `artifacts/74a5a91.patch`: 対象commitのpatch
- `artifacts/Android.bp.before`: 修正前 `Android.bp`
- `artifacts/Android.bp.after`: 修正後 `Android.bp`
- `artifacts/ubsan_throwing_runtime.cpp`: 追加されたUBSan replacement runtime
- `artifacts/SkRawCodec.cpp`: 呼び出し側確認用のSkia RAW codec
- `artifacts/SkRawCodec.h`: 同上
- `artifacts/skia_Android.bp`: `libskia` が `libdng_sdk` を使い、例外を有効にしている証跡
- `artifacts/key-code-excerpts.txt`: 重要差分と呼び出し側catch箇所の抜粋
- `artifacts/fix-commits-availability.txt`: OSV記載fix commitのローカルobject確認結果

039 OK

CVE-2026-0040

039-ok-dng-sdk-ubsan-overflow-abort-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeDoS
SeverityCritical
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-467994860
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0040 is listed in the Android Security Bulletin as a Critical severity DoS issue in System.

特定した具体的な脆弱性

判定: ok

CVE-2026-0040 は、Android の platform/external/dng_sdk における DNG/RAW 画像デコード時の整数オーバーフロー検出が、通常の画像デコード失敗ではなくプロセス abort に直結していた DoS 脆弱性と判断した。攻撃者が細工した DNG/RAW 画像を処理させると、libdng_sdk 内の signed/unsigned integer overflow sanitizer が発火し、修正前は Soong/UBSan minimal runtime により hard abort していた。Android Bulletin/OSV 上の影響は remote DoS、追加権限不要、ユーザー操作不要。

根本原因は DNG SDK の個別演算そのものだけではなく、libdng_sdk が -fexceptions と DNG SDK 例外処理を前提にしている一方で、整数オーバーフロー sanitizer の runtime だけが例外化されず abort するビルド構成だったこと。修正は sanitizer runtime を差し替え、オーバーフロー handler が C++ 例外を投げるようにして、既存の Skia/DNG codec の catch (...) 経路で decode 失敗として処理させるものだった。

原因

libdng_sdk は DNG SDK 由来の異常系を dng_exception で扱う構造で、Android.bp でも cppflags: ["-fexceptions"] が有効だった。Skia 側の SkDngImage::readDng() と SkDngImage::render() は catch (...) を持ち、例外であれば失敗として戻せる。

しかし整数オーバーフロー sanitizer は例外ではなく sanitizer runtime の abort に接続されていた。つまり、ライブラリの通常エラー処理モデルと sanitizer の失敗モデルが不整合だった。攻撃可能な入力が DNG SDK 内の未防御または sanitizer 検出対象の整数演算に到達すると、例外処理を迂回してプロセス終了になる。

どこから特定したか

パッチ解析: 公開統合コミット 74a5a91d169a341db58d57e0bf018d0a8b784cce の件名は Replace ubsan-minimal with throw。コミットメッセージには Bug: 467994860 が含まれ、同時に複数の DNG SDK 関連 CVE/Bug ID がまとめて修正されている。

差分の本質は Android.bp の libdng_sdk 設定変更と ubsan-replacement/ubsan_throwing_runtime.cpp の追加。

保存した付帯ファイル: ・ASB-A-467994860.json: Android OSV JSON
・74a5a91d169a341db58d57e0bf018d0a8b784cce.diff: 公開統合コミットの Gitiles 差分
・commit-*.patch: ローカル取得した external/dng_sdk 履歴上の関連公開コミットの patch
・related_commits.tsv: Bug: 467994860 を含む関連コミット一覧
・Android.bp.parent, Android.bp.fixed: 修正前後の libdng_sdk ビルド設定比較用
・SkRawCodec.cpp.master: Skia DNG codec の例外捕捉経路確認用
・ImageDecoder.cpp.master…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://storage.googleapis.com/android-osv/ASB-A-4679…

validated.md を表示
# CVE-2026-0040 検証結果

## 結論

判定: ok

CVE-2026-0040 は、Android の `platform/external/dng_sdk` における DNG/RAW 画像デコード時の整数オーバーフロー検出が、通常の画像デコード失敗ではなくプロセス abort に直結していた DoS 脆弱性と判断した。攻撃者が細工した DNG/RAW 画像を処理させると、`libdng_sdk` 内の signed/unsigned integer overflow sanitizer が発火し、修正前は Soong/UBSan minimal runtime により hard abort していた。Android Bulletin/OSV 上の影響は remote DoS、追加権限不要、ユーザー操作不要。

根本原因は DNG SDK の個別演算そのものだけではなく、`libdng_sdk` が `-fexceptions` と DNG SDK 例外処理を前提にしている一方で、整数オーバーフロー sanitizer の runtime だけが例外化されず abort するビルド構成だったこと。修正は sanitizer runtime を差し替え、オーバーフロー handler が C++ 例外を投げるようにして、既存の Skia/DNG codec の `catch (...)` 経路で decode 失敗として処理させるものだった。

## 確認した基本情報

- CVE: CVE-2026-0040
- Android reference: A-467994860
- Component: System
- Type: DoS
- Severity: Critical
- Updated AOSP versions: 14, 15, 16, 16-qpr2
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://storage.googleapis.com/android-osv/ASB-A-467994860.json
- 主要修正コミット: https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce

## パッチ解析

公開統合コミット `74a5a91d169a341db58d57e0bf018d0a8b784cce` の件名は `Replace ubsan-minimal with throw`。コミットメッセージには `Bug: 467994860` が含まれ、同時に複数の DNG SDK 関連 CVE/Bug ID がまとめて修正されている。

差分の本質は `Android.bp` の `libdng_sdk` 設定変更と `ubsan-replacement/ubsan_throwing_runtime.cpp` の追加。

- 修正前: `libdng_sdk` は `sanitize.misc_undefined` で `unsigned-integer-overflow` と `signed-integer-overflow` を有効化し、通常の sanitizer runtime にリンクされる。
- 修正後: `sanitize.never: true` と `-fno-sanitize-link-runtime` により既定 runtime を外しつつ、`-fsanitize=signed-integer-overflow,unsigned-integer-overflow` は維持する。
- 追加ファイル: `__ubsan_handle_add_overflow`, `__ubsan_handle_sub_overflow`, `__ubsan_handle_mul_overflow`, `__ubsan_handle_negate_overflow`, `__ubsan_handle_divrem_overflow` が `std::runtime_error` を投げる。

このため、整数オーバーフロー検出時の挙動が「プロセス abort」から「C++ 例外」に変わる。DNG SDK/Skia 側には既に例外を decode 失敗へ変換する設計があるため、修正は入力検証追加ではなくエラー伝播方式の修正である。

## 脆弱性が起きる状況

1. Android の画像デコード経路が DNG/RAW 入力を処理する。
2. Skia の `SkRawCodec` が `libdng_sdk` を使って DNG を parse/render する。
3. 細工された DNG メタデータ、寸法、opcode、tile/area 情報などにより、`libdng_sdk` 内の加算・減算・乗算・符号反転・除算剰余のいずれかで UBSan の signed/unsigned integer overflow が発火する。
4. 修正前は UBSan minimal runtime が abort するため、画像を処理したプロセスが落ちる。
5. 修正後は `ubsan_throwing_runtime.cpp` の handler が `std::runtime_error` を投げ、Skia の DNG codec 側の `catch (...)` で `nullptr`/decode failure になり、ImageDecoder は `DecodeException` または decode error として処理できる。

OSV の詳細文も「`ubsan_throwing_runtime.cpp` の複数関数において、integer overflow によって crash を起こせる可能性」と説明しており、公開パッチと一致する。

## 根本原因

`libdng_sdk` は DNG SDK 由来の異常系を `dng_exception` で扱う構造で、Android.bp でも `cppflags: ["-fexceptions"]` が有効だった。Skia 側の `SkDngImage::readDng()` と `SkDngImage::render()` は `catch (...)` を持ち、例外であれば失敗として戻せる。

しかし整数オーバーフロー sanitizer は例外ではなく sanitizer runtime の abort に接続されていた。つまり、ライブラリの通常エラー処理モデルと sanitizer の失敗モデルが不整合だった。攻撃可能な入力が DNG SDK 内の未防御または sanitizer 検出対象の整数演算に到達すると、例外処理を迂回してプロセス終了になる。

## 面白い点・調査メモ

- パッチは脆弱な演算箇所を個別に直していない。複数の DNG 入力/バグ ID を、UBSan overflow の扱いを一括で「throw」に変えることで修正している。
- `libdng_sdk` には `dng_safe_arithmetic.*` が存在し、多数の overflow-aware helper もある。それでも sanitizer が必要な overflow が残っており、今回の CVE 群はそれらを abort ではなく通常の失敗へ流す方針になっている。
- 公開コミットの `Test:` は `atest ImageDecoderTest#testInterestingDngs`。これは画像デコード経路から DNG の「interesting」サンプルを処理する回帰テストを示すが、今回の作業環境では該当テスト資産の具体ファイル名までは公開取得できなかった。
- OSV JSON には Android 14/15/16/16-qpr2/17-next の各 fix URL が載っている。一部ハッシュは Gitiles の `^!` 差分として直接取得できなかったが、ローカル clone の全履歴検索では同じ Bug ID を持つ公開ブランチ別コミットを複数確認した。

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

- `ASB-A-467994860.json`: Android OSV JSON
- `74a5a91d169a341db58d57e0bf018d0a8b784cce.diff`: 公開統合コミットの Gitiles 差分
- `commit-*.patch`: ローカル取得した `external/dng_sdk` 履歴上の関連公開コミットの patch
- `related_commits.tsv`: `Bug: 467994860` を含む関連コミット一覧
- `Android.bp.parent`, `Android.bp.fixed`: 修正前後の `libdng_sdk` ビルド設定比較用
- `SkRawCodec.cpp.master`: Skia DNG codec の例外捕捉経路確認用
- `ImageDecoder.cpp.master`, `hwui_Android.bp.master`: Android 画像デコード経路確認用
- `dng_sdk.git/`: `platform/external/dng_sdk` の調査用 clone

## 主要 URL / commit

- Android Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Android OSV: https://storage.googleapis.com/android-osv/ASB-A-467994860.json
- public fix: `74a5a91d169a341db58d57e0bf018d0a8b784cce`
- OSV listed fixes:
  - `81ded662eee07fcbb830e6b6c83d1a3d85227ceb` 17-next
  - `475c8cce973f56488cc9f37d00cf0a4069f0e4fe` Android 15
  - `1337d2e14a412ec81a4a32f6251063091922a9e9` Android 16
  - `690688f3b522dc80de007d5c3ac8b8ce61da8870` Android 16-qpr2
  - `7f197e818cbb7b5bc7b9ee5017a36a23650c29de` Android 14

## 再現・検証上の限界

実機または完全な AOSP build 環境で PoC DNG を走らせる検証は行っていない。ただし、公開 OSV の詳細、Bug ID 付き修正コミット、`libdng_sdk` のビルド差分、追加された UBSan handler、Skia 側の `catch (...)` 経路から、脆弱性の発生条件と根本原因はソースコードベースで特定できた。
040 OK

CVE-2026-0041

040-ok-dng-sdk-ubsan-overflow-hard-abort-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeDoS
SeverityCritical
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-467994310
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0041 is listed in the Android Security Bulletin as a Critical severity DoS issue in System.

特定した具体的な脆弱性

判定: ok

タイトル: dng-sdk-ubsan-overflow-hard-abort-dos

CVE-2026-0041 / A-467994310 は、Android の platform/external/dng_sdk における DNG/RAW 画像デコード時の整数オーバーフロー検出が、通常のデコード失敗ではなくプロセス abort に直結していた DoS 脆弱性と判断した。攻撃者が細工した DNG/RAW 入力を画像デコード経路に到達させ、libdng_sdk 内の signed/unsigned integer overflow sanitizer を発火させると、修正前は UBSan minimal runtime が hard abort し、呼び出し側の例外処理に戻る前にプロセスが落ちる。

根本原因は、DNG SDK と Skia 側が C++ 例外で不正入力を回復可能な decode failure に変換する設計である一方、libdng_sdk の整数オーバーフロー sanitizer runtime だけが例外ではなく abort を使っていたこと。修正は個別の演算を1箇所ずつ直すものではなく、UBSan overflow handler を独自実装に差し替え、std::runtime_error を投げるようにして既存の catch (...) 経路へ流すものだった。

原因

根本原因は、信頼できない DNG/RAW 入力から到達可能な整数オーバーフローを、ライブラリの通常エラー処理モデルに統合できていなかったこと。

DNG SDK には dng_safe_arithmetic.h があり、overflow を検査して dng_exception を投げる設計が既に存在する。dng_exceptions.cpp の Throw_dng_error() も最終的に throw dng_exception(err) する。つまり SDK 側は不正入力や算術異常を例外として扱う思想を持っている。

しかしコンパイラ挿入の UBSan overflow instrumentation は、修正前の libdng_sdk では例外ではなく UBSan minimal runtime の abort に接続されていた。このため、DNG SDK 本体や Skia 側が catch (...) で回復できるようにしていても、UBSan による検出だけは回復不能なクラッシュになった。

どこから特定したか

パッチ解析: 公開統合コミット 74a5a91d169a341db58d57e0bf018d0a8b784cce の件名は Replace ubsan-minimal with throw。コミットメッセージには Bug: 467994310 が含まれ、Test: atest ImageDecoderTest#testInterestingDngs も記載されている。同じコミットは 470966846, 467994860, 461790658, 456471487, 453649377, 449728942 も同時に修正対象として列挙していた。

差分の本質は Android.bp の libdng_sdk 設定変更と、ubsan-replacement/ubsan_throwing_runtime.cpp の追加である。

保存した付帯ファイル: ・artifacts/osv-ASB-A-467994310.json: 既存保存済み Android OSV JSON
・artifacts/osv-ASB-A-467994310.refetched.json: 再取得した Android OSV JSON
・artifacts/android-security-bulletin-2026-06-01.html: Android Security Bulletin 保存版
・artifacts/74a5a91.commit.json: Gitiles commit metadata
・artifacts/74a5a91.patch: Gitiles patch
・artifacts/74a5a91d169a341db58d57e0bf018d0a8b784…

URL: https://sou…

validated.md を表示
# CVE-2026-0041 検証結果

## 結論

判定: ok

タイトル: dng-sdk-ubsan-overflow-hard-abort-dos

CVE-2026-0041 / A-467994310 は、Android の `platform/external/dng_sdk` における DNG/RAW 画像デコード時の整数オーバーフロー検出が、通常のデコード失敗ではなくプロセス abort に直結していた DoS 脆弱性と判断した。攻撃者が細工した DNG/RAW 入力を画像デコード経路に到達させ、`libdng_sdk` 内の signed/unsigned integer overflow sanitizer を発火させると、修正前は UBSan minimal runtime が hard abort し、呼び出し側の例外処理に戻る前にプロセスが落ちる。

根本原因は、DNG SDK と Skia 側が C++ 例外で不正入力を回復可能な decode failure に変換する設計である一方、`libdng_sdk` の整数オーバーフロー sanitizer runtime だけが例外ではなく abort を使っていたこと。修正は個別の演算を1箇所ずつ直すものではなく、UBSan overflow handler を独自実装に差し替え、`std::runtime_error` を投げるようにして既存の `catch (...)` 経路へ流すものだった。

## 確認した基本情報

- CVE: CVE-2026-0041
- Android reference: A-467994310
- Component / Type / Severity: System / DoS / Critical
- Updated AOSP versions: 14, 15, 16, 16-qpr2
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://storage.googleapis.com/android-osv/ASB-A-467994310.json
- 修正対象 package: `platform/external/dng_sdk`
- 主要修正コミット: `74a5a91d169a341db58d57e0bf018d0a8b784cce`
- 修正コミット URL: https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce

Bulletin の System セクションでは `CVE-2026-0041 A-467994310 DoS Critical 14, 15, 16, 16-qpr2` と掲載されていた。同じ表の近傍にある CVE-2026-0039/0040/0042/0044/0051/0052/0079 も同じ DNG SDK 修正コミットにリンクされており、横断修正であることが分かる。

OSV の details は以下の趣旨だった。

- `ubsan_throwing_runtime.cpp` の複数関数において integer overflow による UBSan failure の可能性がある。
- 追加権限不要、ユーザー操作不要で remote denial of service につながる。
- affected package は `platform/external/dng_sdk`。

ただし `ubsan_throwing_runtime.cpp` は修正後に追加されたファイルなので、実際の脆弱な入力到達点は DNG SDK の parse/render 側にあり、OSV のファイル名は公開パッチのシグネチャに引っ張られた表現と見るのが自然。

## パッチ解析

公開統合コミット `74a5a91d169a341db58d57e0bf018d0a8b784cce` の件名は `Replace ubsan-minimal with throw`。コミットメッセージには `Bug: 467994310` が含まれ、`Test: atest ImageDecoderTest#testInterestingDngs` も記載されている。同じコミットは `470966846`, `467994860`, `461790658`, `456471487`, `453649377`, `449728942` も同時に修正対象として列挙していた。

差分の本質は `Android.bp` の `libdng_sdk` 設定変更と、`ubsan-replacement/ubsan_throwing_runtime.cpp` の追加である。

修正前の `libdng_sdk` は `libdng_sdk-defaults` から以下を継承していた。

- `rtti: true`
- `cppflags: ["-fexceptions"]`
- `sanitize.misc_undefined`: `unsigned-integer-overflow`, `signed-integer-overflow`

一方、`libdng_sdk` 固有設定はほぼ `cflags: ["-DqDNGValidate=0"]` だけだった。このため、整数オーバーフロー instrumentation は有効だが、検出時の runtime は Soong/UBSan minimal 側に任され、C++ 例外ではなく hard abort になる構成だった。

修正後は `libdng_sdk` に以下が追加された。

- `sanitize.never: true`
- `-fsanitize=signed-integer-overflow,unsigned-integer-overflow`
- `-fno-sanitize-link-runtime`
- `srcs: ["ubsan-replacement/ubsan_throwing_runtime.cpp"]`

追加された `ubsan_throwing_runtime.cpp` は、以下の UBSan overflow handler を実装し、すべて `std::runtime_error` を throw する。

- `__ubsan_handle_add_overflow`
- `__ubsan_handle_sub_overflow`
- `__ubsan_handle_mul_overflow`
- `__ubsan_handle_negate_overflow`
- `__ubsan_handle_divrem_overflow`

つまり修正は sanitizer を無効化して見逃すものではない。検出は維持しつつ、検出後の制御フローを「abort」から「例外」に変え、既存の画像デコード失敗経路へ戻す。

## 脆弱性が起きる状況

1. 攻撃者制御の DNG/RAW 入力が Android の画像デコード経路に渡る。
2. Skia の `SkRawCodec` が `libdng_sdk` を使い、DNG metadata、寸法、tile/area、opcode、mosaic、render 関連値を parse/render する。
3. 入力由来値を使った加算・減算・乗算・符号反転・除算剰余のいずれかで signed/unsigned integer overflow が起き、UBSan handler に到達する。
4. 修正前は UBSan minimal runtime が hard abort する。`catch (...)` では `abort()` を捕捉できないため、画像処理元プロセスが終了する。
5. 修正後は独自 handler が `std::runtime_error` を投げ、Skia/DNG codec 側の `catch (...)` が `nullptr`、`false`、`kInvalidInput`、`kIncompleteInput` などの通常エラーに変換する。

Skia 側の証跡として、`SkRawCodec.cpp.master` では DNG 処理の複数箇所に `catch (...)` がある。例えば DNG の parse/read/render 失敗は `nullptr` や `false` に落ち、ピクセル取得中の例外は `kIncompleteInput` になる。したがって、本来の設計は「不正な DNG -> 例外 -> decode failure」だが、未修正状態では UBSan overflow だけがこの設計を迂回してプロセス終了になっていた。

## 根本原因

根本原因は、信頼できない DNG/RAW 入力から到達可能な整数オーバーフローを、ライブラリの通常エラー処理モデルに統合できていなかったこと。

DNG SDK には `dng_safe_arithmetic.h` があり、overflow を検査して `dng_exception` を投げる設計が既に存在する。`dng_exceptions.cpp` の `Throw_dng_error()` も最終的に `throw dng_exception(err)` する。つまり SDK 側は不正入力や算術異常を例外として扱う思想を持っている。

しかしコンパイラ挿入の UBSan overflow instrumentation は、修正前の `libdng_sdk` では例外ではなく UBSan minimal runtime の abort に接続されていた。このため、DNG SDK 本体や Skia 側が `catch (...)` で回復できるようにしていても、UBSan による検出だけは回復不能なクラッシュになった。

セキュリティ上の問題は、整数オーバーフローがメモリ破壊へ進むこと自体ではなく、オーバーフローが「検出された瞬間」に remote DoS primitive になる点にある。修正後も overflow 検出は残るため、攻撃入力は成功処理されず、通常の decode failure として処理される。

## 面白い点・調査メモ

- 同じ `74a5a91...` が複数の Critical/High DNG SDK DoS CVE に紐付いている。個々の private bug は異なる DNG 入力や異なる UBSan 発火点を持つ可能性が高いが、公開修正の本質は共通して「UBSan hard abort を例外化する」ことだった。
- `ubsan_throwing_runtime.cpp` は脆弱な既存ファイルではなく、新規追加された対策ファイルである。OSV の details は修正シグネチャのファイル名を脆弱箇所のように書いている。
- パッチは `-fsanitize=signed-integer-overflow,unsigned-integer-overflow` を `cflags` で明示し直している。`sanitize.never: true` だけだと instrumentation まで消えるため、`-fsanitize=` と `-fno-sanitize-link-runtime` を併用し、instrumentation は残して runtime だけ差し替えている。
- コミットメッセージは「C++ exceptions are enabled in this library」と明記しており、`Android.bp` の `cppflags: ["-fexceptions"]` と整合する。
- `SkDngHost::PerformAreaTaskThreads()` には、Android では warp effect の DNG が大量メモリを使うためスレッド数を1にする既存コメントがあった。今回の CVE-2026-0041 は OSV 上 integer overflow/remote DoS だが、DNG 処理は画像内容により CPU/メモリ負荷や例外経路が大きく変わる攻撃面であることが分かる。
- ユーザー指定の OriginHQ の patch diffing pipeline 記事は `artifacts/origin-patch-diffing-pipeline.html` に保存した。今回の作業では advisory -> OSV -> public fix -> diff -> call path -> root cause の順に確認した。

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

- `artifacts/osv-ASB-A-467994310.json`: 既存保存済み Android OSV JSON
- `artifacts/osv-ASB-A-467994310.refetched.json`: 再取得した Android OSV JSON
- `artifacts/android-security-bulletin-2026-06-01.html`: Android Security Bulletin 保存版
- `artifacts/74a5a91.commit.json`: Gitiles commit metadata
- `artifacts/74a5a91.patch`: Gitiles patch
- `artifacts/74a5a91d169a341db58d57e0bf018d0a8b784cce.git-show.patch`: `../binaries/dng_sdk.git` からの `git show` 出力
- `artifacts/Android.bp.before`, `artifacts/Android.bp.after`, `artifacts/Android.bp.diff`: 修正前後のビルド設定
- `artifacts/ubsan_throwing_runtime.cpp`: 追加された UBSan replacement runtime
- `artifacts/related-commits-A-467994310.txt`: ローカル clone で `Bug: 467994310` を含む関連コミット一覧
- `artifacts/SkRawCodec.cpp.master`: Skia DNG codec の例外捕捉経路確認用
- `artifacts/hwui_Android.bp.master`: Skia/libhwui 側ビルド確認用
- `artifacts/source-snippets/dng_exceptions.cpp`: DNG SDK 例外送出確認用
- `artifacts/source-snippets/dng_exceptions.h`: DNG SDK 例外型確認用
- `artifacts/source-snippets/dng_safe_arithmetic.h`: DNG SDK の safe arithmetic 設計確認用
- `artifacts/key-code-excerpts.txt`: 重要箇所の grep 抜粋
- `artifacts/origin-patch-diffing-pipeline.html`: 参照手法記事の保存版

## 主要 URL / commit

- Android Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Android OSV: https://storage.googleapis.com/android-osv/ASB-A-467994310.json
- Public fix: https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce
- OriginHQ patch diffing pipeline: https://www.originhq.com/research/patch-diffing-pipeline
- ローカル AOSP/DNG SDK clone: `../binaries/dng_sdk.git`

OSV listed fixes:

- `81ded662eee07fcbb830e6b6c83d1a3d85227ceb` Android 17-next
- `475c8cce973f56488cc9f37d00cf0a4069f0e4fe` Android 15
- `1337d2e14a412ec81a4a32f6251063091922a9e9` Android 16
- `690688f3b522dc80de007d5c3ac8b8ce61da8870` Android 16-qpr2
- `7f197e818cbb7b5bc7b9ee5017a36a23650c29de` Android 14

一部のブランチ別 hash は保存済み Gitiles metadata で `NOT_FOUND` だったが、OSV の fix URL と、ローカル clone の `Bug: 467994310` 検索で同系列の `Replace ubsan-minimal with throw` コミット群を確認した。

## 再現・検証上の限界

実機または完全な AOSP build 環境で PoC DNG を実行する検証は行っていない。また、A-467994310 固有の private bug 本文や添付 DNG は公開されていないため、どの DNG tag/演算式がこの CVE 固有の発火点だったかまでは特定できない。

それでも、公開 OSV、Bug ID 付き修正コミット、`libdng_sdk` のビルド差分、追加された UBSan handler、Skia 側の `catch (...)` 経路から、脆弱性が起きる状況と根本原因はソースコードベースで説明できる。したがって ok 判定とした。
041 OK

CVE-2026-0042

041-ok-dng-sdk-ubsan-resource-exhaustion-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeDoS
SeverityCritical
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-456471487
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0042 is listed in the Android Security Bulletin as a Critical severity DoS issue in System.

特定した具体的な脆弱性

ok: 公開AOSPソースと修正差分から、脆弱性が起きる状況と根本原因を特定できた。

CVE-2026-0042 / A-456471487 は platform/external/dng_sdk のDNG/RAW画像処理に関するDoSで、修正は libdng_sdk のUBSan minimal runtimeによるhard abortを、C++例外に置き換えるものだった。OSVでは「resource exhaustion」「local denial of service」と表現されているが、公開パッチの実体はDNG SDK内で発生するUBSan overflow系エラーをプロセス終了ではなく通常のデコード失敗へ変換する横断修正である。

原因

根本原因は、信頼できないDNG/RAW入力から到達可能なDNG SDK内の異常条件を、ライブラリの通常エラーとして処理せず、UBSan minimal runtimeのプロセスabortに任せていたこと。

より具体的には以下の組み合わせである。

・libdng_sdk-defaults は signed/unsigned integer overflow sanitizerを有効にしていた。
・libdng_sdk と呼び出し側SkiaはC++例外を使う設計で、SkRawCodec はDNG SDK例外を捕捉して kInvalidInput などへ変換していた。
・しかし未修正の libdng_sdk はUBSan minimal runtimeを使っており、overflow検出時に例外ではなくhard abortする。
・DNG/RAWのmetadata、寸法、mask、tile、warp/render処理などは入力ファイル由来の値を大量に扱うため、細工されたローカルファイルから異常な計算やリソース消費条件へ到達しうる。
・その結果、本来は「画像デコード失敗」で済む入力が、システムコンポーネントや画像処理プロセスのクラッシュになる。

どこから特定したか

パッチ差分の要点: 修正前の libdng_sdk-defaults は以下のUBSan integer overflow instrumentationを有効にしていた。

``bp
sanitize: {
misc_undefined: [
"unsigned-integer-overflow",
"signed-integer-overflow",
],
},
`

修正前の libdng_sdk はこのdefaultsを継承し、固有設定はほぼ -DqDNGValidate=0 だけだった。そのため、overflow検出時のruntime動作はSoongが注入するUBSan minimal runtimeに依存していた。

保存した証跡: ・artifacts/android-security-bulletin-2026-06-01.html: Android Security Bulletin保存版
・artifacts/bulletin-row-CVE-2026-0042.html: bulletin上のCVE-2026-0042周辺行
・artifacts/osv-ASB-A-456471487.json: 対象CVEのAndroid OSV
・artifacts/osv-ASB-A-*.json: 同じcommit messageに出る関連CVEのOSV
・artifacts/74a5a91.commit.json: commit metadata/tree diff
・artifacts/74a5a91.patch: 対象commit…

URL: https://source.android.com/docs/security/…

validated.md を表示
# CVE-2026-0042 検証結果

## 判定

ok: 公開AOSPソースと修正差分から、脆弱性が起きる状況と根本原因を特定できた。

CVE-2026-0042 / A-456471487 は `platform/external/dng_sdk` のDNG/RAW画像処理に関するDoSで、修正は `libdng_sdk` のUBSan minimal runtimeによるhard abortを、C++例外に置き換えるものだった。OSVでは「resource exhaustion」「local denial of service」と表現されているが、公開パッチの実体はDNG SDK内で発生するUBSan overflow系エラーをプロセス終了ではなく通常のデコード失敗へ変換する横断修正である。

## 基本情報

- CVE: CVE-2026-0042
- Android Bug ID: A-456471487
- Component: System
- Type: DoS
- Severity: Critical
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Bulletin上の修正リンク: https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce
- OSV: https://storage.googleapis.com/android-osv/ASB-A-456471487.json
- Affected package: `platform/external/dng_sdk`
- 対象AOSP versions: 14, 15, 16, 16-qpr2

## 参照した修正

主解析対象:

- Commit: `74a5a91d169a341db58d57e0bf018d0a8b784cce`
- Subject: `Replace ubsan-minimal with throw`
- Parent: `47cd326e0c8f19cc367663b31d95c03584198fa4`
- AuthorDate: 2026-01-09
- CommitDate: 2026-04-09
- 変更ファイル:
  - `Android.bp`
  - `OWNERS`
  - `ubsan-replacement/ubsan_throwing_runtime.cpp`

OSVに載っているブランチ別fix:

- 17-next: `81ded662eee07fcbb830e6b6c83d1a3d85227ceb`
- 15: `475c8cce973f56488cc9f37d00cf0a4069f0e4fe`
- 16: `1337d2e14a412ec81a4a32f6251063091922a9e9`
- 16-qpr2: `690688f3b522dc80de007d5c3ac8b8ce61da8870`
- 14: `7f197e818cbb7b5bc7b9ee5017a36a23650c29de`

`81ded...` と `7f197...` はGitilesで参照でき、どちらも同じ `Replace ubsan-minimal with throw` 系の修正だった。`475c...`, `1337...`, `690688...` は今回のGitiles公開参照では404だったが、OSVにはfixとして記載されている。

## パッチ差分の要点

修正前の `libdng_sdk-defaults` は以下のUBSan integer overflow instrumentationを有効にしていた。

```bp
sanitize: {
    misc_undefined: [
        "unsigned-integer-overflow",
        "signed-integer-overflow",
    ],
},
```

修正前の `libdng_sdk` はこのdefaultsを継承し、固有設定はほぼ `-DqDNGValidate=0` だけだった。そのため、overflow検出時のruntime動作はSoongが注入するUBSan minimal runtimeに依存していた。

修正後は `libdng_sdk` でSoongのsanitizer runtime注入を止め、instrumentationだけを明示的に残している。

```bp
sanitize: {
    never: true,
},

cflags: [
    "-DqDNGValidate=0",
    "-fsanitize=signed-integer-overflow,unsigned-integer-overflow",
    "-fno-sanitize-link-runtime",
],

srcs: [
    "ubsan-replacement/ubsan_throwing_runtime.cpp"
],
```

追加された `ubsan-replacement/ubsan_throwing_runtime.cpp` は、overflow handlerをすべてC++例外にする。

```cpp
INTERFACE void __ubsan_handle_add_overflow() {
    throw std::runtime_error("ubsan: add-overflow");
}

INTERFACE void __ubsan_handle_sub_overflow() {
    throw std::runtime_error("ubsan: sub-overflow");
}

INTERFACE void __ubsan_handle_mul_overflow() {
    throw std::runtime_error("ubsan: mul-overflow");
}

INTERFACE void __ubsan_handle_negate_overflow() {
    throw std::runtime_error("ubsan: negate-overflow");
}

INTERFACE void __ubsan_handle_divrem_overflow() {
    throw std::runtime_error("ubsan: divrem-overflow");
}
```

commit messageにも「C++ exceptions are enabled in this library」「better solution for ubsan errors than a hard abort」とあり、修正意図は「UBSan検出時にプロセスをabortさせない」ことだと確認できる。

## 脆弱性が起きる状況

AndroidではSkiaのRAW/DNG codec経由で `libdng_sdk` が使われる。保存した `SkRawCodec.android16.cpp` では、DNG入力は概ね以下の経路を通る。

1. `SkRawCodec::MakeFromStream()` がDNG/RAW入力を `SkDngImage::NewFromStream()` に渡す。
2. `SkDngImage::readDng()` が `dng_info::Parse/PostParse` と `dng_negative::Parse/PostParse` を実行する。
3. `SkDngImage::render()` が `ReadStage1Image`, `ReadTransparencyMask`, `BuildStage2Image`, `BuildStage3Image`, `dng_render::Render()` を実行する。
4. 失敗時は `catch (...)` で捕捉され、`readDng()` は `false`、`render()` は `nullptr`、`onGetPixels()` は `kInvalidInput` を返す。

つまりSkia/DNG側の設計では、不正なDNG入力は例外として回復可能なデコード失敗に落ちるはずだった。しかし未修正状態では、DNG SDK内の整数overflowをUBSan minimal runtimeが検出すると、C++例外ではなくhard abortになる。`catch (...)` は `abort()` を捕捉できないため、細工されたDNG/RAW画像をローカルの画像デコード経路に渡すだけで、デコード元プロセスを落とせる。

OSVのCVE-2026-0042説明は「persistent denial of service due to resource exhaustion」「local denial of service」としている。公開資料だけではA-456471487専用の入力ファイルや具体的なDNGタグは確認できなかったが、パッチが同じcommitで列挙する複数Bug IDをまとめて修正していること、`libdng_sdk` に例外が有効であること、Skia側がDNG SDK例外を既に捕捉していることから、A-456471487も「DNG SDKの処理中に攻撃者制御入力がUBSan/例外化されるべき異常条件へ到達し、未修正ではhard abortとしてDoSになる」問題だったと判断できる。

## 根本原因

根本原因は、信頼できないDNG/RAW入力から到達可能なDNG SDK内の異常条件を、ライブラリの通常エラーとして処理せず、UBSan minimal runtimeのプロセスabortに任せていたこと。

より具体的には以下の組み合わせである。

- `libdng_sdk-defaults` は signed/unsigned integer overflow sanitizerを有効にしていた。
- `libdng_sdk` と呼び出し側SkiaはC++例外を使う設計で、`SkRawCodec` はDNG SDK例外を捕捉して `kInvalidInput` などへ変換していた。
- しかし未修正の `libdng_sdk` はUBSan minimal runtimeを使っており、overflow検出時に例外ではなくhard abortする。
- DNG/RAWのmetadata、寸法、mask、tile、warp/render処理などは入力ファイル由来の値を大量に扱うため、細工されたローカルファイルから異常な計算やリソース消費条件へ到達しうる。
- その結果、本来は「画像デコード失敗」で済む入力が、システムコンポーネントや画像処理プロセスのクラッシュになる。

修正はoverflow instrumentation自体を消していない。`-fsanitize=signed-integer-overflow,unsigned-integer-overflow` は維持しつつ、`-fno-sanitize-link-runtime` と独自 `__ubsan_handle_*_overflow` により、検出結果を `std::runtime_error` に変換している。これによりSkia側の既存 `catch (...)` が機能し、攻撃入力はプロセスabortではなくデコード失敗として扱われる。

## 面白い点・調査メモ

- Bulletin上のCVE-2026-0042行は、A-456471487から `74a5a91...` へ直接リンクしている。
- `74a5a91...` のcommit messageには A-456471487 以外に `470966846`, `467994860`, `467994310`, `461790658`, `453649377`, `449728942` が列挙されていた。
- これらはCVE-2026-0039, 0040, 0041, 0051, 0043, 0044に対応し、OSVのdetailsは「integer overflow」「UBSan failure」「improper input validation」「resource exhaustion」など表現が分かれる。公開パッチはこれらを個別式修正ではなく、UBSan runtimeの挙動変更でまとめて潰している。
- OSVのdetailsが `ubsan_throwing_runtime.cpp` を脆弱箇所のように書いているが、このファイルは修正後に追加されたもの。実際の脆弱な入力到達点はDNG SDKのparse/render側で、OSV文言は修正シグネチャのファイル名に引っ張られていると見るのが自然。
- `SkDngHost::PerformAreaTaskThreads()` には、AndroidではDNG warp effectが非常にメモリを使うためスレッド数を1にする、という既存コメントがあった。CVE-2026-0042のOSVがresource exhaustionと書く背景はこの種のDNG処理負荷と関係する可能性がある。ただし今回の公開修正そのものはスレッド数やサイズ上限ではなく、UBSan hard abortの例外化である。
- テスト名は `atest ImageDecoderTest#testInterestingDngs`。公開ソース差分からは具体的なPoC画像名やprivate bugの添付DNGまでは取得できなかった。

## 解析ログ

- `cve.md` を読み、CVE-2026-0042 / A-456471487 / System DoS Critical / bulletin URLを確認。
- Android Security Bulletinを保存し、CVE-2026-0042行が `platform/external/dng_sdk` commit `74a5a91...` にリンクしていることを確認。
- Android OSV `ASB-A-456471487.json` を保存し、affected package、branch別fix、detailsを確認。
- `74a5a91...` のcommit JSON、patch、`Android.bp` 前後差分、追加された `ubsan_throwing_runtime.cpp` を保存。
- Skia `SkRawCodec.android16.cpp` と `skia_Android.bp` を保存し、`libdng_sdk` の呼び出し経路、例外有効化、`catch (...)` による回復経路を確認。
- 同じcommit messageに列挙された関連Android Bug IDのOSVも保存し、CVE-2026-0042が共通パッチの一部であることを確認。

## 保存した証跡

- `artifacts/android-security-bulletin-2026-06-01.html`: Android Security Bulletin保存版
- `artifacts/bulletin-row-CVE-2026-0042.html`: bulletin上のCVE-2026-0042周辺行
- `artifacts/osv-ASB-A-456471487.json`: 対象CVEのAndroid OSV
- `artifacts/osv-ASB-A-*.json`: 同じcommit messageに出る関連CVEのOSV
- `artifacts/74a5a91.commit.json`: commit metadata/tree diff
- `artifacts/74a5a91.patch`: 対象commitのpatch
- `artifacts/Android.bp.before`: 修正前 `Android.bp`
- `artifacts/Android.bp.after`: 修正後 `Android.bp`
- `artifacts/Android.bp.diff`: `Android.bp` 前後差分
- `artifacts/ubsan_throwing_runtime.cpp`: 追加されたUBSan replacement runtime
- `artifacts/SkRawCodec.android16.cpp`: 呼び出し側確認用Skia RAW codec
- `artifacts/skia_Android.bp`: `libskia` が例外を有効にし、`libdng_sdk` に依存する証跡
- `artifacts/key-code-excerpts.txt`: 重要差分と呼び出し側catch箇所の抜粋
- `artifacts/branch-fix-commits-summary.txt`: OSV記載fix commitの参照結果
- `artifacts/origin-patch-diffing-pipeline.html`: 依頼で参照されたpatch diffing pipeline記事の保存版
042 OK

CVE-2026-0044

042-ok-dng-sdk-ubsan-overflow-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeDoS
SeverityCritical
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-449728942
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0044 is listed in the Android Security Bulletin as a Critical severity DoS issue in System.

特定した具体的な脆弱性

CVE-2026-0044 / A-449728942 は、Android frameworkのDNG画像デコード経路で、細工されたDNG入力により external/dng_sdk 内の signed/unsigned integer overflow sanitizer が発火したとき、修正前はUBSan minimal runtimeがプロセスをhard abortさせていたため、通常の「壊れた画像として失敗する」エラー処理を迂回してDoSになる脆弱性だった。

根本原因は、DNG SDK側で整数オーバーフローが起き得ることそのものに加えて、Androidビルド上の libdng_sdk が整数オーバーフローsanitizerを有効にしたまま、検知時の挙動をC++例外ではなくabortにしていたこと。Skia/Framework側はDNGデコード失敗を catch (...)、SkCodec::Result、ImageDecoder.DecodeException / IOException へ変換する設計だが、abortはC++例外ではないため捕捉されず、呼び出しプロセスごと落ちる。

このため、公開ソース差分から脆弱性の成立条件と修正意図を説明できると判断し、フォルダは ok 扱いにする。

原因

根本原因は「信頼できないDNGメタデータ・画像データに基づくDNG SDK内の整数演算がoverflowし得る」ことと、「その検知をプロセスabortとして扱うruntime選択」が重なった点。

DNG SDK自体は巨大な画像寸法、タイル数、CFA pattern、crop size、render size、row stepなど入力由来の値を広く扱う。Skia側にも、過去に dng_stream の offsetInOriginalFile = -1 が dng_negative のunsigned overflow crash pathを踏むため、コンストラクタでoffsetを0にして回避しているコメントがあった。これは今回のCVEそのものの修正ではないが、DNG経路に整数overflow crashが実際に問題になりやすいことを示す面白い周辺証拠である。

今回のパッチは個々のoverflow発生点をすべて潰すのではなく、DNG SDKで整数overflow sanitizerを維持しながら、検知時の制御フローを「abort」から「C++例外」に変えた。C++例外は既存のSkia/DNGエラー処理に合流できるため、攻撃入力があってもプロセス全体のDoSにならない。

どこから特定したか

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://storage.googleapis.com/android-osv/ASB-A-449728942.json / https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce / https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce%5E%21/

validated.md を表示
# CVE-2026-0044 検証結果

## 結論

CVE-2026-0044 / A-449728942 は、Android frameworkのDNG画像デコード経路で、細工されたDNG入力により `external/dng_sdk` 内の signed/unsigned integer overflow sanitizer が発火したとき、修正前はUBSan minimal runtimeがプロセスをhard abortさせていたため、通常の「壊れた画像として失敗する」エラー処理を迂回してDoSになる脆弱性だった。

根本原因は、DNG SDK側で整数オーバーフローが起き得ることそのものに加えて、Androidビルド上の `libdng_sdk` が整数オーバーフローsanitizerを有効にしたまま、検知時の挙動をC++例外ではなくabortにしていたこと。Skia/Framework側はDNGデコード失敗を `catch (...)`、`SkCodec::Result`、`ImageDecoder.DecodeException` / `IOException` へ変換する設計だが、abortはC++例外ではないため捕捉されず、呼び出しプロセスごと落ちる。

このため、公開ソース差分から脆弱性の成立条件と修正意図を説明できると判断し、フォルダは `ok` 扱いにする。

## 基本情報

- CVE: CVE-2026-0044
- Android reference: A-449728942
- Component: System
- Type: DoS
- Severity: Critical
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- 対象AOSP: 14, 15, 16, 16-qpr2
- パッケージ: `platform/external/dng_sdk`
- OSV: https://storage.googleapis.com/android-osv/ASB-A-449728942.json

OSVの説明では、整数オーバーフローによりsystem crashを起こせるremote DoSで、追加権限およびユーザー操作は不要とされている。

## 修正コミットと差分

主に確認した公開修正:

- `platform/external/dng_sdk` `74a5a91d169a341db58d57e0bf018d0a8b784cce`
- 件名: `Replace ubsan-minimal with throw`
- Change-Id: `I7b8414e4b5c2f2ca44f572fb72e625d1907f7902`
- Bug: `470966846`, `467994860`, `467994310`, `461790658`, `456471487`, `453649377`, `449728942`
- Test: `atest ImageDecoderTest#testInterestingDngs`

修正前の `libdng_sdk-defaults` は以下を有効化していた。

- `-DqDNGUsingSanitizer=1`
- `sanitize.misc_undefined: ["unsigned-integer-overflow", "signed-integer-overflow"]`
- `cppflags: ["-fexceptions"]`

修正前の `libdng_sdk` はこの設定を継承しつつ、通常のSoong sanitizer runtimeを使っていた。修正後は `libdng_sdk` に対して次の変更が入った。

- `sanitize.never: true` で標準UBSan runtimeリンクを止める
- `-fsanitize=signed-integer-overflow,unsigned-integer-overflow`
- `-fno-sanitize-link-runtime`
- `ubsan-replacement/ubsan_throwing_runtime.cpp` を追加

追加されたruntimeは以下のUBSan handlerをC++例外へ変換する。

- `__ubsan_handle_add_overflow`
- `__ubsan_handle_sub_overflow`
- `__ubsan_handle_mul_overflow`
- `__ubsan_handle_negate_overflow`
- `__ubsan_handle_divrem_overflow`

つまり修正は、個別のDNGパーサ処理に境界チェックを足すものではなく、「整数オーバーフロー検知時にabortせずthrowする」ビルド/runtime変更である。

## 到達経路

framework側では `ImageDecoder` がDNG MIMEをサポートしている。

- `frameworks/base/graphics/java/android/graphics/ImageDecoder.java`
- `isMimeTypeSupported()` に `image/x-adobe-dng` が含まれる
- `decodeHeader()` / `decodeBitmap()` は `Source` からnative `ImageDecoder` を作る

native側では:

- `frameworks/base/libs/hwui/jni/ImageDecoder.cpp`
- `native_create()` が `SkCodec::MakeFromStream()` を呼ぶ
- `ImageDecoder_nDecodeBitmap()` が `decoder->decode()` を呼ぶ
- `SkCodec::Result` は `DecodeException` / `IOException` に変換される

Skia側では:

- `external/skia/src/codec/SkRawCodec.cpp`
- `dng_info::Parse()`, `dng_negative::Parse()`, `ReadStage1Image()`, `BuildStage2Image()`, `BuildStage3Image()`, `dng_render::Render()`, `dng_image::Get()` などのDNG SDK呼び出しがある
- これらは複数箇所で `try { ... } catch (...) { ... }` に包まれ、壊れたDNGは `nullptr`, `kInvalidInput`, `kIncompleteInput` などへ変換される

したがって本来の期待動作は「悪いDNG入力はデコード失敗として返す」こと。修正前はUBSan minimalがabortするため、この既存の回復経路に入れなかった。

## 脆弱性の成立条件

攻撃者が、DNG SDK内の整数演算で signed/unsigned overflow を起こすDNG/RAW入力を、Android frameworkの画像デコード経路に処理させる。

成立時の流れ:

1. `ImageDecoder` / `SkCodec` がDNGとして入力を処理する。
2. `SkRawCodec` がDNG SDKへパースまたはレンダリングを委譲する。
3. DNG SDK内の演算でUBSanの整数オーバーフローhandlerに到達する。
4. 修正前はUBSan minimal runtimeがabortし、C++ `catch (...)` とJava例外変換を迂回する。
5. 呼び出しプロセスがクラッシュしDoSになる。

修正後:

1. 同じoverflow handlerが `std::runtime_error` をthrowする。
2. Skiaの `catch (...)` が捕捉する。
3. `SkCodec::Result` / `ImageDecoder.DecodeException` / `IOException` として呼び出し元に返る。
4. プロセスabortを避けられる。

## 根本原因

根本原因は「信頼できないDNGメタデータ・画像データに基づくDNG SDK内の整数演算がoverflowし得る」ことと、「その検知をプロセスabortとして扱うruntime選択」が重なった点。

DNG SDK自体は巨大な画像寸法、タイル数、CFA pattern、crop size、render size、row stepなど入力由来の値を広く扱う。Skia側にも、過去に `dng_stream` の `offsetInOriginalFile = -1` が `dng_negative` のunsigned overflow crash pathを踏むため、コンストラクタでoffsetを0にして回避しているコメントがあった。これは今回のCVEそのものの修正ではないが、DNG経路に整数overflow crashが実際に問題になりやすいことを示す面白い周辺証拠である。

今回のパッチは個々のoverflow発生点をすべて潰すのではなく、DNG SDKで整数overflow sanitizerを維持しながら、検知時の制御フローを「abort」から「C++例外」に変えた。C++例外は既存のSkia/DNGエラー処理に合流できるため、攻撃入力があってもプロセス全体のDoSにならない。

## 付帯ファイル

主要成果物は `artifacts/` に保存した。

- `74a5a91d169a341db58d57e0bf018d0a8b784cce.diff`: 統合修正差分
- `81ded662eee07fcbb830e6b6c83d1a3d85227ceb.diff`: 17-next系公開fix差分
- `7f197e818cbb7b5bc7b9ee5017a36a23650c29de.diff`: 14系公開fix差分
- `ASB-A-449728942.json`: Android OSV JSON
- `dng_sdk_Android_bp_before.txt` / `dng_sdk_Android_bp_after.txt`: 修正前後のビルド設定
- `dng_sdk_matching_commits.log`: 同一Change-Id/bugを含む公開コミット一覧
- `branches_contains_matching_commits.txt`: 公開ブランチ到達性確認
- `SkRawCodec.cpp`: DNG SDK呼び出しと例外捕捉経路
- `frameworks_base/libs_hwui_jni_ImageDecoder.cpp`: native ImageDecoder経路
- `frameworks_base/graphics_java_android_graphics_ImageDecoder.java`: Java ImageDecoder API/MIME/例外経路
- `analysis-notes.md`: コマンド結果からの要点メモ

OSVに掲載された `475c8cce...`, `1337d2e...`, `690688f...` は公開Gitilesで `NOT_FOUND` だったため、その取得結果も `.json` / 空diffとして残した。

## 参考URL

- Android Security Bulletin June 2026: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV JSON: https://storage.googleapis.com/android-osv/ASB-A-449728942.json
- 統合fix: https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce
- 統合fix diff: https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce%5E%21/
- 17-next系fix: https://android.googlesource.com/platform/external/dng_sdk/+/81ded662eee07fcbb830e6b6c83d1a3d85227ceb
- 14系fix: https://android.googlesource.com/platform/external/dng_sdk/+/7f197e818cbb7b5bc7b9ee5017a36a23650c29de
043 OK

CVE-2026-0051

043-ok-dng-sdk-ubsan-hard-abort-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeDoS
SeverityCritical
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-461790658
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0051 is listed in the Android Security Bulletin as a Critical severity DoS issue in System.

特定した具体的な脆弱性

ok: 公開AOSPソース、Android Bulletin、Android OSV、修正差分から、脆弱性が起きる状況と根本原因を説明できる。

タイトル: dng-sdk-ubsan-hard-abort-dos

CVE-2026-0051 / A-461790658 は、AndroidのDNG/RAW画像デコード経路で使われる platform/external/dng_sdk のDoS脆弱性だった。細工されたDNG/RAW入力により libdng_sdk 内のsigned/unsigned integer overflow sanitizerが発火したとき、修正前はUBSan minimal runtimeがC++例外ではなくhard abortを実行するため、本来の画像デコード失敗経路を迂回してデコード元プロセスをクラッシュさせられる。

根本原因は、DNG SDKと呼び出し側SkiaがC++例外で不正入力を回復可能エラーに変換する設計である一方、整数オーバーフローsanitizerのruntimeだけが例外化されず、プロセスabortに直結していたビルド/runtime構成の不整合である。

原因

根本原因は、信頼できないDNG/RAW入力から到達可能な整数オーバーフロー検出を、ライブラリ内の通常エラーとして扱わず、UBSan minimalのプロセスabortに任せていたこと。

具体的には以下の組み合わせが問題だった。

・libdng_sdk-defaults で signed-integer-overflow / unsigned-integer-overflow のUBSanが有効だった。
・libdng_sdk はDNGメタデータ、寸法、tile、sample、opcode、render sizeなど、入力ファイル由来の値を使う多数の整数計算を持つ。
・DNG SDKとSkia RAW codecはC++例外を前提に不正入力を回復可能なデコード失敗へ変換する設計だった。
・しかしコンパイラ挿入のUBSan overflow handlerだけはC++例外ではなくhard abortに接続されていた。
・その結果、攻撃者制御入力がoverflow検出点に到達すると、メモリ破壊まで進まなくても検出時点でプロセスDoSになる。

どこから特定したか

パッチ差分の要点: 修正前の libdng_sdk-defaults はC++例外を有効化しつつ、signed/unsigned integer overflowのUBSan instrumentationを有効にしていた。

``bp
rtti: true,
cppflags: ["-fexceptions"],

sanitize: {
misc_undefined: [
"unsigned-integer-overflow",
"signed-integer-overflow",
],
},
`

保存した証跡: ・artifacts/android-security-bulletin-2026-06-01.html: Android Security Bulletin保存版
・artifacts/bulletin-row-CVE-2026-0051.html: Bulletin上の対象行
・artifacts/ASB-A-461790658.json: Android OSV JSON
・artifacts/74a5a91d169a341db58d57e0bf018d0a8b784cce.commit.json: 公開修正commit metadata
・artifacts/74a5a91d169a341db58d57e0bf018d0a8b784cce.patch: 公開修正diff
・artifacts/Andr…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://storage.googleapis.com/androi…

validated.md を表示
# CVE-2026-0051 検証結果

## 判定

ok: 公開AOSPソース、Android Bulletin、Android OSV、修正差分から、脆弱性が起きる状況と根本原因を説明できる。

タイトル: `dng-sdk-ubsan-hard-abort-dos`

CVE-2026-0051 / A-461790658 は、AndroidのDNG/RAW画像デコード経路で使われる `platform/external/dng_sdk` のDoS脆弱性だった。細工されたDNG/RAW入力により `libdng_sdk` 内のsigned/unsigned integer overflow sanitizerが発火したとき、修正前はUBSan minimal runtimeがC++例外ではなくhard abortを実行するため、本来の画像デコード失敗経路を迂回してデコード元プロセスをクラッシュさせられる。

根本原因は、DNG SDKと呼び出し側SkiaがC++例外で不正入力を回復可能エラーに変換する設計である一方、整数オーバーフローsanitizerのruntimeだけが例外化されず、プロセスabortに直結していたビルド/runtime構成の不整合である。

## 基本情報

- CVE: CVE-2026-0051
- Android reference ID: A-461790658
- Component: System
- Subcomponent/package: `platform/external/dng_sdk`
- Type: DoS
- Severity: Critical
- 対象AOSP versions: 14, 15, 16, 16-qpr2
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://storage.googleapis.com/android-osv/ASB-A-461790658.json
- 公開修正: https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce

`cve.md` から、CVE番号、A-461790658、System / DoS / Critical、Bulletin URLを確認した。Bulletin保存版ではCVE-2026-0051の行が `A-461790658` から `74a5a91d169a341db58d57e0bf018d0a8b784cce` に直接リンクしている。

## 参照した修正

主解析対象:

- Repository: `platform/external/dng_sdk`
- Commit: `74a5a91d169a341db58d57e0bf018d0a8b784cce`
- Parent: `47cd326e0c8f19cc367663b31d95c03584198fa4`
- Subject: `Replace ubsan-minimal with throw`
- AuthorDate: 2026-01-09
- CommitDate: 2026-04-09
- Change-Id: `I7b8414e4b5c2f2ca44f572fb72e625d1907f7902`
- Test: `atest ImageDecoderTest#testInterestingDngs`

commit messageには以下のBug IDが列挙されており、この中に今回の `Bug: 461790658` が含まれている。

- `470966846`
- `467994860`
- `467994310`
- `461790658`
- `456471487`
- `453649377`
- `449728942`

OSV上のbranch別fix:

- 17-next: `81ded662eee07fcbb830e6b6c83d1a3d85227ceb`、公開Gitilesで取得可能
- 14: `7f197e818cbb7b5bc7b9ee5017a36a23650c29de`、公開Gitilesで取得可能
- 15: `475c8cce973f56488cc9f37d00cf0a4069f0e4fe`、公開Gitilesでは調査時点で404
- 16: `1337d2e14a412ec81a4a32f6251063091922a9e9`、公開Gitilesでは調査時点で404
- 16-qpr2: `690688f3b522dc80de007d5c3ac8b8ce61da8870`、公開Gitilesでは調査時点で404

公開取得できた17-next/14のfixも同じ `Replace ubsan-minimal with throw` 系の修正で、commit messageに `Bug: 461790658` を含む。

## パッチ差分の要点

修正前の `libdng_sdk-defaults` はC++例外を有効化しつつ、signed/unsigned integer overflowのUBSan instrumentationを有効にしていた。

```bp
rtti: true,
cppflags: ["-fexceptions"],

sanitize: {
    misc_undefined: [
        "unsigned-integer-overflow",
        "signed-integer-overflow",
    ],
},
```

しかし修正前の `libdng_sdk` 自体は、ほぼ `-DqDNGValidate=0` だけを指定しており、overflow検出時のruntime処理はSoongがリンクする通常のUBSan minimal runtimeに依存していた。

修正後は `libdng_sdk` に限って標準sanitizer runtimeのリンクを止め、同じoverflow sanitizerを明示的に維持しつつ、独自runtimeを追加している。

```bp
sanitize: {
    never: true,
},

cflags: [
    "-DqDNGValidate=0",
    "-fsanitize=signed-integer-overflow,unsigned-integer-overflow",
    "-fno-sanitize-link-runtime",
],

srcs: [
    "ubsan-replacement/ubsan_throwing_runtime.cpp"
],
```

追加された `ubsan-replacement/ubsan_throwing_runtime.cpp` は、以下のUBSan overflow handlerをすべて `std::runtime_error` に変換する。

- `__ubsan_handle_add_overflow`
- `__ubsan_handle_sub_overflow`
- `__ubsan_handle_mul_overflow`
- `__ubsan_handle_negate_overflow`
- `__ubsan_handle_divrem_overflow`

つまり修正は「整数オーバーフロー検出を消す」ものではない。検出は維持したまま、検出後の制御フローをhard abortからC++例外へ変える修正である。

## 脆弱性が起きる状況

`libdng_sdk` はAndroidのSkia RAW/DNG codec経由で画像デコードに使われる。保存した `SkRawCodec.cpp` では、DNG入力はおおむね以下の経路を通る。

1. `SkRawCodec::MakeFromStream()` がRAW/DNG入力に対して `SkDngImage::NewFromStream()` を作る。
2. `SkDngImage::readDng()` が `dng_info::Parse/PostParse` と `dng_negative::Parse/PostParse` を呼ぶ。
3. `SkDngImage::render()` が `ReadStage1Image`、`ReadTransparencyMask`、`BuildStage2Image`、`BuildStage3Image`、`dng_render::Render()` などを実行する。
4. Skia側は複数箇所で `catch (...)` を持ち、DNG SDK由来の例外を `false`、`nullptr`、`kInvalidInput`、`kIncompleteInput` などへ変換する。

このため、本来の設計では、不正DNG入力は「画像デコード失敗」として処理されるべきである。しかし未修正状態では、DNG SDK内の入力由来値を使った整数演算でUBSan overflow handlerに到達すると、UBSan minimal runtimeが `abort()` 相当のhard abortを起こす。`catch (...)` はabortを捕捉できないため、通常のエラー変換に入らず、画像デコードを行ったプロセスが落ちる。

OSVの説明は「追加権限不要、ユーザー操作不要のremote denial of service」としている。典型的には、悪性DNG/RAWコンテンツをAndroidの画像デコード経路、プレビュー、メディア処理、またはSystem側で画像を処理する経路に到達させ、対象プロセスをクラッシュさせる問題と解釈できる。

## 根本原因

根本原因は、信頼できないDNG/RAW入力から到達可能な整数オーバーフロー検出を、ライブラリ内の通常エラーとして扱わず、UBSan minimalのプロセスabortに任せていたこと。

具体的には以下の組み合わせが問題だった。

- `libdng_sdk-defaults` で `signed-integer-overflow` / `unsigned-integer-overflow` のUBSanが有効だった。
- `libdng_sdk` はDNGメタデータ、寸法、tile、sample、opcode、render sizeなど、入力ファイル由来の値を使う多数の整数計算を持つ。
- DNG SDKとSkia RAW codecはC++例外を前提に不正入力を回復可能なデコード失敗へ変換する設計だった。
- しかしコンパイラ挿入のUBSan overflow handlerだけはC++例外ではなくhard abortに接続されていた。
- その結果、攻撃者制御入力がoverflow検出点に到達すると、メモリ破壊まで進まなくても検出時点でプロセスDoSになる。

修正後は、同じoverflow検出が `std::runtime_error("ubsan: ...")` を投げる。Skia側の既存 `catch (...)` がこれを捕捉できるため、攻撃入力はプロセスクラッシュではなく通常のデコード失敗に落ちる。

## 面白い点・調査メモ

- OSVのdetailsは「`ubsan_throwing_runtime.cpp` の複数関数でimproper input validationによりsystem crash」と読めるが、このファイルは修正後に新規追加されたruntimeである。実際の入力到達点はDNG SDKのparse/render側の多数の算術処理で、OSV文言は修正ファイル名を脆弱箇所のように表現している可能性が高い。
- 同じ `74a5a91...` は複数のDNG SDK CVEに使われている。公開パッチは個別のDNGタグや演算式を1つずつ修正するものではなく、「UBSan overflow検出時にプロセスを落とさない」横断修正だった。
- commit messageのテストは `atest ImageDecoderTest#testInterestingDngs` で、Android frameworkの画像デコード経路を想定した回帰テストであることが分かる。ただしPoC DNGやBug ID固有の添付ファイルは公開資料からは取得できなかった。
- `libdng_sdk` では `-fexceptions` とRTTIが明示されており、例外化はライブラリの既存設計に沿った修正だった。
- 取得できた17-next/14のbranch fixも `Bug: 461790658` を含むため、A-461790658固有にこの統合修正へ紐付くことを確認できた。

## 解析ログ

- `cve.md` を読み、CVE-2026-0051 / A-461790658 / System DoS Critical / bulletin URLを確認。
- Android Security Bulletin June 2026を保存し、CVE-2026-0051行が `platform/external/dng_sdk` commit `74a5a91...` にリンクしていることを確認。
- Android OSV `ASB-A-461790658.json` を保存し、affected package、branch別fix、detailsを確認。
- Gitilesから `74a5a91...` のcommit JSON、patch、修正前後 `Android.bp`、追加された `ubsan_throwing_runtime.cpp` を保存。
- OSVに出るbranch別fix commitの公開可用性を確認し、17-next/14は取得可能、15/16/16-qpr2は公開Gitilesで404だったことを保存。
- Skia RAW codecとSkia Android.bpの証跡を保存し、`libdng_sdk` 依存、`-fexceptions`、DNG SDK呼び出し側の `catch (...)` 経路を確認。
- 依頼で参照されたOriginのpatch diffing pipeline記事を保存し、公開パッチ、メタデータ、呼び出し経路、根本原因の順で差分解析した。

## 保存した証跡

- `artifacts/android-security-bulletin-2026-06-01.html`: Android Security Bulletin保存版
- `artifacts/bulletin-row-CVE-2026-0051.html`: Bulletin上の対象行
- `artifacts/ASB-A-461790658.json`: Android OSV JSON
- `artifacts/74a5a91d169a341db58d57e0bf018d0a8b784cce.commit.json`: 公開修正commit metadata
- `artifacts/74a5a91d169a341db58d57e0bf018d0a8b784cce.patch`: 公開修正diff
- `artifacts/Android.bp.before`: 修正前 `Android.bp`
- `artifacts/Android.bp.after`: 修正後 `Android.bp`
- `artifacts/ubsan_throwing_runtime.cpp`: 追加されたUBSan replacement runtime
- `artifacts/SkRawCodec.cpp`: Skia RAW/DNG codec確認用
- `artifacts/SkRawCodec.h`: 同上
- `artifacts/skia_Android.bp`: Skia側の例外有効化と `libdng_sdk` 依存確認用
- `artifacts/key-code-excerpts.txt`: 重要箇所抜粋
- `artifacts/fix-commits-availability.txt`: OSV記載fix commitの公開取得結果
- `artifacts/*commit_or_error.txt`: branch別fix commit取得結果
- `artifacts/origin-patch-diffing-pipeline.html`: 依頼参照記事の保存版
- `artifacts/SHA256SUMS.txt`: 保存成果物のSHA-256

## 再検証用コマンド

```sh
curl -L 'https://storage.googleapis.com/android-osv/ASB-A-461790658.json'
curl -L 'https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce?format=JSON' | sed '1s/^)]}//'
curl -L 'https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce%5E%21/?format=TEXT' | base64 -d
curl -L 'https://android.googlesource.com/platform/external/dng_sdk/+/47cd326e0c8f19cc367663b31d95c03584198fa4/Android.bp?format=TEXT' | base64 -d
curl -L 'https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce/Android.bp?format=TEXT' | base64 -d
curl -L 'https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce/ubsan-replacement/ubsan_throwing_runtime.cpp?format=TEXT' | base64 -d
```
044 OK

CVE-2026-0052

044-ok-dng-sdk-ubsan-overflow-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeDoS
SeverityCritical
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-467352655
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0052 is listed in the Android Security Bulletin as a Critical severity DoS issue in System.

特定した具体的な脆弱性

ok: ソースコード差分から、脆弱性の成立条件・根本原因・修正方針を説明できる。

タイトル: dng-sdk-ubsan-overflow-dos

原因

根本原因は、入力由来の整数オーバーフローそのものだけではなく、Androidの libdng_sdk ビルド設定で「未定義/危険な整数演算の検出」と「ライブラリとしてのエラー処理方針」が噛み合っていなかったこと。

具体的には以下の組み合わせが問題だった。

・libdng_sdk-defaults で signed-integer-overflow / unsigned-integer-overflow のUBSanを有効化していた。
・libdng_sdk はDNG入力を処理するライブラリで、入力値由来のサイズ・オフセット・タイル・サンプル数などの演算に到達しうる。
・DNG SDK本体は C++ 例外を有効にしており、dng_exception で不正入力を扱う作りだった。
・しかしUBSan runtimeは例外ではなく abort で処理していたため、攻撃者制御の不正DNGが「処理失敗」ではなく「プロセスクラッシュ」になった。

このため、個別の演算箇所を全て塞ぐのではなく、UBSanが発火した場合も例外として上位へ戻すランタイム差し替えが採用されている。

どこから特定したか

解析したファイル: ・artifacts/ASB-A-467352655.osv.json: OSV APIから取得した脆弱性情報
・74a5a91d.diff: bulletinから到達する Android 16 security release の公開差分
・74a5a91d.commit.json: 公開コミットメタデータ
・artifacts/81ded662eee07fcbb830e6b6c83d1a3d85227ceb.diff: 17-next用fixとしてOSVに載る公開差分
・artifacts/7f197e818cbb7b5bc7b9ee5017a36a23650c29de.diff: Android 14用fixとしてOSVに載る公開差分
・artifacts/source-snippets/Android…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://osv.dev/vulnerability/ASB-A-467352655 / https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce / https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce^!/?format=TEXT'

validated.md を表示
# CVE-2026-0052 検証結果

## 判定

ok: ソースコード差分から、脆弱性の成立条件・根本原因・修正方針を説明できる。

タイトル: dng-sdk-ubsan-overflow-dos

## 基本情報

- CVE: CVE-2026-0052
- Android bug ID: A-467352655
- Component: System
- Subcomponent/package: `platform/external/dng_sdk`
- 種別: DoS
- 重要度: Critical
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://osv.dev/vulnerability/ASB-A-467352655
- 公開修正コミット: https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce

OSVの詳細文は「`ubsan_throwing_runtime.cpp` の複数関数で integer overflow によりクラッシュを起こせる可能性があり、追加権限・ユーザー操作なしの remote DoS につながる」という内容だった。ただし実際のパッチは `ubsan_throwing_runtime.cpp` を新規追加するものであり、既存の脆弱な演算箇所を個別に直す修正ではなかった。

## 解析したファイル

- `artifacts/ASB-A-467352655.osv.json`: OSV APIから取得した脆弱性情報
- `74a5a91d.diff`: bulletinから到達する Android 16 security release の公開差分
- `74a5a91d.commit.json`: 公開コミットメタデータ
- `artifacts/81ded662eee07fcbb830e6b6c83d1a3d85227ceb.diff`: 17-next用fixとしてOSVに載る公開差分
- `artifacts/7f197e818cbb7b5bc7b9ee5017a36a23650c29de.diff`: Android 14用fixとしてOSVに載る公開差分
- `artifacts/source-snippets/Android.bp.before`: 修正前 `Android.bp`
- `artifacts/source-snippets/Android.bp.after`: 修正後 `Android.bp`
- `artifacts/source-snippets/ubsan_throwing_runtime.cpp`: 追加されたUBSan差し替えランタイム
- `artifacts/source-snippets/dng_exceptions.cpp`: DNG SDKの既存例外処理
- `artifacts/source-snippets/dng_safe_arithmetic.cpp`: DNG SDKの安全演算コード

15/16/16-qpr2用としてOSVに載っていた `475c8cce973f56488cc9f37d00cf0a4069f0e4fe`、`1337d2e14a412ec81a4a32f6251063091922a9e9`、`690688f3b522dc80de007d5c3ac8b8ce61da8870` は、調査時点で Gitiles が `NOT_FOUND` を返した。その結果も同名 `.json` / 空 `.diff` として artifacts に残した。

## パッチ内容

修正前の `libdng_sdk-defaults` は以下のように signed/unsigned integer overflow のUBSanを有効にしていた。

```bp
sanitize: {
    misc_undefined: [
        "unsigned-integer-overflow",
        "signed-integer-overflow",
    ],
},
```

一方、公開ライブラリ `libdng_sdk` 側はその設定を継承したまま、独自のUBSanランタイムを持っていなかった。そのため、DNGパース・画像展開中にUBSanが検出する整数オーバーフローに到達すると、通常の「不正画像としてデコード失敗」ではなく、UBSan minimal runtime のハード abort でプロセスが終了する構成だった。

修正後は `libdng_sdk` に限って Soong の sanitizer runtime リンクを `never: true` で止め、同じ overflow sanitizer を `cflags` で明示し、`-fno-sanitize-link-runtime` と新規 `ubsan-replacement/ubsan_throwing_runtime.cpp` を追加している。

```bp
sanitize: {
    never: true,
},

cflags: [
    "-DqDNGValidate=0",
    "-fsanitize=signed-integer-overflow,unsigned-integer-overflow",
    "-fno-sanitize-link-runtime",
],

srcs: [
    "ubsan-replacement/ubsan_throwing_runtime.cpp"
],
```

追加されたハンドラは以下の5種類のUBSan overflow callbackを実装し、abortの代わりに C++ 例外を投げる。

- `__ubsan_handle_add_overflow`
- `__ubsan_handle_sub_overflow`
- `__ubsan_handle_mul_overflow`
- `__ubsan_handle_negate_overflow`
- `__ubsan_handle_divrem_overflow`

`Android.bp` では既に `rtti: true` と `cppflags: ["-fexceptions"]` が指定されており、コミットメッセージも「C++ exceptions are enabled in this library and are a much better solution for ubsan errors than a hard abort」と説明している。つまり修正の狙いは、検出を弱めることではなく、検出後のエラー伝播をプロセス終了から例外へ変えること。

## どういう脆弱性だったか

攻撃者が細工したDNG/RAW系画像をAndroidの画像デコード経路に渡すと、`external/dng_sdk` のDNGパーサ・デコーダ内で攻撃者制御値を使った整数演算が行われる。そこで signed/unsigned integer overflow、加算・減算・乗算・除算剰余・符号反転 overflow のいずれかがUBSanに検出されると、修正前ビルドではUBSan minimal runtimeが abort し、呼び出し元が例外やエラー戻り値として扱う前にプロセスが落ちる。

Android bulletin/OSVでは user interaction not needed / remote DoS とされている。典型的には、DNG画像を処理するアプリ、画像プレビュー、メディア処理、または画像デコードを行うサービスに悪性ファイル・コンテンツを到達させることで、対象プロセスをクラッシュさせる脆弱性と解釈できる。

重要なのは、DNG SDKには `dng_exception` や `ThrowOverflow` など、壊れた入力を例外として扱う既存設計がある点。通常のDNG SDK由来エラーは例外で呼び出し元へ戻せるが、コンパイラ挿入のUBSan overflow trapだけがその設計を迂回していた。

## 根本原因

根本原因は、入力由来の整数オーバーフローそのものだけではなく、Androidの `libdng_sdk` ビルド設定で「未定義/危険な整数演算の検出」と「ライブラリとしてのエラー処理方針」が噛み合っていなかったこと。

具体的には以下の組み合わせが問題だった。

- `libdng_sdk-defaults` で `signed-integer-overflow` / `unsigned-integer-overflow` のUBSanを有効化していた。
- `libdng_sdk` はDNG入力を処理するライブラリで、入力値由来のサイズ・オフセット・タイル・サンプル数などの演算に到達しうる。
- DNG SDK本体は C++ 例外を有効にしており、`dng_exception` で不正入力を扱う作りだった。
- しかしUBSan runtimeは例外ではなく abort で処理していたため、攻撃者制御の不正DNGが「処理失敗」ではなく「プロセスクラッシュ」になった。

このため、個別の演算箇所を全て塞ぐのではなく、UBSanが発火した場合も例外として上位へ戻すランタイム差し替えが採用されている。

## 修正後の挙動

修正後も `-fsanitize=signed-integer-overflow,unsigned-integer-overflow` は維持される。整数オーバーフロー検出時には `__ubsan_handle_*_overflow` が呼ばれ、`std::runtime_error("ubsan: ...")` が throw される。これにより、DNGデコード処理はプロセス全体を abort せず、例外処理・エラー処理の経路へ戻れる。

この修正は「整数オーバーフローを発生させないように全ての演算を安全化する」ものではない。セキュリティ上の価値は、攻撃者が到達可能なUBSan検出を DoS primitive から通常のデコード失敗へ落とす点にある。

## 調査中に分かった面白い点・注意点

- Bulletin上の CVE-2026-0052 / A-467352655 のリンク先は `74a5a91d...` だが、この公開コミットメッセージには `Bug: 467352655` が含まれていない。代わりに `470966846`、`467994860`、`467994310`、`461790658`、`456471487`、`453649377`、`449728942` が列挙されている。OSV側では A-467352655 が同じfix群に明示的に紐付いているため、bulletin/OSVのマッピングを採用した。
- 同じパッチが複数CVE/bugのDoSをまとめて緩和している可能性が高い。個々のCVEは異なるDNG入力・異なるoverflow到達点を表すが、公開修正は「UBSan overflow時にabortしない」という横断的対策。
- OSVの詳細文は「`ubsan_throwing_runtime.cpp` の複数関数に integer overflow」と読めるが、実際には追加された `ubsan_throwing_runtime.cpp` が脆弱箇所というより、複数のUBSan overflow handlerでクラッシュを例外へ変える修正ファイルである。説明文はパッチファイル名を脆弱箇所として機械的に記述しているように見える。
- Skiaリポジトリも確認しようとしたが、blobless clone検索で大量取得が発生したため中断した。今回の根本原因特定には `external/dng_sdk` の公開差分とOSV情報で十分だった。

## 再検証用コマンド

```sh
curl -L 'https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce^!/?format=TEXT' | base64 -d
curl -L 'https://api.osv.dev/v1/vulns/ASB-A-467352655'
git clone --filter=blob:none https://android.googlesource.com/platform/external/dng_sdk ../binaries/dng_sdk.git
git -C ../binaries/dng_sdk.git fetch origin 74a5a91d169a341db58d57e0bf018d0a8b784cce 81ded662eee07fcbb830e6b6c83d1a3d85227ceb 7f197e818cbb7b5bc7b9ee5017a36a23650c29de
```
045 OK

CVE-2026-0080

045-ok-dng-sdk-ubsan-overflow-hard-abort-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeDoS
SeverityCritical
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-462431872
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0080 is listed in the Android Security Bulletin as a Critical severity DoS issue in System.

特定した具体的な脆弱性

ok: 脆弱性の根本原因をソースコード差分と呼び出し側コードから特定できた。

このCVEは platform/external/dng_sdk の libdng_sdk が、DNG/RAW画像処理中にUBSanで検出された整数オーバーフローをプロセスabortとして扱っていたため、細工されたDNG/RAW入力で画像デコード元プロセスをクラッシュさせられる DoS だった。修正は個別の算術式を1つ直すものではなく、libdng_sdk の整数オーバーフロー sanitizer runtime を独自実装に差し替え、UBSan検出をC++例外に変換して既存のDNG/Skia例外処理へ戻すものだった。

原因

根本原因は、信頼できないDNG/RAWファイル由来の値で到達可能な整数算術オーバーフローを、ライブラリ内の通常エラーとして扱わず、UBSan minimal のプロセスabortに任せていたこと。

より具体的には以下の組み合わせ。

・libdng_sdk-defaults で signed/unsigned integer overflow sanitizer が有効だった。
・libdng_sdk はC++例外を有効化しており、DNG SDK/Skia側は不正入力を例外で回復する設計だった。
・しかしUBSan minimal runtimeは例外を投げず、overflow検出時にhard abortする。
・DNGのmetadata、寸法、tile、opcode、render処理などは攻撃者制御入力から多数の整数計算に到達する。
・そのため、DNG SDK内のoverflowがメモリ破壊に進む前でも、検出された瞬間にプロセスDoSになる。

どこから特定したか

パッチ差分の要点: 修正前の libdng_sdk-defaults はC++例外を有効化しつつ、signed/unsigned integer overflow sanitizer も有効にしていた。

``bp
rtti: true,
cppflags: ["-fexceptions"],

sanitize: {
misc_undefined: [
"unsigned-integer-overflow",
"signed-integer-overflow",
],
},
`

しかし修正前の libdng_sdk 自体は defaults を継承するだけで、UBSan runtime を差し替えていなかった。

保存した証跡: ・artifacts/android-security-bulletin-2026-06-01.html: Android Security Bulletin保存版
・artifacts/osv-ASB-A-462431872.json: 対象CVEのAndroid OSV
・artifacts/74a5a91_commit_full.txt: commit metadata/stat
・artifacts/74a5a91.patch: ローカルgitから保存した対象commitのpatch
・artifacts/Android.bp.before: 修正前 Android.bp
・artifacts/Android.bp.after: 修正後 Android.bp
・artifacts/ubsan_thro…

URL: https://source.android.com/docs/security/bullet…

validated.md を表示
# CVE-2026-0080 検証結果

## 判定

ok: 脆弱性の根本原因をソースコード差分と呼び出し側コードから特定できた。

このCVEは `platform/external/dng_sdk` の `libdng_sdk` が、DNG/RAW画像処理中にUBSanで検出された整数オーバーフローをプロセスabortとして扱っていたため、細工されたDNG/RAW入力で画像デコード元プロセスをクラッシュさせられる DoS だった。修正は個別の算術式を1つ直すものではなく、`libdng_sdk` の整数オーバーフロー sanitizer runtime を独自実装に差し替え、UBSan検出をC++例外に変換して既存のDNG/Skia例外処理へ戻すものだった。

## 基本情報

- CVE: CVE-2026-0080
- Android Bug ID: A-462431872
- Component: System
- Type: DoS
- Severity: Critical
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Bulletin上の修正リンク: https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce
- OSV: https://storage.googleapis.com/android-osv/ASB-A-462431872.json
- 対象AOSP versions: 14, 15, 16, 16-qpr2

## 参照した修正

主に以下のAOSP commitを解析した。

- `74a5a91d169a341db58d57e0bf018d0a8b784cce`
- Subject: `Replace ubsan-minimal with throw`
- Parent: `47cd326e0c8f19cc367663b31d95c03584198fa4`
- AuthorDate: 2026-01-09
- CommitDate: 2026-04-09
- 変更ファイル:
  - `Android.bp`
  - `OWNERS`
  - `ubsan-replacement/ubsan_throwing_runtime.cpp`

OSV上のブランチ別fixは以下。

- 17-next: `81ded662eee07fcbb830e6b6c83d1a3d85227ceb`
- 15: `475c8cce973f56488cc9f37d00cf0a4069f0e4fe`
- 16: `1337d2e14a412ec81a4a32f6251063091922a9e9`
- 16-qpr2: `690688f3b522dc80de007d5c3ac8b8ce61da8870`
- 14: `7f197e818cbb7b5bc7b9ee5017a36a23650c29de`

ローカルmirrorでは `81ded...` と `7f197...` が取得済みで、15/16/16-qpr2 の3件はobject未取得だった。可用性は `artifacts/fix-commits-availability.txt` に保存した。

## パッチ差分の要点

修正前の `libdng_sdk-defaults` はC++例外を有効化しつつ、signed/unsigned integer overflow sanitizer も有効にしていた。

```bp
rtti: true,
cppflags: ["-fexceptions"],

sanitize: {
    misc_undefined: [
        "unsigned-integer-overflow",
        "signed-integer-overflow",
    ],
},
```

しかし修正前の `libdng_sdk` 自体は defaults を継承するだけで、UBSan runtime を差し替えていなかった。

```bp
cc_library {
    name: "libdng_sdk",
    defaults: ["libdng_sdk-defaults"],
    cflags: ["-DqDNGValidate=0"],
}
```

修正後は `libdng_sdk` に対してSoongの sanitizer runtime 注入を止め、整数オーバーフロー instrumentation は明示的に維持し、runtimeはリンクしない構成になった。

```bp
sanitize: {
    never: true,
},

cflags: [
    "-DqDNGValidate=0",
    "-fsanitize=signed-integer-overflow,unsigned-integer-overflow",
    "-fno-sanitize-link-runtime",
],

srcs: [
    "ubsan-replacement/ubsan_throwing_runtime.cpp"
],
```

追加された `ubsan_throwing_runtime.cpp` は、UBSanの整数オーバーフロー handler をすべて `std::runtime_error` に変換する。

```cpp
INTERFACE void __ubsan_handle_add_overflow() {
    throw std::runtime_error("ubsan: add-overflow");
}

INTERFACE void __ubsan_handle_sub_overflow() {
    throw std::runtime_error("ubsan: sub-overflow");
}

INTERFACE void __ubsan_handle_mul_overflow() {
    throw std::runtime_error("ubsan: mul-overflow");
}

INTERFACE void __ubsan_handle_negate_overflow() {
    throw std::runtime_error("ubsan: negate-overflow");
}

INTERFACE void __ubsan_handle_divrem_overflow() {
    throw std::runtime_error("ubsan: divrem-overflow");
}
```

## 脆弱性が起きる状況

`libdng_sdk` は Android の Skia RAW/DNG codec 経由で使われる。保存した `SkRawCodec.cpp` では、DNG入力に対して以下の流れになる。

1. `SkRawCodec::MakeFromStream()` がPIEX previewで処理できないRAW/DNGを `SkDngImage::NewFromStream()` に渡す。
2. `SkDngImage::readDng()` が `dng_info::Parse/PostParse`、`dng_negative::Parse/PostParse`、metadata同期を実行する。
3. `SkRawCodec::onGetPixels()` が `SkDngImage::render()` を呼び、`ReadStage1Image`、`BuildStage2Image`、`BuildStage3Image`、`dng_render::Render()` を実行する。

Skia側はDNG SDKが例外を投げる前提で作られている。`readDng()` と `render()` は `catch (...)` で失敗を捕捉し、それぞれ `false` / `nullptr` を返す。`onGetPixels()` は `nullptr` を `kInvalidInput` に変換する。DNG処理スレッド内の例外も `SkDngHost::PerformAreaTask()` で捕捉され、DNG例外として再送出される。

つまり本来の失敗経路は「不正なDNG入力 -> 例外 -> 画像デコード失敗」だが、未修正では整数オーバーフローだけが UBSan minimal runtime によりプロセスabortになる。`catch (...)` は `abort()` を捕捉できないため、細工されたDNG/RAWを画像デコードさせるだけで、デコードを行ったプロセスを落とせる。

OSVの説明もこの理解と一致する。要約すると、`ubsan_throwing_runtime.cpp` の複数関数に関連する整数オーバーフローでクラッシュを起こせ、追加権限やユーザー操作なしに remote DoS になり得る、という内容である。

短い原文抜粋: "cause a crash due to an integer overflow"

ここで `ubsan_throwing_runtime.cpp` は修正後に追加されたファイル名なので、OSVの表現は「修正シグネチャの場所」を指している。実際の攻撃入力到達点はDNG SDK内の複数のparse/render系算術処理であり、個別の式はこの公開パッチだけではCVE別に分離されていない。

## 根本原因

根本原因は、信頼できないDNG/RAWファイル由来の値で到達可能な整数算術オーバーフローを、ライブラリ内の通常エラーとして扱わず、UBSan minimal のプロセスabortに任せていたこと。

より具体的には以下の組み合わせ。

- `libdng_sdk-defaults` で signed/unsigned integer overflow sanitizer が有効だった。
- `libdng_sdk` はC++例外を有効化しており、DNG SDK/Skia側は不正入力を例外で回復する設計だった。
- しかしUBSan minimal runtimeは例外を投げず、overflow検出時にhard abortする。
- DNGのmetadata、寸法、tile、opcode、render処理などは攻撃者制御入力から多数の整数計算に到達する。
- そのため、DNG SDK内のoverflowがメモリ破壊に進む前でも、検出された瞬間にプロセスDoSになる。

修正は sanitizer instrumentation 自体を外していない。`-fsanitize=signed-integer-overflow,unsigned-integer-overflow` を維持したうえで、`-fno-sanitize-link-runtime` と独自 `__ubsan_handle_*_overflow` により、検出結果をC++例外に変換している。これは「overflowを見逃す」修正ではなく、「overflowを通常のデコード失敗として安全に処理する」修正である。

## 面白い点・調査メモ

- Bulletin HTMLでは `CVE-2026-0080` / `A-462431872` が `74a5a91...` に直接リンクされている。
- OSVでも `ASB-A-462431872` の `references.FIX` は同じ `74a5a91...` で、affected package は `platform/external/dng_sdk` になっている。
- 一方、`74a5a91...` の commit message には `Bug: 462431872` が出ていない。message に列挙されているのは `470966846`, `467994860`, `467994310`, `461790658`, `456471487`, `453649377`, `449728942` である。
- それでも、Bulletin と OSV がこのCVEを同じパッチへ明示的に対応付けているため、CVE-2026-0080 は同じDNG SDK UBSan-hard-abort問題群に後から紐付けられた、または同じ共通修正で同時に解消された別入力ケースと判断した。
- 同じ `74a5a91...` は `CVE-2026-0040`, `CVE-2026-0041`, `CVE-2026-0042`, `CVE-2026-0044`, `CVE-2026-0051`, `CVE-2026-0052` などにも対応している。個別CVEは異なるDNG入力や到達箇所を指す可能性があるが、公開差分上の修正点は共通して「UBSan検出をabortから例外へ変換する」ことだった。
- `SkRawCodec` 側はすでに `catch (...)` を広く置いており、パッチ後の `std::runtime_error` も捕捉される。既存の呼び出し側設計を活かすためのruntime差し替えになっている。

## 保存した証跡

- `artifacts/android-security-bulletin-2026-06-01.html`: Android Security Bulletin保存版
- `artifacts/osv-ASB-A-462431872.json`: 対象CVEのAndroid OSV
- `artifacts/74a5a91_commit_full.txt`: commit metadata/stat
- `artifacts/74a5a91.patch`: ローカルgitから保存した対象commitのpatch
- `artifacts/Android.bp.before`: 修正前 `Android.bp`
- `artifacts/Android.bp.after`: 修正後 `Android.bp`
- `artifacts/ubsan_throwing_runtime.cpp`: 追加されたUBSan replacement runtime
- `artifacts/SkRawCodec.cpp`: 呼び出し側確認用のSkia RAW codec
- `artifacts/SkRawCodec.h`: 同上
- `artifacts/skia_Android.bp`: `libskia` が `libdng_sdk` を使い、例外を有効にしている証跡
- `artifacts/key-code-excerpts-from-previous-dng-analysis.txt`: 重要差分と呼び出し側catch箇所の抜粋
- `artifacts/fix-commits-availability.txt`: OSV記載fix commitのローカルobject確認結果
046 OK

CVE-2026-0059

046-ok-bluetooth-sdp-attribute-seq-heap-overflow

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeRCE
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-447536200
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0059 is listed in the Android Security Bulletin as a High severity RCE issue in System.

特定した具体的な脆弱性

CVE-2026-0059 は Android Bluetooth SDP クライアントの送信パケット生成処理にある heap buffer overflow である。修正対象は platform/packages/modules/Bluetooth の system/stack/sdp で、問題の中心は sdpu_build_attrib_seq() が SDP_DATA_BUF_SIZE 固定バッファの残量を知らないまま、num_attr_filters * 3 バイト相当の AttributeIDList を書き込んでいた点。

通常の SDP_InitDiscoveryDb() API は num_attr > SDP_MAX_ATTR_FILTERS を拒否し、SDP_MAX_ATTR_FILTERS は 15 なので、正常な API 呼び出しだけでは巨大な属性リストは作れない。したがって攻撃条件は、リモート SDP 応答などを契機に discovery DB / CCB 周辺の状態が壊れ、p_ccb->p_db->num_attr_filters が本来の上限を超えた値として使われる状況である。その状態で SDP Service Search Attribute Request または Service Attribute Request が再送/継続送信されると、修正前は 4112 バイトの heap buffer を越えて書き込む。

ソースコード差分で脆弱な書き込み箇所と修正が確認できるため、判定は ok とする。タイトル案: 046-ok-bluetooth-sdp-attribute-seq-heap-overflow

原因

根本原因は、低レベル builder の sdpu_build_attrib_seq() が「呼び出し元の discovery DB は常に SDP_InitDiscoveryDb() で初期化され、num_attr_filters <= SDP_MAX_ATTR_FILTERS が保たれる」という外部不変条件に依存していたこと。

SDP_InitDiscoveryDb() には以下の検証がある。

・num_attr > SDP_MAX_ATTR_FILTERS なら失敗
・SDP_MAX_ATTR_FILTERS は 15
・SDP_MAX_UUID_FILTERS は 3

このため通常状態では AttributeIDList は最大でも 15 * 3 + 2 = 47 バイト程度で、4112 バイトの SDP_DATA_BUF_SIZE を越えない。しかし CCB が保持する p_db は discovery 中の可変状態であり、壊れた DB、解放後再利用、またはメモリ破壊後の DB を参照した場合、builder 側には最後の防衛線がなかった。

どこから特定したか

確認した公開情報: ・Bulletin: Android Security Bulletin 2026-06-01, updated 2026-06-03
・Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
・CVE: CVE-2026-0059
・Reference: A-447536200
・Component/Subcomponent: System / Bluetooth SDP (platform/packages/modules/Bluetooth, system/stack/sdp)
・Type/Severity: RCE / High
・Affected/fixed AOSP branches: 14,…

パッチ差分の要点: 修正前:

・sdpu_build_attrib_seq(uint8_t* p_out, uint16_t* p_attr, uint16_t num_attrs) は出力先 pointer だけを受け取る。
・p_attr != NULL の場合、uint16_t xx = num_attrs * 3 として AttributeIDList の content length を作る。
・header は 2 または 3 バイトだが、呼び出し元の SDP_DATA_BUF_SIZE 残量と比較しない。
・その後 for (xx = 0; xx < num_attrs; xx++) で各属性につき 3 バイトを書き込む。

修正後:

URL: https://source.android.com/docs/security/bulletin/20…

validated.md を表示
# CVE-2026-0059 検証メモ

## 結論

CVE-2026-0059 は Android Bluetooth SDP クライアントの送信パケット生成処理にある heap buffer overflow である。修正対象は `platform/packages/modules/Bluetooth` の `system/stack/sdp` で、問題の中心は `sdpu_build_attrib_seq()` が `SDP_DATA_BUF_SIZE` 固定バッファの残量を知らないまま、`num_attr_filters * 3` バイト相当の AttributeIDList を書き込んでいた点。

通常の `SDP_InitDiscoveryDb()` API は `num_attr > SDP_MAX_ATTR_FILTERS` を拒否し、`SDP_MAX_ATTR_FILTERS` は 15 なので、正常な API 呼び出しだけでは巨大な属性リストは作れない。したがって攻撃条件は、リモート SDP 応答などを契機に discovery DB / CCB 周辺の状態が壊れ、`p_ccb->p_db->num_attr_filters` が本来の上限を超えた値として使われる状況である。その状態で SDP Service Search Attribute Request または Service Attribute Request が再送/継続送信されると、修正前は 4112 バイトの heap buffer を越えて書き込む。

ソースコード差分で脆弱な書き込み箇所と修正が確認できるため、判定は ok とする。タイトル案: `046-ok-bluetooth-sdp-attribute-seq-heap-overflow`

## 確認した公開情報

- Bulletin: Android Security Bulletin 2026-06-01, updated 2026-06-03
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- CVE: CVE-2026-0059
- Reference: A-447536200
- Component/Subcomponent: System / Bluetooth SDP (`platform/packages/modules/Bluetooth`, `system/stack/sdp`)
- Type/Severity: RCE / High
- Affected/fixed AOSP branches: 14, 15, 16, 16-qpr2, 17-next
- OSV: https://osv.dev/vulnerability/ASB-A-447536200

## 修正コミット

OSV から確認した関連 commit:

- `26185859d969eccd062fdcd82e97a8b63e7244f0`
- `5288e3e85ba98e8ef6b91f287e1aa18f1bb28ac5`
- `af3196b8ac375e6c2c1f04e314eb456925b61535`
- `ce1de9ef78ca4ff7b408d934815a8967e390eb6a`
- `d0b636f59cc176ec4f565ee52c07f7a55f6d9765`

解析では `94566a29d020042ec4b423119f4d019d958b1aaf^!` の diff も確認した。これは OSV の signature と同じ `sdp_discovery.cc`, `sdp_utils.cc`, `sdpint.h` を変更しており、`sdpu_build_attrib_seq` の残量検証追加が本質的修正である。

## パッチ差分の要点

修正前:

- `sdpu_build_attrib_seq(uint8_t* p_out, uint16_t* p_attr, uint16_t num_attrs)` は出力先 pointer だけを受け取る。
- `p_attr != NULL` の場合、`uint16_t xx = num_attrs * 3` として AttributeIDList の content length を作る。
- header は 2 または 3 バイトだが、呼び出し元の `SDP_DATA_BUF_SIZE` 残量と比較しない。
- その後 `for (xx = 0; xx < num_attrs; xx++)` で各属性につき 3 バイトを書き込む。

修正後:

- `sdpu_build_attrib_seq(..., uint16_t& bytes_left)` に変更。
- `content_len` と `header_len` を計算し、`bytes_left < content_len + header_len` なら `DCHECK` して書き込みを中止。
- 呼び出し元の `process_service_search_attr_rsp()` と `process_service_attr_rsp()` が `base_bytes` を計算し、ヘッダ、handle、max attr count、continuation state 分を差し引いた残量を `sdpu_build_attrib_seq()` に渡す。
- `sdp_snd_service_search_req()` 側にも base byte 計算の修正が入っており、コメント上の「service record count」と実際のフィールドの取り違えも直っている。

## 到達経路

問題のある書き込みは、SDP クライアントが相手 SDP server へ次の request を送るときに発生する。

1. Bluetooth SDP discovery が開始され、`tCONN_CB` に `tSDP_DISCOVERY_DB* p_db` が保持される。
2. 相手 SDP server から Service Search Attribute Response または Service Attribute Response を受ける。
3. 応答に continuation state がある、または次の handle を問い合わせる必要がある。
4. `process_service_search_attr_rsp()` または `process_service_attr_rsp()` が `BT_HDR* p_msg = osi_malloc(SDP_DATA_BUF_SIZE)` で 4112 バイトの送信バッファを確保する。
5. 修正前は `p_ccb->p_db->num_attr_filters` をそのまま `sdpu_build_attrib_seq()` に渡す。
6. `num_attr_filters` が本来の上限 15 を超えて大きい値になっている場合、`sdpu_build_attrib_seq()` が `p_msg` の末尾を越えて書く。

## 根本原因

根本原因は、低レベル builder の `sdpu_build_attrib_seq()` が「呼び出し元の discovery DB は常に `SDP_InitDiscoveryDb()` で初期化され、`num_attr_filters <= SDP_MAX_ATTR_FILTERS` が保たれる」という外部不変条件に依存していたこと。

`SDP_InitDiscoveryDb()` には以下の検証がある。

- `num_attr > SDP_MAX_ATTR_FILTERS` なら失敗
- `SDP_MAX_ATTR_FILTERS` は 15
- `SDP_MAX_UUID_FILTERS` は 3

このため通常状態では AttributeIDList は最大でも `15 * 3 + 2 = 47` バイト程度で、4112 バイトの `SDP_DATA_BUF_SIZE` を越えない。しかし CCB が保持する `p_db` は discovery 中の可変状態であり、壊れた DB、解放後再利用、またはメモリ破壊後の DB を参照した場合、builder 側には最後の防衛線がなかった。

## 影響と exploit 条件

`SDP_DATA_BUF_SIZE` は `BT_DEFAULT_BUFFER_SIZE` で、値は `4096 + 16 = 4112`。修正前の `sdpu_build_attrib_seq()` は `num_attrs` が大きいと出力サイズを制限しない。例えば `num_attr_filters = 0xffff` なら header length 計算用の `uint16_t xx = num_attrs * 3` は 65533 になる一方、ループは 65535 回まわり、属性本体だけで 196605 バイトを書こうとする。

リモート peer が単独で正規 API の `num_attr` を 15 超に設定することはできない。したがって CVE-2026-0059 は、リモート SDP 応答によって discovery の continuation/再送パスへ誘導しつつ、別の SDP DB lifetime/corruption 条件で `num_attr_filters` または `p_db` の内容を壊せる場合に RCE primitive になるタイプの修正と考えるのが妥当である。

面白い点として、このパッチは `SDP_InitDiscoveryDb()` の上限を下げるのではなく、送信 packet builder に残量を渡している。つまり Android 側の判断は「入力 API の制約だけではセキュリティ境界として不十分で、固定長 heap buffer へ書く関数自身が境界を確認すべき」というものだったと読める。

## 付帯ファイル

- `artifacts/94566a29d020042ec4b423119f4d019d958b1aaf.diff`: 解析した raw diff
- `artifacts/pre_sdp_utils.cc`, `artifacts/post_sdp_utils.cc`: `sdpu_build_attrib_seq()` 修正前後
- `artifacts/pre_sdp_discovery.cc`, `artifacts/post_sdp_discovery.cc`: 呼び出し元修正前後
- `artifacts/pre_sdpint.h`, `artifacts/post_sdpint.h`: 関数 prototype 修正前後
- `artifacts/pre_extra/sdp_api.cc`: `SDP_InitDiscoveryDb()` の上限検証
- `artifacts/pre_extra/bt_target.h`: `SDP_DATA_BUF_SIZE`, `SDP_MAX_ATTR_FILTERS`, `SDP_MAX_UUID_FILTERS` の定義
- `artifacts/ASB-A-447536200.osv.json`: OSV API から取得した advisory JSON
- `artifacts/overflow_notes.txt`: バッファサイズと overflow 閾値の計算メモ

## 検証ログ

- `cve.md` から CVE、A-447536200、System/RCE/High、bulletin URL を確認。
- Android Security Bulletin 2026-06-01 の System 表で CVE-2026-0059 と参照 ID を確認。
- OSV `ASB-A-447536200` から affected package と branch 別 fixed commit を確認。
- Gitiles から `94566a29...^!` raw diff と修正前後の `sdp_*` ファイルを取得。
- `sdpu_build_attrib_seq()` が修正前に `bytes_left` を受け取らず、属性シーケンスを書き放題だったことを確認。
- `SDP_InitDiscoveryDb()` が `num_attr > SDP_MAX_ATTR_FILTERS` を拒否することを確認。
- `bt_target.h` で `SDP_MAX_ATTR_FILTERS=15`, `SDP_DATA_BUF_SIZE=4112` を確認。
- 通常 API だけでは再現しないが、壊れた `p_db->num_attr_filters` を使う送信パスでは heap overflow になると判断。
047 OK

CVE-2025-26418

047-ok-car-device-policy-disclaimer-ack-permission-bypass

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityHigh
Updated AOSP versions14, 15
ReferencesA-351830787
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-26418 is listed in the Android Security Bulletin as a High severity EoP issue in System.

特定した具体的な脆弱性

ok: ソースコード差分から脆弱性と根本原因を特定できた。

タイトル案: car-device-policy-disclaimer-ack-permission-bypass

原因

根本原因は、権限が必要な binder service method で caller identity に基づく runtime permission check をしていなかったこと。

より具体的には、CarDevicePolicyManager の他の user 管理 API には MANAGE_USERS / CREATE_USERS などの permission 要件が付いている一方、setUserDisclaimerAcknowledged() だけが漏れていた。さらに CarDevicePolicyService 側も removeUser() 等と同じく下位 service に任せる形ではなく、直接 disclaimer 状態と DPM ack を変更しているにもかかわらず、MANAGE_USERS または cross-user 権限の検証を行っていなかった。

どこから特定したか

解析した修正コミット: ・17-next: https://android.googlesource.com/platform/packages/services/Car/+/1111e31c89e9ed293f1c6947d29819ec85ab1079
- 保存: 1111e31c89e9ed293f1c6947d29819ec85ab1079_full.patch
・Android 14: https://android.googlesource.com/platform/packages/services/Car/+/dd8e3f0ca750fd170e4afce0cbf2a9323c43dfe5
- 保存: dd8e3f0ca750fd170e4afce0cbf2a9323c43dfe5_full.patch
・A…

保存した付帯ファイル: ・ASB-A-351830787.json: Android OSV JSON
・1111e31c89e9ed293f1c6947d29819ec85ab1079_full.patch: 17-next の完全パッチ
・dd8e3f0ca750fd170e4afce0cbf2a9323c43dfe5_full.patch: Android 14 の完全パッチ
・6b03abf9c9dbbc35dfd2e64df31f7d19e77445d8_gitiles_response.txt: Android 15 fix URL の Gitiles 応答
・CarDevicePolicyService_before_next.java / CarDevicePolicyService_after_next.java…

URL: https:/…

validated.md を表示
# CVE-2025-26418 検証結果

## 判定

ok: ソースコード差分から脆弱性と根本原因を特定できた。

タイトル案: `car-device-policy-disclaimer-ack-permission-bypass`

## 基本情報

- CVE: CVE-2025-26418
- Android Bug ID: A-351830787
- Component: System
- Subcomponent / package: `platform/packages/services/Car`、AAOS `CarDevicePolicyService`
- 種別 / 重要度: EoP / High
- 影響バージョン: Android 14, 15
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://storage.googleapis.com/android-osv/ASB-A-351830787.json
- NVD description: `CarDevicePolicyService.java` の `setUserDisclaimerAcknowledged` で permission check が欠けており、managed device に account を追加するときの user dialog を bypass できる。

## 解析した修正コミット

- 17-next: https://android.googlesource.com/platform/packages/services/Car/+/1111e31c89e9ed293f1c6947d29819ec85ab1079
  - 保存: `1111e31c89e9ed293f1c6947d29819ec85ab1079_full.patch`
- Android 14: https://android.googlesource.com/platform/packages/services/Car/+/dd8e3f0ca750fd170e4afce0cbf2a9323c43dfe5
  - 保存: `dd8e3f0ca750fd170e4afce0cbf2a9323c43dfe5_full.patch`
- Android 15: OSV は `6b03abf9c9dbbc35dfd2e64df31f7d19e77445d8` を fix として列挙しているが、調査時点で Gitiles は `NOT_FOUND` を返した。
  - 保存: `6b03abf9c9dbbc35dfd2e64df31f7d19e77445d8_gitiles_response.txt`

## 差分の要点

修正は 2 ファイルだけだった。

- `service/src/com/android/car/admin/CarDevicePolicyService.java`
  - `setUserDisclaimerAcknowledged(int userId)` の先頭に `enforcePermission()` を追加。
  - `enforcePermission()` は caller に `android.permission.MANAGE_USERS` または `android.permission.INTERACT_ACROSS_USERS` がなければ `SecurityException` を投げる。
- `car-lib/src/android/car/admin/CarDevicePolicyManager.java`
  - hidden API `setUserDisclaimerAcknowledged(UserHandle user)` に `@RequiresPermission(anyOf = {MANAGE_USERS, INTERACT_ACROSS_USERS})` を追加。
  - これは API 利用者向けの注釈で、防御の本体は service 側の runtime check。

Android 14 cherry-pick も同じ意味の修正で、行番号差と `@AddedInOrBefore` の有無以外は本質的に同一。

## 脆弱性の内容

AAOS の `CarDevicePolicyService` は、新規ユーザーに対して Device Policy の免責 / disclaimer 表示を扱う。`DevicePolicyManager.ACTION_SHOW_NEW_USER_DISCLAIMER` を受けると対象 user の状態を `RECEIVED` にし、通知を出す。その後 UI 側がユーザー同意を得ると `setUserDisclaimerAcknowledged(int userId)` が呼ばれ、次の処理を行う。

- 内部状態を `NEW_USER_DISCLAIMER_STATUS_ACKED` にする。
- `cancelUserDisclaimerNotification(user)` で disclaimer 通知を消す。
- 対象 user の `DevicePolicyManager.acknowledgeNewUserDisclaimer()` を呼ぶ。

修正前の `setUserDisclaimerAcknowledged()` は、この状態遷移を行う前に caller 権限を一切確認していなかった。結果として、権限を持たないローカルアプリが Car service の binder 経由でこの method を呼べると、managed device に account / user を追加する際に本来ユーザーへ表示される disclaimer dialog / notification を、ユーザー操作なしで ACK 済みにできる。

## 到達経路

保存した `ICar_after_next.aidl` では、アプリ向けに `ICar.getCarService(String serviceName)` が定義されている。保存した `ICarImpl_after_next.java` の `getCarService()` では、`Car.CAR_DEVICE_POLICY_SERVICE` の case で `mCarDevicePolicyService` を返しており、この case 自体に permission check はない。

`Car_after_next.java` では `CAR_DEVICE_POLICY_SERVICE = "car_device_policy_service"` が定義され、`createCarManagerLocked()` が返された binder から `new CarDevicePolicyManager(this, binder)` を作る。`CarDevicePolicyManager_before_next.java` の修正前 `setUserDisclaimerAcknowledged(UserHandle user)` は `mService.setUserDisclaimerAcknowledged(user.getIdentifier())` を呼ぶだけで、manager 側にも注釈すらなかった。

AIDL 側の `ICarDevicePolicyService_before_next.aidl` にも `void setUserDisclaimerAcknowledged(int userId);` があり、AIDL 宣言上の permission enforcement はない。したがって修正前の実防御は service method 内に置く必要があったが、それが欠けていた。

## 根本原因

根本原因は、権限が必要な binder service method で caller identity に基づく runtime permission check をしていなかったこと。

より具体的には、`CarDevicePolicyManager` の他の user 管理 API には `MANAGE_USERS` / `CREATE_USERS` などの permission 要件が付いている一方、`setUserDisclaimerAcknowledged()` だけが漏れていた。さらに `CarDevicePolicyService` 側も `removeUser()` 等と同じく下位 service に任せる形ではなく、直接 disclaimer 状態と DPM ack を変更しているにもかかわらず、`MANAGE_USERS` または cross-user 権限の検証を行っていなかった。

## 攻撃条件と影響

- 攻撃条件:
  - AAOS / Car service が有効な環境。
  - ローカルアプリが Car service binder を取得し、hidden API 反射または binder/AIDL 互換呼び出しで `setUserDisclaimerAcknowledged(userId)` を呼ぶ。
  - 追加の実行権限は不要、ユーザー操作不要という OSV/NVD の記載と整合する。
- 影響:
  - managed device に account を追加する場面で、本来ユーザーに表示される disclaimer / agreement を見せずに ACK 済み状態へ進められる。
  - notification がキャンセルされ、`DevicePolicyManager.acknowledgeNewUserDisclaimer()` が呼ばれるため、単なる UI 表示バグではなく DPM 側の同意済み状態まで進む。

## 修正の妥当性

修正後は `setUserDisclaimerAcknowledged()` の冒頭で `enforcePermission()` を実行するため、権限なし caller は状態変更、通知キャンセル、DPM ack の前に `SecurityException` で止まる。要求権限は `MANAGE_USERS` または `INTERACT_ACROSS_USERS` で、対象 user の disclaimer ack という cross-user / user 管理操作の性質に合っている。

面白い点として、API 注釈だけでなく service 側に実 check を追加しているため、hidden API を迂回して直接 binder を叩くケースも防げる。一方で `setUserDisclaimerShown()` には今回 permission check が追加されていない。`SHOWN` への変更だけでは DPM の ack や通知キャンセルを起こさないため、CVE の本体は `ACKED` 遷移に絞られていると見てよい。

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

- `ASB-A-351830787.json`: Android OSV JSON
- `1111e31c89e9ed293f1c6947d29819ec85ab1079_full.patch`: 17-next の完全パッチ
- `dd8e3f0ca750fd170e4afce0cbf2a9323c43dfe5_full.patch`: Android 14 の完全パッチ
- `6b03abf9c9dbbc35dfd2e64df31f7d19e77445d8_gitiles_response.txt`: Android 15 fix URL の Gitiles 応答
- `CarDevicePolicyService_before_next.java` / `CarDevicePolicyService_after_next.java`
- `CarDevicePolicyManager_before_next.java` / `CarDevicePolicyManager_after_next.java`
- `CarDevicePolicyService_before_android14.java` / `CarDevicePolicyService_after_android14.java`
- `ICarDevicePolicyService_before_next.aidl`
- `ICar_after_next.aidl`
- `ICarImpl_after_next.java`
- `Car_after_next.java`
- `*_excerpt.txt`: line number 付き抜粋
- `artifacts_index.txt`: 付帯ファイル一覧

048 OK

CVE-2025-48581

048-ok-apexd-verified-session-update-block-eop

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityHigh
Updated AOSP versions16
ReferencesA-428945391
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-48581 is listed in the Android Security Bulletin as a High severity EoP issue in System.

特定した具体的な脆弱性

特定できた。CVE-2025-48581 は platform/system/apex の apexd/apexd.cpp にある VerifyNoOverlapInSessions() のロジックエラーで、VERIFIED 状態の APEX staged-install セッションが存在するだけで、別パッケージの staged install と non-staged install まで拒否していた問題だった。

攻撃・障害条件は、apexd に SubmitStagedSession() 済みだが MarkStagedSessionReady() または AbortStagedSession() で完了していないセッションが残ること。この状態では VerifyNoOverlapInSessions() が "Session <id> is being staged." を返し、以後の APEX 更新をブロックする。APEX/Mainline はセキュリティ更新の配布経路なので、更新停止によって既知脆弱性を残せることが EoP として扱われている。

根本原因は、VERIFIED を「短時間だけ存在する排他中間状態」と仮定し、セッションが未完了のまま残る異常系を install 全体の拒否条件にしていたこと。修正はこの VERIFIED に対するグローバル拒否を削除し、従来どおり STAGED 状態で同じ APEX パッケージ名が既に staged されている場合だけ拒否するように緩和している。

原因

記載なし。

どこから特定したか

パッチ差分の要点: 脆弱な親コミットでは VerifyNoOverlapInSessions() が全セッションを走査し、セッション状態が SessionState::VERIFIED なら即エラーにしていた。

``cpp
// We don't want to install/stage while another session is being staged.
if (session.GetState() == SessionState::VERIFIED) {
return Error() << "Session " << session.GetId() << " is being staged.";
}
`

保存した付帯ファイル: ・artifacts/ASB-A-428945391.json: OSV JSON
・artifacts/android-security-bulletin-2026-06-01.html: 対象 bulletin
・artifacts/android-security-bulletin-2025-11-01.html: 参照確認用に保存した旧 bulletin
・artifacts/nvd-CVE-2025-48581.html: NVD ページ
・artifacts/origin-patch-diffing-pipeline.html: 指定された参考記事
・artifacts/13bbfe3ef2953e9805d57d3219cc122e485ba90f.diff: 本体修正 diff
・artifa…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-…

validated.md を表示
# CVE-2025-48581 / A-428945391 パッチ解析

## 結論

特定できた。CVE-2025-48581 は `platform/system/apex` の `apexd/apexd.cpp` にある `VerifyNoOverlapInSessions()` のロジックエラーで、`VERIFIED` 状態の APEX staged-install セッションが存在するだけで、別パッケージの staged install と non-staged install まで拒否していた問題だった。

攻撃・障害条件は、apexd に `SubmitStagedSession()` 済みだが `MarkStagedSessionReady()` または `AbortStagedSession()` で完了していないセッションが残ること。この状態では `VerifyNoOverlapInSessions()` が `"Session <id> is being staged."` を返し、以後の APEX 更新をブロックする。APEX/Mainline はセキュリティ更新の配布経路なので、更新停止によって既知脆弱性を残せることが EoP として扱われている。

根本原因は、`VERIFIED` を「短時間だけ存在する排他中間状態」と仮定し、セッションが未完了のまま残る異常系を install 全体の拒否条件にしていたこと。修正はこの `VERIFIED` に対するグローバル拒否を削除し、従来どおり `STAGED` 状態で同じ APEX パッケージ名が既に staged されている場合だけ拒否するように緩和している。

## 対象情報

- CVE: `CVE-2025-48581`
- Android bug/reference: `A-428945391`
- Component: `System`
- Subcomponent/package: `platform/system/apex` / `apexd`
- 種別: `EoP`
- 重大度: `High`
- 影響バージョン: Android 16
- bulletin URL: `https://source.android.com/docs/security/bulletin/2026/2026-06-01`
- OSV: `https://osv.dev/vulnerability/ASB-A-428945391`

## 主要コミット

ASB 2026-06-01 の `A-428945391` 行から直接辿れる公開コミット:

- `platform/system/apex` `13bbfe3ef2953e9805d57d3219cc122e485ba90f`
  - subject: `apexd: loosen no-overlap check on install`
  - 親: `9921a73777f97def1d8851dd0a1529f1c45bcc72`
  - 解析上の本体修正。
- `platform/system/apex` `5a33fa4202cb5f06d7f02f3a2b8d13780d7cb3f5`
  - subject: `New Patch Level for android mainline`
  - `com.google.android.mainline.patchlevel.2` feature XML を追加。
- `platform/system/apex` `117f34be6322c6a608a1c3e06f1d03ec32da60b3`
  - subject: `Move feature under the sysconfig folder to make it accessible by the device.`
  - patch level XML を `sysconfig` 配下へ移動。

OSV JSON には branch 別に `platform/build` と `platform/system/apex` の fix も載る。`platform/build` の公開コミット `a89e1ec183c96413380b5e2db37581b7031d04ea` は `apexd.mainline_patch_level_2` を `PRODUCT_PACKAGES` に追加する補助変更。OSV に載っている Android 16 用の一部ハッシュ `43dd1249...`, `b9c9fb3d...`, `9c3d1d96...`, `de6947a...` は調査時点の public Gitiles では `NOT_FOUND` だったため、ASB 直リンクの公開 cherrypick を主証跡にした。

## パッチ差分の要点

脆弱な親コミットでは `VerifyNoOverlapInSessions()` が全セッションを走査し、セッション状態が `SessionState::VERIFIED` なら即エラーにしていた。

```cpp
// We don't want to install/stage while another session is being staged.
if (session.GetState() == SessionState::VERIFIED) {
  return Error() << "Session " << session.GetId() << " is being staged.";
}
```

修正コミット `13bbfe3e...` はこのブロックを削除した。残ったチェックは `SessionState::STAGED` の既存セッションに対して、同じ APEX package name が含まれている場合だけ `"already staged"` として拒否するもの。

同じ変更は `VerifyPackagesStagedInstall()` と `VerifyPackageNonStagedInstall()` のコメントにも現れており、以前は「同じパッケージが staged 済み、または別セッションが being staged なら拒否」だった説明から、後者が削除されている。

テストでも、次の 2 つの拒否期待が削除された。

- `RejectStagingIfAnotherSessionIsBeingStaged`
- `RejectInstallIfAnotherSessionIsBeingStaged`

どちらも、1 つ目の staged session を `SubmitStagedSession()` した後に `MarkStagedSessionReady()` を呼ばず、別 APEX の staging/install が `"being staged"` で失敗することを期待していた。つまり削除されたテスト自体が、修正前の問題条件を再現している。

## 脆弱性が起きる状況

`SubmitStagedSession()` の状態遷移コメントでは、staged APEX セッションは次の流れになっている。

```text
SubmitStagedSession -> VERIFIED
MarkStagedSessionReady -> STAGED
reboot / ActivateStagedSessions -> ACTIVATED
```

`SubmitStagedSession()` は APEX ファイル検証後、apexd 独自のセッションを作成し、APEX 名や hash などを保存して `SessionState::VERIFIED` として commit する。その後、PackageInstaller 側から `MarkStagedSessionReady()` が来ると `STAGED` に進む。コミットメッセージには「SubmitStagedSession で始まり、MarkStagedSessionReady または AbortStagedSession で終わる」「しかし submitted されたが finished していないセッションが存在し得る」「結果として further installs が無効化される」と明記されている。

修正前はこの未完了 `VERIFIED` セッションを no-overlap 判定が全 install の拒否条件にしていたため、別名の APEX パッケージでも更新できない。`InstallPackage()` を通る non-staged install も同じ `VerifyNoOverlapInSessions(Single(apex_file), sessions)` を呼ぶため、staged install だけでなく通常の APEX install も巻き込まれる。

セキュリティ上の意味は「APEX/Mainline セキュリティ更新を止められる」こと。任意コード実行やメモリ破壊ではなく、更新機構の状態管理ミスによってセキュリティパッチ適用を妨害できるロジックバグである。

## 修正の性質

修正は暫定緩和に近い。コミットメッセージに `Until we have a proper fix for this, let's loosen the check.` とあり、理想的には `VERIFIED` セッションが残る原因や lifecycle の回復処理を直すべきだが、セキュリティ更新を止めないために no-overlap の条件を緩めている。

`STAGED` の同一 APEX パッケージ拒否は残っているため、同一 APEX の競合更新を防ぐ目的は維持されている。一方で、別パッケージの更新は `VERIFIED` セッションの存在だけでは止めなくなった。

`patchlevel/com.google.android.mainline.patchlevel.2.xml` と `platform/build` の `apexd.mainline_patch_level_2` 追加は、修正済み Mainline patch level を device から認識可能にするための付帯変更と判断した。実際の脆弱ロジック修正は `13bbfe3e...` / `e8474ce3f...` 系列。

## 調査メモ

- `cve.md` は 2026-06-01 bulletin を指す。検索結果には 2025-11 bulletin を指す古いミラーや記事もあったが、今回保存した ASB 2026-06-01 HTML には `CVE-2025-48581` 行が存在し、`A-428945391` から `5a33fa4...`, `13bbfe3...`, `117f34b...` へリンクしている。
- OSV の detail は「`VerifyNoOverlapInSessions` で security updates を block できる logic error」と明示しており、差分と一致する。
- `13bbfe3e...` の commit message には公開 bug `424874098`, `425478146`, `433787201` が出ている。`433787201` は「apexd outage」および patch level 付与に関係している。
- ローカルにこの作業ディレクトリ配下の AOSP checkout は見当たらなかったため、Gitiles の公開ソースと diff を保存して解析した。Pixel 固有バイナリ解析は不要だった。

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

- `artifacts/ASB-A-428945391.json`: OSV JSON
- `artifacts/android-security-bulletin-2026-06-01.html`: 対象 bulletin
- `artifacts/android-security-bulletin-2025-11-01.html`: 参照確認用に保存した旧 bulletin
- `artifacts/nvd-CVE-2025-48581.html`: NVD ページ
- `artifacts/origin-patch-diffing-pipeline.html`: 指定された参考記事
- `artifacts/13bbfe3ef2953e9805d57d3219cc122e485ba90f.diff`: 本体修正 diff
- `artifacts/5a33fa4202cb5f06d7f02f3a2b8d13780d7cb3f5.diff`: patch level 追加 diff
- `artifacts/117f34be6322c6a608a1c3e06f1d03ec32da60b3.diff`: patch level sysconfig 移動 diff
- `artifacts/a89e1ec183c96413380b5e2db37581b7031d04ea.diff`: `platform/build` 側の PRODUCT_PACKAGES 追加 diff
- `artifacts/e8474ce3f0a27b9781b6eaf518520941a3820111.diff`: 同一ロジック修正の別 branch 公開 diff
- `artifacts/apexd.cpp.9921a737_to_13bb.diff`: 親コミットから修正コミットへの `apexd.cpp` diff
- `artifacts/apexd_test.cpp.9921a737_to_13bb.diff`: 親コミットから修正コミットへの test diff
- `artifacts/key-code-excerpts.txt`: 脆弱箇所、修正後、状態遷移、削除テストの抜粋
- `artifacts/commit-summary.tsv`: 解析対象コミット一覧
049 OK

CVE-2025-48612

049-ok-nfc-payment-default-key-injection-eop

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-429417453
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-48612 is listed in the Android Security Bulletin as a High severity EoP issue in System.

特定した具体的な脆弱性

脆弱性を特定できた。CVE-2025-48612 は Android Settings の NFC デフォルト決済アプリ選択画面 DefaultPaymentSettings#setDefaultKey() における key 文字列の不適切なパースが原因の EoP。Work profile 側のアプリが、決済サービスの ComponentName 文字列に空白とユーザー ID を注入できると、Settings は work profile の候補を選択したつもりで main user の Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT を更新し得る。

フォルダ名は 049-ok-nfc-payment-default-key-injection-eop としてよい。

原因

根本原因は、セキュリティ境界上の識別子を構造化データではなく空白区切り文字列として扱ったこと。

・ComponentName と userId を "<flattened component> <userId>" という ad-hoc 形式に連結していた。
・復元時に split(" ") で分解し、分割結果の 2 要素目を信頼して userId としていた。
・その key が実際に PaymentBackend#getPaymentAppInfos() で列挙された候補そのものか検証していなかった。
・user/profile 境界を表す userId が、backend object ではなく attacker-influenced な表示/選択 key から決まっていた。

どこから特定したか

解析した URL / commit: ・Android June 2026 Security Bulletin:
- https://source.android.com/docs/security/bulletin/2026/2026-06-01
・初回修正:
- https://android.googlesource.com/platform/packages/apps/Settings/+/aa744e8988f0e7b77a71087edd4d2546b58d2f24
- commit title: [nfc] Fix string injection in default payment app selector
- Bug: 429417453
・関連回帰修正:
- https://android.googles…

保存した付帯ファイル: ・artifacts/aa744e8988f0e7b77a71087edd4d2546b58d2f24.patch
・artifacts/aa744e8988f0e7b77a71087edd4d2546b58d2f24.commit.json
・artifacts/94c4cecfe4aff8e558bfc25054b60ee7cd9b11c4.patch
・artifacts/94c4cecfe4aff8e558bfc25054b60ee7cd9b11c4.commit.json
・artifacts/f2babe193c762ee4ee1b03a77e55d4a4acb1f3b0.patch
・artifacts/f2babe193c762ee4ee1b03a77e55d4a4acb1f3b0.commi…

URL:…

validated.md を表示
# CVE-2025-48612 検証メモ

## 結論

脆弱性を特定できた。CVE-2025-48612 は Android Settings の NFC デフォルト決済アプリ選択画面 `DefaultPaymentSettings#setDefaultKey()` における key 文字列の不適切なパースが原因の EoP。Work profile 側のアプリが、決済サービスの `ComponentName` 文字列に空白とユーザー ID を注入できると、Settings は work profile の候補を選択したつもりで main user の `Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT` を更新し得る。

フォルダ名は `049-ok-nfc-payment-default-key-injection-eop` としてよい。

## 基本情報

- CVE: `CVE-2025-48612`
- Android bug: `A-429417453`
- Component: `System`
- Type / Severity: `EoP` / `High`
- Bulletin: `https://source.android.com/docs/security/bulletin/2026/2026-06-01`
- Bulletin 記載バージョン: Android `14, 15, 16, 16-qpr2`
- 2026-06 Bulletin の System 節では「local escalation of privilege / no additional execution privileges / user interaction is not needed」と説明されている。
- 公開 CVE 系データベースでは、`DefaultPaymentSettings.java` の `setDefaultKey` において work profile のアプリが main user のデフォルト NFC payment 設定を変更できる、原因は improper input validation と説明されている。

## 解析した URL / commit

- Android June 2026 Security Bulletin:
  - `https://source.android.com/docs/security/bulletin/2026/2026-06-01`
- 初回修正:
  - `https://android.googlesource.com/platform/packages/apps/Settings/+/aa744e8988f0e7b77a71087edd4d2546b58d2f24`
  - commit title: `[nfc] Fix string injection in default payment app selector`
  - Bug: `429417453`
- 関連回帰修正:
  - `https://android.googlesource.com/platform/packages/apps/Settings/+/94c4cecfe4aff8e558bfc25054b60ee7cd9b11c4`
  - commit title: `[nfc] Fix default payment app selection`
  - Bug: `462013908`
- revert:
  - `https://android.googlesource.com/platform/packages/apps/Settings/+/f2babe193c762ee4ee1b03a77e55d4a4acb1f3b0`
- reland:
  - `https://android.googlesource.com/platform/packages/apps/Settings/+/46ddb9d440cad942163700985242d2206f29cc40`
- December 2025 Bulletin の履歴:
  - `https://source.android.com/docs/security/bulletin/2025-12-01`
  - 2026-02-10 更新で CVE-2025-48612 / A-429417453 は「contactless payments の default payment app 切替を制限する可能性がある regression」のため 2025-12 bulletin から削除され、後続 bulletin で更新版が必要とされた。

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

- `artifacts/aa744e8988f0e7b77a71087edd4d2546b58d2f24.patch`
- `artifacts/aa744e8988f0e7b77a71087edd4d2546b58d2f24.commit.json`
- `artifacts/94c4cecfe4aff8e558bfc25054b60ee7cd9b11c4.patch`
- `artifacts/94c4cecfe4aff8e558bfc25054b60ee7cd9b11c4.commit.json`
- `artifacts/f2babe193c762ee4ee1b03a77e55d4a4acb1f3b0.patch`
- `artifacts/f2babe193c762ee4ee1b03a77e55d4a4acb1f3b0.commit.json`
- `artifacts/46ddb9d440cad942163700985242d2206f29cc40.patch`
- `artifacts/46ddb9d440cad942163700985242d2206f29cc40.commit.json`
- `artifacts/src-83447688f8e3e8f009f1e7d275a14ea00ee7953a/`
  - 修正前の `DefaultPaymentSettings.java`, `PaymentBackend.java`, `RadioButtonPickerFragment.java`
- `artifacts/src-aa744e8988f0e7b77a71087edd4d2546b58d2f24/`
  - 初回修正後ソース
- `artifacts/src-94c4cecfe4aff8e558bfc25054b60ee7cd9b11c4/`
  - 回帰修正後ソース
- `artifacts/framework/PackageParser.java.master.java`
- `artifacts/framework/FrameworkParsingPackageUtils.java.master.java`
- `artifacts/patch-analysis-notes.md`

## 脆弱なコードパス

修正前の `DefaultPaymentSettings` は候補ごとの key を次のように生成していた。

```java
return mKey + " " + mUserId;
```

ここで `mKey` は `appInfo.componentName.flattenToString()`、`mUserId` はその payment service が属する user/profile ID である。

選択時の `setDefaultKey()` は key を空白で分割していた。

```java
String[] keys = key.split(" ");
if (keys.length >= 2) {
    mPaymentBackend.setDefaultPaymentApp(ComponentName.unflattenFromString(keys[0]),
            Integer.parseInt(keys[1]));
}
```

この処理は「`flattenToString()` した ComponentName には空白が含まれない」という前提に依存している。しかし Settings 側では、候補一覧から得た backend object と照合せず、UI preference key 文字列を信頼して `ComponentName` と `userId` に再解釈していた。

攻撃例を単純化すると、work profile の payment service 由来の key が次のように組み立てられる状況が問題になる。

```text
com.attacker/.PayService 0 10
```

本来末尾の `10` が work profile の userId だが、`split(" ")` 後の `keys[1]` は `0` になる。その結果、`setDefaultPaymentApp(..., 0)` が呼ばれ、main user 側のデフォルト NFC payment 設定を更新できる。

`PaymentBackend#setDefaultPaymentApp(ComponentName app, int userId)` は current user の enabled profiles を走査し、指定された `userId` に対して `Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT` を `putStringForUser()` で書き、他 profile 側は `null` にする。したがって、userId 注入が成立すると work profile の選択 UI/候補を起点に main user の secure setting が変更される。

## 根本原因

根本原因は、セキュリティ境界上の識別子を構造化データではなく空白区切り文字列として扱ったこと。

- `ComponentName` と `userId` を `"<flattened component> <userId>"` という ad-hoc 形式に連結していた。
- 復元時に `split(" ")` で分解し、分割結果の 2 要素目を信頼して userId としていた。
- その key が実際に `PaymentBackend#getPaymentAppInfos()` で列挙された候補そのものか検証していなかった。
- user/profile 境界を表す `userId` が、backend object ではなく attacker-influenced な表示/選択 key から決まっていた。

## パッチ内容

初回修正 `aa744e...` は次の変更を入れている。

- `mAppInfos` を `List<PaymentAppInfo>` から `Map<String, PaymentAppInfo>` に変更。
- `PaymentAppInfo#getKey()` を追加し、`componentName` と `userHandle` の `Objects.hash()` から opaque key を作る。
- `getDefaultKey()` は `defaultAppInfo.getKey()` を返す。
- `setDefaultKey(String key)` は `mAppInfos.get(key)` で既存候補を引き、見つかった `PaymentAppInfo` の `componentName` と `userHandle.getIdentifier()` を使って `setDefaultPaymentApp()` を呼ぶ。

これにより、ユーザー ID は key 文字列から parse されず、Settings が列挙済みの `PaymentAppInfo.userHandle` から取得される。未知 key の場合も `setDefaultPaymentApp()` を呼ばないため、文字列注入で任意 userId を渡す経路がなくなる。

## 回帰と再修正で分かったこと

最初のパッチには機能回帰があった。`PaymentAppInfo#getKey()` を導入した一方で、候補行 `NfcPaymentCandidateInfo` の key 生成はまだ `componentName + " " + userId` の形式に残っていた。そのため UI で選択された key が `mAppInfos` の hash key と一致せず、default payment app の切替が失敗し得た。

このため `f2babe...` で一度 revert され、December 2025 Bulletin でも CVE-2025-48612 は「regression の可能性」のため削除された。その後 `94c4...` が `NfcPaymentCandidateInfo` に渡す key を `appInfo.getKey()` に変更し、`NfcPaymentCandidateInfo#getKey()` も `mKey` をそのまま返すようにした。最終的に `46ddb...` で security fix が reland されている。

この経緯は、security fix 自体は正しいが、既存 UI の candidate key と backend key の整合を同時に直す必要があったことを示している。

## ok 判定理由

ソースコード差分から、脆弱関数、入力の信頼境界、userId 注入の成立条件、main user 設定変更に到達する sink、修正後に経路が消える理由を説明できる。CVE 公開説明、Bulletin の参照 commit、commit message の `[nfc] Fix string injection in default payment app selector` とも一致するため `ok` と判断した。
050 OK

CVE-2026-0045

050-ok-rfcomm-temp-bond-auth-direction-bypass

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-380091558
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0045 is listed in the Android Security Bulletin as a High severity EoP issue in System.

特定した具体的な脆弱性

特定できた。CVE-2026-0045 は platform/packages/modules/Bluetooth の Classic Bluetooth RFCOMM security check にあるロジックエラーで、一時ボンド (BOND_TYPE_TEMPORARY) の相手が secure RFCOMM service にアクセスする場面で、必要な persistent bonding への昇格判定が接続方向を正しく見ていなかった。

修正前の btm_sec_is_upgrade_possible() は、temp bond からの security upgrade 条件として BTM_SEC_OUT_AUTHENTICATE だけを見ていた。つまり incoming / acceptor 側の secure RFCOMM で BTM_SEC_IN_AUTHENTICATE が要求されるケースでは、既存の一時リンクキーを「昇格可能」と判定できず、後続の security procedure が正しく bonding を開始しない。この結果、secure connection が期待する bonding を迂回できる。

原因

根本原因は、Classic Bluetooth security record の direction-specific bit を抽象化せず、outgoing 用の BTM_SEC_OUT_AUTHENTICATE を incoming path でも暗黙に使っていたこと。

sec_rec.security_required は BTM_SEC_OUT_* と BTM_SEC_IN_* の両方を保持する。btm_sec_is_upgrade_possible() には is_originator が渡されており、MITM 判定ではすでに is_originator ? BTM_SEC_OUT_MITM : BTM_SEC_IN_MITM を使っていた。一方で、temp bond + authentication required の新規判定だけが BTM_SEC_OUT_AUTHENTICATE 固定で追加されていた。この不整合により、incoming secure service で必要な bonding upgrade が欠落した。

どこから特定したか

解析した修正コミット: OSV JSON は fix として次の3コミットを列挙している。

パッチ差分の要点: bta_jv_rfcomm_connect() は Java/アプリ側の secure RFCOMM client socket 接続から呼ばれる RFCOMM client 作成処理で、修正前は接続前に BTM_SetSecurityLevel(true, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX, sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0) を呼んでいた。

保存した付帯ファイル: ・artifacts/ASB-A-380091558.json: Android OSV JSON
・artifacts/android-security-bulletin-2026-06-01.html: 対象 bulletin
・artifacts/nvd-CVE-2026-0045.html: NVD HTML
・artifacts/origin-patch-diffing-pipeline.html: 指定された参考記事
・artifacts/commit-summary.tsv: 解析対象コミット一覧
・artifacts/2ad8e1e0e0e5adae3abcbab34b9e36eda4a2e36f.patch: ASB直リンクのbackportパッチ
・artifacts/dc64fbcebd…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01` / https://android.googlesource.…

validated.md を表示
# CVE-2026-0045 / A-380091558 パッチ解析

## 結論

特定できた。CVE-2026-0045 は `platform/packages/modules/Bluetooth` の Classic Bluetooth RFCOMM security check にあるロジックエラーで、一時ボンド (`BOND_TYPE_TEMPORARY`) の相手が secure RFCOMM service にアクセスする場面で、必要な persistent bonding への昇格判定が接続方向を正しく見ていなかった。

修正前の `btm_sec_is_upgrade_possible()` は、temp bond からの security upgrade 条件として `BTM_SEC_OUT_AUTHENTICATE` だけを見ていた。つまり incoming / acceptor 側の secure RFCOMM で `BTM_SEC_IN_AUTHENTICATE` が要求されるケースでは、既存の一時リンクキーを「昇格可能」と判定できず、後続の security procedure が正しく bonding を開始しない。この結果、secure connection が期待する bonding を迂回できる。

根本原因は、`sec_rec.security_required` が outgoing 用と incoming 用の別ビットを持つにもかかわらず、temp bond から persistent bond へ昇格させる判定で接続方向 (`is_originator`) を考慮していなかったこと。修正は `is_originator ? BTM_SEC_OUT_AUTHENTICATE : BTM_SEC_IN_AUTHENTICATE` を使い、方向に対応する authentication 要求があり、かつ現在が temp bond なら upgrade possible として再ペアリング/ボンディングへ進める。

同じ修正系列には、outgoing secure RFCOMM connect が `"RFC_MUX"` の service record に `sec_mask` をグローバルに設定してしまい、その後の incoming RFCOMM MUX connection まで bonding 要求を引きずる問題の修正も含まれる。コミットタイトルはこの副作用 (`RFCOMM MUX connection request must not start bonding`) を強調しているが、OSV/NVD の CVE説明が指す bonding bypass の中核は `btm_sec_is_upgrade_possible()` の方向別判定修正で説明できる。

## 対象情報

- CVE: `CVE-2026-0045`
- Android bug/reference: `A-380091558`
- Component: `System`
- Subcomponent/package: `platform/packages/modules/Bluetooth`
- 種別: `EoP`
- 重大度: `High`
- 影響バージョン: Android 14, 15, 16, 16-qpr2
- bulletin URL: `https://source.android.com/docs/security/bulletin/2026/2026-06-01`
- ASB行の公開修正: `https://android.googlesource.com/platform/packages/modules/Bluetooth/+/2ad8e1e0e0e5adae3abcbab34b9e36eda4a2e36f`
- OSV: `https://storage.googleapis.com/android-osv/ASB-A-380091558.json`
- NVD: `https://nvd.nist.gov/vuln/detail/CVE-2026-0045`

## 解析した修正コミット

OSV JSON は fix として次の3コミットを列挙している。

- `dc64fbcebd089d82075ca5c26144ba3933189198`
  - subject: `Upgrade security If it is on temp bonding & authentication is requirement`
  - `btm_sec_is_upgrade_possible()` に temp bond + authentication required なら upgrade possible とする処理を追加。
  - ただしこの初期修正は `BTM_SEC_OUT_AUTHENTICATE` 固定で、incoming 側を扱えていない。
- `3cce3201a64ebe5806fa0842ea0475ee68ed8910`
  - subject: `RFCOMM MUX connection request must not start bonding`
  - `bta_jv_rfcomm_connect()` の `"RFC_MUX"` に対するグローバル `BTM_SetSecurityLevel()` を flag 有効時に抑止。
  - `btm_sec_is_upgrade_possible()` を `OUT_AUTHENTICATE || IN_AUTHENTICATE` から、接続方向に応じた片側ビットへ修正。
- `b779276319f462e9a1f61e97375d78c219188813`
  - subject: `Flag removal : upgrade_temp_bonding_on_auth_req`
  - flag を削除し、方向別 bonding upgrade 判定を恒久化。

ASB 2026-06-01 から直接リンクされる Android 14/15/16/16-qpr2 用 cherrypick は次。

- `2ad8e1e0e0e5adae3abcbab34b9e36eda4a2e36f`
  - subject: `RFCOMM MUX connection request must not start bonding`
  - parent: `ab906156f47eaead385190502647fe508229dfbf`
  - `3cce...` 系の修正と flag removal をまとめた backport。
  - `Bug: 380091558` を含むため、今回の主証跡にした。

## パッチ差分の要点

`bta_jv_rfcomm_connect()` は Java/アプリ側の secure RFCOMM client socket 接続から呼ばれる RFCOMM client 作成処理で、修正前は接続前に `BTM_SetSecurityLevel(true, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX, sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0)` を呼んでいた。

この呼び出しは、outgoing secure socket の `sec_mask` を RFCOMM MUX の security service record に登録する。コミットメッセージによると、この security requirement は outgoing insecure socket 接続時にしかリセットされず、以後の incoming RFCOMM MUX connection にも bonding requirement が残ってしまう。修正後はこの `BTM_SetSecurityLevel()` 呼び出しを削除し、実際の RFCOMM connection 作成時に `RFCOMM_CreateConnectionWithSecurity(..., sec_mask, cfg)` へ渡すだけにしている。

よりCVE説明に直結する変更は `system/stack/btm/btm_sec.cc` の `btm_sec_is_upgrade_possible()` である。修正前の Android 14/15/16 系 backport parent では次の条件だった。

```cpp
if (com::android::bluetooth::flags::upgrade_temp_bonding_on_auth_req() &&
    (p_dev_rec->sec_rec.security_required & BTM_SEC_OUT_AUTHENTICATE) &&
    p_dev_rec->sec_rec.is_bond_type_temporary()) {
  is_possible = true;
}
```

修正後は次のように接続方向で確認するビットを切り替える。

```cpp
if ((p_dev_rec->sec_rec.security_required &
     (is_originator ? BTM_SEC_OUT_AUTHENTICATE : BTM_SEC_IN_AUTHENTICATE)) &&
    p_dev_rec->sec_rec.is_bond_type_temporary()) {
  is_possible = true;
}
```

`btm_sec_mx_access_request()` では pairing 中または既存リンクキーありのケースで `!btm_sec_is_upgrade_possible(p_dev_rec, is_originator)` が legacy/no-upgrade 経路に入る条件として使われる。さらに同じ関数内には `access_secure_service_from_temp_bond()` があり、`!locally_initiated && (security_req & BTM_SEC_IN_AUTHENTICATE) && is_bond_type_temporary()` なら secure RFCOMM service への temp bond アクセスとして拒否/再処理対象にする。したがって incoming secure RFCOMM では `BTM_SEC_IN_AUTHENTICATE` を見て upgrade possible と判断する必要がある。

## 脆弱性が起きる状況

攻撃・再現条件は次のように整理できる。

- 攻撃者側Bluetooth deviceとAndroid端末の間に、永続ボンドではない一時リンクキー/temp bond が存在する。
- Android側で secure RFCOMM server socket / secure RFCOMM service が待ち受けており、incoming 側の security requirement として `BTM_SEC_IN_AUTHENTICATE` が必要になる。
- 攻撃者が incoming RFCOMM connection を開始する。
- 修正前の `btm_sec_is_upgrade_possible()` は temp bond の昇格条件として `BTM_SEC_OUT_AUTHENTICATE` だけを確認するため、incoming secure service の `BTM_SEC_IN_AUTHENTICATE` 要求を見落とす。
- その結果、secure service へ入る前に persistent bonding へ昇格させるべきところで security upgrade が走らず、bonding requirement を迂回できる。

NVD/OSV の説明は「`bta_jv_rfcomm_connect` において、コードのロジックエラーにより secure connection の bonding bypass があり得る。追加権限不要、ユーザー操作不要の local EoP」としている。`bta_jv_rfcomm_connect()` の outgoing RFCOMM MUX service record 汚染と、`btm_sec_is_upgrade_possible()` の方向別 authentication 判定漏れは同じ修正系列で、後者が bonding bypass の直接条件になる。

## 根本原因

根本原因は、Classic Bluetooth security record の direction-specific bit を抽象化せず、outgoing 用の `BTM_SEC_OUT_AUTHENTICATE` を incoming path でも暗黙に使っていたこと。

`sec_rec.security_required` は `BTM_SEC_OUT_*` と `BTM_SEC_IN_*` の両方を保持する。`btm_sec_is_upgrade_possible()` には `is_originator` が渡されており、MITM 判定ではすでに `is_originator ? BTM_SEC_OUT_MITM : BTM_SEC_IN_MITM` を使っていた。一方で、temp bond + authentication required の新規判定だけが `BTM_SEC_OUT_AUTHENTICATE` 固定で追加されていた。この不整合により、incoming secure service で必要な bonding upgrade が欠落した。

加えて、`bta_jv_rfcomm_connect()` が `"RFC_MUX"` の service record を outgoing secure socket の都度上書きしていたため、方向や接続単位の要求をグローバルなRFCOMM MUX状態に漏らしていた。これは「incoming RFCOMM MUX request が bonding を開始してしまう」副作用であり、同じ設計ミス、つまり接続単位・方向単位の security requirement を共有状態に混ぜていたことの別の現れと見てよい。

## 修正の妥当性

修正後は、temp bond からの security upgrade 判定が接続方向に合った authentication bit を見るため、outgoing secure RFCOMM では `BTM_SEC_OUT_AUTHENTICATE`、incoming secure RFCOMM では `BTM_SEC_IN_AUTHENTICATE` によって再ペアリング/ボンディングへ進める。

また `bta_jv_rfcomm_connect()` から RFCOMM MUX service record への `BTM_SetSecurityLevel()` が削除されたことで、outgoing secure socket の要求が後続の incoming MUX connection に残留しなくなる。secure connection 自体の `sec_mask` は `RFCOMM_CreateConnectionWithSecurity()` に渡され続けるため、接続単位の要求は保持される。

## 調査メモ

- `cve.md` の `A-380091558` は ASB 2026-06-01 HTML で `CVE-2026-0045` 行から `2ad8e1e0...` へリンクされている。
- OSV JSON の Vanir signature は `system/bta/jv/bta_jv_act.cc` の `bta_jv_rfcomm_connect` と、`system/stack/btm/btm_sec.cc` の `btm_sec_is_upgrade_possible` / `security_upgrade_possible` を指している。
- NVD HTML は直接取得時に最初403だったが、User-Agent付きで保存できた。説明文はOSVの `details` と同じ。
- コミットタイトルだけ読むと「incoming RFCOMM が bonding を開始してしまうDoS/UX問題」に見えるが、CVEのEoP説明は「secure connection の bonding bypass」。差分を追うと、同じ修正系列で「グローバルRFC_MUX security requirementの残留」と「temp bond upgrade判定の方向混同」を同時に直していることが分かる。
- `BTM_SetSecurityLevel()` 直前コメントに `MTIM protection` とあるが、文脈上は `MITM protection` のtypoと思われる。このtypo自体は修正対象ではない。
- Pixel固有バイナリ解析は不要。対象はAOSP公開ソースの `packages/modules/Bluetooth`。

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

- `artifacts/ASB-A-380091558.json`: Android OSV JSON
- `artifacts/android-security-bulletin-2026-06-01.html`: 対象 bulletin
- `artifacts/nvd-CVE-2026-0045.html`: NVD HTML
- `artifacts/origin-patch-diffing-pipeline.html`: 指定された参考記事
- `artifacts/commit-summary.tsv`: 解析対象コミット一覧
- `artifacts/2ad8e1e0e0e5adae3abcbab34b9e36eda4a2e36f.patch`: ASB直リンクのbackportパッチ
- `artifacts/dc64fbcebd089d82075ca5c26144ba3933189198.patch`: temp bond upgrade初期修正
- `artifacts/3cce3201a64ebe5806fa0842ea0475ee68ed8910.patch`: RFCOMM MUX contamination / direction check修正
- `artifacts/b779276319f462e9a1f61e97375d78c219188813.patch`: flag removal
- `artifacts/*commit.json`: 各Gitiles commit JSON
- `artifacts/before_2ad_bta_jv_act.cc` / `artifacts/after_2ad_bta_jv_act.cc`: ASB直リンク前後の `bta_jv_act.cc`
- `artifacts/before_2ad_btm_sec.cc` / `artifacts/after_2ad_btm_sec.cc`: ASB直リンク前後の `btm_sec.cc`
- `artifacts/before_3cce_bta_jv_act.cc` / `artifacts/after_3cce_bta_jv_act.cc`: upstream修正前後の `bta_jv_act.cc`
- `artifacts/before_3cce_btm_sec.cc` / `artifacts/after_3cce_btm_sec.cc`: upstream修正前後の `btm_sec.cc`
- `artifacts/key-code-excerpts.txt`: 行番号付きの重要コード抜粋
051 OK

CVE-2026-0075

051-ok-contactsprovider-json-sqlite-exception-oracle

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-465133716
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0075 is listed in the Android Security Bulletin as a High severity EoP issue in System.

特定した具体的な脆弱性

判定: ok

CVE-2026-0075 は ContactsProvider2 (CP2, packages/providers/ContactsProvider) の SQL 例外メッセージ漏えいによる side-channel 型の権限昇格/情報取得問題だった。READ_CONTACTS を持たない呼び出し元でも、ContactsProvider の query() などに渡す selection / sortOrder / 書き込み系の selection に SQLite JSON1 関数を含む式を混ぜ、SQLite が返す JSON 関連の実行時例外メッセージの有無を観測できた。

実質的には SQL injection で任意の SELECT を実行する問題ではなく、Provider が許可している SQL 断片と SQLite の遅延評価・詳細な例外文字列を組み合わせた boolean oracle である。秘密データに依存する条件式が真のときだけ json_extract('not json', '$.x') のような malformed JSON 例外を発生させることで、戻り値では読めない Contacts DB 内の値を 1 bit ずつ推測できる。

原因

根本原因は、ContactsProvider が外部アプリから受け取る SQL 断片を完全な安全な DSL に変換せず、SQLite の式評価機能を残したまま、SQLite の詳細な実行時例外を呼び出し元へ返していたこと。

具体的には以下が重なっている。

どこから特定したか

公開情報: ・Bulletin: Android Security Bulletin 2026-06-01
・URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
・CVE: CVE-2026-0075
・Android bug: A-465133716
・Component: System
・Type: EoP
・Severity: High
・Updated AOSP versions: 14, 15, 16, 16-qpr2
・公開修正 commit: bb9f36b3ff6d42136afb61d527e1e8f67242fe32
・commit URL: https://android.googlesource.com/pl…

解析したファイル: ・artifacts/bb9f36b3.patch: 公開 commit の patch
・artifacts/ContactsProvider2_before.java: 修正前 ContactsProvider2.java
・artifacts/ContactsProvider2_after.java: 修正後 ContactsProvider2.java
・artifacts/ContactsDatabaseHelper_before.java: 修正前 SQL 検証ロジック
・artifacts/SqlChecker_before.java: SQL tokenizer / checker
・artifacts/commit_bb9f36b3_metadata.txt: commit metadata…

パッチ差分: 修正 commit は…

validated.md を表示
# CVE-2026-0075 検証メモ

## 結論

判定: ok

CVE-2026-0075 は ContactsProvider2 (CP2, `packages/providers/ContactsProvider`) の SQL 例外メッセージ漏えいによる side-channel 型の権限昇格/情報取得問題だった。`READ_CONTACTS` を持たない呼び出し元でも、ContactsProvider の `query()` などに渡す `selection` / `sortOrder` / 書き込み系の `selection` に SQLite JSON1 関数を含む式を混ぜ、SQLite が返す JSON 関連の実行時例外メッセージの有無を観測できた。

実質的には SQL injection で任意の `SELECT` を実行する問題ではなく、Provider が許可している SQL 断片と SQLite の遅延評価・詳細な例外文字列を組み合わせた boolean oracle である。秘密データに依存する条件式が真のときだけ `json_extract('not json', '$.x')` のような malformed JSON 例外を発生させることで、戻り値では読めない Contacts DB 内の値を 1 bit ずつ推測できる。

## 公開情報

- Bulletin: Android Security Bulletin 2026-06-01
- URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- CVE: CVE-2026-0075
- Android bug: A-465133716
- Component: System
- Type: EoP
- Severity: High
- Updated AOSP versions: 14, 15, 16, 16-qpr2
- 公開修正 commit: `bb9f36b3ff6d42136afb61d527e1e8f67242fe32`
- commit URL: https://android.googlesource.com/platform/packages/providers/ContactsProvider/+/bb9f36b3ff6d42136afb61d527e1e8f67242fe32

## 解析したファイル

- `artifacts/bb9f36b3.patch`: 公開 commit の patch
- `artifacts/ContactsProvider2_before.java`: 修正前 `ContactsProvider2.java`
- `artifacts/ContactsProvider2_after.java`: 修正後 `ContactsProvider2.java`
- `artifacts/ContactsDatabaseHelper_before.java`: 修正前 SQL 検証ロジック
- `artifacts/SqlChecker_before.java`: SQL tokenizer / checker
- `artifacts/commit_bb9f36b3_metadata.txt`: commit metadata
- `artifacts/related_commits_side_channel_cp2.txt`: 同一 Change-Id の関連 commit
- `artifacts/sqlite_json_oracle_demo.txt`: ローカル SQLite で確認した JSON 例外 oracle の最小再現

AOSP mirror は `../binaries/ContactsProvider.git` に bare clone として保存した。

## パッチ差分

修正 commit は `ContactsProvider2.java` のみを変更している。追加された中心ロジックは `maybeStripAndThrowSQLiteExceptionWithJson(Exception e, String permission, LogFields.Builder logBuilder)` で、以下の条件を満たす例外を `"Stripped exception message"` に置き換える。

- 例外が `SQLiteException`
- 呼び出し元が対象権限を持たない
- 例外メッセージに大文字小文字無視で `json` が含まれる

適用箇所は `insert()` / `update()` / `delete()` / `query()` の catch 節。`query()` ではさらに `cursor.getCount()` を `try` ブロック内に移動している。これは SQLite の実行時例外が `qb.query()` の返却時ではなく Cursor 消費時に発生し得るためで、修正前は `finally` のログ処理側で `getCount()` していたため catch 節で strip できなかった。

権限は読み取り query では `READ_CONTACTS`、書き込み系では `WRITE_CONTACTS` を見る。コメント上も `checkCallingPermission()` を意図的に使っており、非 Binder thread や identity clear 後の self-call で「自分自身の権限」によって詳細エラーを許してしまうことを避けている。

## 根本原因

根本原因は、ContactsProvider が外部アプリから受け取る SQL 断片を完全な安全な DSL に変換せず、SQLite の式評価機能を残したまま、SQLite の詳細な実行時例外を呼び出し元へ返していたこと。

具体的には以下が重なっている。

- `ContactsDatabaseHelper.DISALLOW_SUB_QUERIES` は修正前で `false`。
- `validateSql()` は `SqlChecker.ensureNoInvalidTokens()` を呼ぶだけで、関数呼び出しや `CASE WHEN` のような式構文を禁止しない。
- `SqlChecker` はトークン列を走査して禁止トークンや `x_` private prefix、セミコロン等を見る実装で、`json_extract(...)` 自体は SQL 関数トークンとして通過し得る。
- `SQLiteQueryBuilder.setStrict(true)` は projection map などの制約には有効だが、許可された selection/sortOrder 式の実行時副作用、特に JSON1 関数の詳細エラーまでは隠さない。
- 修正前の `query()` は Cursor を返す前に実行時例外を十分に捕捉せず、Cursor 消費時の `SQLiteException` が詳細メッセージごと呼び出し側に出る。

## 脆弱性の成り立ち

攻撃者は ContactsProvider に対して通常の `ContentResolver.query()` を実行する。`READ_CONTACTS` がなくても、URI によっては空 Cursor、限定結果、または権限チェック前後の実行経路があり、重要なのは「DB の式が評価され、SQLite 例外の有無または内容が呼び出し元で観測できる」点である。

典型的な oracle は次の形になる。

```sql
CASE
  WHEN <contacts DB 内の秘密に依存する条件>
  THEN json_extract('not json', '$.a')
  ELSE 1
END
```

ローカル SQLite で確認した結果:

- `json_extract('not json', '$.a')` は `malformed JSON` を返す。
- 条件が真で malformed JSON 側が評価されると例外になる。
- 条件が偽で正常 JSON 側だけが評価されると正常終了する。

この性質により、例えば `substr(display_name,1,1)='A'` のような条件を変えながら問い合わせると、戻り値として連絡先を読めなくても、例外の有無から DB 内の文字列や行存在を推測できる。公開 commit message も「malformed queries」「side channel attacks」「return strings from SQLite exception」と説明しており、差分と一致する。

## 修正内容の意味

修正は SQL パーサを強化して JSON 関数を禁止するのではなく、`json` を含む `SQLiteException` のメッセージを、該当 Contacts 権限を持たない呼び出し元にだけ隠すものだった。`READ_CONTACTS` を持つ呼び出し元には詳細メッセージを維持している。commit message の理由どおり、`READ_CONTACTS` を持つアプリは Contacts DB を読めるため、この side channel が新しい情報境界を越えないからである。

興味深い点は、修正が `query()` だけでなく `insert/update/delete` にも入っていること。書き込み系でも selection や ContentValues key に由来する SQLite 例外が発生し得るため、`WRITE_CONTACTS` を持たない呼び出し元に対して JSON 例外文字列を隠している。

## ok 判定理由

公開ソースコードと patch から、脆弱性の場所、攻撃に必要な入力面、漏えい primitive、修正の意図を説明できる。特に `query()` の `cursor.getCount()` 移動により、問題が単なるログ整形ではなく Cursor 遅延評価時の SQLite 例外捕捉であることも確認できた。

PoC APK や実機検証は実施していないが、AOSP ソースと SQLite JSON1 の挙動から、脆弱性が起きる状況は十分に説明可能と判断した。
052 OK

CVE-2026-0086

052-ok-disable-supervision-callingpackage-null

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityHigh
Updated AOSP versions16-qpr2
ReferencesA-476417007
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0086 is listed in the Android Security Bulletin as a High severity EoP issue in System.

特定した具体的な脆弱性

脆弱性は特定できた。packages/apps/Settings の DisableSupervisionActivity が exported activity として外部から起動可能であるにもかかわらず、認可判定で Activity.getCallingPackage() が null になり得ることを拒否していなかった。結果を要求しない通常の startActivity() で起動すると callingPackage == null になり、端末状態によっては「呼び出し元が正規の supervision app ではない」ことを検出できず、supervision の無効化と supervision data の削除処理へ進めた。

ok 判定にした理由は、公開 commit のソース差分、追加テスト、Android framework の getCallingPackage() の仕様、Settings manifest の exported 設定から、脆弱な条件と修正理由をソースコード上で説明できるため。

原因

根本原因は、呼び出し元 ID として Activity.getCallingPackage() を認可に使っているのに、null を「認証情報なし」として fail closed していなかったこと。

Android framework の Activity.java には、呼び出し元が result を期待していない、つまり startActivityForResult 系で起動していない場合、calling package は null になると明記されている。保存した artifacts/Activity_android16.java の該当箇所では、getCallingPackage() は「reply 先の package、なければ null」を返す API であり、任意の起動元を常に識別する API ではない。

そのため、外部 caller が startActivity() で DisableSupervisionActivity を起動すると、Settings 側では callingPackage == null と観測される。

どこから特定したか

パッチ差分の要点: 修正前の DisableSupervisionActivity.onCreate() は次の条件で不正 caller を拒否していた。

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://osv.dev/vulnerability/ASB-A-476417007 / https://android.googlesource.com/platform/packages/apps/Settings/+/f0922db8cc4c1cb515c8a2a580993aa061481f65 / https://android.googlesource.com/platform/packages/apps/Settings/+/ff671ddafc28d5e73bdfdbb9cc7826d441ff65c3

validated.md を表示
# CVE-2026-0086 検証結果

## 結論

脆弱性は特定できた。`packages/apps/Settings` の `DisableSupervisionActivity` が exported activity として外部から起動可能であるにもかかわらず、認可判定で `Activity.getCallingPackage()` が `null` になり得ることを拒否していなかった。結果を要求しない通常の `startActivity()` で起動すると `callingPackage == null` になり、端末状態によっては「呼び出し元が正規の supervision app ではない」ことを検出できず、supervision の無効化と supervision data の削除処理へ進めた。

ok 判定にした理由は、公開 commit のソース差分、追加テスト、Android framework の `getCallingPackage()` の仕様、Settings manifest の exported 設定から、脆弱な条件と修正理由をソースコード上で説明できるため。

## 基本情報

- CVE: CVE-2026-0086
- Android bug ID: A-476417007
- Component: System
- Subcomponent/package: `platform/packages/apps/Settings`
- Type/Severity: EoP / High
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Bulletin 上の対象: Android 16-qpr2
- OSV: https://osv.dev/vulnerability/ASB-A-476417007

## 参照した修正

- 17-next commit: `f0922db8cc4c1cb515c8a2a580993aa061481f65`
  - URL: https://android.googlesource.com/platform/packages/apps/Settings/+/f0922db8cc4c1cb515c8a2a580993aa061481f65
  - commit message: `Add null check to caller permission check in DisableSupervisionActivity.`
  - `Bug: 476417007`
- 16-qpr2 commit として OSV に記載されている commit: `ff671ddafc28d5e73bdfdbb9cc7826d441ff65c3`
  - URL: https://android.googlesource.com/platform/packages/apps/Settings/+/ff671ddafc28d5e73bdfdbb9cc7826d441ff65c3
  - 調査時点では android.googlesource.com から 404。ヘッダと raw 応答は `artifacts/ff671ddafc28d5e73bdfdbb9cc7826d441ff65c3.headers` と `artifacts/ff671ddafc28d5e73bdfdbb9cc7826d441ff65c3.raw` に保存した。

保存した主な付帯ファイル:

- `artifacts/ASB-A-476417007.json`
- `artifacts/f0922db8cc4c1cb515c8a2a580993aa061481f65.commit.json`
- `artifacts/f0922db8cc4c1cb515c8a2a580993aa061481f65.diff`
- `artifacts/src_pre/DisableSupervisionActivity.kt`
- `artifacts/src_post/DisableSupervisionActivity.kt`
- `artifacts/src_post/DisableSupervisionActivityTest.kt`
- `artifacts/src_pre/AndroidManifest.xml`
- `artifacts/src_post/AndroidManifest.xml`
- `artifacts/src_post/SupervisionHelper.kt`
- `artifacts/Activity_android16.java`
- `artifacts/attack_notes.md`

## パッチ差分の要点

修正前の `DisableSupervisionActivity.onCreate()` は次の条件で不正 caller を拒否していた。

```kotlin
val supervisionApps = supervisionRoleHolders
val devicePolicyManager = getSystemService(DevicePolicyManager::class.java)
val isAllowedProfileOwner = isCallingPackageSupervisionProfileOwner(devicePolicyManager)
if (
    callingPackage != systemSupervisionPackageName &&
        !supervisionApps.contains(callingPackage) &&
        !isAllowedProfileOwner
) {
    setResultAndFinish(RESULT_CANCELED)
    return
}
```

修正後は `isCallingPackageAllowed()` に分離され、最初に `callingPackage == null` を拒否する。

```kotlin
private fun isCallingPackageAllowed(supervisionApps: List<String>): Boolean {
    if (callingPackage == null) {
        return false
    }
    if (callingPackage == systemSupervisionPackageName ||
        supervisionApps.contains(callingPackage)) {
        return true
    }

    val devicePolicyManager = getSystemService(DevicePolicyManager::class.java)
    return isCallingPackageSupervisionProfileOwner(devicePolicyManager)
}
```

追加された robotest は `onCreate_callerNull_doesNotDisableSupervision()` で、`shadowActivity.setCallingPackage(null)` の場合に `SupervisionManager` へ触れず、role removal も呼ばず、`RESULT_CANCELED` で終了することを確認している。

## 根本原因

根本原因は、呼び出し元 ID として `Activity.getCallingPackage()` を認可に使っているのに、`null` を「認証情報なし」として fail closed していなかったこと。

Android framework の `Activity.java` には、呼び出し元が result を期待していない、つまり `startActivityForResult` 系で起動していない場合、calling package は `null` になると明記されている。保存した `artifacts/Activity_android16.java` の該当箇所では、`getCallingPackage()` は「reply 先の package、なければ null」を返す API であり、任意の起動元を常に識別する API ではない。

そのため、外部 caller が `startActivity()` で `DisableSupervisionActivity` を起動すると、Settings 側では `callingPackage == null` と観測される。

## 脆弱性が成立する流れ

`AndroidManifest.xml` では `DisableSupervisionActivity` が `android:exported="true"` で、`android.app.supervision.action.DISABLE_SUPERVISION` の intent-filter を持つ。追加 permission は設定されていない。

攻撃側は通常の activity 起動で次の intent を投げられる。

```kotlin
startActivity(
    Intent("android.app.supervision.action.DISABLE_SUPERVISION")
        .setPackage("com.android.settings")
)
```

この場合 `callingPackage == null` になる。修正前の拒否条件では、端末上で `systemSupervisionPackageName == null` のとき、先頭項 `callingPackage != systemSupervisionPackageName` が `null != null` で false になる。`&&` 条件全体が false になるため、`supervisionApps.contains(null)` や profile owner 判定が false でも拒否ブロックに入らない。

認可を抜けると、`otherSupervisionApps = supervisionApps.filter { it != callingPackage }` を計算し、他の supervision role holder がいなければ `deleteSupervisionData(disableSupervision = true)` に進む。この helper は `SupervisionManager.setSupervisionEnabled(false)`、`setSupervisionRecoveryInfo(null)`、`UserManager.removeUserEvenWhenDisallowed(supervisingUser)` を実行する。つまり supervision を解除し、回復情報と supervising profile を削除できる。

## 影響

ローカルの未特権アプリが、ユーザー操作なしで Settings の exported activity を起動し、監督・ペアレンタルコントロール系の supervision state/data を削除または無効化できる可能性がある。これは Android Bulletin の EoP High と一致する。ここでの「権限昇格」は、通常アプリが持たない supervision 解除権限を Settings 経由で行使できるという意味。

## 面白い点・調査メモ

- Bulletin の CVE 行には commit link が出ていなかったが、OSV JSON には `platform/packages/apps/Settings` と修正 commit が記載されていた。
- OSV の 16-qpr2 commit は調査時点で 404 だった。17-next commit は `Bug: 476417007` を含み、NVD/OSV の説明と完全に一致する。
- 修正は manifest の非公開化や permission 追加ではなく、`callingPackage == null` を拒否する最小修正だった。つまり exported activity 自体は正規 supervision app/profile owner から呼ばれる設計として残されている。
- `Log.e` から `Log.d` への変更も含まれるが、セキュリティ上の本質は null check である。
- 旧コードの `revokeSupervisionRole()` には `packageName == null` の防御が既にあったが、その前に supervision data deletion が走るため不十分だった。role removal の防御位置が遅すぎる。

## 検証ステータス

ソースコード差分から脆弱な条件、攻撃入口、修正内容、根本原因を確認できたため `ok`。
053 OK

CVE-2026-0088

053-ok-certinstaller-app-label-ui-spoofing

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-471127462
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0088 is listed in the Android Security Bulletin as a High severity EoP issue in System.

特定した具体的な脆弱性

特定できた。CVE-2026-0088 は platform/packages/apps/CertInstaller の CertInstaller.java#getCallingAppLabel() で、呼び出し元アプリの表示名を ApplicationInfo.loadLabel() で取得し、そのまま CA 証明書インストール警告ダイアログ本文へ埋め込んでいた UI spoofing 脆弱性だった。

攻撃アプリが android:label に大量の改行や不可視/空白系文字を含めると、CertInstaller の警告文中にそのラベルがそのまま表示される。結果として「この CA 証明書は Settings でインストールする必要がある」「信頼できる組織の CA 証明書だけをインストールすること」といった重要な警告部分を画面外へ押し下げ、ユーザーに不完全または誤解を招くダイアログを見せることができる。

修正は appInfo.loadLabel(pm) を appInfo.loadSafeLabel(pm) に置き換える 1 行。loadSafeLabel() は TextUtils.makeSafeForPresentation() を使い、既定で trim と first-line 化を行うため、改行で警告文を押し下げる攻撃を防ぐ。

原因

根本原因は、セキュリティ警告 UI に表示する外部制御可能なアプリラベルへ loadLabel() を使ったこと。

PackageItemInfo#loadLabel() は最大長の切り詰めは行うが、通常はラベルを安全表示用に単一行化しない。Android 16 の PackageItemInfo.java でも、通常経路では TextUtils.trimToSize(loadUnsafeLabel(pm), MAX_SAFE_LABEL_LENGTH) に留まる。一方、loadSafeLabel() は makeSafeForPresentation(..., SAFE_STRING_FLAG_TRIM | SAFE_STRING_FLAG_FIRST_LINE) を使うため、表示用に危険な改行や余白を取り除ける。

つまり、CertInstaller 側で呼び出し元アプリ名を「普通の一覧表示用ラベル」として扱い、セキュリティダイアログ向けの安全ラベルに変換していなかったことが問題だった。

どこから特定したか

根拠 URL / commit / artifacts: 保存した付帯ファイルは artifacts/ 配下。

パッチ差分: 差分は以下の 1 行。

``diff
・return appInfo.loadLabel(pm);
+ return appInfo.loadSafeLabel(pm);
`

対象箇所は CertInstaller.java#getCallingAppLabel()。修正前は、mCredentials.getReferrer() で取得した呼び出し元 package name から PackageManager#getApplicationInfo() を呼び、ApplicationInfo#loadLabel() の戻り値をそのまま返していた。

この戻り値は createRedirectCaCertificateDialog() で次の文字列に埋め込まれる。

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01` / https://storage.googleapis.com/android-osv/ASB-A-471127462.json` / https://android.googlesource.com/platform/packages/apps/CertInstaller/+/c935d8d079131d200b11389bf01ab0ff8034ad00` / https://android.googlesource.com/platform/packages/apps/CertInstaller/+/3dced430d0a90c017892…

validated.md を表示
# CVE-2026-0088 検証結果

## 結論

特定できた。CVE-2026-0088 は `platform/packages/apps/CertInstaller` の `CertInstaller.java#getCallingAppLabel()` で、呼び出し元アプリの表示名を `ApplicationInfo.loadLabel()` で取得し、そのまま CA 証明書インストール警告ダイアログ本文へ埋め込んでいた UI spoofing 脆弱性だった。

攻撃アプリが `android:label` に大量の改行や不可視/空白系文字を含めると、CertInstaller の警告文中にそのラベルがそのまま表示される。結果として「この CA 証明書は Settings でインストールする必要がある」「信頼できる組織の CA 証明書だけをインストールすること」といった重要な警告部分を画面外へ押し下げ、ユーザーに不完全または誤解を招くダイアログを見せることができる。

修正は `appInfo.loadLabel(pm)` を `appInfo.loadSafeLabel(pm)` に置き換える 1 行。`loadSafeLabel()` は `TextUtils.makeSafeForPresentation()` を使い、既定で trim と first-line 化を行うため、改行で警告文を押し下げる攻撃を防ぐ。

## 確認した初期情報

- CVE: `CVE-2026-0088`
- Android bug/reference: `A-471127462`
- Component: `System`
- Type: `EoP`
- Severity: `High`
- Bulletin: `https://source.android.com/docs/security/bulletin/2026/2026-06-01`
- Updated AOSP versions: `14, 15, 16, 16-qpr2`
- 対象パッケージ: `platform/packages/apps/CertInstaller`
- 対象ファイル: `src/com/android/certinstaller/CertInstaller.java`

## 根拠 URL / commit / artifacts

保存した付帯ファイルは `artifacts/` 配下。

- OSV: `https://storage.googleapis.com/android-osv/ASB-A-471127462.json`
  - 保存先: `artifacts/ASB-A-471127462.json`
- 代表修正 commit:
  - `c935d8d079131d200b11389bf01ab0ff8034ad00`
  - URL: `https://android.googlesource.com/platform/packages/apps/CertInstaller/+/c935d8d079131d200b11389bf01ab0ff8034ad00`
  - diff: `artifacts/c935d8d079131d200b11389bf01ab0ff8034ad00.diff`
  - commit metadata: `artifacts/c935d8d079131d200b11389bf01ab0ff8034ad00.commit.txt`
- Android 14 側修正 commit:
  - `3dced430d0a90c017892ffeed3389c2592ff0378`
  - URL: `https://android.googlesource.com/platform/packages/apps/CertInstaller/+/3dced430d0a90c017892ffeed3389c2592ff0378`
  - diff: `artifacts/3dced430d0a90c017892ffeed3389c2592ff0378.diff`
  - commit metadata: `artifacts/3dced430d0a90c017892ffeed3389c2592ff0378.commit.txt`
- OSV に記録されていた修正 URL:
  - `17-next`: `0034ca47f9c3552e0f2d5e361f210eb92e6db805`
  - `15`: `41228b5ffcfc45257a37fe818aa54ae8c5004b3b`
  - `16`: `188975dcb8d48bf13b0c4edfd65f55e5d618cd19`
  - `16-qpr2`: `21f346008305d857a4779eb98ee67e69fc7b0511`
  - `14`: `3dced430d0a90c017892ffeed3389c2592ff0378`
  - generic fix reference: `c935d8d079131d200b11389bf01ab0ff8034ad00`
- 前後ソース:
  - `artifacts/CertInstaller.before.java`
  - `artifacts/CertInstaller.after.java`
  - `artifacts/CertInstallerMain.before.java`
  - `artifacts/strings.before.xml`
  - `artifacts/PackageItemInfo.android16.java`
- キー行抽出:
  - `artifacts/rg-key-lines.txt`

## パッチ差分

差分は以下の 1 行。

```diff
-        return appInfo.loadLabel(pm);
+        return appInfo.loadSafeLabel(pm);
```

対象箇所は `CertInstaller.java#getCallingAppLabel()`。修正前は、`mCredentials.getReferrer()` で取得した呼び出し元 package name から `PackageManager#getApplicationInfo()` を呼び、`ApplicationInfo#loadLabel()` の戻り値をそのまま返していた。

この戻り値は `createRedirectCaCertificateDialog()` で次の文字列に埋め込まれる。

```xml
This certificate from %1$s must be installed in Settings.
Only install CA certificates from organizations you trust.
```

そのため `%1$s` に入るアプリラベルが複数行・長大・表示上危険な文字列であっても、警告ダイアログの本文レイアウトへそのまま影響した。

## 脆弱性が起きる状況

1. 攻撃アプリが自身の manifest の `android:label` に、例えば大量の `\n` を含む表示名を設定する。
2. 攻撃アプリが `android.credentials.INSTALL` または `ACTION_VIEW` で CA 証明書を CertInstaller に渡す。
3. 公開 Activity である `CertInstallerMain` が、内部 Activity `CertInstaller` へ証明書データと `Intent.EXTRA_REFERRER = getLaunchedFromPackage()` を渡す。
4. `CertInstaller` は referrer package の `ApplicationInfo` を引き、修正前は `loadLabel()` で取得した未安全化ラベルを警告ダイアログに埋め込む。
5. 攻撃者が用意した改行入りラベルにより、CA 証明書の危険性を説明する本文後半が画面外に押し出され、ユーザーは重要な警告を見落とす。

攻撃の本質は「呼び出し元アプリ名」という信用境界外の UI 文字列を、セキュリティ意思決定用ダイアログに未サニタイズで入れたこと。CA 証明書のインストールは端末の信頼ストアへ影響し、通信の監視・改ざんに直結し得るため、Android Security Bulletin では System EoP High と評価されている。

## 根本原因

根本原因は、セキュリティ警告 UI に表示する外部制御可能なアプリラベルへ `loadLabel()` を使ったこと。

`PackageItemInfo#loadLabel()` は最大長の切り詰めは行うが、通常はラベルを安全表示用に単一行化しない。Android 16 の `PackageItemInfo.java` でも、通常経路では `TextUtils.trimToSize(loadUnsafeLabel(pm), MAX_SAFE_LABEL_LENGTH)` に留まる。一方、`loadSafeLabel()` は `makeSafeForPresentation(..., SAFE_STRING_FLAG_TRIM | SAFE_STRING_FLAG_FIRST_LINE)` を使うため、表示用に危険な改行や余白を取り除ける。

つまり、CertInstaller 側で呼び出し元アプリ名を「普通の一覧表示用ラベル」として扱い、セキュリティダイアログ向けの安全ラベルに変換していなかったことが問題だった。

## 修正内容の妥当性

修正後は `getCallingAppLabel()` が `appInfo.loadSafeLabel(pm)` を返す。これにより:

- 先頭/末尾の不要な空白が除去される。
- ラベルは first line に制限される。
- `makeSafeForPresentation()` の既存 framework 実装により、セキュリティ UI での表示に適した文字列になる。

修正 commit message も「crafted label により CA certificate installation warning を off-screen に押し下げられる」と明示しており、今回の差分と脆弱性説明は一致する。

## 調査時に分かったこと / メモ

- OSV details は `In getCallingAppLabel of CertInstaller.java, there is a possible way to hide a sensitive security dialogue due to misleading or insufficient UI.` と説明している。
- commit message は PoC app を手動でインストールして、修正後にダイアログが正しく表示されることを確認したと書いている。
- Bulletin/OSV には `User interaction is not needed for exploitation` とあるが、commit message には `potentially tricking users into installing untrusted CA certificates` とあり、実際の危険性は UI spoofing によるユーザー誤誘導として説明されている。この点は公開メタデータとパッチ説明のニュアンスがずれている。
- `CertInstallerMain` は外部公開されているが、実際の `CertInstaller` Activity は `exported=false`。ただし `CertInstallerMain` が `getLaunchedFromPackage()` を `Intent.EXTRA_REFERRER` として内部 Activity へ渡すため、攻撃者は自分の package のラベルをダイアログに表示させられる。
- 攻撃者が任意の referrer package 名を extras で注入する経路は潰されている。`CertInstallerMain.startInstallActivity()` は外部 Intent に `Intent.EXTRA_REFERRER` が含まれていれば削除し、`getLaunchedFromPackage()` で上書きする。したがって問題は package 名偽装ではなく、正しい package に紐づく「アプリラベル」の表示安全性不足。
- AOSP ソース差分で十分に特定できたため、Pixel firmware やバイナリは取得していない。`../binaries` への保存物はない。

## 判定

`ok`。ソースコード、修正 diff、commit message、OSV の説明から、脆弱性の発生条件と根本原因を特定できた。
054 OK

CVE-2026-0093

054-ok-request-manage-credentials-label-spoofing-eop

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-473812391
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0093 is listed in the Android Security Bulletin as a High severity EoP issue in System.

特定した具体的な脆弱性

判定: ok

CVE-2026-0093 は、Settings の RequestManageCredentials 画面におけるアプリラベル表示の UI spoofing による System EoP と判断した。攻撃者アプリが android.security.MANAGE_CREDENTIALS の同意画面を正規に起動し、改行・空白・長大文字列などを含む細工したアプリ表示名で、ユーザーに見える「どのアプリ/どの対象に証明書管理を許可するか」の文脈を隠す。ユーザーが Allow を押すと、攻撃者アプリが KeyChain credential management app として登録され、KeyChain 資格情報を管理できる。

根本原因は、セキュリティ上重要な同意 UI で、外部アプリが制御できる ApplicationInfo.loadLabel() の戻り値を loadSafeLabel() で正規化せずに TextView へ渡していたこと。修正は loadLabel() を loadSafeLabel(pm, DEFAULT_MAX_LABEL_SIZE_PX, SAFE_STRING_FLAG_TRIM | SAFE_STRING_FLAG_FIRST_LINE) に置き換え、ラベルを先頭行・trim・幅制限付きで表示するもの。

原因

Android のアプリラベルはアプリ自身が制御できる UI 入力であり、セキュリティ境界に近い同意 UI では安全化して使う必要がある。修正前コードは次を満たしていなかった。

・改行を除去しない
・先頭/末尾の表示攪乱用空白を除去しない
・UI テンプレートに入れる前の表示幅制限を適用しない
・セキュリティ上の意思決定画面で、攻撃者制御文字列を信頼していた

PackageItemInfo.loadLabel() は最大 1000 文字への trimToSize は行うが、改行を先頭行に制限しない。AOSP の PackageItemInfo には「loadLabel を呼ぶときは safe labels を常に使うべき」という趣旨のコメントもある。

修正後の loadSafeLabel() は TextUtils.makeSafeForPresentation() を経由する。確認した実装では:

どこから特定したか

確認した公開情報: ・Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
・CVE: CVE-2026-0093
・References: A-473812391
・Component/Subcomponent: System
・Type/Severity: EoP / High
・AOSP commit: 88ab2340c2559d8b74cdf4e2acc14fb5327f2481
・Commit URL: https://android.googlesource.com/platform/packages/apps/Settings/+/88ab2340c2559d8b74cdf4e2acc14fb5327f2481
・P…

パッチ解析: 保存した diff: artifacts/88ab2340c2559d8b74cdf4e2acc14fb5327f2481.diff

変更ファイルは 2 つ。

・src/com/android/settings/security/RequestManageCredentials.java
・src/com/android/settings/security/CredentialManagementAppAdapter.java

差分の本質は 3 箇所の置換。

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/packages/apps/Settings/+/88ab…

validated.md を表示
# CVE-2026-0093 検証メモ

## 結論

判定: ok

CVE-2026-0093 は、Settings の `RequestManageCredentials` 画面におけるアプリラベル表示の UI spoofing による System EoP と判断した。攻撃者アプリが `android.security.MANAGE_CREDENTIALS` の同意画面を正規に起動し、改行・空白・長大文字列などを含む細工したアプリ表示名で、ユーザーに見える「どのアプリ/どの対象に証明書管理を許可するか」の文脈を隠す。ユーザーが Allow を押すと、攻撃者アプリが KeyChain credential management app として登録され、KeyChain 資格情報を管理できる。

根本原因は、セキュリティ上重要な同意 UI で、外部アプリが制御できる `ApplicationInfo.loadLabel()` の戻り値を `loadSafeLabel()` で正規化せずに `TextView` へ渡していたこと。修正は `loadLabel()` を `loadSafeLabel(pm, DEFAULT_MAX_LABEL_SIZE_PX, SAFE_STRING_FLAG_TRIM | SAFE_STRING_FLAG_FIRST_LINE)` に置き換え、ラベルを先頭行・trim・幅制限付きで表示するもの。

## 確認した公開情報

- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- CVE: CVE-2026-0093
- References: A-473812391
- Component/Subcomponent: System
- Type/Severity: EoP / High
- AOSP commit: `88ab2340c2559d8b74cdf4e2acc14fb5327f2481`
- Commit URL: https://android.googlesource.com/platform/packages/apps/Settings/+/88ab2340c2559d8b74cdf4e2acc14fb5327f2481
- Parent commit: `46ddb9d440cad942163700985242d2206f29cc40`
- 参考にした patch diffing 手法: https://www.originhq.com/research/patch-diffing-pipeline

## パッチ解析

保存した diff: `artifacts/88ab2340c2559d8b74cdf4e2acc14fb5327f2481.diff`

変更ファイルは 2 つ。

- `src/com/android/settings/security/RequestManageCredentials.java`
- `src/com/android/settings/security/CredentialManagementAppAdapter.java`

差分の本質は 3 箇所の置換。

- `RequestManageCredentials.loadHeader()` の画面タイトル
- `CredentialManagementAppAdapter.HeaderViewHolder.bindView()` のヘッダー画面タイトル
- `CredentialManagementAppAdapter.AppAuthenticationViewHolder.bindView()` の認証ポリシー内アプリ名

修正前は、呼び出し元アプリまたは認証ポリシー対象アプリのラベルを `applicationInfo.loadLabel(...)` で取得し、そのまま表示していた。修正後は `DEFAULT_MAX_LABEL_SIZE_PX`、`SAFE_STRING_FLAG_TRIM`、`SAFE_STRING_FLAG_FIRST_LINE` を指定した `loadSafeLabel(...)` に変更された。

commit message には次の趣旨が明記されている。

- `RequestManageCredentials` の脆弱性修正
- アプリ開発者が、アプリが要求する permission をユーザーから隠せる問題
- `loadSafeLabel` でラベルを trim することで修正
- `Bug: 473812391`

## 脆弱性が起きる状況

1. 攻撃者アプリが、自身の表示名に改行、先頭/末尾空白、非常に長い文字列、HTML 由来の改行に変換される表現などを含める。
2. 攻撃者アプリが `android.security.MANAGE_CREDENTIALS` action で Settings の `RequestManageCredentials` を起動し、`KeyChain.EXTRA_AUTHENTICATION_POLICY` に認証ポリシーを渡す。
3. Settings は `getLaunchedFromPackage()` から呼び出し元 package を取得し、同意 UI を表示する。
4. 修正前は同意 UI のタイトルや対象アプリ一覧に `loadLabel()` の未安全化ラベルがそのまま入るため、ラベルの改行・余白・長さで本来の同意文や対象情報を見えにくくできる。
5. ユーザーが画面下部の `Allow` を押すと、`setCredentialManagementApp(mCredentialManagerPackage, mAuthenticationPolicy)` が呼ばれ、攻撃者アプリが credential management app になる。

Manifest では `RequestManageCredentials` が exported で、`android.security.MANAGE_CREDENTIALS` の intent-filter を持つ。

```text
artifacts/AndroidManifest.pre.xml:2412-2418
activity .security.RequestManageCredentials
android:exported="true"
action android.security.MANAGE_CREDENTIALS
```

同意画面のタイトル文言は `Allow <app_name> to install certificates on this device?` であり、ここに攻撃者制御のアプリラベルが差し込まれる。説明文には、これらの証明書が端末固有 ID をアプリや URL に共有して本人確認に使われることが書かれている。

## EoP としての影響

`RequestManageCredentials.java` のクラスコメントは、この画面で許可されたアプリがユーザーの KeyChain credentials を管理でき、次の DevicePolicyManager API を使えると説明している。

- `installKeyPair`
- `removeKeyPair`
- `generateKeyPair`
- `setKeyPairCertificate`

実際の許可処理は `setOrUpdateCredentialManagementAppAndFinish()` で、`mKeyChainConnection.getService().setCredentialManagementApp(mCredentialManagerPackage, mAuthenticationPolicy)` を呼ぶ。つまり、UI 偽装によりユーザー同意を誤誘導できれば、通常アプリが本来ユーザーに明確に理解させた上でしか得られない credential management app の地位を得る。

これは任意コード実行やメモリ破壊ではなく、セキュリティ同意 UI の表示不備による権限昇格である。

## 根本原因

Android のアプリラベルはアプリ自身が制御できる UI 入力であり、セキュリティ境界に近い同意 UI では安全化して使う必要がある。修正前コードは次を満たしていなかった。

- 改行を除去しない
- 先頭/末尾の表示攪乱用空白を除去しない
- UI テンプレートに入れる前の表示幅制限を適用しない
- セキュリティ上の意思決定画面で、攻撃者制御文字列を信頼していた

`PackageItemInfo.loadLabel()` は最大 1000 文字への `trimToSize` は行うが、改行を先頭行に制限しない。AOSP の `PackageItemInfo` には「`loadLabel` を呼ぶときは safe labels を常に使うべき」という趣旨のコメントもある。

修正後の `loadSafeLabel()` は `TextUtils.makeSafeForPresentation()` を経由する。確認した実装では:

- `SAFE_STRING_FLAG_TRIM`: 端の空白や NBSP を除去
- `SAFE_STRING_FLAG_FIRST_LINE`: 最初の改行以降を切り捨て
- `DEFAULT_MAX_LABEL_SIZE_PX`: 1000px 相当で ellipsize
- HTML 由来の改行や制御文字も表示安全化の対象

## 面白い点・調査メモ

- `RequestManageCredentials` は overlay 対策として `SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS` と `setFilterTouchesWhenObscured(true)` を使っている。つまり典型的な overlay tapjacking は意識されていたが、同じ同意 UI 内に差し込まれるアプリラベルの spoofing は残っていた。
- 修正は文字列 sanitization のみで、呼び出し元検証や KeyChain 側の権限モデルは変更されていない。これは、フロー自体は正規機能で、問題はユーザーに提示される意味を攻撃者制御ラベルで壊せる点だったことを示す。
- `CredentialManagementAppAdapter.AppAuthenticationViewHolder` も修正対象になっているため、呼び出し元アプリ名だけでなく、認証ポリシー内に列挙されるアプリ名側の表示偽装も問題視されている。
- `loadSafeLabel()` の `FIRST_LINE` が入っていることから、特に改行を使った「1 行目だけ安全そうな名前に見せ、2 行目以降で同意文や対象一覧を押し下げる」攻撃が主要シナリオと考えられる。
- Pixel 固有バイナリではなく AOSP Settings の Java ソースパッチで完結しているため、ファームウェアや `../binaries` への保存は不要だった。

## 付帯ファイル

`artifacts/` に保存した主なファイル:

- `commit_88ab2340c2559d8b74cdf4e2acc14fb5327f2481.json`
- `88ab2340c2559d8b74cdf4e2acc14fb5327f2481.diff`
- `RequestManageCredentials.pre.java`
- `RequestManageCredentials.post.java`
- `CredentialManagementAppAdapter.pre.java`
- `CredentialManagementAppAdapter.post.java`
- `AndroidManifest.pre.xml`
- `settings_strings.pre.xml`
- `request_manage_credentials.pre.xml`
- `request_manage_credentials_header.pre.xml`
- `app_authentication_item.pre.xml`
- `PackageItemInfo.android-16.0.0_r1.java`
- `TextUtils.android-16.0.0_r1.java`
- `Credentials.android-16.0.0_r1.java`

## 付帯ファイル SHA-256

```text
1c65a294107d91caff24b711bc2712b7e05ae84554cf28fea5c86ad10813cb17  artifacts/88ab2340c2559d8b74cdf4e2acc14fb5327f2481.diff
1f9b4703f4639612ff3eb1b30023abd4bddefe211868b7afa6a65889af0b22ec  artifacts/AndroidManifest.pre.xml
28f2d6e5ab59a9aa1732ab48d763665a5d0b50fea28b4d02665fddb0064aff10  artifacts/commit_88ab2340c2559d8b74cdf4e2acc14fb5327f2481.json
4e07d90ead2e8f0d1cf058358dce09b982a384f636f7c20c8a71594fd0d5425c  artifacts/CredentialManagementAppAdapter.post.java
5bce5a8a641a2ef3050edfe2c3cecadfc5c210b3fc6a66d63c25af2c9cef5521  artifacts/request_manage_credentials.pre.xml
69a35c696b0991e414e080c10e8980221a2418a0cd71075dcde226846d6b833f  artifacts/app_authentication_item.pre.xml
7c00ed4d198d9a442e9b6b78efc79993b525cf876237f92930676f6cfcb46afb  artifacts/settings_strings.pre.xml
7d4994b7ea66d2e30527673f515226b65a7e5243dfd76bbb781369e4d04f6c31  artifacts/Credentials.android-16.0.0_r1.java
98ee17ea5aad11b46c25a3eccfaa66812ec5c8631eec128c88ce46e66092b60a  artifacts/RequestManageCredentials.pre.java
a9edd4b34d8e22f50e22249b60a49634087634359e7569035ce96f5976655584  artifacts/request_manage_credentials_header.pre.xml
bb09c981c8cebf282c88a62cbe71cb3c46e0c8c02a939977e8c6f76f82f81ad2  artifacts/TextUtils.android-16.0.0_r1.java
c2d3c0667fe14347abb9635d6490a3f4e8283fd62eb77338be42915db1fd7ef5  artifacts/CredentialManagementAppAdapter.pre.java
d2db78f553b48f534efe21453d16ed8b580cc970ed37781ed51476f966855fa1  artifacts/RequestManageCredentials.post.java
ebdf1ca01c8ec0836b41a42893332edb3ed2896e28fef4c70ad04bed91e7ddb1  artifacts/PackageItemInfo.android-16.0.0_r1.java
```
055 OK

CVE-2026-0094

055-ok-keychain-app-label-ui-injection-eop

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-471173239
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0094 is listed in the Android Security Bulletin as a High severity EoP issue in System.

特定した具体的な脆弱性

CVE-2026-0094 は KeyChain の証明書選択 UI におけるアプリラベルの UI injection だった。

攻撃アプリは自身の application label に改行、タブ、制御文字、過剰な空白などを含められる。パッチ前の KeyChainActivity.getApplicationLabel() は PackageManager.getApplicationLabel() の戻り値をそのまま String 化し、証明書選択ダイアログの説明文に埋め込んでいた。そのため、攻撃アプリは KeyChain の「どのアプリに証明書利用を許可するか」という説明領域のレイアウトを操作し、ユーザーに正当なアプリやサーバーからの要求に見える文言を作れる。

ユーザーが誤認して Select を押すと、KeyChain は選択された秘密鍵エイリアスに対する grant を呼び出し元 UID に与える。結果として、攻撃アプリが本来得られないクライアント証明書/秘密鍵利用権を得るため、System コンポーネントの High severity EoP と判断できる。

原因

根本原因は「セキュリティ判断に使う UI 文脈へ、攻撃者制御のアプリ表示名を表示用サニタイズなしで埋め込んだこと」。

KeyChainActivity は package name と UID の確認自体は行っているが、ユーザーに提示する識別子として package label を採用していた。Android のアプリラベルはアプリ開発者が制御でき、改行などの表示制御文字を含められる。証明書選択ダイアログのヘッダは wrap_content の単純な TextView で、ラベルを安全な一行表示へ変換していなかったため、ラベルが説明文全体の視覚構造を壊せた。

どこから特定したか

パッチ解析: 変更ファイルは src/com/android/keychain/KeyChainActivity.java 1件のみ。

パッチ前:

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/packages/apps/KeyChain/+/b8d3fe7c5e4b3b637c37c77fa31a026b3bf03818 / https://android.googlesource.com/platform/packages/apps/KeyChain/+/b8d3fe7c5e4b3b637c37c77fa31a026b3bf03818%5E%21/

validated.md を表示
# CVE-2026-0094 検証結果

## 判定

`ok`。AOSP の公開 commit と前後ソースから、脆弱性の発生箇所、攻撃者制御データ、ユーザー判断を誤らせる UI、修正内容を特定できた。

タイトル: `keychain-app-label-ui-injection-eop`

## 基本情報

- CVE: CVE-2026-0094
- Android reference ID: A-471173239
- Bulletin: Android Security Bulletin 2026-06-01
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Component/Subcomponent: System / packages/apps/KeyChain
- Severity/Type: High / EoP
- Affected/updated AOSP versions listed by bulletin: 14, 15, 16, 16-qpr2
- Patch commit: `b8d3fe7c5e4b3b637c37c77fa31a026b3bf03818`
- Parent commit: `6e905f8096930b0076125603db55f0815ef3efd0`
- Commit URL: https://android.googlesource.com/platform/packages/apps/KeyChain/+/b8d3fe7c5e4b3b637c37c77fa31a026b3bf03818
- Diff URL: https://android.googlesource.com/platform/packages/apps/KeyChain/+/b8d3fe7c5e4b3b637c37c77fa31a026b3bf03818%5E%21/

## 結論

CVE-2026-0094 は KeyChain の証明書選択 UI におけるアプリラベルの UI injection だった。

攻撃アプリは自身の application label に改行、タブ、制御文字、過剰な空白などを含められる。パッチ前の `KeyChainActivity.getApplicationLabel()` は `PackageManager.getApplicationLabel()` の戻り値をそのまま `String` 化し、証明書選択ダイアログの説明文に埋め込んでいた。そのため、攻撃アプリは KeyChain の「どのアプリに証明書利用を許可するか」という説明領域のレイアウトを操作し、ユーザーに正当なアプリやサーバーからの要求に見える文言を作れる。

ユーザーが誤認して `Select` を押すと、KeyChain は選択された秘密鍵エイリアスに対する grant を呼び出し元 UID に与える。結果として、攻撃アプリが本来得られないクライアント証明書/秘密鍵利用権を得るため、System コンポーネントの High severity EoP と判断できる。

## パッチ解析

変更ファイルは `src/com/android/keychain/KeyChainActivity.java` 1件のみ。

パッチ前:

```java
private String getApplicationLabel() {
    PackageManager pm = getPackageManager();
    try {
        return pm.getApplicationLabel(pm.getApplicationInfo(mSenderPackageName, 0)).toString();
    } catch (PackageManager.NameNotFoundException e) {
        return mSenderPackageName;
    }
}
```

パッチ後:

```java
private String getApplicationLabel() {
    PackageManager pm = getPackageManager();
    String label;
    try {
        label = pm.getApplicationLabel(pm.getApplicationInfo(mSenderPackageName, 0)).toString();
    } catch (PackageManager.NameNotFoundException e) {
        label = mSenderPackageName;
    }
    if (label != null) {
        label = TextUtils.makeSafeForPresentation(
                label,
                PackageItemInfo.MAX_SAFE_LABEL_LENGTH,
                PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
                TextUtils.SAFE_STRING_FLAG_TRIM | TextUtils.SAFE_STRING_FLAG_FIRST_LINE)
                    .toString();
    }
    return label;
}
```

修正は `TextUtils.makeSafeForPresentation()` の導入である。指定フラグは `SAFE_STRING_FLAG_TRIM | SAFE_STRING_FLAG_FIRST_LINE` で、表示用ラベルを最大長/表示幅で制限し、先頭行のみを残し、前後空白や制御文字を除去する。`TextUtils` 側の実装では HTML として正規化したあと、改行に到達すると後続を削除し、非改行の制御文字も除去する。

## 攻撃経路

1. 攻撃アプリが manifest の `android:label`、またはラベルリソースに改行等を含む文字列を設定する。
2. 攻撃アプリが `KeyChain.choosePrivateKeyAlias()` 系の API で証明書選択 UI を起動する。
3. `KeyChainActivity.onResume()` は `ActivityManager.getService().getLaunchedFromPackage(activityToken)` で呼び出し元 package を特定する。
4. `chooseCertificate()` が証明書一覧ダイアログを表示し、ヘッダ `contextView` に以下の形式の文言をセットする。

```java
String contextMessage = String.format(res.getString(R.string.requesting_application),
        getApplicationLabel());
...
contextView.setText(contextMessage);
```

文字列リソースは次の通り。

```xml
<string name="requesting_application">The app %s has requested a certificate. Choosing a certificate will let the app use this identity with servers now and in the future.</string>
<string name="requesting_server">The app has identified the requesting server as %s, but you should only give the app access to the certificate if you trust the app.</string>
<string name="allow_button">Select</string>
```

5. パッチ前は `%s` に攻撃者制御の複数行ラベルがそのまま入るため、説明文の先頭や次行に偽のアプリ名/注意文/空白を差し込める。
6. ユーザーが誤って証明書エイリアスを選択して `Select` を押すと、`finish(alias)` から `ResponseSender` が呼ばれ、KeyChain サービスへ grant が設定される。

## 根本原因

根本原因は「セキュリティ判断に使う UI 文脈へ、攻撃者制御のアプリ表示名を表示用サニタイズなしで埋め込んだこと」。

KeyChainActivity は package name と UID の確認自体は行っているが、ユーザーに提示する識別子として package label を採用していた。Android のアプリラベルはアプリ開発者が制御でき、改行などの表示制御文字を含められる。証明書選択ダイアログのヘッダは `wrap_content` の単純な `TextView` で、ラベルを安全な一行表示へ変換していなかったため、ラベルが説明文全体の視覚構造を壊せた。

## 影響

- 攻撃者権限: ローカルの通常アプリ。特別な Android パーミッションは不要と考えられる。
- ユーザー操作: 証明書選択 UI でユーザーが証明書を選び `Select` する必要がある。
- 影響対象資産: Android KeyChain に保存されたクライアント証明書/秘密鍵の利用許可。
- EoP の意味: 攻撃アプリが UI 偽装によって、ユーザーが意図しない証明書エイリアス grant を自身の UID に付与させる。

## 面白い点・調査メモ

- Commit message は「CVE-2017-13295 の variant」と明記している。古い Android 系の UI injection/表示名サニタイズ不備と同型の問題が KeyChainActivity に残っていた形。
- `getApplicationLabel()` は証明書選択ダイアログだけでなく、証明書ロード中の snackbar にも使われていた。権限付与判断に直結する主経路はダイアログヘッダだが、ロード中表示も同じ未サニタイズデータを表示していた。
- `getCallingAppPackageName()` と UID 解決により「どの package から起動されたか」の機械的な識別は行われていた。欠けていたのは、その識別子をユーザーへ安全に提示する処理。
- パッチはレイアウトや権限付与ロジックには触らず、表示ラベルの正規化だけに限定されている。これは原因が grant 処理そのものではなく、ユーザーを誤誘導する表示の完全性にあったことを示している。
- `SAFE_STRING_FLAG_FIRST_LINE` は改行を空白化するのではなく最初の改行以降を切り捨てる。ラベル末尾に正当なアプリ名を置くような偽装も潰せる一方、先頭行だけで紛らわしい名前を使う問題は別途通常のアプリ名なりすまし対策の範囲になる。

## 解析に使った付帯ファイル

- `artifacts/b8d3fe7c5e4b3b637c37c77fa31a026b3bf03818.diff`: Gitiles から取得した commit diff
- `artifacts/commit_b8d3fe7c5e4b3b637c37c77fa31a026b3bf03818.json`: Gitiles JSON commit metadata
- `artifacts/KeyChainActivity_before.java`: parent commit の KeyChainActivity
- `artifacts/KeyChainActivity_after.java`: patched commit の KeyChainActivity
- `artifacts/strings_after.xml`: 関連 string resource
- `artifacts/cert_chooser_header.xml`: ダイアログヘッダ TextView layout
- `artifacts/TextUtils_android16.java`: `makeSafeForPresentation()` 実装確認用

## 再現 PoC の最小イメージ

攻撃アプリのラベル例:

```xml
<application
    android:label="Trusted VPN

System certificate request approved by administrator
">
```

実際の悪用では攻撃アプリが `KeyChain.choosePrivateKeyAlias()` を呼び、ユーザーの端末に利用可能なクライアント証明書がある状態で、証明書選択ダイアログを表示させる。パッチ前はこの複数行ラベルが説明文中にそのまま入り、証明書利用を要求している主体を誤認させられる。パッチ後はラベルが `Trusted VPN` のように先頭行へ制限され、制御文字による説明文レイアウト操作は成立しない。
056 OK

CVE-2026-0095

056-ok-l2cap-clone-buf-size-truncation-eop

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-484861632
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0095 is listed in the Android Security Bulletin as a High severity EoP issue in System.

特定した具体的な脆弱性

ok。CVE-2026-0095 は Android Bluetooth stack の L2CAP FCR/LE CoC 送信分割処理にあるヒープバッファオーバーフローだった。

根本原因は l2c_fcr_clone_buf() が、コピー先バッファサイズを uint16_t で保持していたこと。LE Credit Based Connection の peer MPS は L2CAP_LE_MAX_MPS == 65533 まで受け入れられるため、no_of_bytes + sizeof(BT_HDR) + new_offset + L2CAP_FCS_LEN が 65535 を超える。修正前はこの値が 16bit に切り詰められ、小さいバッファを osi_malloc() した後に memcpy(..., no_of_bytes) で大きくコピーしていた。

パッチは buf_size を uint16_t から uint32_t に変更し、割当サイズの切り詰めを止めている。

原因

メモリ確保サイズの計算結果を、入力値の最大範囲より狭い uint16_t に格納したこと。

no_of_bytes, new_offset, BT_HDR, FCS の合計は16bitを超え得るのに、割当サイズだけ16bitへ切り詰めていた。一方、コピー長と BT_HDR.len は元の no_of_bytes のままなので、割当サイズとコピーサイズが不一致になった。

どこから特定したか

パッチ差分: 保存済み: artifacts/abc8b696.patch

``diff
・uint16_t buf_size = no_of_bytes + sizeof(BT_HDR) + new_offset + L2CAP_FCS_LEN;
+ uint32_t buf_size = no_of_bytes + sizeof(BT_HDR) + new_offset + L2CAP_FCS_LEN;
`

該当関数は l2c_fcr_clone_buf(BT_HDR* p_buf, uint16_t new_offset, uint16_t no_of_bytes)。修正前は buf_size だけが16bitで、直後のコピー長 no_of_bytes は切り詰められない。

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/packages/modules/Bluetooth/+/abc8b696b615415de6608afb726b1da4214fb6af / https://android.googlesource.com/platform/packages/modules/Bluetooth/+/abc8b696b615415de6608afb726b1da4214fb6af%5E%21/ / https://www.originhq.com/research/patch-diffing-pipeline

validated.md を表示
# CVE-2026-0095 検証結果

## 結論

`ok`。CVE-2026-0095 は Android Bluetooth stack の L2CAP FCR/LE CoC 送信分割処理にあるヒープバッファオーバーフローだった。

根本原因は `l2c_fcr_clone_buf()` が、コピー先バッファサイズを `uint16_t` で保持していたこと。LE Credit Based Connection の peer MPS は `L2CAP_LE_MAX_MPS == 65533` まで受け入れられるため、`no_of_bytes + sizeof(BT_HDR) + new_offset + L2CAP_FCS_LEN` が 65535 を超える。修正前はこの値が 16bit に切り詰められ、小さいバッファを `osi_malloc()` した後に `memcpy(..., no_of_bytes)` で大きくコピーしていた。

パッチは `buf_size` を `uint16_t` から `uint32_t` に変更し、割当サイズの切り詰めを止めている。

## 対象情報

- CVE: CVE-2026-0095
- Android bug: A-484861632
- Component: System
- Type / Severity: EoP / High
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Bulletin上の修正対象: Android 14, 15, 16, 16-qpr2
- 公開commit: https://android.googlesource.com/platform/packages/modules/Bluetooth/+/abc8b696b615415de6608afb726b1da4214fb6af
- 親commit: `ce76f82dac2a8e0e247ca9c838bda57fb9a27b04`
- 変更ファイル: `system/stack/l2cap/l2c_fcr.cc`
- commit message: `Avoid buffer overflow`

## パッチ差分

保存済み: `artifacts/abc8b696.patch`

```diff
-  uint16_t buf_size = no_of_bytes + sizeof(BT_HDR) + new_offset + L2CAP_FCS_LEN;
+  uint32_t buf_size = no_of_bytes + sizeof(BT_HDR) + new_offset + L2CAP_FCS_LEN;
```

該当関数は `l2c_fcr_clone_buf(BT_HDR* p_buf, uint16_t new_offset, uint16_t no_of_bytes)`。修正前は `buf_size` だけが16bitで、直後のコピー長 `no_of_bytes` は切り詰められない。

```cpp
BT_HDR* p_buf2 = (BT_HDR*)osi_malloc(buf_size);
p_buf2->offset = new_offset;
p_buf2->len = no_of_bytes;
memcpy(((uint8_t*)(p_buf2 + 1)) + p_buf2->offset,
       ((uint8_t*)(p_buf + 1)) + p_buf->offset,
       no_of_bytes);
```

## 到達経路

主な到達経路は LE CoC の送信分割処理。

1. LE signaling の `L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ` または `L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES` で peer の `mtu` / `mps` を読む。
2. `mps` は `L2CAP_LE_MIN_MPS <= mps <= L2CAP_LE_MAX_MPS` だけで検証され、`L2CAP_LE_MAX_MPS` は 65533。
3. 検証後、`p_ccb->tx_mps = mps` になる。
4. アプリ側ソケット送信では `size = std::min(size, (int)sock->tx_mtu)` で読み、`BTA_JvL2capWrite()` に `BT_HDR` を渡す。
5. L2CAP送信時、`l2c_lcc_get_next_xmit_sdu_seg()` が `no_of_bytes_to_send = min(p_buf->len, max_pdu...)` を計算し、`l2c_fcr_clone_buf(p_buf, L2CAP_LCC_OFFSET, no_of_bytes_to_send)` を呼ぶ。

関連コード保存:

- `artifacts/l2c_ble.pre.cc`
- `artifacts/btif_sock_l2cap.pre.cc`
- `artifacts/l2c_fcr.pre.cc`
- `artifacts/l2c_fcr.post.cc`
- 抜粋: `artifacts/l2c_ble_relevant_lines.txt`, `artifacts/btif_sock_l2cap_relevant_lines.txt`, `artifacts/l2c_fcr_relevant_lines.txt`

## オーバーフロー条件

定数:

- `sizeof(BT_HDR) == 8`
- `L2CAP_FCS_LEN == 2`
- `L2CAP_MIN_OFFSET == 13`
- `L2CAP_LCC_OFFSET == 15`
- `L2CAP_LE_MAX_MPS == 65533`

修正前:

```text
uint16_t buf_size = no_of_bytes + new_offset + 10
```

LE CoC の先頭fragmentでは `new_offset = L2CAP_LCC_OFFSET = 15`。peer が `mps = 65533` を提示し、アプリが十分大きいSDUを書き込むと:

```text
本来の割当サイズ = 65533 + 15 + 10 = 65558
16bit切り詰め後 = 65558 mod 65536 = 22
コピー長         = 65533
```

さらにコピー先は `allocation_base + sizeof(BT_HDR) + offset = base + 8 + 15 = base + 23` なので、22バイトしか確保されていない場合はコピー開始時点で既に1バイト範囲外になる。

詳細な算術メモ: `artifacts/overflow_arithmetic.md`

## どういう脆弱性だったか

Bluetoothプロセス内のヒープ破壊。peer が大きな LE CoC MPS/MTU を交渉し、ローカル側アプリがそのL2CAPソケットへ大きなSDUを書き込むと、Bluetooth stack が送信PDUを分割する過程で過小確保したバッファへ最大約64KBをコピーできる。

AndroidのBluetooth native stackはアプリプロセスではなくBluetoothサービス側で動くため、メモリ破壊が制御可能ならBluetoothサービス権限への昇格につながる。bulletin上の分類が System / EoP / High になっているのはこのためと考えられる。

## 根本原因

メモリ確保サイズの計算結果を、入力値の最大範囲より狭い `uint16_t` に格納したこと。

`no_of_bytes`, `new_offset`, `BT_HDR`, `FCS` の合計は16bitを超え得るのに、割当サイズだけ16bitへ切り詰めていた。一方、コピー長と `BT_HDR.len` は元の `no_of_bytes` のままなので、割当サイズとコピーサイズが不一致になった。

## 調査中に分かった面白い点

- パッチは1行だけだが、LE CoC の仕様上 `mps` が 65533 まで許容されるため、16bitサイズ計算との相性が悪い。
- `malloc_l2cap_buf()` 側は `BT_HDR_SIZE + L2CAP_MIN_OFFSET + len + L2CAP_FCS_LENGTH` で元SDU用バッファを確保しており、問題は元バッファではなく、送信fragmentを作る clone 側にある。
- `l2c_fcr_clone_buf()` は Classic ERTM の再送キュー複製にも使われる共通ヘルパーだが、現実的に64KB級の値へ到達しやすいのは LE CoC の MPS/MTU 経路。
- LE CoCの `mps > L2CAP_LE_MAX_MPS` は拒否されるが、`L2CAP_LE_MAX_MPS` 自体が 65533 なので、`sizeof(BT_HDR) + offset + FCS` を足すと必ず16bit境界を超える。

## 解析に使ったURLと成果物

- Android Security Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- 参照commit: https://android.googlesource.com/platform/packages/modules/Bluetooth/+/abc8b696b615415de6608afb726b1da4214fb6af
- commit diff: https://android.googlesource.com/platform/packages/modules/Bluetooth/+/abc8b696b615415de6608afb726b1da4214fb6af%5E%21/
- 参考にした手法記事: https://www.originhq.com/research/patch-diffing-pipeline
- 保存patch: `artifacts/abc8b696.patch`
- 修正前ソース: `artifacts/l2c_fcr.pre.cc`, `artifacts/l2c_ble.pre.cc`, `artifacts/btif_sock_l2cap.pre.cc`
- 修正後ソース: `artifacts/l2c_fcr.post.cc`
- 定数・型定義: `artifacts/system_stack_include_bt_hdr.h`, `artifacts/system_stack_include_l2cap_types.h`, `artifacts/system_stack_include_l2cdefs.h`, `artifacts/system_stack_l2cap_l2c_int.h`
- 算術メモ: `artifacts/overflow_arithmetic.md`

057 OK

CVE-2026-0096

057-ok-app-label-injection-bt-forget-device

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityHigh
Updated AOSP versions16, 16-qpr2
ReferencesA-473005624
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0096 is listed in the Android Security Bulletin as a High severity EoP issue in System.

特定した具体的な脆弱性

このCVEは特定できた。脆弱性は packages/apps/Settings の ForgetDeviceDialogFragment#getAppLabel() におけるアプリラベル注入である。

Bluetooth機器を「Forget device」する確認ダイアログは、Flags.enableRemoveAssociationBtUnpair() が有効で、その機器に Companion Device Manager の association が存在する場合、機器のunpairだけでなく関連associationも削除する。このときダイアログ本文に関連アプリ名を表示するが、修正前は攻撃者制御のアプリラベルを PackageManager.getApplicationLabel() で取得し、そのまま本文に埋め込んでいた。

攻撃者アプリが改行、HTML由来の改行、前後空白、過大な文字列などを含むラベルを設定すると、Settingsの確認ダイアログ本文を誤解させられる。ユーザーは本来削除されるassociation/対象アプリを正しく認識できず、Bluetooth機器のforget操作に伴って攻撃者が意図したassociation削除を承認してしまう可能性がある。Android bulletin/OSV上の分類は System / EoP / High で、「misleading or insufficient UI によりユーザーを騙してdeviceをforgetさせる」問題と説明されている。

原因

根本原因は、信頼できないアプリ由来の表示名を、システム設定アプリのセキュリティ関連確認UIにそのまま合成していたこと。

問題の流れ:

1. CompanionDeviceManager.getAllAssociations() から、対象Bluetooth MACアドレスに紐づく AssociationInfo を列挙する。
2. 各associationの packageName に対して getAppLabel(packageName) を呼ぶ。
3. 修正前の getAppLabel() は mPackageManager.getApplicationLabel(mPackageManager.getApplicationInfo(packageName, 0)) を返す。
4. 返されたラベルを ListFormatter で結合し、bluetooth_unpair_dialog_with_associations_body の引数として確認ダイアログ本文に埋め込む。
5. confirm時には mDevice.unpair() と mCompanionDeviceManager.disassociate(ai.getId()) が実行される。

どこから特定したか

保存した付帯ファイル: ・ASB-A-473005624.json: Android OSV JSON。
・24b35_commit.json: 公開cherrypickコミットのGitiles log JSON。
・62b7_commit.json: 17-next修正コミットのGitiles log JSON。
・24b35b078f392dc4d649338ec123dd3f8928440b.diff: 公開cherrypickのGitiles diff。
・62b7a2483f4eef4ff0f02ccb81fe6cfea9819ef8.diff: 17-next修正コミットのGitiles diff。
・ForgetDeviceDialogFragment_vulnerable_24b35_parent.java: 公開修…

URL: https://android.googlesource.com/platform/packages/apps/Settings/+/24b35b078f392dc4d649338ec123dd3f8928440b / https://source.android.com/docs/security/bulletin/2026/2026-06-01

validated.md を表示
# CVE-2026-0096 / A-473005624 検証結果

## 結論

このCVEは特定できた。脆弱性は `packages/apps/Settings` の `ForgetDeviceDialogFragment#getAppLabel()` におけるアプリラベル注入である。

Bluetooth機器を「Forget device」する確認ダイアログは、`Flags.enableRemoveAssociationBtUnpair()` が有効で、その機器に Companion Device Manager の association が存在する場合、機器のunpairだけでなく関連associationも削除する。このときダイアログ本文に関連アプリ名を表示するが、修正前は攻撃者制御のアプリラベルを `PackageManager.getApplicationLabel()` で取得し、そのまま本文に埋め込んでいた。

攻撃者アプリが改行、HTML由来の改行、前後空白、過大な文字列などを含むラベルを設定すると、Settingsの確認ダイアログ本文を誤解させられる。ユーザーは本来削除されるassociation/対象アプリを正しく認識できず、Bluetooth機器のforget操作に伴って攻撃者が意図したassociation削除を承認してしまう可能性がある。Android bulletin/OSV上の分類は System / EoP / High で、「misleading or insufficient UI によりユーザーを騙してdeviceをforgetさせる」問題と説明されている。

## 根本原因

根本原因は、信頼できないアプリ由来の表示名を、システム設定アプリのセキュリティ関連確認UIにそのまま合成していたこと。

問題の流れ:

1. `CompanionDeviceManager.getAllAssociations()` から、対象Bluetooth MACアドレスに紐づく `AssociationInfo` を列挙する。
2. 各associationの `packageName` に対して `getAppLabel(packageName)` を呼ぶ。
3. 修正前の `getAppLabel()` は `mPackageManager.getApplicationLabel(mPackageManager.getApplicationInfo(packageName, 0))` を返す。
4. 返されたラベルを `ListFormatter` で結合し、`bluetooth_unpair_dialog_with_associations_body` の引数として確認ダイアログ本文に埋め込む。
5. confirm時には `mDevice.unpair()` と `mCompanionDeviceManager.disassociate(ai.getId())` が実行される。

`getApplicationLabel()` / `loadLabel()` 系はラベル長を一定上限に切るだけで、表示上危険な改行や端の空白を必ず除去するAPIではない。確認ダイアログの本文に入れる前にUI表示用のsafe labelへ変換していなかったことが直接原因である。

## パッチ内容

公開修正コミット:

- `24b35b078f392dc4d649338ec123dd3f8928440b`
  - URL: https://android.googlesource.com/platform/packages/apps/Settings/+/24b35b078f392dc4d649338ec123dd3f8928440b
  - commit message: `Fix app label injection in ForgetDeviceDialogFragment`
  - Bug: `473005624`
  - Cherrypick-From: `08db8c5058a3257b9dbc8ba2647bf7d0b46a42a9`
  - Change-Id: `I49bf86eec5e1402b5797f5a8118b96e7505c3877`

本体差分は `src/com/android/settings/bluetooth/ForgetDeviceDialogFragment.java` の `getAppLabel()` だけで、次の置換を行う。

```java
- return mPackageManager.getApplicationLabel(
-         mPackageManager.getApplicationInfo(packageName, 0));
+ return mPackageManager.getApplicationInfo(packageName, 0).loadSafeLabel(
+         mPackageManager,
+         PackageItemInfo.MAX_SAFE_LABEL_LENGTH,
+         TextUtils.SAFE_STRING_FLAG_TRIM
+                 | TextUtils.SAFE_STRING_FLAG_FIRST_LINE);
```

`PackageItemInfo.loadSafeLabel()` は内部で `TextUtils.makeSafeForPresentation()` を呼ぶ。今回指定されたフラグの効果は以下。

- `PackageItemInfo.MAX_SAFE_LABEL_LENGTH`: 最大1000文字だけを処理対象にする。
- `TextUtils.SAFE_STRING_FLAG_TRIM`: 端の空白やNBSPを除去する。
- `TextUtils.SAFE_STRING_FLAG_FIRST_LINE`: 最初の改行以降を破棄する。

これにより、攻撃者がアプリラベルに複数行の偽メッセージや空白による視覚的なずらしを仕込んでも、確認ダイアログに埋め込まれる前に1行の安全な表示名へ正規化される。

## 悪用条件と影響

想定条件:

- 攻撃者がインストール済みアプリのラベルを制御できる。
- そのアプリが Companion Device Manager association を作成し、対象Bluetooth機器のMACアドレスに紐づいている。
- ユーザーがSettings上で該当Bluetooth機器のforget操作を行う。
- `Flags.enableRemoveAssociationBtUnpair()` が有効なビルド/構成である。

影響:

- SettingsのシステムUI内で、攻撃者制御のアプリラベルが確認本文の一部として表示される。
- 改行などにより、削除対象アプリ名や確認文の意味を偽装できる。
- ユーザーの判断を誤らせ、Bluetooth unpairとassociation削除を実行させられる。
- Bulletin上は「local escalation of privilege」と評価されている。ユーザー操作を経由するUI欺瞞型だが、システム設定アプリが持つassociation削除動作を攻撃者の意図通りに誘導できる点が権限昇格相当と見なされている。

## 調査メモ

- 既存 `cve.md` 確認:
  - CVE: `CVE-2026-0096`
  - Reference: `A-473005624`
  - Component: `System`
  - Type/Severity: `EoP / High`
  - Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
  - Updated AOSP versions: `16`, `16-qpr2`
- OSV JSONには `17-next`, `16`, `16-qpr2` の affected range とfixが記録されていた。
- OSV detailsは `getAppLabel of ForgetDeviceDialogFragment.java` で「misleading or insufficient UI」によりユーザーを騙してdeviceをforgetさせる可能性がある、と明記している。
- OSVの `16` / `16-qpr2` fix URLである `08db8c...` と `db5cc...` は、調査時点でGitilesの直接diff取得が404だった。公開参照として到達可能な `24b35b...` は `08db8c...` からのcherrypickで、同じ `Change-Id` を持つ。
- `17-next` fix `62b7a2483f4eef4ff0f02ccb81fe6cfea9819ef8` も同一内容の差分だった。
- テスト差分は既存テストのmockを `getApplicationLabel(appInfo)` から `appInfo.loadSafeLabel(... TRIM | FIRST_LINE)` に合わせただけで、悪意ある複数行ラベルの回帰テストは追加されていない。ここは面白い点で、パッチ自体は明確だがテストは脆弱性シナリオを直接固定していない。

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

- `ASB-A-473005624.json`: Android OSV JSON。
- `24b35_commit.json`: 公開cherrypickコミットのGitiles log JSON。
- `62b7_commit.json`: 17-next修正コミットのGitiles log JSON。
- `24b35b078f392dc4d649338ec123dd3f8928440b.diff`: 公開cherrypickのGitiles diff。
- `62b7a2483f4eef4ff0f02ccb81fe6cfea9819ef8.diff`: 17-next修正コミットのGitiles diff。
- `ForgetDeviceDialogFragment_vulnerable_24b35_parent.java`: 公開修正コミット親の脆弱版ファイル。
- `ForgetDeviceDialogFragment_fixed_24b35.java`: 公開修正コミット後のファイル。
- `ForgetDeviceDialogFragment_24b35_file.diff`: 脆弱版と修正版の最小ファイル差分。
- `ForgetDeviceDialogFragmentTest_vulnerable_24b35_parent.java`: 修正前テスト。
- `ForgetDeviceDialogFragmentTest_fixed_24b35.java`: 修正後テスト。
- `ForgetDeviceDialogFragmentTest_24b35_file.diff`: テスト差分。
- `PackageItemInfo_main.java`, `TextUtils_main.java`: `loadSafeLabel()` と `makeSafeForPresentation()` の挙動確認用。

## 判定

`ok`。ソースコード差分、OSV詳細、公開cherrypickのcommit message、前後コードから、脆弱性の発生箇所・条件・根本原因・修正意図を説明できる。
058 OK

CVE-2026-0098

058-ok-documentsui-extra-package-name-saf-bypass-eop

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-397217317
Also listed under Google Play system updatesDocuments UI.
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0098 is listed in the Android Security Bulletin as a High severity EoP issue in System.

特定した具体的な脆弱性

CVE-2026-0098 は、DocumentsUI が Intent.EXTRA_PACKAGE_NAME による呼び出し元パッケージ名の override を「system app / updated system app であること」だけで許可していたため、platform 署名されていないプリインストール系 system app が呼び出し元を別パッケージに偽装できた問題です。

この偽装名は単なる表示名だけではなく、Storage Access Framework(SAF) の制限判定 CompatChanges.isChangeEnabled(RESTRICT_STORAGE_ACCESS_FRAMEWORK, packageName, user) に使われます。そのため、攻撃者が system app フラグを持つが platform 署名ではないアプリとして DocumentsUI の picker を起動し、EXTRA_PACKAGE_NAME に SAF 制限が無効になる別パッケージ名を指定すると、DocumentsUI が本来の呼び出し元ではなく偽装先パッケージの compat state で /Android/data、/Android/obb、/Android/sandbox 配下への EXTRA_INITIAL_URI 制限を判定してしまいます。ユーザーが選択を完了すると、呼び出し元アプリは本来制限される場所への URI 権限を得られる可能性があります。

原因

根本原因は、呼び出し元 package name override という identity delegation を、暗号学的な同一主体性ではなく ApplicationInfo の配置フラグで認可したことです。

FLAG_SYSTEM / FLAG_UPDATED_SYSTEM_APP は「端末イメージに含まれる」「プリロードアプリの更新版である」という属性で、OEM/Google/キャリア等の非 platform 署名アプリにも付き得ます。これらを platform trusted proxy と同等に扱うと、非 platform 署名の system app が任意の package name を DocumentsUI 内部の policy decision に注入できます。今回の policy decision は SAF compat 制限であり、packageName 依存の判定結果を攻撃者が選べることになっていました。

どこから特定したか

保存した解析 artifact: ・artifacts/0c8b7870ece9dcdd9a6cb56a98db20fcfacfcc56.diff - 公開パッチ差分
・artifacts/Shared_pre_0284f3e0.java - 親コミットの Shared.java
・artifacts/Shared_post_0c8b7870.java - 修正コミットの Shared.java
・artifacts/DocumentsUI_repo/ - 解析用に clone した DocumentsUI リポジトリ
・artifacts/relevant_ripgrep.txt - 関連シンボル検索結果
・artifacts/related_commits.txt - 同 Change-Id 関連コミットのメタデータ
・artifacts…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/packages/apps/DocumentsUI/+/0c8b7870ece9dcdd9a6cb56a98db20fcfacfcc56 / https://android.googlesource.com/platform/packages/apps/DocumentsUI/+/0c8b7870ece9dcdd9a6cb56a98db20fcfacfcc56%5E%21/ / https://android.googlesource.com/platform/frameworks/base/+/refs/heads/mai…

validated.md を表示
# CVE-2026-0098: DocumentsUI の EXTRA_PACKAGE_NAME 信頼境界不備による SAF 制限回避

## 結論

CVE-2026-0098 は、DocumentsUI が `Intent.EXTRA_PACKAGE_NAME` による呼び出し元パッケージ名の override を「system app / updated system app であること」だけで許可していたため、platform 署名されていないプリインストール系 system app が呼び出し元を別パッケージに偽装できた問題です。

この偽装名は単なる表示名だけではなく、Storage Access Framework(SAF) の制限判定 `CompatChanges.isChangeEnabled(RESTRICT_STORAGE_ACCESS_FRAMEWORK, packageName, user)` に使われます。そのため、攻撃者が system app フラグを持つが platform 署名ではないアプリとして DocumentsUI の picker を起動し、`EXTRA_PACKAGE_NAME` に SAF 制限が無効になる別パッケージ名を指定すると、DocumentsUI が本来の呼び出し元ではなく偽装先パッケージの compat state で `/Android/data`、`/Android/obb`、`/Android/sandbox` 配下への `EXTRA_INITIAL_URI` 制限を判定してしまいます。ユーザーが選択を完了すると、呼び出し元アプリは本来制限される場所への URI 権限を得られる可能性があります。

パッチは override 許可条件を `FLAG_SYSTEM` / `FLAG_UPDATED_SYSTEM_APP` から `PackageManager.checkSignatures(callingUid, Process.SYSTEM_UID) == SIGNATURE_MATCH` に変更し、platform/system UID と同じ証明書で署名されたコアシステムコンポーネントだけが package name override を使えるようにしています。ソース差分から根本原因と悪用条件を説明できるため、この調査結果は `ok` と判断します。

## 確認した advisory 情報

- Bulletin: Android Security Bulletin - June 2026
- URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- CVE: CVE-2026-0098
- Reference: A-397217317
- Component: System
- Subcomponent/Mainline note: Google Play system updates の Documents UI にも掲載
- Type/Severity: EoP / High
- Updated AOSP versions: 14, 15, 16, 16-qpr2

Bulletin の System セクションでは `CVE-2026-0098 A-397217317 EoP High 14, 15, 16, 16-qpr2` として公開変更にリンクされています。また Google Play system updates では `Documents UI CVE-2026-0098` として listed です。

## パッチ情報

一次パッチ:

- Repository: `platform/packages/apps/DocumentsUI`
- Commit: `0c8b7870ece9dcdd9a6cb56a98db20fcfacfcc56`
- Parent: `0284f3e0b34966164cfcaaff0b93d758e32da700`
- Title: `Use signature-based trust for package name overrides`
- URL: https://android.googlesource.com/platform/packages/apps/DocumentsUI/+/0c8b7870ece9dcdd9a6cb56a98db20fcfacfcc56
- Diff: https://android.googlesource.com/platform/packages/apps/DocumentsUI/+/0c8b7870ece9dcdd9a6cb56a98db20fcfacfcc56%5E%21/
- Bugs: `424853397`, `397217317`
- Change-Id: `I0c337720e42f6492573d261ae66fa88c511cd99e`

同一 Change-Id の関連コミットは `artifacts/related_commits.txt` に保存しました。確認できたブランチ対応は `artifacts/commit_branch_map.txt` に保存しています。例: `bb5a2aa6...` は `android14-platform-release`、`a712c946...` は `android14-security-release`、`b05353f6...` は `android15-security-release`、`0c8b7870...` は `android16-security-release` に含まれます。

## 差分の要点

脆弱版 `Shared.getCallingPackageName(Activity)`:

```java
String callingPackage = activity.getCallingPackage();
ApplicationInfo info = activity.getPackageManager().getApplicationInfo(callingPackage, 0);
if (isSystemApp(info) || isUpdatedSystemApp(info)) {
    final String extra = activity.getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
    if (extra != null && !TextUtils.isEmpty(extra)) {
        callingPackage = extra;
    }
}
```

修正版:

```java
String callingPackage = activity.getCallingPackage();
ApplicationInfo info = activity.getPackageManager().getApplicationInfo(callingPackage, 0);
if (activity.getIntent() != null
        && isTrustedSystemSignature(activity.getPackageManager(), info.uid)) {
    final String extra = activity.getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
    if (extra != null && !TextUtils.isEmpty(extra)) {
        callingPackage = extra;
    }
}
```

追加された信頼判定:

```java
private static boolean isTrustedSystemSignature(PackageManager pm, int callingUid) {
    return pm.checkSignatures(callingUid, android.os.Process.SYSTEM_UID)
            == PackageManager.SIGNATURE_MATCH;
}
```

削除された `isSystemApp()` / `isUpdatedSystemApp()` は `ApplicationInfo.FLAG_SYSTEM` と `ApplicationInfo.FLAG_UPDATED_SYSTEM_APP` だけを見る実装でした。これは「システムパーティションにいる/更新済みプリロードである」ことを示す配置属性であり、platform key で署名された trusted delegate であることは保証しません。

## 影響するコードパス

`getCallingPackageName()` の重要な利用先:

- `Shared.shouldRestrictStorageAccessFramework()`
  - `CompatChanges.isChangeEnabled(RESTRICT_STORAGE_ACCESS_FRAMEWORK, packageName, Process.myUserHandle())` に渡す packageName を返す。
  - `RESTRICT_STORAGE_ACCESS_FRAMEWORK = 141600225L` は target SDK > Q で有効化される compat change。
- `ActionHandler.shouldPreemptivelyRestrictRequestedInitialUri()`
  - `DocumentsContract.EXTRA_INITIAL_URI` が ExternalStorageProvider の `/Android/data`、`/Android/obb`、`/Android/sandbox` 配下を指す場合、SAF privacy restriction として初期表示を拒否する。
  - ただし最初に `Shared.shouldRestrictStorageAccessFramework(mActivity)` が false なら制限処理を抜ける。
- `BaseActivity.getState()`
  - `state.restrictScopeStorage` の初期化に使う。
- `BaseActivity.getExcludedAuthorities()`
  - `DocumentsContract.EXTRA_EXCLUDE_SELF` 使用時に、呼び出し元 package の provider authorities を除外する。
- `LastAccessedStorage`
  - per-package の last accessed stack を保存/復元する。
- `Shared.getCallingAppName()` / `Metrics.logPickerLaunchedFrom()`
  - UI 表示とメトリクス。

EoP として最も直接的な経路は SAF 制限回避です。`ActionHandler` のコメントにも、Android 11 以降は `ACTION_OPEN_DOCUMENT` / `ACTION_OPEN_DOCUMENT_TREE` で `/Android/data`、`/Android/obb`、`/Android/sandbox` とそのサブディレクトリをユーザーに選ばせない方針だと明記されています。

## 悪用シナリオ

前提:

1. 攻撃者アプリが `FLAG_SYSTEM` または `FLAG_UPDATED_SYSTEM_APP` を持つ。
2. ただし platform/system UID と同一署名ではない。
3. 攻撃者アプリが DocumentsUI の exported picker activity を `startActivityForResult` / Activity Result API で起動できる。
4. 攻撃者が `Intent.EXTRA_PACKAGE_NAME` に別パッケージ名を指定する。

手順例:

1. 攻撃者アプリが `ACTION_OPEN_DOCUMENT` または `ACTION_OPEN_DOCUMENT_TREE` の Intent を作る。
2. `DocumentsContract.EXTRA_INITIAL_URI` に ExternalStorageProvider の `/Android/data/...`、`/Android/obb/...`、または `/Android/sandbox/...` 配下の document URI を指定する。
3. `Intent.EXTRA_PACKAGE_NAME` に targetSdk <= Q など、`RESTRICT_STORAGE_ACCESS_FRAMEWORK` が無効になるパッケージ名を指定する。
4. 脆弱版 DocumentsUI は実際の呼び出し元が system/updated system app なら override を受け入れ、偽装先 packageName で compat change を問い合わせる。
5. `shouldPreemptivelyRestrictRequestedInitialUri()` が false 側に倒れ、restricted initial URI が拒否されず、その場所から picker を開始できる。
6. ユーザーが選択を承認すると、activity result と URI grant は実際の呼び出し元へ戻るため、攻撃者アプリが本来制限される外部ストレージ領域の document/tree URI 権限を得る。

第三者の通常アプリだけでは `FLAG_SYSTEM` 条件を満たせないため、この問題は任意の Play-installed app から直接使える形ではありません。ただし、Android の信頼境界としては「プリインストールされているが platform 署名ではない app」を trusted delegate と見なしてしまうことが問題です。パッチタイトルと本文もこの点を明確にしており、`installation status (FLAG_SYSTEM)` ではなく `cryptographic signatures` に信頼モデルを移す、と説明しています。

## 根本原因

根本原因は、呼び出し元 package name override という identity delegation を、暗号学的な同一主体性ではなく `ApplicationInfo` の配置フラグで認可したことです。

`FLAG_SYSTEM` / `FLAG_UPDATED_SYSTEM_APP` は「端末イメージに含まれる」「プリロードアプリの更新版である」という属性で、OEM/Google/キャリア等の非 platform 署名アプリにも付き得ます。これらを platform trusted proxy と同等に扱うと、非 platform 署名の system app が任意の package name を DocumentsUI 内部の policy decision に注入できます。今回の policy decision は SAF compat 制限であり、packageName 依存の判定結果を攻撃者が選べることになっていました。

修正後は `checkSignatures(callingUid, SYSTEM_UID)` により、system UID と同じ platform 証明書を持つ UID だけが override できます。これは「platform コンポーネントが別アプリの代行で DocumentsUI を起動する」という本来用途を残しつつ、単なるプリインストールアプリを除外する設計です。

## 付帯メモ

- Bulletin では System セクションに出ていますが、Google Play system updates では Documents UI と明記されています。DocumentsUI は Mainline/Google Play system update としても配布され得るため、この分類になっていると見られます。
- パッチ自体は `Shared.java` 1ファイルのみで、テスト追加は見当たりません。commit message の `Test: manual` と一致します。
- `getCallingPackageName()` は last accessed state や app label にも使われるため、偽装による状態汚染や UI 誤表示も副作用として起こり得ます。ただし High EoP としての中核は、policy/compat 判定に偽装 packageName が使われる点です。
- 修正版は `activity.getIntent() != null` も追加しています。主修正ではありませんが、null intent の defensive check が追加された形です。

## 保存した解析 artifact

- `artifacts/0c8b7870ece9dcdd9a6cb56a98db20fcfacfcc56.diff` - 公開パッチ差分
- `artifacts/Shared_pre_0284f3e0.java` - 親コミットの `Shared.java`
- `artifacts/Shared_post_0c8b7870.java` - 修正コミットの `Shared.java`
- `artifacts/DocumentsUI_repo/` - 解析用に clone した DocumentsUI リポジトリ
- `artifacts/relevant_ripgrep.txt` - 関連シンボル検索結果
- `artifacts/related_commits.txt` - 同 Change-Id 関連コミットのメタデータ
- `artifacts/commit_branch_map.txt` - 関連コミットを含む remote branch の確認結果
- `artifacts/android-security-bulletin-2026-06-01.html` - Bulletin の保存コピー
- `artifacts/cts_android16_log.json`, `artifacts/cts_main_log.json` - CTS 側の公開 log 確認用。Bug ID/キーワードで明確な専用 CTS 追加は確認できませんでした。

## 参考 URL

- Android Security Bulletin June 2026: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Patch commit: https://android.googlesource.com/platform/packages/apps/DocumentsUI/+/0c8b7870ece9dcdd9a6cb56a98db20fcfacfcc56
- Patch diff: https://android.googlesource.com/platform/packages/apps/DocumentsUI/+/0c8b7870ece9dcdd9a6cb56a98db20fcfacfcc56%5E%21/
- `DocumentsContract.EXTRA_INITIAL_URI` / DocumentsContract reference source: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/main/core/java/android/provider/DocumentsContract.java
059 OK

CVE-2026-0099

059-ok-nfc-hostapdu-null-binding-bal-eop

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-385917501
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0099 is listed in the Android Security Bulletin as a High severity EoP issue in System.

特定した具体的な脆弱性

ok: 脆弱性を特定できた。

タイトル: nfc-hostapdu-null-binding-bal-eop

対象は NFC Host Card Emulation の HostEmulationManager.java。NFC サービスが HostApduService に Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS 付きでバインドするが、対象サービスが onBind() で null を返す、または binding が死んだ場合の ServiceConnection.onNullBinding() / onBindingDied() 処理が不足していた。その結果、NFC 側が BAL (Background Activity Launch) を許可したバインド状態を正しく閉じず、悪性または壊れた HCE サービスがバックグラウンドから Activity を起動できる状態が残り得る。

原因

根本原因は「BAL権限付きのサービスバインドに対する異常系ライフサイクル処理漏れ」。

HostEmulationManager はHCEサービスへバインドするとき、通常サービスとpayment serviceの両方で次のフラグを使っていた。

``java
Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
`

AndroidのBAL制限では、バックグラウンドActivity起動は原則制限されるが、「background activity starts を許可されたサービスにバインドされているアプリ」は例外になる。つまり NFC がこのフラグで第三者アプリの HostApduService にバインドすると、そのサービス側に Activity 起動の特権的な例外が渡る。

どこから特定したか

参照した公開情報: ・Android Security Bulletin 2026-06-01: https://source.android.com/docs/security/bulletin/2026/2026-06-01
・OSV: https://osv.dev/vulnerability/ASB-A-385917501
・OSV JSON: https://api.osv.dev/v1/vulns/ASB-A-385917501
・AOSP修正としてOSVに記載されたコミット:
- Android 14 / platform/packages/apps/Nfc: 2e5fa5ea2cd3a8cad10616ce33c37f087486fe5f
- Android 15 / platform/packages/…

保存した付帯ファイル: ・artifacts/ASB-A-385917501.osv.json: OSV APIの生データ
・artifacts/ASB-A-385917501.summary.json: OSV要約
・artifacts/lineage_modules_486978_ps3.patch: Android 16系相当の packages/modules/Nfc 差分
・artifacts/HostEmulationManager_modules_before.java
・artifacts/HostEmulationManager_modules_after.java
・artifacts/HostEmulationManager_modules_before_after.diff
・artifacts/lineag…

パッチ差分の要点: And…

validated.md を表示
# CVE-2026-0099 検証結果

## 判定

ok: 脆弱性を特定できた。

タイトル: `nfc-hostapdu-null-binding-bal-eop`

対象は NFC Host Card Emulation の `HostEmulationManager.java`。NFC サービスが `HostApduService` に `Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS` 付きでバインドするが、対象サービスが `onBind()` で null を返す、または binding が死んだ場合の `ServiceConnection.onNullBinding()` / `onBindingDied()` 処理が不足していた。その結果、NFC 側が BAL (Background Activity Launch) を許可したバインド状態を正しく閉じず、悪性または壊れた HCE サービスがバックグラウンドから Activity を起動できる状態が残り得る。

## 既存 cve.md の確認

- CVE: CVE-2026-0099
- 参照ID: A-385917501
- Component: System
- Type / Severity: EoP / High
- Updated AOSP versions: 14, 15, 16, 16-qpr2
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01

Android Security Bulletin では System の High EoP として掲載されている。OSV では詳細が公開されており、「`HostEmulationManager.java` の `onNullBinding` のロジックエラーにより background activity launch が可能になり、local privilege escalation につながる」と説明されている。

## 参照した公開情報

- Android Security Bulletin 2026-06-01: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://osv.dev/vulnerability/ASB-A-385917501
- OSV JSON: https://api.osv.dev/v1/vulns/ASB-A-385917501
- AOSP修正としてOSVに記載されたコミット:
  - Android 14 / `platform/packages/apps/Nfc`: `2e5fa5ea2cd3a8cad10616ce33c37f087486fe5f`
  - Android 15 / `platform/packages/apps/Nfc`: `21e3d5ef1fe63f3b281f5123bb96d1eb0e603228`
  - Android 16 / `platform/packages/modules/Nfc`: `f6fc44fac696ab4ef6d148986443b9a47afc78a2`
  - Android 16-qpr2 / `platform/packages/modules/Nfc`: `2d4b7ed433917f2146cbb1043b739eb8f96c0f09`
- Android Developers BAL説明: https://developer.android.com/guide/components/activities/secure-bal
- 参考にした patch-diffing pipeline 記事: https://www.originhq.com/research/patch-diffing-pipeline

注: `android.googlesource.com` の上記コミット直URLは調査時点で 404 / fetch時にHTTP 500 になったため、OSVでコミットIDを確認したうえで、同じ修正を取り込んだ LineageOS Gerrit の公開チェリーピックから差分と前後ソースを保存した。

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

- `artifacts/ASB-A-385917501.osv.json`: OSV APIの生データ
- `artifacts/ASB-A-385917501.summary.json`: OSV要約
- `artifacts/lineage_modules_486978_ps3.patch`: Android 16系相当の `packages/modules/Nfc` 差分
- `artifacts/HostEmulationManager_modules_before.java`
- `artifacts/HostEmulationManager_modules_after.java`
- `artifacts/HostEmulationManager_modules_before_after.diff`
- `artifacts/lineage_apps_489422_ps1.patch`: 旧 `packages/apps/Nfc` 系の差分
- `artifacts/HostEmulationManager_apps_before.java`
- `artifacts/HostEmulationManager_apps_after.java`
- `artifacts/HostEmulationManager_apps_before_after.diff`
- `artifacts/key_code_references.txt`: 重要行の `rg` 出力
- `artifacts/SHA256SUMS`: 付帯ファイルのSHA-256

## パッチ差分の要点

Android 16系相当の差分では、`NfcNci/src/com/android/nfc/cardemulation/HostEmulationManager.java` に以下が追加されている。

- payment service 用 `mPaymentConnection` に `onNullBinding(ComponentName name)` を追加し、`mContext.unbindService(this)` を呼ぶ。
- 通常HCE service 用 `HostEmulationServiceConnection` に `onBindingDied(ComponentName name)` を追加し、`unbindServiceIfNeededLocked()` を呼ぶ。
- 同じ通常HCE service 用接続に `onNullBinding(ComponentName name)` を追加し、`mContext.unbindService(this)` を呼ぶ。
- event proto に `SERVICE_NULL_BINDING = 3` を追加し、null binding をログ可能にしている。

Android 14/15系相当の `packages/apps/Nfc` 差分ではより直接的で、payment service と通常 service の両方について `onBindingDied()` / `onNullBinding()` からそれぞれ `unbindPaymentServiceLocked()` / `unbindServiceIfNeededLocked()` を呼ぶようにしている。

## 根本原因

根本原因は「BAL権限付きのサービスバインドに対する異常系ライフサイクル処理漏れ」。

`HostEmulationManager` はHCEサービスへバインドするとき、通常サービスとpayment serviceの両方で次のフラグを使っていた。

```java
Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
```

AndroidのBAL制限では、バックグラウンドActivity起動は原則制限されるが、「background activity starts を許可されたサービスにバインドされているアプリ」は例外になる。つまり NFC がこのフラグで第三者アプリの `HostApduService` にバインドすると、そのサービス側に Activity 起動の特権的な例外が渡る。

正常な `onServiceDisconnected()` では `mPaymentService` / `mPaymentServiceName` や `mServiceBound` がクリアされる。しかし修正前は、サービスが null binding を返すケース、特に `Service.onBind()` が null を返して `ServiceConnection.onNullBinding()` が呼ばれるケースを処理していなかった。通常サービス側では `onBindingDied()` も未処理だった。

このため、システム側のバインド・許可状態と `HostEmulationManager` 内部の接続管理がずれ、BAL許可付きのバインドが期待より長く残る。悪性HCEアプリは、NFC決済/カードエミュレーションのサービスとして選択・ルーティングされることで、ユーザー操作なし、またはNFCタップの文脈でNFCプロセスからBAL許可付きバインドを受け、その後 null binding / binding died を使ってバインド終了処理を回避し、バックグラウンドからActivityを前面に出せる。

## 脆弱性の成立条件

想定される攻撃条件:

1. 攻撃者アプリが `HostApduService` を宣言し、NFC HCE / payment service として端末に登録される。
2. NFCトランザクション、優先payment serviceのバインド、またはAID解決により `HostEmulationManager` が攻撃者サービスへバインドする。
3. `HostEmulationManager` は `BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS` 付きで `bindServiceAsUser()` する。
4. 攻撃者サービスが null binding を返す、または binding died 状態を作る。
5. 修正前コードでは `onNullBinding()` / 一部 `onBindingDied()` が未実装で、NFC側が即時に `unbindService()` / 状態クリアを行わない。
6. 攻撃者アプリはBAL例外を利用し、バックグラウンドからActivityを起動できる。

影響は、バックグラウンド起動制限のバイパスによるローカル権限昇格。ここでの「権限昇格」はLinux UIDの昇格ではなく、通常アプリには許されないUI前面化能力、すなわちBAL制限の迂回を得ることを指す。Android Developersの説明でも、無制限なBALはフィッシング、tapjacking、UI hijacking などのセキュリティリスクになる。

## なぜパッチで直るか

修正後は、null binding または binding died の通知を受けた瞬間にNFC側が該当 `ServiceConnection` を unbind する。

- 旧 `packages/apps/Nfc` 系: `onNullBinding()` / `onBindingDied()` から既存の `unbindPaymentServiceLocked()` / `unbindServiceIfNeededLocked()` を呼び、`mPaymentServiceBound` / `mServiceBound` と service名をクリアする。
- 新 `packages/modules/Nfc` 系: 通常serviceでは `onBindingDied()` で `unbindServiceIfNeededLocked()`、`onNullBinding()` で `mContext.unbindService(this)`。payment serviceの null binding も `mContext.unbindService(this)` で接続を閉じる。

これにより、BAL権限付きバインドが「サービスが有効に接続されていないのに残る」状態を防ぐ。修正は機能追加ではなく、バインド異常系のライフサイクルを閉じるアクセス制御修正である。

## 調査時のメモ

- AOSPのOSVデータは対象ファイルと修正コミットをかなり正確に示していた。`vanir_signatures` の対象ファイルも `HostEmulationManager.java`。
- `packages/modules/Nfc` の公開チェリーピックはコミットメッセージに `Bug: 385917501` と元AOSPコミット `cfbd02ac1630e339535cea673c3c4fa155fa668e` を含む。OSVの 17-next 修正コミットと一致する。
- `packages/apps/Nfc` 系のLineageOS差分は件名が `Several BAL bypasses in HostApduService.` で、問題の性質を明示している。本文も「`onBindingDied` or `onNullBinding` で unbinding する」と説明している。
- Android 16系の payment service `onBindingDied()` は修正前から再バインド処理を持っていたが、`onNullBinding()` はなかった。CVE説明が特に `onNullBinding` を名指ししているため、主因は null binding の未処理と判断した。
- 通常service側では `onBindingDied()` も未処理だったため、同じBAL権限付きバインドの後始末漏れとして一緒に修正されている。

## 実行した主なコマンド

```sh
sed -n '1,240p' 059-CVE-2026-0099-System-EoP-High/cve.md
curl -L --fail 'https://api.osv.dev/v1/vulns/ASB-A-385917501'
curl -L --fail 'https://review.lineageos.org/changes/LineageOS%2Fandroid_packages_modules_Nfc~486978/revisions/3/patch?download' | base64 -d
curl -L --fail 'https://review.lineageos.org/changes/LineageOS%2Fandroid_packages_modules_Nfc~486978/revisions/3/files/NfcNci%2Fsrc%2Fcom%2Fandroid%2Fnfc%2Fcardemulation%2FHostEmulationManager.java/content?parent=1' | base64 -d
curl -L --fail 'https://review.lineageos.org/changes/LineageOS%2Fandroid_packages_modules_Nfc~486978/revisions/3/files/NfcNci%2Fsrc%2Fcom%2Fandroid%2Fnfc%2Fcardemulation%2FHostEmulationManager.java/content' | base64 -d
curl -L --fail 'https://review.lineageos.org/changes/LineageOS%2Fandroid_packages_apps_Nfc~489422/revisions/1/patch?download' | base64 -d
diff -u artifacts/HostEmulationManager_modules_before.java artifacts/HostEmulationManager_modules_after.java
diff -u artifacts/HostEmulationManager_apps_before.java artifacts/HostEmulationManager_apps_after.java
rg -n 'onNullBinding|onBindingDied|BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS|unbindPaymentServiceLocked|unbindServiceIfNeededLocked'
```
060 OK

CVE-2026-28574

060-ok-nfc-hce-onserviceconnected-race-permanent-bal

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeEoP
SeverityHigh
Updated AOSP versions16, 16-qpr2
ReferencesA-496735702
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-28574 is listed in the Android Security Bulletin as a High severity EoP issue in System.

特定した具体的な脆弱性

ok: 脆弱性を特定できた。

タイトル: nfc-hce-onserviceconnected-race-permanent-bal

対象は NFC Host Card Emulation の HostEmulationManager.java。NFC が HCE サービスへ Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS 付きでバインドした後、サービス接続完了の onServiceConnected() が届く前に NFC transaction が終了して STATE_IDLE へ戻る race があった。修正前は、この race 後に到着した onServiceConnected() が「既に idle かつ preferred service ではない」と判断して単に return し、対応する unbindService() と接続マップ削除を行わなかった。その結果、悪性 HCE アプリへの BAL (Background Activity Launch) 許可付き service binding が残り、バックグラウンドから Activity を起動できる状態が継続し得た。

原因

根本原因は、非同期 service binding の lifecycle と NFC transaction state の同期不備。

該当コードでは、通常 HCE service を bind するときに次のフラグを使っている。

``java
Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
`

Android の BAL 制限では、background activity starts を許可された service に bind されているアプリはバックグラウンド Activity 起動の例外になり得る。したがって NFC が第三者アプリの HostApduService にこのフラグ付きで bind すると、その binding が生きている間は対象アプリが通常より強い UI 起動能力を持つ。

どこから特定したか

参照した公開情報: ・Android Security Bulletin 2026-06-01: https://source.android.com/docs/security/bulletin/2026/2026-06-01
・OSV HTML: https://osv.dev/vulnerability/ASB-A-496735702
・OSV JSON: https://storage.googleapis.com/android-osv/ASB-A-496735702.json
・Android Developers BAL説明: https://developer.android.com/guide/components/activities/secure-bal
・参考にした patch-diffing pipel…

保存した付帯ファイル: ・477d0eb9f0f6ff7c0d40b7c19ce71aa4a294dc13.diff: Gitiles の公式差分
・commit_477d0eb9.json: Gitiles の公式 commit metadata
・artifacts/ASB-A-496735702.osv.json: OSV JSON
・artifacts/ASB-A-496735702.osv.html: OSV HTML
・artifacts/github_commit_80d5ad7.json: GitHub ミラー commit metadata と patch
・artifacts/HostEmulationManager_mirror_before.java: ミラー上の修正前ソース
・artifacts/HostE…

パッチ差分の要点: 修正は…

validated.md を表示
# CVE-2026-28574 検証結果

## 判定

ok: 脆弱性を特定できた。

タイトル: `nfc-hce-onserviceconnected-race-permanent-bal`

対象は NFC Host Card Emulation の `HostEmulationManager.java`。NFC が HCE サービスへ `Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS` 付きでバインドした後、サービス接続完了の `onServiceConnected()` が届く前に NFC transaction が終了して `STATE_IDLE` へ戻る race があった。修正前は、この race 後に到着した `onServiceConnected()` が「既に idle かつ preferred service ではない」と判断して単に `return` し、対応する `unbindService()` と接続マップ削除を行わなかった。その結果、悪性 HCE アプリへの BAL (Background Activity Launch) 許可付き service binding が残り、バックグラウンドから Activity を起動できる状態が継続し得た。

## 既存 cve.md の確認

- CVE: CVE-2026-28574
- 参照ID: A-496735702
- Component: System
- Type / Severity: EoP / High
- Updated AOSP versions: 16, 16-qpr2
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01

Android Security Bulletin では System の High EoP として掲載されている。OSV では「`HostEmulationManager.java` の `onServiceConnected` に race condition があり BAL が可能」と説明されている。

## 参照した公開情報

- Android Security Bulletin 2026-06-01: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV HTML: https://osv.dev/vulnerability/ASB-A-496735702
- OSV JSON: https://storage.googleapis.com/android-osv/ASB-A-496735702.json
- Android Developers BAL説明: https://developer.android.com/guide/components/activities/secure-bal
- 参考にした patch-diffing pipeline 記事: https://www.originhq.com/research/patch-diffing-pipeline
- AOSP / Gitiles commit:
  - bulletin 参照 commit: `477d0eb9f0f6ff7c0d40b7c19ce71aa4a294dc13`
  - commit message: `Fix permanent BAL grant via onServiceConnected race`
  - Bug: `496735702`
  - parent: `127162a9e7645b4ac8bfc5ece80e0dabb9ddf61f`
  - cherrypick元: `6564c573280aad995b6e71536a1b8c190c63afea`
- OSVに記載された AOSP fix:
  - `17-next`: `6564c573280aad995b6e71536a1b8c190c63afea`
  - `16`: `8559b91e8d43dad73f579666b6688922c947ca9e`
  - `16-qpr2`: `c5c23ea09d082c9c63e83928c3c28bb48fd1625e`
- 補助的に確認した GitHub ミラー:
  - repo: `PixelOS-AOSP/android_packages_modules_Nfc`
  - commit: `80d5ad79344a4be9e852838b3005ff5bf7e16bcc`
  - parent: `28d91d7e08a2537461f03e34e9a04ebd8badbc0d`
  - message と patch は AOSP commit と同じ `Fix permanent BAL grant via onServiceConnected race`

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

- `477d0eb9f0f6ff7c0d40b7c19ce71aa4a294dc13.diff`: Gitiles の公式差分
- `commit_477d0eb9.json`: Gitiles の公式 commit metadata
- `artifacts/ASB-A-496735702.osv.json`: OSV JSON
- `artifacts/ASB-A-496735702.osv.html`: OSV HTML
- `artifacts/github_commit_80d5ad7.json`: GitHub ミラー commit metadata と patch
- `artifacts/HostEmulationManager_mirror_before.java`: ミラー上の修正前ソース
- `artifacts/HostEmulationManager_mirror_after.java`: ミラー上の修正後ソース
- `artifacts/HostEmulationManager_mirror_before_after.diff`: 修正前後ソースの diff
- `artifacts/SHA256SUMS`: 保存した付帯ファイルの SHA-256

注: `android.googlesource.com` から完全な Java blob を `?format=TEXT` で取得しようとしたが、調査時点では大きい blob の取得が `curl: (35) Recv failure: Connection reset by peer` で失敗した。そのため、公式 Gitiles からは commit metadata と小さい diff を保存し、完全な前後ソースは同一パッチを持つ GitHub ミラーから保存した。

## パッチ差分の要点

修正は `NfcNci/src/com/android/nfc/cardemulation/HostEmulationManager.java` の `HostEmulationServiceConnection.onServiceConnected()` のみ。

修正前:

```java
/* Service is already deactivated and not preferred, don't bind */
if (mState.get() == STATE_IDLE && !name.equals(preferredServiceName)) {
    return;
}
```

修正後:

```java
/* Service is already deactivated and not preferred, don't bind */
if (mState.get() == STATE_IDLE && !name.equals(preferredServiceName)) {
    try {
        mContext.unbindService(this);
    } catch (IllegalArgumentException e) {
        Log.w(TAG, "Failed to unbind " + name, e);
    }
    mComponentNameToConnectionsMap.remove(
            new ComponentNameAndUser(mUserId, name));
    return;
}
```

つまり、race 後に不要になった service の `onServiceConnected()` が遅れて届いた場合でも、BAL 許可付き binding を明示的に閉じ、複数 binding 用の `mComponentNameToConnectionsMap` からも削除するようになった。

## 根本原因

根本原因は、非同期 service binding の lifecycle と NFC transaction state の同期不備。

該当コードでは、通常 HCE service を bind するときに次のフラグを使っている。

```java
Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
```

Android の BAL 制限では、background activity starts を許可された service に bind されているアプリはバックグラウンド Activity 起動の例外になり得る。したがって NFC が第三者アプリの `HostApduService` にこのフラグ付きで bind すると、その binding が生きている間は対象アプリが通常より強い UI 起動能力を持つ。

複数 service binding が有効な場合、`bindServiceIfNeededLocked()` は `bindServiceAsUser()` の前に `mComponentNameToConnectionsMap` へ `HostEmulationConnection` を登録する。しかし `onServiceConnected()` が届くまでは `mMessenger` は null のまま。

一方、非アクティブ service の後始末を行う `unbindInactiveServicesLocked()` は、preferred service ではない接続について `connection.mMessenger != null` の場合だけ `mContext.unbindService(connection.mServiceConnection)` を呼ぶ。`mMessenger == null`、つまり bind 要求後まだ接続完了していない entry は unbind されない。その後、このメソッドは retained map を作り直すため、未接続 entry は map からも消える。

この状態で遅れて `onServiceConnected()` が来ると、修正前コードは `mState == STATE_IDLE && !name.equals(preferredServiceName)` で早期 return するだけだった。すでに map から消えているため後続の inactivity cleanup からも追跡されず、かつ `return` 前に `unbindService(this)` もしないため、BAL 許可付き binding が永続的に残り得る。

## 脆弱性の成立条件

想定される攻撃条件:

1. 攻撃者アプリが HCE の `HostApduService` を宣言し、AID などを通じて NFC service の bind 対象になる。
2. NFC transaction または polling loop 処理で `HostEmulationManager` が攻撃者 service へ `BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS` 付きで `bindServiceAsUser()` する。
3. `onServiceConnected()` が返る前に NFC transaction が終了し、`returnToIdleStateLocked()` により `mState` が `STATE_IDLE` になる。
4. `mUnbindInactiveServicesRunnable` / `unbindInactiveServicesLocked()` が走るが、対象 connection は `mMessenger == null` のため unbind されず、map からだけ消える。
5. その後、攻撃者 service の `onServiceConnected()` が遅れて呼ばれる。
6. 修正前は idle かつ preferred service ではないため、その callback は何もせず `return` する。
7. NFC プロセスから攻撃者アプリへの BAL 許可付き binding が残り、攻撃者アプリがバックグラウンドから Activity を起動できる。

影響はローカル権限昇格。ここでの EoP は Linux UID の昇格ではなく、通常アプリが持たない background activity launch 能力を得ることによる Android framework 上の権限境界突破である。OSV は「追加の実行権限不要、ユーザー操作不要」と記載している。

## なぜパッチで直るか

修正後は、遅れて届いた `onServiceConnected()` が「既に idle で preferred service でもない」と判断した時点で、callback に対応する `ServiceConnection` 自体を `mContext.unbindService(this)` で閉じる。さらに `mComponentNameToConnectionsMap.remove(new ComponentNameAndUser(mUserId, name))` で複数 binding 用の追跡情報も削除する。

これにより、bind 要求と接続完了 callback の間に transaction state が変わっても、BAL 許可付き service binding が orphan にならない。修正はアクセス制御そのものの追加ではなく、特権付き binding の非同期 lifecycle を閉じる race 修正である。

## 調査時のメモ

- 直前の CVE-2026-0099 も NFC HCE の BAL bypass で、`onNullBinding()` / `onBindingDied()` の後始末漏れだった。今回の CVE-2026-28574 は同じ BAL 領域だが、主因は null binding ではなく `onServiceConnected()` が遅れて届く race。
- `unbindInactiveServicesLocked()` が `mMessenger != null` の connection だけ unbind する点が重要だった。接続完了前の entry は unbind されず、しかも retained map に残らないため、後から callback が来た時点では通常の cleanup 経路から外れている。
- `UNBIND_SERVICES_DELAY_MS` は `10_000`。非アクティブ service を遅延 unbind する設計自体は性能・transaction 継続性のためだが、未接続状態を考慮していなかった。
- Gitiles の commit message が `Fix permanent BAL grant via onServiceConnected race` と非常に直接的で、OSV の `possible way to perform BAL due to a race condition` と一致していた。
- Android Developers の BAL 説明では、background activity starts を許可された service に bind されている app は BAL 例外になり得る。今回の `BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS` が実質的な権限付与点である。

## 実行した主なコマンド

```sh
sed -n '1,220p' 060-CVE-2026-28574-System-EoP-High/cve.md
curl -L 'https://android.googlesource.com/platform/packages/modules/Nfc/+/477d0eb9f0f6ff7c0d40b7c19ce71aa4a294dc13%5E%21/?format=TEXT' | base64 -d
curl -L 'https://android.googlesource.com/platform/packages/modules/Nfc/+/477d0eb9f0f6ff7c0d40b7c19ce71aa4a294dc13?format=JSON'
curl -L 'https://storage.googleapis.com/android-osv/ASB-A-496735702.json'
curl -L 'https://api.github.com/repos/PixelOS-AOSP/android_packages_modules_Nfc/commits/80d5ad7'
curl -L 'https://raw.githubusercontent.com/PixelOS-AOSP/android_packages_modules_Nfc/28d91d7e08a2537461f03e34e9a04ebd8badbc0d/NfcNci/src/com/android/nfc/cardemulation/HostEmulationManager.java'
curl -L 'https://raw.githubusercontent.com/PixelOS-AOSP/android_packages_modules_Nfc/80d5ad79344a4be9e852838b3005ff5bf7e16bcc/NfcNci/src/com/android/nfc/cardemulation/HostEmulationManager.java'
diff -u artifacts/HostEmulationManager_mirror_before.java artifacts/HostEmulationManager_mirror_after.java
rg -n 'BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS|bindServiceAsUser|onServiceConnected|mComponentNameToConnectionsMap|unbindInactiveServicesLocked|STATE_IDLE'
shasum -a 256 477d0eb9f0f6ff7c0d40b7c19ce71aa4a294dc13.diff commit_477d0eb9.json artifacts/*
```
061 OK

CVE-2025-48600

061-ok-cross-user-info-disclosure

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeID
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-435188844
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-48600 is listed in the Android Security Bulletin as a High severity ID issue in System.

特定した具体的な脆弱性

判定: ok。

CVE-2025-48600 は frameworks/base の PackageManager / ComputerEngine.java 周辺で、横断ユーザの情報を返す経路に権限チェック漏れまたはチェック主体の取り違えがあった情報漏えい脆弱性だった。OSV の説明は「multiple files」「missing permission check」「reveal information across users」で、公開された Vanir signature は ComputerEngine#resolveContentProvider、hasCrossUserPermission、queryIntentServicesInternal、getInstalledApplications、getComponentEnabledSetting に集中している。

根本原因は主に2つ。

1. resolveContentProvider() が userId@authority 形式の authority を正規化する前に mUserManager.exists(userId) を実行していたため、authority から取り出した実 userId が未作成ユーザでも後段の provider 解決へ渡り得た。
2. 横断ユーザ権限チェックで、PackageManager 内部の「照会対象 UID」と、実際に Binder API を呼んだ UID が混同されていた。旧コードは一部で Context#checkCallingOrSelfPermission() や引数 callingUid を使っており、実 caller の横断ユーザ権限を正しく強制できない経路があった。

原因

根本原因は、ユーザ境界で使う値を正規化・検証する順序と、権限チェックの主体が一貫していなかったこと。

・authority 文字列は単なる provider 名ではなく userId@authority を含み得る。
・メソッド引数の userId は最終的に解決する userId とは限らない。
・旧コードは正規化後 userId の存在確認をしていなかった。
・direct provider 解決の ComponentResolverBase#queryProvider() は自前で user existence check を持たず、呼び出し元の検証に依存していた。
・PackageUserStateDefault が「installed=true」相当のデフォルト状態を返すため、未作成 userId が有効な user state のように扱われた。
・PackageManager の callingUid 引数には「照会対象 / 可視性判定用 UID」としての意味があり、Binder API を呼んだ主体とは別物になり得る。旧コードはこの2つを横断ユーザ権限チェックで混同していた。

どこから特定したか

解析した公開修正: 保存済み差分は artifacts/ に格納した。

パッチ解析: d1ec2efc... は provider authority を userId@authority として解釈する処理を追加した。

``java
String authorityWithoutUserId = ContentProvider.getAuthorityWithoutUserId(name);
userId = ContentProvider.getUserIdFromAuthority(name, userId);

final ProviderInfo providerInfo = mComponentResolver.queryProvider(this,
authorityWithoutUserId, flags, userId);
`

保存した付帯ファイル: ・artifacts/ASB-A-435188844.json
・artifacts/bulletin-2026-06-01.html
・artifacts/bulletin-2025-12-01.html
・artifacts/02fc7472_commit.txt
・artifacts/02fc7472_frameworks_base.diff
・artifacts/d1ec2efc0b8941a0585712d5b4cec95fd9f12f17.commit.txt
・artifacts/d1ec2efc0b8941a0585712d5b4cec95fd9f12f17.diff
・artifacts/57eaa465cabb9a74cc57cbb16657c36ad9fc2d58.commit.txt…

validated.md を表示
# CVE-2025-48600 検証結果

## 結論

判定: **ok**。

CVE-2025-48600 は `frameworks/base` の PackageManager / `ComputerEngine.java` 周辺で、横断ユーザの情報を返す経路に権限チェック漏れまたはチェック主体の取り違えがあった情報漏えい脆弱性だった。OSV の説明は「multiple files」「missing permission check」「reveal information across users」で、公開された Vanir signature は `ComputerEngine#resolveContentProvider`、`hasCrossUserPermission`、`queryIntentServicesInternal`、`getInstalledApplications`、`getComponentEnabledSetting` に集中している。

根本原因は主に2つ。

1. `resolveContentProvider()` が `userId@authority` 形式の authority を正規化する前に `mUserManager.exists(userId)` を実行していたため、authority から取り出した実 userId が未作成ユーザでも後段の provider 解決へ渡り得た。
2. 横断ユーザ権限チェックで、PackageManager 内部の「照会対象 UID」と、実際に Binder API を呼んだ UID が混同されていた。旧コードは一部で `Context#checkCallingOrSelfPermission()` や引数 `callingUid` を使っており、実 caller の横断ユーザ権限を正しく強制できない経路があった。

これにより、本来は別ユーザまたは存在しないユーザとして拒否されるべき provider / package / component 情報が、呼び出し元へ返る可能性があった。実データの読み書きまで到達する EoP ではなく、CVE-2025-48600 としては「ユーザ境界を越えた情報開示」として整理される。

## 基本情報

- CVE: `CVE-2025-48600`
- Reference: `A-435188844`
- Component: `System`
- Type: `ID`
- Severity: `High`
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://storage.googleapis.com/android-osv/ASB-A-435188844.json
- Affected / fixed AOSP versions: 14, 15, 16, 16-qpr2
- 公開Bulletin上の直接リンク: `02fc7472ebb27fd394caafa8b87d4daead295d70`
- 注意点: 2026-06 Bulletin の表では `A-435188844` が `02fc7472...` にリンクされているが、OSV では `d1ec2efc...`、`57eaa465...`、`6775f075...` など複数の修正が紐づく。単一コミットだけを見ると修正範囲を過小評価する。

## 解析した公開修正

保存済み差分は `artifacts/` に格納した。

- `d1ec2efc0b8941a0585712d5b4cec95fd9f12f17`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/d1ec2efc0b8941a0585712d5b4cec95fd9f12f17
  - 件名: `Parse authority to separate userId and non-user parts of it`
  - 内容: `10@com.example` のような authority を userId と実 authority に分離して provider 解決する。
- `57eaa465cabb9a74cc57cbb16657c36ad9fc2d58`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/57eaa465cabb9a74cc57cbb16657c36ad9fc2d58
  - 件名: `Checking userId in com.android.server.pm.ComputerEngine#resolveContentProvider`
  - 内容: authority から取り出した実 userId に対して `mUserManager.exists(userId)` と `updateFlagsForComponent()` を実行するよう順序を修正。
- `6775f07552f15f6e4b934bb9552f7a6abff8060b`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/6775f07552f15f6e4b934bb9552f7a6abff8060b
  - 件名: `Check cross user permissions for a given UID`
  - 内容: 指定 UID の権限確認では `hasPermission(permission, callingUid)` を使い、public Binder API の enforcement では `Binder.getCallingUid()` を使うよう修正。
- `02fc7472ebb27fd394caafa8b87d4daead295d70`
  - URL: https://android.googlesource.com/platform/frameworks/base/+/02fc7472ebb27fd394caafa8b87d4daead295d70
  - `57eaa465...` の cherry-pick。2026-06 Bulletin の `A-435188844` から直接リンクされる。

OSV には Android 16 向け `90eff817...` と 16-qpr2 向け `f3e6526...` も記載されているが、通常の Gitiles URL からは今回取得できなかった。fix URL 自体は `ASB-A-435188844.json` に保存済み。

## パッチ解析

### 1. `resolveContentProvider()` の userId 検証順序

`d1ec2efc...` は provider authority を `userId@authority` として解釈する処理を追加した。

```java
String authorityWithoutUserId = ContentProvider.getAuthorityWithoutUserId(name);
userId = ContentProvider.getUserIdFromAuthority(name, userId);

final ProviderInfo providerInfo = mComponentResolver.queryProvider(this,
        authorityWithoutUserId, flags, userId);
```

しかしこの時点では、先頭の存在確認はまだ正規化前の引数 `userId` に対して行われていた。

```java
if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForComponent(flags, userId);
```

そのため、呼び出し元が実在する userId を引数に渡しつつ、authority に `999@some.provider` のような未作成 userId を含めると、存在確認後に `userId` が 999 へ上書きされる。`57eaa465...` / `02fc7472...` はこの順序を入れ替え、実際に解決へ使う userId を検証するようにした。

```java
String authorityWithoutUserId = ContentProvider.getAuthorityWithoutUserId(name);
userId = ContentProvider.getUserIdFromAuthority(name, userId);

if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForComponent(flags, userId);
```

後段の `ComponentResolverBase#queryProvider()` は authority map から provider を引き、`packageState.getUserStateOrDefault(userId)` で user state を取得する。未登録 userId では `PackageUserStateInternal.DEFAULT` に倒れ、`PackageUserStateDefault#isInstalled()` は `true` を返す。つまり、未作成ユーザが「通常インストール済み」のように見え、`ApplicationInfo` / `ProviderInfo` が生成され得る。

### 2. 横断ユーザ権限チェックの主体混同

`6775f075...` では、`hasCrossUserPermission()` が引数 `callingUid` を受け取っているにもかかわらず、旧コードは引数なし `hasPermission()` を呼んでいた。

```java
boolean permissionGranted = requireFullPermission ? hasPermission(
        Manifest.permission.INTERACT_ACROSS_USERS_FULL)
        : (hasPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
        || hasPermission(Manifest.permission.INTERACT_ACROSS_USERS));
```

引数なし `hasPermission()` は `mContext.checkCallingOrSelfPermission(permission)` に依存するため、検査対象は「指定 UID」ではなく Binder caller または system_server 自身になる。修正後は次のように明示的に対象 UID を渡す。

```java
boolean permissionGranted = requireFullPermission ? hasPermission(
        Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingUid)
        : (hasPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingUid)
        || hasPermission(Manifest.permission.INTERACT_ACROSS_USERS, callingUid));
```

同じコミットで、`queryIntentServicesInternal()`、`getInstalledApplications()`、`getComponentEnabledSetting()` の public API 境界では、代理対象の `callingUid` ではなく `Binder.getCallingUid()` に対して `enforceCrossUserPermission()` / `enforceCrossUserOrProfilePermission()` を行うよう変更されている。これは「結果フィルタ用の UID」と「実際に横断ユーザアクセスを要求した UID」を分離する修正である。

## 脆弱性が起きる状況

`resolveContentProvider` 系では次の条件で問題が起きる。

1. 呼び出し元が `PackageManager.resolveContentProvider()` / `IPackageManager.resolveContentProvider()` または system_server 内の provider 解決経路に到達する。
2. authority に `userId@authority` 形式を含める。例: `999@com.example.provider`。
3. 引数 `userId` は実在ユーザなので旧コードの先頭チェックを通過する。
4. その後 `ContentProvider.getUserIdFromAuthority()` により `userId=999` へ上書きされる。
5. 旧コードは上書き後の userId を存在確認しないまま `ComponentResolverBase#queryProvider()` に渡す。
6. `queryProvider()` は `PackageUserStateInternal.DEFAULT` を使って `ProviderInfo` / `ApplicationInfo` を作れる。
7. 呼び出し元は、本来存在しないユーザまたは横断ユーザとして拒否されるべき provider 情報を観測できる。

UID混同系では次の条件で問題が起きる。

1. PackageManager の内部関数が、結果の見え方を決めるために `callingUid` 引数を受け取る。
2. 旧コードはその `callingUid` を横断ユーザ enforcement に使う、または `checkCallingOrSelfPermission()` によって実質 system_server / Binder caller の権限を見る。
3. public Binder API では実際の呼び出し元が横断ユーザ権限を持つかを確認すべきだが、旧コードでは代理 UID や system_server 文脈が混ざり得る。
4. 結果として、別ユーザの installed app / service / component / provider 情報が返る可能性がある。

## 根本原因

根本原因は、ユーザ境界で使う値を正規化・検証する順序と、権限チェックの主体が一貫していなかったこと。

- authority 文字列は単なる provider 名ではなく `userId@authority` を含み得る。
- メソッド引数の `userId` は最終的に解決する userId とは限らない。
- 旧コードは正規化後 userId の存在確認をしていなかった。
- direct provider 解決の `ComponentResolverBase#queryProvider()` は自前で user existence check を持たず、呼び出し元の検証に依存していた。
- `PackageUserStateDefault` が「installed=true」相当のデフォルト状態を返すため、未作成 userId が有効な user state のように扱われた。
- PackageManager の `callingUid` 引数には「照会対象 / 可視性判定用 UID」としての意味があり、Binder API を呼んだ主体とは別物になり得る。旧コードはこの2つを横断ユーザ権限チェックで混同していた。

## 調査メモ

- 2025-12 Bulletin では CVE-2025-48600 と CVE-2025-48615 が一度掲載されたが、2025-12-17 の更新で「incomplete fix」として ASB#2025-12 から削除されている。2026-06 Bulletin で `A-435188844` として再掲載され、更新日 2026-06-03 に AOSP links が追加された。
- `A-435188844` のOSVレコードと `A-365086157` / CVE-2025-22426 のOSVレコードは、少なくとも 17-next の修正コミット集合と Vanir signature がほぼ同じである。Bulletin 上では前者が ID、後者が EoP として別CVEに分かれているため、同じ root cause が情報漏えい面と権限昇格面の両方に評価された可能性が高い。
- Bulletin の `A-435188844` から直接リンクされる `02fc7472...` の commit message は `Bug:401188957` を参照している。公開表の reference とコミット本文の Bug ID が一致しない。
- `d1ec2efc...` は `10@com.example` を正しく user 10 の provider として扱うための機能修正だが、この変更だけでは正規化後 userId の存在確認が足りず、`57eaa465...` が追加で必要になっている。
- 今回はAOSP公開ソースの差分だけで脆弱条件と根本原因を説明できるため、Pixel firmware / バイナリ解析は不要だった。

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

- `artifacts/ASB-A-435188844.json`
- `artifacts/bulletin-2026-06-01.html`
- `artifacts/bulletin-2025-12-01.html`
- `artifacts/02fc7472_commit.txt`
- `artifacts/02fc7472_frameworks_base.diff`
- `artifacts/d1ec2efc0b8941a0585712d5b4cec95fd9f12f17.commit.txt`
- `artifacts/d1ec2efc0b8941a0585712d5b4cec95fd9f12f17.diff`
- `artifacts/57eaa465cabb9a74cc57cbb16657c36ad9fc2d58.commit.txt`
- `artifacts/57eaa465cabb9a74cc57cbb16657c36ad9fc2d58.diff`
- `artifacts/6775f07552f15f6e4b934bb9552f7a6abff8060b.commit.txt`
- `artifacts/6775f07552f15f6e4b934bb9552f7a6abff8060b.diff`
- `artifacts/ComputerEngine_before_57eaa.java`
- `artifacts/ComputerEngine_after_57eaa.java`
- `artifacts/ComputerEngine_before_6775.java`
- `artifacts/ComputerEngine_after_6775.java`
- `artifacts/ComponentResolverBase.java`
- `artifacts/ContentProvider.java`
- `artifacts/PackageStateInternal.java`
- `artifacts/PackageUserStateInternal.java`
- `artifacts/PackageUserStateDefault.java`
- `artifacts/ApplicationPackageManager.java`
- `artifacts/UriGrantsManagerService.java`
062 OK

CVE-2025-48616

062-ok-keyguard-lockdown-strongauth-desync-id

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeID
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-438973280
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-48616 is listed in the Android Security Bulletin as a High severity ID issue in System.

特定した具体的な脆弱性

判定: ok

CVE-2025-48616 は、SystemUI の KeyguardViewMediator が lockdown 中かどうかを判定する際に、KeyguardUpdateMonitor が受け取った strong auth tracker の状態ではなく、別経路の LockPatternUtils.isUserInLockdown() を再参照していたことによる情報漏えい脆弱性と判断した。

脆弱な状態では、lock task / screen pinning などで keyguard が外部的に無効化されている最中にユーザー lockdown が発生した場合、SystemUI が lockdown を見落として keyguard を表示しない、または表示中の keyguard を外部無効化で隠してしまう可能性がある。結果として、lockdown が本来強制すべきロック画面が出ず、固定中アプリの画面などロック前の表示内容が見え続けるため、Android Bulletin の分類どおり Information Disclosure になる。

原因

根本原因は、strong auth 変更通知を受けた SystemUI の処理中に、通知元である KeyguardUpdateMonitor.StrongAuthTracker のキャッシュ状態ではなく、LockPatternUtils 経由で LockSettingsService の状態を再取得していたこと。

関連コード:

どこから特定したか

確認した公開情報: ・CVE: CVE-2025-48616
・Android bug/reference: A-438973280
・Component: System
・Type: ID
・Severity: High
・Updated AOSP versions: 14, 15, 16, 16-qpr2
・Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
・公開修正コミット: https://android.googlesource.com/platform/frameworks/base/+/aa9fbb1b74eb11ce0bd48f0c4cab43fc32a23b4e
・Commit: aa9fbb1b74eb11c…

保存した付帯ファイル: ・aa9fbb1b74eb11ce0bd48f0c4cab43fc32a23b4e.diff: Gitiles から取得した完全 diff
・commit.json: Gitiles commit JSON
・KeyguardViewMediator.before.java
・KeyguardViewMediator.after.java
・KeyguardViewMediatorTest.before.java
・KeyguardViewMediatorTest.after.java
・KeyguardUpdateMonitorCallback.before.java
・KeyguardUpdateMonitorCallback.after.java
・KeyguardUpdateMonitor.java…

URL: https://s…

validated.md を表示
# CVE-2025-48616 検証結果

## 結論

判定: ok

CVE-2025-48616 は、SystemUI の `KeyguardViewMediator` が lockdown 中かどうかを判定する際に、`KeyguardUpdateMonitor` が受け取った strong auth tracker の状態ではなく、別経路の `LockPatternUtils.isUserInLockdown()` を再参照していたことによる情報漏えい脆弱性と判断した。

脆弱な状態では、lock task / screen pinning などで keyguard が外部的に無効化されている最中にユーザー lockdown が発生した場合、SystemUI が lockdown を見落として keyguard を表示しない、または表示中の keyguard を外部無効化で隠してしまう可能性がある。結果として、lockdown が本来強制すべきロック画面が出ず、固定中アプリの画面などロック前の表示内容が見え続けるため、Android Bulletin の分類どおり Information Disclosure になる。

## 確認した公開情報

- CVE: CVE-2025-48616
- Android bug/reference: A-438973280
- Component: System
- Type: ID
- Severity: High
- Updated AOSP versions: 14, 15, 16, 16-qpr2
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- 公開修正コミット: https://android.googlesource.com/platform/frameworks/base/+/aa9fbb1b74eb11ce0bd48f0c4cab43fc32a23b4e
- Commit: `aa9fbb1b74eb11ce0bd48f0c4cab43fc32a23b4e`
- Parent: `2ae33e496027d4ec197953f6bf8511ecd5873e57`
- Change-Id: `I076f5a8cacd14fc8ab8893aedf98ff831a9c195f`
- Commit message の再現メモ: `pin an app; lock down device; observe keyguard always shows (repeat 10x times)`

## パッチ内容

変更は `frameworks/base` の SystemUI 側 3 ファイル。

- `packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java`
  - `onStrongAuthStateChanged()` のコメントを更新し、strong auth state に応答する処理では `KeyguardUpdateMonitor` を truth source とするよう明記。
- `packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java`
  - lockdown 判定 3 箇所を `mLockPatternUtils.isUserInLockdown(...)` から `mUpdateMonitor.isUserInLockdown(...)` に変更。
- `packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java`
  - `onLockdown_showKeyguard_evenIfKeyguardIsNotEnabledExternally`
  - `doNotHideKeyguard_whenLockdown_onKeyguardNotEnabledExternally`
  - 上記テストの mock truth source を `mUpdateMonitor.isUserInLockdown()` に変更。

実装差分の本質は次の 3 箇所だけ。

```diff
- if (mLockPatternUtils.isUserInLockdown(mSelectedUserInteractor.getSelectedUserId())) {
+ if (mUpdateMonitor.isUserInLockdown(mSelectedUserInteractor.getSelectedUserId())) {
    doKeyguardLocked(null);
}

- if (mLockPatternUtils.isUserInLockdown(...)) {
+ if (mUpdateMonitor.isUserInLockdown(...)) {
    Log.d(TAG, "keyguardEnabled(false) overridden by user lockdown");
    return;
}

if (!mExternallyEnabled
-        && !mLockPatternUtils.isUserInLockdown(...)) {
+        && !mUpdateMonitor.isUserInLockdown(...)) {
    ... not showing because externally disabled ...
    return;
}
```

## 根本原因

根本原因は、strong auth 変更通知を受けた SystemUI の処理中に、通知元である `KeyguardUpdateMonitor.StrongAuthTracker` のキャッシュ状態ではなく、`LockPatternUtils` 経由で LockSettingsService の状態を再取得していたこと。

関連コード:

- `KeyguardUpdateMonitor.isUserInLockdown(int)` は `mStrongAuthTracker.getStrongAuthForUser(userId)` の `STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN` bit を見る。
- `KeyguardUpdateMonitor.StrongAuthTracker.onStrongAuthRequiredChanged(int)` は `notifyStrongAuthAllowedChanged(userId)` を呼び、SystemUI 内の各 callback に strong auth state 変更を伝搬する。
- `LockPatternUtils.isUserInLockdown(int)` は binder 経由の `getLockSettings().getStrongAuthForUser(userId)` をその場で読んで bit を見る。
- `LockPatternUtils.StrongAuthTracker.handleStrongAuthRequiredChanged(...)` は tracker のローカル `mStrongAuthRequiredForUser` を更新してから `onStrongAuthRequiredChanged(userId)` を呼ぶ。

つまり、`onStrongAuthStateChanged()` の callback は `KeyguardUpdateMonitor` が strong auth 変更を受けている文脈で発火している。ここで別コンポーネントの `LockPatternUtils` に問い合わせ直すと、commit message のとおり `LockPatternUtils and the StrongAuthTracker check for lockdown may be out of sync` になり得る。セキュリティ判断に使う truth source が callback の発火元と一致していないことが問題だった。

## 脆弱性が起きる状況

脆弱性の主要条件は次の組み合わせ。

1. keyguard が外部的に無効化されている。`KeyguardViewMediator` では `setKeyguardEnabled(false)` により `mExternallyEnabled = false` になる。コメント上の例は通話だが、修正コミットの手動テストは screen pinning / lock task を示している。
2. ユーザーが lockdown を発生させる。strong auth flag に `STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN` が立つ。
3. SystemUI の `onStrongAuthStateChanged()` または keyguard 表示判定が、更新済みの `KeyguardUpdateMonitor` ではなく、同期していない可能性のある `LockPatternUtils` の値を参照する。
4. `mExternallyEnabled == false` かつ lockdown 判定が false に見えると、`doKeyguardLocked()` が `not showing because externally disabled` の early return に入り、keyguard 表示が抑止される。また、表示済み keyguard に対する `setKeyguardEnabled(false)` でも、lockdown override が効かずに `hideLocked()` 側へ進み得る。

この条件では、lockdown は本来「ロック画面を必ず出し、認証まで内容を見せない」方向に働くべきだが、外部 keyguard disable の状態が優先されてしまう。修正後は、strong auth 変更通知を持っている `mUpdateMonitor.isUserInLockdown()` を見て `doKeyguardLocked(null)` を実行し、さらに外部 disable による非表示化も lockdown 中は拒否する。

## なぜ ID か

攻撃者が任意コード実行や権限昇格を得るパッチではなく、ロック画面表示の抑止・非表示化により、ロック前に表示されていた固定アプリや画面内容が lockdown 後も見えることが問題になる。Android Bulletin の Type は ID であり、パッチとテストも「lockdown 時には keyguard を表示し続ける」ことだけを保証しているため、情報漏えいとして整合する。

## 検証メモ

- コミットは `Flag: EXEMPT CVE_FIX` 付きだが、Bug は A-438973280 で Bulletin の CVE と一致した。
- 修正はロジックの置換のみで、認可チェック追加や新規 API 追加ではない。
- `KeyguardUpdateMonitorCallback` のコメント変更が重要で、将来同じ callback で `LockPatternUtils` を truth source にしないよう明示している。
- Android 公式の lock task mode 説明では、lock task 中はロック画面が無効化されることが説明されている。修正コミットの `pin an app; lock down device` はこの状態で lockdown を重ねる再現手順と読める。
- Pixel 固有バイナリではなく AOSP `frameworks/base` の Java 修正で完結するため、`../binaries` へのファームウェア保存は不要だった。

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

- `aa9fbb1b74eb11ce0bd48f0c4cab43fc32a23b4e.diff`: Gitiles から取得した完全 diff
- `commit.json`: Gitiles commit JSON
- `KeyguardViewMediator.before.java`
- `KeyguardViewMediator.after.java`
- `KeyguardViewMediatorTest.before.java`
- `KeyguardViewMediatorTest.after.java`
- `KeyguardUpdateMonitorCallback.before.java`
- `KeyguardUpdateMonitorCallback.after.java`
- `KeyguardUpdateMonitor.java`
- `LockPatternUtils.java`
- `LockSettingsStrongAuth.java`
- `evidence_line_snippets.txt`: 解析で参照した主要箇所の行番号付き抜粋

## 取得 URL

- https://source.android.com/docs/security/bulletin/2026/2026-06-01
- https://android.googlesource.com/platform/frameworks/base/+/aa9fbb1b74eb11ce0bd48f0c4cab43fc32a23b4e
- https://android.googlesource.com/platform/frameworks/base/+/aa9fbb1b74eb11ce0bd48f0c4cab43fc32a23b4e%5E%21/?format=TEXT
- https://android.googlesource.com/platform/frameworks/base/+/2ae33e496027d4ec197953f6bf8511ecd5873e57/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java?format=TEXT
- https://android.googlesource.com/platform/frameworks/base/+/aa9fbb1b74eb11ce0bd48f0c4cab43fc32a23b4e/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java?format=TEXT
- https://android.googlesource.com/platform/frameworks/base/+/aa9fbb1b74eb11ce0bd48f0c4cab43fc32a23b4e/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java?format=TEXT
- https://android.googlesource.com/platform/frameworks/base/+/aa9fbb1b74eb11ce0bd48f0c4cab43fc32a23b4e/core/java/com/android/internal/widget/LockPatternUtils.java?format=TEXT
- https://android.googlesource.com/platform/frameworks/base/+/aa9fbb1b74eb11ce0bd48f0c4cab43fc32a23b4e/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java?format=TEXT
- https://developer.android.com/work/dpc/dedicated-devices/lock-task-mode
063 OK

CVE-2026-0050

063-ok-bluetooth-rebond-access-permission-reuse-id

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeID
SeverityHigh
Updated AOSP versions15, 16, 16-qpr2
ReferencesA-290364858
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0050 is listed in the Android Security Bulletin as a High severity ID issue in System.

特定した具体的な脆弱性

特定できた。CVE-2026-0050 は Android Bluetooth の AdapterService.handleBondStateChanged() における、再ペアリング時のアクセス許可失効漏れによる情報漏えいである。

過去にユーザーが許可した Bluetooth デバイスと同じ BD_ADDR で別デバイスが bond を試みると、Bluetooth stack が BOND_NONE 遷移を受け取らない場合がある。修正前は toState == BOND_NONE の時だけ MAP/PBAP/SAP の永続アクセス許可を削除していたため、同じアドレスで再 bond した別デバイスが、古いデバイスに対する「常に許可」を引き継ぎ、ユーザー確認なしにメッセージ、電話帳、SIM アクセス系プロファイルへ接続できる。

これは bulletin の分類通り System / ID / High と見てよい。Bluetooth の近接攻撃・同一 BD_ADDR のなりすまし・再ペアリングという条件は必要だが、Android アプリ権限は不要で、ユーザー確認ダイアログをバイパスして機微情報へ到達する。

原因

根本原因は、Bluetooth の profile access permission が device.getAddress() をキーに SharedPreferences へ永続保存される一方で、再 bond 開始時に古い許可を失効させる状態遷移条件が不足していたこと。

AdapterService の保存処理:

どこから特定したか

取得・保存した証跡: 主な付帯ファイルは artifacts/ に保存した。

パッチ差分: 修正前:

``java
if (toState == BOND_NONE) {
// Remove the permissions for unbonded devices
setMessageAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN);
setPhonebookAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN);
setSimAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN);
}
`

921aaec06df0b5974d0fbbb40443935b15019270 の修正後:

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/packages/modules/Bluetooth/+/d0f7d128d436220e10c876c131208f580b4bb829` / https://api.osv.dev/v1/vulns/ASB-A-290364858`

validated.md を表示
# CVE-2026-0050 / A-290364858 検証メモ

## 結論

特定できた。CVE-2026-0050 は Android Bluetooth の `AdapterService.handleBondStateChanged()` における、再ペアリング時のアクセス許可失効漏れによる情報漏えいである。

過去にユーザーが許可した Bluetooth デバイスと同じ BD_ADDR で別デバイスが bond を試みると、Bluetooth stack が `BOND_NONE` 遷移を受け取らない場合がある。修正前は `toState == BOND_NONE` の時だけ MAP/PBAP/SAP の永続アクセス許可を削除していたため、同じアドレスで再 bond した別デバイスが、古いデバイスに対する「常に許可」を引き継ぎ、ユーザー確認なしにメッセージ、電話帳、SIM アクセス系プロファイルへ接続できる。

これは bulletin の分類通り System / ID / High と見てよい。Bluetooth の近接攻撃・同一 BD_ADDR のなりすまし・再ペアリングという条件は必要だが、Android アプリ権限は不要で、ユーザー確認ダイアログをバイパスして機微情報へ到達する。

## 入力情報

- CVE: `CVE-2026-0050`
- Android bug / reference: `A-290364858`
- Component: `System`
- Type: `ID`
- Severity: `High`
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- ASB row: `CVE-2026-0050` -> `https://android.googlesource.com/platform/packages/modules/Bluetooth/+/d0f7d128d436220e10c876c131208f580b4bb829`
- OSV: `https://api.osv.dev/v1/vulns/ASB-A-290364858`
- OSV details: `In handleBondStateChanged of AdapterService.java, there is a possible sensitive information disclosure due to a permissions bypass.`

## 取得・保存した証跡

主な付帯ファイルは `artifacts/` に保存した。

- `artifacts/ASB-A-290364858.json`, `artifacts/ASB-A-290364858.pretty.json`: OSV metadata
- `artifacts/android-security-bulletin-2026-06-01.html`: ASB HTML
- `artifacts/origin-patch-diffing-pipeline.html`: 参照された patch diffing pipeline 記事
- `artifacts/d0f7d128d436220e10c876c131208f580b4bb829.commit.txt`
- `artifacts/d0f7d128d436220e10c876c131208f580b4bb829.patch`
- `artifacts/921aaec06df0b5974d0fbbb40443935b15019270.commit.txt`
- `artifacts/921aaec06df0b5974d0fbbb40443935b15019270.patch`
- `artifacts/afca6806043387957c3730c7465f75b1ec407f63.commit.txt`
- `artifacts/afca6806043387957c3730c7465f75b1ec407f63.patch`
- `artifacts/AdapterService.*.java`: 修正前後の `AdapterService.java`
- `artifacts/AdapterService.before_after_921aaec.diff`
- `artifacts/AdapterService.before_after_d0f7.diff`
- `artifacts/AdapterServiceTest.921aaec06df0b5974d0fbbb40443935b15019270.java`
- `artifacts/BluetoothMapService.921aaec.java`
- `artifacts/BluetoothPbapService.921aaec.java`
- `artifacts/SapService.921aaec.java`
- `artifacts/DatabaseManager.921aaec.java`
- `artifacts/commit-summary.txt`

OSV上のブランチ別 fix は以下だった。

- `17-next`: `921aaec06df0b5974d0fbbb40443935b15019270`, `afca6806043387957c3730c7465f75b1ec407f63`
- `15`: `9c2be9f0da10486e20658fcb68ee2669ffdfe9f4`
- `16`: `f83a53408ee5055c4e0b2a0dc7692811b78be7c9`
- `16-qpr2`: `a8d133dacaeadf95d888a3731a17a382ebe7da2c`

調査時点で `9c2be...`, `f83a...`, `a8d...` は公開 Gitiles から commit/diff を取得できず `NOT_FOUND` だった。ASB掲載の `d0f7...` は `f83a...` からの cherrypick と commit message に書かれており、公開されている `921aaec...` と同じ修正内容を持つため、根本原因の特定には十分だった。

## パッチ差分

修正前:

```java
if (toState == BOND_NONE) {
    // Remove the permissions for unbonded devices
    setMessageAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN);
    setPhonebookAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN);
    setSimAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN);
}
```

`921aaec06df0b5974d0fbbb40443935b15019270` の修正後:

```java
if (toState == BOND_NONE
        || (Flags.rebokePermissionOnUnbond() && fromState == BOND_BONDED)) {
    // Remove the permissions for unbonded devices
    setMessageAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN);
    setPhonebookAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN);
    setSimAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN);
}
```

ASB掲載の `d0f7d128d436220e10c876c131208f580b4bb829` では flag guard が外れて、常に `fromState == BOND_BONDED` で削除する形になっている。

```java
if (toState == BOND_NONE || fromState == BOND_BONDED) {
    setMessageAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN);
    setPhonebookAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN);
    setSimAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN);
}
```

後続の `afca6806043387957c3730c7465f75b1ec407f63` は `reboke_permission_on_unbond` flag を削除し、同じく無条件で `fromState == BOND_BONDED` を有効にする cleanup だった。

## 根本原因

根本原因は、Bluetooth の profile access permission が `device.getAddress()` をキーに SharedPreferences へ永続保存される一方で、再 bond 開始時に古い許可を失効させる状態遷移条件が不足していたこと。

`AdapterService` の保存処理:

```java
int getDeviceAccessFromPrefs(BluetoothDevice device, String prefFile) {
    SharedPreferences prefs = getSharedPreferences(prefFile, Context.MODE_PRIVATE);
    if (!prefs.contains(device.getAddress())) {
        return BluetoothDevice.ACCESS_UNKNOWN;
    }
    return prefs.getBoolean(device.getAddress(), false)
            ? BluetoothDevice.ACCESS_ALLOWED
            : BluetoothDevice.ACCESS_REJECTED;
}

void setDeviceAccessFromPrefs(BluetoothDevice device, int value, String prefFile) {
    SharedPreferences pref = getSharedPreferences(prefFile, Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = pref.edit();
    if (value == BluetoothDevice.ACCESS_UNKNOWN) {
        editor.remove(device.getAddress());
    } else {
        editor.putBoolean(device.getAddress(), value == BluetoothDevice.ACCESS_ALLOWED);
    }
    editor.apply();
}
```

`phonebook_access_permission`, `message_access_permission`, `sim_access_permission` の3ファイルに、BD_ADDR単位で `ACCESS_ALLOWED` / `ACCESS_REJECTED` が保存される。修正前は `BOND_NONE` にならなければ `ACCESS_UNKNOWN` へ戻らない。

commit message には以下の状況が明記されている。

- 以前 bonded だったデバイスと同じアドレスのデバイスが再 bond する。
- 新しいデバイスが別個体であっても、AdapterService が `BOND_NONE` state change を受け取らないことがある。
- その結果、ユーザーに新しいデバイスへの同意を求められない。

この説明とコード差分が一致する。つまり、識別子として使った BD_ADDR に対し「同一アドレスなら同一デバイス」という暗黙の信頼を置き、bonding identity の更新境界で許可を失効しなかったことが本質的な設計バグである。

## 情報漏えい経路

`setMessageAccessPermission`, `setPhonebookAccessPermission`, `setSimAccessPermission` が消す3つの許可は、各プロファイルの接続時認可に直接使われる。

### MAP / message access

`BluetoothMapService.onConnect()` は `mAdapterService.getMessageAccessPermission(mRemoteDevice)` を見て、`ACCESS_ALLOWED` ならユーザー確認なしに SDP search へ進む。`ACCESS_UNKNOWN` の場合のみ `ACTION_CONNECTION_ACCESS_REQUEST` を出す。

このため古い `ACCESS_ALLOWED` が残ると、攻撃者デバイスは message access の確認 UI を出さずに MAP 接続できる。MAP は SMS/MMS 系の Message Access Profile なので ID として妥当。

### PBAP / phonebook access

`BluetoothPbapService.checkOrGetPhonebookPermission()` は `getPhonebookAccessPermission()` が `ACCESS_ALLOWED` なら `AUTHORIZED` を state machine に送り、`ACCESS_UNKNOWN` の場合だけ `REQUEST_TYPE_PHONEBOOK_ACCESS` の確認 UI を出す。

古い許可が残ると、PBAP Phone Book Access Server への接続が自動許可され、電話帳・通話履歴・ローカル電話番号などの電話帳系情報へ到達できる。

### SAP / SIM access

`SapService.SocketAcceptThread` は incoming RFCOMM 接続後に `getSimAccessPermission(mRemoteDevice)` を見て、`ACCESS_ALLOWED` なら `startSapServerSession()` を呼ぶ。`ACCESS_REJECTED` でなければ `REQUEST_TYPE_SIM_ACCESS` の確認 UI を出す。

古い `ACCESS_ALLOWED` が残ると、SIM Access Profile もユーザー確認なしで開始される。

## 再現条件の推定

1. 被害端末が Bluetooth デバイス A とペアリング済み。
2. ユーザーが A に対して MAP/PBAP/SAP の接続を「常に許可」する。
3. Android 側の SharedPreferences に A の BD_ADDR をキーとして `ACCESS_ALLOWED` が残る。
4. 攻撃者デバイス B が A と同じ BD_ADDR を使い、再 bond を試みる。
5. Bluetooth stack / AdapterService が `BOND_NONE` を観測せず、`BOND_BONDED -> BOND_BONDING` などで再ペアリングが進む。
6. 修正前の `handleBondStateChanged()` は `toState == BOND_NONE` でないため、保存済み許可を削除しない。
7. B が MAP/PBAP/SAP に接続すると `ACCESS_ALLOWED` と判定され、ユーザー確認が出ない。

修正後は `fromState == BOND_BONDED` でも3つの許可を `ACCESS_UNKNOWN` に戻すため、同一アドレスの再 bond では必ず再同意が必要になる。

## テストから分かること

追加テスト `testRemovePermissionBondedToBonding()` は `handleBondStateChanged(mDevice, BOND_BONDED, BOND_BONDING)` を呼び、SharedPreferences editor の `remove()` が3回呼ばれることを検証している。3回は message / phonebook / sim の3許可に対応する。

このテストは、脆弱な状態遷移が「unbond 完了」ではなく「bonded から bonding へ戻る再ペアリング開始」だったことを強く示している。

## 面白い点・調査メモ

- flag 名が `reboke_permission_on_unbond` と typo している。後続 commit `afca680...` で flag 自体が削除され、常時有効化されている。
- コメントは「unbonded devices の権限削除」のままだが、実際の修正は unbond だけではなく `fromState == BOND_BONDED` の再 bond 境界を扱っている。
- ASBの公開リンク `d0f7...` は 2026-04-09 committer の cherrypick で、commit message に `Cherrypick-From: ... f83a...` とある。OSVの Android 16 fix と整合するが、`f83a...` 自体は公開Gitilesで取得できなかった。
- CVEの直接の漏えいはコード上「ブロードキャストのextra漏えい」ではなく、「保存済み profile access permission の再利用による profile-level 認可バイパス」と見るべき。

## 判定

`ok`。公開AOSPソースとパッチ差分から脆弱性条件、根本原因、修正内容、漏えい対象プロファイルを説明できる。

推奨フォルダ名: `063-ok-bluetooth-rebond-access-permission-reuse-id`
064 OK

CVE-2025-48648

064-ok-sdk-sandbox-notification-identity-confusion-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeDoS
SeverityHigh
Updated AOSP versions14, 15, 16
ReferencesA-396667508
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2025-48648 is listed in the Android Security Bulletin as a High severity DoS issue in System.

特定した具体的な脆弱性

ok: ソースコード差分から脆弱性の発生条件と根本原因を特定できた。

タイトル: sdk-sandbox-notification-identity-confusion-dos

原因

PackageManagerInternal.isSameApp() は、名前の印象と違い、純粋な「この UID がこの package を所有しているか」だけを見る API ではなかった。SDK sandbox UID に対して次の特別扱いがある。

``java
if (Process.isSdkSandboxUid(callingUid)) {
return packageName.equals(mRequiredSdkSandboxPackage);
}
`

つまり SDK sandbox プロセスからの Binder 呼び出しでは、pkg が platform の required SDK sandbox package 名なら isSameApp()` が true になる。NotificationManagerService はこの helper を所有者検査として使っていたため、SDK Runtime 内のコードが SDK sandbox package 名義で NotificationManager API の同一アプリ検査を通過できた。

どこから特定したか

解析した一次情報: ・AOSP commit: https://android.googlesource.com/platform/frameworks/base/+/b88956f3198d591897fd81191b71b001d12e2c19
・Diff: https://android.googlesource.com/platform/frameworks/base/+/b88956f3198d591897fd81191b71b001d12e2c19%5E%21/
・Parent: 09055276288a68cf35b0f84ba32e28822f74ecf9
・Commit title: Update isSameApp check
・Commit message 要点: Only check uid, witho…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/frameworks/base/+/b88956f3198d591897fd81191b71b001d12e2c19 / https://android.googlesource.com/platform/frameworks/base/+/b88956f3198d591897fd81191b71b001d12e2c19%5E%21/

validated.md を表示
# CVE-2025-48648 検証結果

## 判定

ok: ソースコード差分から脆弱性の発生条件と根本原因を特定できた。

タイトル: `sdk-sandbox-notification-identity-confusion-dos`

## 基本情報

- CVE: CVE-2025-48648
- Android bug/reference: A-396667508
- Component/subcomponent: System / NotificationManagerService 周辺
- 種別: DoS
- 重要度: High
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Bulletin 記載: 2026-06-01 patch level、Updated AOSP versions 14, 15, 16

## 解析した一次情報

- AOSP commit: https://android.googlesource.com/platform/frameworks/base/+/b88956f3198d591897fd81191b71b001d12e2c19
- Diff: https://android.googlesource.com/platform/frameworks/base/+/b88956f3198d591897fd81191b71b001d12e2c19%5E%21/
- Parent: `09055276288a68cf35b0f84ba32e28822f74ecf9`
- Commit title: `Update isSameApp check`
- Commit message 要点: `Only check uid, without a sandbox sdk exception`
- Bug: `396667508`
- Fixes: `317957802`
- Changed file: `services/core/java/com/android/server/notification/NotificationManagerService.java`

保存した artifact:

- `artifacts/b88956f3198d591897fd81191b71b001d12e2c19.diff`
- `artifacts/NotificationManagerService.pre.java`
- `artifacts/NotificationManagerService.post.java`
- `artifacts/PackageManagerInternal.java`
- `artifacts/PackageManagerService.pre.java`
- `artifacts/Process.java`
- `artifacts/android-security-bulletin-2026-06-01.html`
- `artifacts/commit.json`
- `artifacts/diff-key-context.txt`
- `artifacts/SHA256SUMS.txt`
- `artifacts/patch-analysis.md`

## パッチの中心

`NotificationManagerService.checkCallerIsSameApp(pkg, uid, userId)` が、旧実装では `PackageManagerInternal.isSameApp(pkg, uid, userId)` を呼んでいた。

修正後は、`mPackageManagerInternal.getPackageUid(pkg, 0L, userId)` で package の実 UID を取得し、`UserHandle.isSameApp(uid, packageUid)` で比較するようになった。

```java
// old
if (!mPackageManagerInternal.isSameApp(pkg, uid, userId)) {
    throw new SecurityException("Package " + pkg + " is not owned by uid " + uid);
}

// new
if (!UserHandle.isSameApp(uid, mPackageManagerInternal.getPackageUid(pkg, 0L, userId))) {
    throw new SecurityException("Package " + pkg + " is not owned by uid " + uid);
}
```

## 根本原因

`PackageManagerInternal.isSameApp()` は、名前の印象と違い、純粋な「この UID がこの package を所有しているか」だけを見る API ではなかった。SDK sandbox UID に対して次の特別扱いがある。

```java
if (Process.isSdkSandboxUid(callingUid)) {
    return packageName.equals(mRequiredSdkSandboxPackage);
}
```

つまり SDK sandbox プロセスからの Binder 呼び出しでは、`pkg` が platform の required SDK sandbox package 名なら `isSameApp()` が true になる。NotificationManagerService はこの helper を所有者検査として使っていたため、SDK Runtime 内のコードが SDK sandbox package 名義で NotificationManager API の同一アプリ検査を通過できた。

## 脆弱性の成立条件

1. 攻撃者コードが SDK Runtime / SDK sandbox プロセスで実行される。
2. Binder caller UID が `Process.isSdkSandboxUid(uid) == true` になる。`Process.java` では SDK sandbox UID 範囲は `20000..29999`。
3. NotificationManager API 呼び出しで `pkg` / `opPkg` に required SDK sandbox package 名を使う。
4. 旧実装の `checkCallerIsSameApp()` が `PackageManagerInternal.isSameApp()` の SDK sandbox 例外により成功する。
5. `enqueueNotificationWithTag()`、`createNotificationChannels()`、`deleteNotificationChannel()` など、本来 SDK sandbox から直接扱わせるべきでない通知状態操作に到達できる。

## 影響

SDK sandbox は第三者 SDK をホストアプリから分離するための実行環境だが、旧実装では SDK sandbox package 名義で NotificationManagerService の同一 app 検査をすり抜けられた。特に通知チャネル作成・削除、通知 enqueue、通知 permission 状態参照などの通知サービス状態を SDK sandbox UID/package で操作できる。

DoS としての本質は、通常アプリ package ではなく shared/platform 側の SDK sandbox package identity に通知状態を作成・変更できる点にある。悪意ある SDK が通知チャネルや通知を作成・削除・蓄積することで、SDK sandbox package に紐づく通知状態を汚染し、通知サービス側の正常動作を妨害できる。Bulletin の分類は System DoS / High。

## 修正の意味

修正後は `PackageManagerInternal.isSameApp()` の SDK sandbox 例外を使わず、package の実 UID と Binder caller UID を比較する。SDK sandbox UID は通常の package UID とは一致しないため、SDK sandbox から SDK sandbox package 名を指定しても `SecurityException` になる。

また `areNotificationsEnabledForPackage(pkg, uid)` には次の明示的な拒否が追加された。

```java
if (Process.isSdkSandboxUid(uid)) {
    return false;
}
```

これにより SDK sandbox UID を通知有効な通常 app UID として扱わない。

## 調査メモ

- commit は `NotificationManagerServiceTest` の大規模な修正を含む。旧 test fixture は `isSameApp(anyString(), mUid, anyInt())` を広く true にしており、commit message でも「test setup が too permissive」と説明されている。これは本番コードのバグと同じく、`isSameApp` の意味を広く扱いすぎた問題をテストが隠していたことを示す。
- `PackageManagerInternal.isSameApp()` の JavaDoc には SDK sandbox UID の特別扱いが明記されているため、helper 自体が不正というより、NotificationManagerService の所有者検査に使ったことが問題。
- 同じ commit で `resolveNotificationUid(USER_ALL)` の扱いも `USER_SYSTEM` から `UserHandle.getUserId(callingUid)` へ変わっている。これは multi-user identity の隣接 hardening と見られるが、CVE の主因は SDK sandbox exception を含む `isSameApp()` の使用。
- このワークスペース直下には AOSP checkout がなかったため、Gitiles の公開ソースを一次情報として差分と修正前後ファイルを保存した。Pixel firmware/binary 解析は不要だった。

## 再現イメージ

旧実装での概念的な呼び出し:

```text
SDK sandbox process UID = 20000..29999
pkg/opPkg = PackageManager#getSdkSandboxPackageName()

NotificationManagerService.enqueueNotificationWithTag(pkg, opPkg, ...)
  -> resolveNotificationUid(opPkg, pkg, sandboxUid, userId)
  -> isCallerSameApp(pkg, sandboxUid, userId)
  -> PackageManagerInternal.isSameApp(pkg, sandboxUid, userId)
  -> Process.isSdkSandboxUid(sandboxUid) && pkg == mRequiredSdkSandboxPackage
  -> true
  -> notificationUid = sandboxUid
  -> 通知・チャネル状態操作へ進む
```

修正後は `getPackageUid(pkg)` と sandbox UID の `UserHandle.isSameApp()` が一致せず、同じ流れは `SecurityException` で止まる。

065 OK

CVE-2026-0060

065-ok-angle-system-driver-brick-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeDoS
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-459639258
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0060 is listed in the Android Security Bulletin as a High severity DoS issue in System.

特定した具体的な脆弱性

CVE-2026-0060 は、開発者向けオプションの Experimental: Enable ANGLE が persist.graphics.egl=angle を永続化し、再起動後にシステム全体の OpenGL ES ドライバ選択を ANGLE 側へ寄せることで、端末が再起動後に使用不能になる可能性がある System DoS と判断した。

公開AOSPパッチ dc00e06e9bb1d59e65b0620a3a4cb19fa23160b1 はコード修正ではなく、Settings の説明文と再起動確認ダイアログに「データをバックアップすること」「再起動失敗時は factory reset が必要になること」を追加する警告強化だった。つまり根本のドライバ切替機構は維持され、脆弱性としての実体は「商用端末上で危険な実験的システムドライバ切替をユーザーが十分な警告なしに実行でき、永続プロパティにより復旧困難なDoSへ発展する」ことにある。

このCVEは、ソースコード上で発火経路を確認できたため ok とする。

原因

根本原因は、実験的で端末をbrick相当にし得るシステムGLESドライバ切替を、開発者オプションの通常スイッチとして提供し、その状態を再起動後も残る persist.graphics.egl に保存していたこと。特に修正前UIでは、互換性問題の警告はcamera/video appsへの影響に留まり、端末が再起動後に使用不能になりfactory resetが必要になる可能性を明示していなかった。

実装上の防御境界はBinder権限で保たれているが、Settingsは正規のsystem権限でその境界内にいるため、UI操作がそのまま危険な永続システム状態へ変換される。パッチはこの設計を変更せず、危険性の明示でリスクを下げている。

どこから特定したか

パッチ差分: 保存ファイル: artifacts/diff-dc00e06e9bb1d59e65b0620a3a4cb19fa23160b1.patch

変更は packages/apps/Settings/res/values/strings.xml の2文字列のみ。

保存した主な付帯ファイル: ・artifacts/android-security-bulletin-2026-06-01.html
・artifacts/originhq-patch-diffing-pipeline.html
・artifacts/commit-dc00e06e9bb1d59e65b0620a3a4cb19fa23160b1.txt
・artifacts/diff-dc00e06e9bb1d59e65b0620a3a4cb19fa23160b1.patch
・artifacts/development_settings.post.xml
・artifacts/GraphicsDriverEnableAngleAsSystemDriverController.post.java
・artifacts/GpuServic…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/packages/apps/Settings/+/dc00e06e9bb1d59e65b0620a3a4cb19fa23160b1

validated.md を表示
# CVE-2026-0060 検証結果

## 結論

CVE-2026-0060 は、開発者向けオプションの `Experimental: Enable ANGLE` が `persist.graphics.egl=angle` を永続化し、再起動後にシステム全体の OpenGL ES ドライバ選択を ANGLE 側へ寄せることで、端末が再起動後に使用不能になる可能性がある System DoS と判断した。

公開AOSPパッチ `dc00e06e9bb1d59e65b0620a3a4cb19fa23160b1` はコード修正ではなく、Settings の説明文と再起動確認ダイアログに「データをバックアップすること」「再起動失敗時は factory reset が必要になること」を追加する警告強化だった。つまり根本のドライバ切替機構は維持され、脆弱性としての実体は「商用端末上で危険な実験的システムドライバ切替をユーザーが十分な警告なしに実行でき、永続プロパティにより復旧困難なDoSへ発展する」ことにある。

このCVEは、ソースコード上で発火経路を確認できたため `ok` とする。

## 基本情報

- CVE: CVE-2026-0060
- Android reference: A-459639258
- Component/Subcomponent: System / Settings developer option + graphics driver selection
- 種別/深刻度: DoS / High
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Bulletin上の修正リンク: https://android.googlesource.com/platform/packages/apps/Settings/+/dc00e06e9bb1d59e65b0620a3a4cb19fa23160b1
- 対象コミット: `dc00e06e9bb1d59e65b0620a3a4cb19fa23160b1`
- 親コミット: `bd2167e785ecb2c12cee9714f21c212f9a8fe550`

## パッチ差分

保存ファイル: `artifacts/diff-dc00e06e9bb1d59e65b0620a3a4cb19fa23160b1.patch`

変更は `packages/apps/Settings/res/values/strings.xml` の2文字列のみ。

- `enable_angle_as_system_driver_summary`
  - 旧: ANGLEをdefault OpenGL ES driverとして有効化し、camera/video appsと非互換の可能性がある、という警告。
  - 新: 上記に加えて、switchを有効にする前にdevice dataをbackupするよう追記。
- `reboot_dialog_enable_angle_as_system_driver`
  - 旧: system OpenGL ES driver変更にはrebootが必要、という説明。
  - 新: reboot前にbackupすること、reboot failedの場合はfactory resetが必要になることを追記。

面白い点として、ControllerやGLES Loaderのコードはこのコミットでは変わっていない。`artifacts/controller-pre-post.diff` は0バイトで、`GraphicsDriverEnableAngleAsSystemDriverController.pre.java` と `.post.java` は同一だった。したがってこのセキュリティ修正は、危険な状態遷移を技術的にブロックするものではなく、ユーザー同意・警告の改善である。

## 発火経路

1. Settings の開発者向けオプションに `enable_angle_as_system_driver` という `SwitchPreferenceCompat` が存在する。
   - 保存ファイル: `artifacts/development_settings.post.xml`
   - 表示名: `Experimental: Enable ANGLE`

2. このスイッチは `GraphicsDriverEnableAngleAsSystemDriverController` に処理される。
   - 保存ファイル: `artifacts/GraphicsDriverEnableAngleAsSystemDriverController.post.java`
   - `onPreferenceChange()` は `GraphicsEnvironment.getInstance().toggleAngleAsSystemDriver(enableAngleAsSystemDriver)` を呼び、再起動確認ダイアログを表示する。
   - Controllerは `persist.graphics.egl` が `angle` ならスイッチON、空文字ならOFFとして扱う。

3. Java `GraphicsEnvironment.toggleAngleAsSystemDriver()` はJNI経由で native に渡る。
   - 保存ファイル: `artifacts/GraphicsEnvironment.main.java`
   - 保存ファイル: `artifacts/android_os_GraphicsEnvironment.main.cpp`

4. `GraphicsEnv::nativeToggleAngleAsSystemDriver()` は `IGpuService` に委譲し、`GpuService::toggleAngleAsSystemDriver()` が `persist.graphics.egl` を書く。
   - 保存ファイル: `artifacts/GraphicsEnv.main.cpp`
   - 保存ファイル: `artifacts/GpuService.main.cpp`
   - `enabled=true` なら `persist.graphics.egl=angle`
   - `enabled=false` なら `persist.graphics.egl=""`
   - Binder側は `AID_SYSTEM` かつ `ACCESS_GPU_SERVICE` を要求するため、任意アプリが直接このサービスを叩く脆弱性ではない。Settings/System経由の危険なユーザー操作が問題。

5. EGL Loader はドライバsuffix探索で `persist.graphics.egl` を最優先に見る。
   - 保存ファイル: `artifacts/EGL_Loader.main.cpp`
   - `HAL_SUBNAME_KEY_PROPERTIES` は `persist.graphics.egl`, `ro.hardware.egl`, `ro.board.platform` の順。
   - suffixが `angle` の場合、`/system/lib(64)` 側の `lib*_angle.so` をロードしようとする。
   - ANGLEを使うべきプロセスでは `attempt_to_load_angle()` が先に走り、ロードできない場合は `LOG_ALWAYS_FATAL_IF(!hnd, "Failed to load ANGLE.")` でプロセスを落とす。

6. `GraphicsEnvironment.setupAngle()` はアプリプロセス初期化時にANGLE情報をC++へ渡す。
   - `setupAngleFromSystem()` は `nativeSetAngleInfo("system", false, packageName, features)` を呼ぶ。
   - C++側 `GraphicsEnv::setAngleInfo()` は path が `"system"` の場合 `mShouldUseSystemAngle=true`、非空pathなので `mShouldUseAngle=true` にする。

## 脆弱性の内容

この設定は単なるアプリ単位のANGLE opt-inではなく、`persist.graphics.egl` という永続プロパティでシステム全体のGLESドライバ選択に影響する。再起動後、SystemUI、Launcher、Settings、カメラ、動画系アプリなど、GLES/EGLを初期化するプロセスがANGLEをロードする経路に入る。

商用端末でANGLE as system driverが十分に検証されていない、または端末固有のgraphics stack/camera/video pathと非互換な場合、重要UIプロセスや復旧に必要なSettings自身がクラッシュ・起動失敗する。ユーザーは通常のUIから `persist.graphics.egl` を戻せなくなり、パッチ文言の通り factory reset が必要になる。これが High severity DoS の実体と考えられる。

## 根本原因

根本原因は、実験的で端末をbrick相当にし得るシステムGLESドライバ切替を、開発者オプションの通常スイッチとして提供し、その状態を再起動後も残る `persist.graphics.egl` に保存していたこと。特に修正前UIでは、互換性問題の警告はcamera/video appsへの影響に留まり、端末が再起動後に使用不能になりfactory resetが必要になる可能性を明示していなかった。

実装上の防御境界はBinder権限で保たれているが、Settingsは正規のsystem権限でその境界内にいるため、UI操作がそのまま危険な永続システム状態へ変換される。パッチはこの設計を変更せず、危険性の明示でリスクを下げている。

## 解析メモ

- `isAngleDeveloperOptionEnabled()` は `debug.graphics.angle.developeroption.enable` を見た上で、現在のソースでは「temporarily disabling for broader rollout」として常に `false` を返す。ただし、すでに `persist.graphics.egl=angle` の場合はOFFに戻せるようスイッチを無効化しない実装になっている。
- `GraphicsDriverEnableAngleAsSystemDriverController` の定数名に `ENABLE_ANELE_AS_SYSTEM_DRIVER_KEY` というtypoがあるが、値は正しい `enable_angle_as_system_driver`。
- Reboot dialogをcancel/dismissした場合、Controllerは `toggleSwitchBack()` で `persist.graphics.egl` を元へ戻す。危険なのは、ユーザーがrebootを承認し、永続プロパティが反映された状態でboot後のgraphics stackが壊れるケース。
- コミットメッセージには「released commercial android deviceでこのswitchを触るとdeviceがunusableになり、復旧にfactory resetが必要」と明記されている。これはCVEのDoS性を直接説明している。

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

- `artifacts/android-security-bulletin-2026-06-01.html`
- `artifacts/originhq-patch-diffing-pipeline.html`
- `artifacts/commit-dc00e06e9bb1d59e65b0620a3a4cb19fa23160b1.txt`
- `artifacts/diff-dc00e06e9bb1d59e65b0620a3a4cb19fa23160b1.patch`
- `artifacts/development_settings.post.xml`
- `artifacts/GraphicsDriverEnableAngleAsSystemDriverController.post.java`
- `artifacts/GpuService.main.cpp`
- `artifacts/IGpuService.main.cpp`
- `artifacts/GraphicsEnv.main.cpp`
- `artifacts/GraphicsEnvironment.main.java`
- `artifacts/android_os_GraphicsEnvironment.main.cpp`
- `artifacts/EGL_Loader.main.cpp`

## ハッシュ

```text
5c0e8a11804d74392ceac14227e7f5cb6953e724c15488e0a5a8046efb755f1a  commit-dc00e06e9bb1d59e65b0620a3a4cb19fa23160b1.txt
9d95466373fbc5783a70fd315850f1cf6ceeb01771e4286706cf40328b457df9  diff-dc00e06e9bb1d59e65b0620a3a4cb19fa23160b1.patch
28b660aca2989cb815ce55b53606f227521ea7049506ba54cf1abd9f5df3aba5  GraphicsDriverEnableAngleAsSystemDriverController.post.java
212c06be86236c11e1336afbd47bfab0bc7be6f246aa040b33daa19ec61e069a  GpuService.main.cpp
68f763bc9c9226af6de8c9b55befe24ff50783c35d60deb8e2b8f9a0aa0cf96c  EGL_Loader.main.cpp
e54451ea17c49827dad83c0b2203018c2dbc6c2cd329f963ad13ffcbc5faa0a3  GraphicsEnvironment.main.java
```
066 OK

CVE-2026-0067

066-ok-dng-sdk-ubsan-logic-error-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeDoS
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-470967228
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0067 is listed in the Android Security Bulletin as a High severity DoS issue in System.

特定した具体的な脆弱性

ok: ソースコード差分と呼び出し側コードから、脆弱性の成立条件と根本原因を説明できる。

タイトル: dng-sdk-ubsan-logic-error-dos

CVE-2026-0067 / A-470967228 は platform/external/dng_sdk のDNG/RAW画像デコードに関するDoSだった。公開修正は、libdng_sdk でUBSan minimal runtimeが検出時にプロセスをhard abortする構成をやめ、UBSan handlerをC++例外に変換する独自runtimeへ差し替えるものだった。これにより、細工されたDNG入力でDNG SDK内の異常条件に到達しても、画像デコード元プロセス全体のクラッシュではなく、通常のデコード失敗として扱えるようになる。

原因

根本原因は、信頼できないDNG/RAW入力を処理する libdng_sdk で、UBSan検出時のエラー処理方針がライブラリ全体の例外ベースの失敗処理と噛み合っていなかったこと。

具体的には以下の組み合わせで成立していた。

・libdng_sdk-defaults で signed-integer-overflow / unsigned-integer-overflow のUBSanが有効だった。
・libdng_sdk と呼び出し側SkiaはC++例外を使える構成で、DNG SDK由来の失敗を catch (...) で回復する設計だった。
・しかし未修正の libdng_sdk はUBSan minimal runtimeを使っており、UBSan発火時に例外ではなくhard abortする。
・DNG/RAWファイル由来の値はparse/render処理の多数の整数演算に流れ込むため、細工された入力でUBSan発火点へ到達できる。
・その結果、本来は不正画像として拒否されるべき入力が、画像デコード元プロセスのクラッシュになる。

どこから特定したか

保存した証跡: ・artifacts/android-security-bulletin-2026-06-01.html: Android Security Bulletin保存版
・artifacts/bulletin-row-CVE-2026-0067.html: bulletin上のCVE-2026-0067周辺行
・artifacts/osv-ASB-A-470967228.json: 対象CVEのAndroid OSV
・artifacts/74a5a91.commit.json: Gitiles commit JSON
・artifacts/74a5a91_commit_full.txt: commit metadata/message
・artifacts/74a5a91.patch: 対象commitのpat…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://storage.googleapis.com/android-osv/ASB-A-470967228.json / https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce / https://storage.googleapis.com/android-osv/ASB-A-470967228.json'

validated.md を表示
# CVE-2026-0067 検証結果

## 判定

ok: ソースコード差分と呼び出し側コードから、脆弱性の成立条件と根本原因を説明できる。

タイトル: dng-sdk-ubsan-logic-error-dos

CVE-2026-0067 / A-470967228 は `platform/external/dng_sdk` のDNG/RAW画像デコードに関するDoSだった。公開修正は、`libdng_sdk` でUBSan minimal runtimeが検出時にプロセスをhard abortする構成をやめ、UBSan handlerをC++例外に変換する独自runtimeへ差し替えるものだった。これにより、細工されたDNG入力でDNG SDK内の異常条件に到達しても、画像デコード元プロセス全体のクラッシュではなく、通常のデコード失敗として扱えるようになる。

## 基本情報

- CVE: CVE-2026-0067
- Android bug ID: A-470967228
- Component: System
- Subcomponent/package: `platform/external/dng_sdk`
- 種別: DoS
- 重要度: High
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://storage.googleapis.com/android-osv/ASB-A-470967228.json
- 公開修正コミット: https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce
- 対象AOSP versions: 14, 15, 16, 16-qpr2

## 参照した修正

主解析対象:

- Commit: `74a5a91d169a341db58d57e0bf018d0a8b784cce`
- Subject: `Replace ubsan-minimal with throw`
- Parent: `47cd326e0c8f19cc367663b31d95c03584198fa4`
- AuthorDate: 2026-01-09
- CommitDate: 2026-04-09
- 変更ファイル:
  - `Android.bp`
  - `OWNERS`
  - `ubsan-replacement/ubsan_throwing_runtime.cpp`

OSVに載っているブランチ別fix:

- 17-next: `81ded662eee07fcbb830e6b6c83d1a3d85227ceb`
- 15: `475c8cce973f56488cc9f37d00cf0a4069f0e4fe`
- 16: `1337d2e14a412ec81a4a32f6251063091922a9e9`
- 16-qpr2: `690688f3b522dc80de007d5c3ac8b8ce61da8870`
- 14: `7f197e818cbb7b5bc7b9ee5017a36a23650c29de`

ローカルの `../binaries/dng_sdk.git` では `81ded...` と `7f197...` を確認でき、どちらも同じ `Replace ubsan-minimal with throw` 系の修正だった。`475c...`, `1337...`, `690688...` は `GIT_NO_LAZY_FETCH=1` でローカルobject未取得だったため、可用性結果を `artifacts/branch-fix-commits-availability.txt` に保存した。

## パッチ内容

修正前の `libdng_sdk-defaults` は signed/unsigned integer overflow のUBSan instrumentationを有効にしていた。

```bp
sanitize: {
    misc_undefined: [
        "unsigned-integer-overflow",
        "signed-integer-overflow",
    ],
},
```

同じdefaults内では `rtti: true` と `cppflags: ["-fexceptions"]` も指定されており、DNG SDKは例外を使える構成だった。一方、修正前の公開ライブラリ `libdng_sdk` はdefaultsを継承したまま、固有設定はほぼ `-DqDNGValidate=0` だけだった。このため、コンパイラが挿入したUBSan handlerはSoongがリンクするUBSan minimal runtimeに依存し、検出時にC++例外ではなくプロセスabortへ進む構成だった。

修正後は `libdng_sdk` だけでSoongのsanitizer runtime注入を止め、overflow instrumentation自体は明示的に維持するようになった。

```bp
sanitize: {
    never: true,
},

cflags: [
    "-DqDNGValidate=0",
    "-fsanitize=signed-integer-overflow,unsigned-integer-overflow",
    "-fno-sanitize-link-runtime",
],

srcs: [
    "ubsan-replacement/ubsan_throwing_runtime.cpp"
],
```

追加された `ubsan-replacement/ubsan_throwing_runtime.cpp` は、以下のUBSan overflow handlerを実装し、いずれも `std::runtime_error` をthrowする。

- `__ubsan_handle_add_overflow`
- `__ubsan_handle_sub_overflow`
- `__ubsan_handle_mul_overflow`
- `__ubsan_handle_negate_overflow`
- `__ubsan_handle_divrem_overflow`

コミットメッセージにも、C++ exceptionsがこのライブラリで有効であり、UBSan errorをhard abortするより例外がよい、という趣旨が明記されていた。つまり修正の本質は「UBSan検出を消す」ことではなく、「検出後の制御フローをプロセス終了から例外へ変える」ことである。

## どういう脆弱性だったか

攻撃者が細工したDNG/RAW画像をAndroidの画像デコード経路に渡すと、`external/dng_sdk` 内でファイル由来のmetadata、寸法、tile、mask、render関連値を使った多数の計算に到達する。そこでUBSanが検出する異常条件、特にsigned/unsigned integer overflow系のhandlerに到達すると、未修正ビルドではUBSan minimal runtimeがhard abortし、呼び出し元のエラー処理に戻る前にプロセスが終了する。

Skia側の `SkRawCodec.cpp` を確認すると、DNG入力は `SkDngImage::NewFromStream()` から `readDng()`、`render()` へ進む。`readDng()` と `render()` はどちらも `catch (...)` で失敗を捕捉し、`false` または `nullptr` を返す。`SkRawCodec::MakeFromStream()` や `onGetPixels()` 側では、これらの失敗を `kInvalidInput` 等へ変換する。

したがって本来の設計では、不正なDNG入力は「例外 -> デコード失敗」として処理されるはずだった。しかしUBSan minimal runtimeの `abort()` はC++例外ではないため、`catch (...)` では捕捉できない。この食い違いにより、ユーザー操作や追加権限なしで到達するDNGデコードが、ローカルの永続DoSに使える状態になっていた。

OSVのdetailsは以下の趣旨だった。

- `ubsan_throwing_runtime.cpp` の複数関数にlogic errorによるpermanent DoSの可能性
- local denial of service
- additional execution privileges不要
- user interaction不要

ただし `ubsan_throwing_runtime.cpp` は修正で新規追加されたファイルである。実際の脆弱箇所はこのファイル自体ではなく、DNG SDK内の入力到達可能なUBSan発火点と、未修正時のUBSan minimal runtimeによるhard abort動作の組み合わせと見るべきである。

## 根本原因

根本原因は、信頼できないDNG/RAW入力を処理する `libdng_sdk` で、UBSan検出時のエラー処理方針がライブラリ全体の例外ベースの失敗処理と噛み合っていなかったこと。

具体的には以下の組み合わせで成立していた。

- `libdng_sdk-defaults` で `signed-integer-overflow` / `unsigned-integer-overflow` のUBSanが有効だった。
- `libdng_sdk` と呼び出し側SkiaはC++例外を使える構成で、DNG SDK由来の失敗を `catch (...)` で回復する設計だった。
- しかし未修正の `libdng_sdk` はUBSan minimal runtimeを使っており、UBSan発火時に例外ではなくhard abortする。
- DNG/RAWファイル由来の値はparse/render処理の多数の整数演算に流れ込むため、細工された入力でUBSan発火点へ到達できる。
- その結果、本来は不正画像として拒否されるべき入力が、画像デコード元プロセスのクラッシュになる。

修正は、`-fsanitize=signed-integer-overflow,unsigned-integer-overflow` を維持したまま、`-fno-sanitize-link-runtime` と独自 `__ubsan_handle_*_overflow` を追加し、検出を `std::runtime_error` に変換している。これにより既存の `catch (...)` が機能し、DoS primitiveが通常のデコード失敗へ落ちる。

## 面白い点・調査メモ

- Bulletin上のCVE-2026-0067行は A-470967228 から `74a5a91...` へ直接リンクしている。
- `74a5a91...` のcommit messageには `Bug: 470967228` が含まれていない。代わりに `470966846`, `467994860`, `467994310`, `461790658`, `456471487`, `453649377`, `449728942` が列挙されている。OSVとbulletinはA-470967228も同じfixに紐付けているため、この公開コミットが複数CVE/bugをまとめて直した横断修正だと判断した。
- 同じ修正は近傍のDNG SDK DoS系CVEでも使われている。個々のprivate bugは異なるDNG入力や異なるUBSan発火点を持つ可能性があるが、公開パッチのセキュリティ上の本質は共通して「UBSan hard abortを例外化する」ことだった。
- OSVのdetailsは修正後に追加された `ubsan_throwing_runtime.cpp` を脆弱箇所のように書いている。これは公開差分のシグネチャから機械的に生成された説明に引っ張られている可能性が高い。
- CVE-2026-0067固有のPoC DNG、private bug本文、具体的なDNG tagや演算式は公開情報からは確認できなかった。ただし、ソース差分、OSV、Skia呼び出し側の例外処理から、脆弱性の成立状況と根本原因は十分に説明可能と判断した。
- 依頼で参照されたOriginのpatch diffing pipeline記事は `artifacts/origin-patch-diffing-pipeline.html` に保存した。今回の作業では、bulletinからfix commitを取得し、前後差分、OSV、呼び出し側コード、ブランチ別fix可用性を証跡化する形で進めた。

## 解析ログ

- `cve.md` を読み、CVE-2026-0067 / A-470967228 / System DoS High / bulletin URLを確認。
- Android Security Bulletinを保存し、CVE-2026-0067行が `platform/external/dng_sdk` commit `74a5a91...` にリンクしていることを確認。
- Android OSV `ASB-A-470967228.json` を保存し、affected package、branch別fix、detailsを確認。
- `74a5a91...` のcommit metadata、patch、`Android.bp` 前後、追加された `ubsan_throwing_runtime.cpp` を保存。
- `../binaries/dng_sdk.git` を使い、対象commitと17-next/14用fix commitの存在、差分内容を確認。
- `../binaries/skia.git` から `SkRawCodec.cpp` と `Android.bp` を保存し、DNG SDK呼び出し経路、`catch (...)` による回復経路、Skia側の `libdng_sdk` 依存を確認。

## 保存した証跡

- `artifacts/android-security-bulletin-2026-06-01.html`: Android Security Bulletin保存版
- `artifacts/bulletin-row-CVE-2026-0067.html`: bulletin上のCVE-2026-0067周辺行
- `artifacts/osv-ASB-A-470967228.json`: 対象CVEのAndroid OSV
- `artifacts/74a5a91.commit.json`: Gitiles commit JSON
- `artifacts/74a5a91_commit_full.txt`: commit metadata/message
- `artifacts/74a5a91.patch`: 対象commitのpatch
- `artifacts/Android.bp.before`: 修正前 `Android.bp`
- `artifacts/Android.bp.after`: 修正後 `Android.bp`
- `artifacts/Android.bp.diff`: `Android.bp` 前後差分
- `artifacts/ubsan_throwing_runtime.cpp`: 追加されたUBSan replacement runtime
- `artifacts/SkRawCodec.cpp`: 呼び出し側確認用Skia RAW codec
- `artifacts/SkRawCodec.h`: 同上
- `artifacts/skia_Android.bp`: Skia側の例外有効化と `libdng_sdk` 依存確認用
- `artifacts/key-code-excerpts.txt`: 重要差分と呼び出し側catch箇所の抜粋
- `artifacts/branch-fix-commits-availability.txt`: OSV記載fix commitのローカルobject確認結果
- `artifacts/81ded662eee07fcbb830e6b6c83d1a3d85227ceb.stat.txt`: 17-next fix commit stat
- `artifacts/81ded662eee07fcbb830e6b6c83d1a3d85227ceb.patch`: 17-next fix差分
- `artifacts/7f197e818cbb7b5bc7b9ee5017a36a23650c29de.stat.txt`: Android 14 fix commit stat
- `artifacts/7f197e818cbb7b5bc7b9ee5017a36a23650c29de.patch`: Android 14 fix差分
- `artifacts/origin-patch-diffing-pipeline.html`: 依頼で参照されたpatch diffing pipeline記事の保存版

## 再検証用コマンド

```sh
curl -L 'https://storage.googleapis.com/android-osv/ASB-A-470967228.json'
curl -L 'https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce^!/?format=TEXT' | base64 -d
git -C ../binaries/dng_sdk.git show --stat --oneline 74a5a91d169a341db58d57e0bf018d0a8b784cce
git -C ../binaries/dng_sdk.git diff 47cd326e0c8f19cc367663b31d95c03584198fa4 74a5a91d169a341db58d57e0bf018d0a8b784cce -- Android.bp ubsan-replacement/ubsan_throwing_runtime.cpp
git -C ../binaries/skia.git show HEAD:src/codec/SkRawCodec.cpp
```
067 OK

CVE-2026-0074

067-ok-launcher-imagedecoder-memory-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeDoS
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-468061774
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0074 is listed in the Android Security Bulletin as a High severity DoS issue in System.

特定した具体的な脆弱性

ok: 脆弱性を特定できた。

CVE-2026-0074 は、Launcher/System UI 側が他アプリ由来の画像 drawable を Launcher process 内でデコードするとき、ImageDecoder 経路にプロセス単位のサイズ上限がなく、巨大な画像ヘッダを持つアイコン/ショートカット/ウィジェット関連画像を読ませることで Launcher process の過大メモリ確保、OOM、クラッシュを起こせる DoS だったと判断する。

原因

根本原因は、外部アプリが制御できる drawable resource を信頼境界外入力として扱うべき Launcher process に、ImageDecoder のヘッダ段階で一律にサイズ制限を掛ける仕組みがなかったこと。

ResourcesImpl.decodeImageDrawable() は元々 local listener で ALLOCATOR_SOFTWARE を指定するだけで、info.size を見て setTargetSize() する処理がなかった。個別の call site をすべて修正するのではなく、framework に process default listener を追加し、Launcher process 全体の decode policy として downscale/拒否を適用したのが今回の修正である。

どこから特定したか

パッチ差分の要点: frameworks/base の ImageDecoder には、process/thread default OnHeaderDecodedListener が追加された。修正後の callHeaderDecoded() は、decode 呼び出しごとの local listener だけでなく、先に thread default、なければ process default listener を呼ぶ。これにより、呼び出し元が個別に listener を渡していない ImageDecoder.decodeDrawable() / decodeBitmap() にも、プロセス共通の防御処理を強制できる。

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01` / https://android.googlesource.com/platform/frameworks/base/+/4abc0b8da1e97accf0213fd228f663f0fc6176a4` / https://android.googlesource.com/platform/packages/apps/Launcher3/+/8c33391368b8d4c08e4f32d8503dc97d9eff4b90`

validated.md を表示
# CVE-2026-0074 検証結果

## 判定

ok: 脆弱性を特定できた。

CVE-2026-0074 は、Launcher/System UI 側が他アプリ由来の画像 drawable を Launcher process 内でデコードするとき、`ImageDecoder` 経路にプロセス単位のサイズ上限がなく、巨大な画像ヘッダを持つアイコン/ショートカット/ウィジェット関連画像を読ませることで Launcher process の過大メモリ確保、OOM、クラッシュを起こせる DoS だったと判断する。

## cve.md の確認内容

- CVE: `CVE-2026-0074`
- Bulletin URL: `https://source.android.com/docs/security/bulletin/2026/2026-06-01`
- Component: `System`
- Subcomponent: 記載なし
- Type: `DoS`
- Severity: `High`
- References: `A-468061774`
- Updated AOSP versions: `14, 15, 16, 16-qpr2`

## 参照した URL / commit / 保存ファイル

- Android Security Bulletin 2026-06-01
  - `https://source.android.com/docs/security/bulletin/2026/2026-06-01`
  - 保存: `android-security-bulletin-2026-06-01.html`
- `platform/frameworks/base` commit `4abc0b8da1e97accf0213fd228f663f0fc6176a4`
  - `https://android.googlesource.com/platform/frameworks/base/+/4abc0b8da1e97accf0213fd228f663f0fc6176a4`
  - 保存: `4abc0b8da1e97accf0213fd228f663f0fc6176a4.diff`, `4abc0b8da1e97accf0213fd228f663f0fc6176a4.commit.json`
- `platform/packages/apps/Launcher3` commit `8c33391368b8d4c08e4f32d8503dc97d9eff4b90`
  - `https://android.googlesource.com/platform/packages/apps/Launcher3/+/8c33391368b8d4c08e4f32d8503dc97d9eff4b90`
  - 保存: `8c33391368b8d4c08e4f32d8503dc97d9eff4b90.diff`, `8c33391368b8d4c08e4f32d8503dc97d9eff4b90.commit.json`
- 解析用に保存した関連ソース
  - `framework/ImageDecoder.java`
  - `framework/ResourcesImpl.java`
  - `framework/Icon.java`
  - `LauncherProcessImageListener.kt`
  - `QuickstepProcessInitializer.java`
  - `LauncherProcessImageListenerTest.kt`
  - `LauncherIconProvider.java`
  - `CacheableShortcutInfo.kt`
  - `IconCache.java`
  - `IconRequestInfo.java`
  - `analysis_notes.md`

## パッチ差分の要点

`frameworks/base` の `ImageDecoder` には、process/thread default `OnHeaderDecodedListener` が追加された。修正後の `callHeaderDecoded()` は、decode 呼び出しごとの local listener だけでなく、先に thread default、なければ process default listener を呼ぶ。これにより、呼び出し元が個別に listener を渡していない `ImageDecoder.decodeDrawable()` / `decodeBitmap()` にも、プロセス共通の防御処理を強制できる。

Launcher3 側では `QuickstepProcessInitializer.setupImageDecoder()` が追加され、Launcher 起動時に `ImageDecoder.setDefaultProcessListener(new LauncherProcessImageListener(...))` を登録する。設定値は `quickstep/res/values/config.xml` に追加された `max_launcher_memory_mb=300` と `allowed_image_mime_types` である。

`LauncherProcessImageListener` はヘッダ取得時に MIME type を allowlist と照合し、`width * height * 8` bytes が上限を超える場合に `ImageDecoder.setTargetSize()` を呼ぶ。8 bytes/pixel は RGBA_F16 を想定したワーストケースで、300 MiB の上限なら約 39,321,600 pixels までに抑えられる。

## 脆弱性が起きる状況

Launcher はアプリ一覧、ショートカット、ウィジェットピッカー、最近使ったタスクなどで外部アプリ由来の画像を読む。確認した代表経路は次の通り。

- アプリのアイコン resource: `LauncherIconProvider.loadAppInfoIcon()` が `Resources.getDrawableForDensity()` を呼ぶ。
- framework resource decode: `ResourcesImpl.loadDrawableForCookie()` が非 XML drawable を `ImageDecoder.decodeDrawable()` で読む。
- ショートカット: `CacheableShortcutInfo.getIcon()` が `LauncherApps.getShortcutIconDrawable()` から Drawable を得て、Launcher の icon cache へ入れる。

攻撃者アプリが、manifest icon、roundIcon、shortcut icon、widget preview など Launcher が読み込む画像として、圧縮サイズは小さいがヘッダ上の pixel dimensions が非常に大きい PNG/JPEG/WebP 等を提供する。脆弱版では Launcher process 内で `ImageDecoder.decodeDrawable()` がデコードを進める前に Launcher 用のサイズ上限を設定できないため、巨大 bitmap の確保を試み、Launcher process が OOM で落ちる。Launcher はホーム/タスク UI の中核なので、繰り返し読み込み対象になる画像なら復帰後も再クラッシュし、端末操作に影響する DoS になる。

## 根本原因

根本原因は、外部アプリが制御できる drawable resource を信頼境界外入力として扱うべき Launcher process に、`ImageDecoder` のヘッダ段階で一律にサイズ制限を掛ける仕組みがなかったこと。

`ResourcesImpl.decodeImageDrawable()` は元々 local listener で `ALLOCATOR_SOFTWARE` を指定するだけで、`info.size` を見て `setTargetSize()` する処理がなかった。個別の call site をすべて修正するのではなく、framework に process default listener を追加し、Launcher process 全体の decode policy として downscale/拒否を適用したのが今回の修正である。

## 修正の効果

- Launcher process で `ImageDecoder` を使う decode は、local listener の有無にかかわらず `LauncherProcessImageListener` を通る。
- 巨大画像はデコード前に target size を縮小される。
- 未許可 MIME type または null MIME type は `IOException` で拒否される。
- テスト `LauncherProcessImageListenerTest.kt` は、上限未満なら target size を設定しないこと、上限超過なら期待サイズへ縮小すること、未許可/null MIME type を拒否することを確認している。

## 調査時メモ

- このパッチは `Icon.loadDrawable()` の URI/DATA 経路に残る `BitmapFactory` decode を直接直しているわけではない。CVE-2026-0074 の修正は、Launcher が resource/drawable 経由で使う `ImageDecoder` に process default listener を差し込むもの。
- `ImageDecoder` に追加された API は `@hide` であり、通常アプリ向け API ではなく、Launcher のような platform process が防御ポリシーをまとめて適用するためのもの。
- MIME allowlist は DoS の本筋であるメモリ上限とは別に、Launcher process が想定外形式を処理する面も狭めている。
- Pixel 固有バイナリではなく AOSP/Launcher3 のソース差分で説明可能な System DoS のため、`../binaries` への firmware 保存は不要だった。
068 OK

CVE-2026-0079

068-ok-dng-sdk-ubsan-overflow-abort-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeDoS
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-470966318
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0079 is listed in the Android Security Bulletin as a High severity DoS issue in System.

特定した具体的な脆弱性

特定できた。CVE-2026-0079 は Android の DNG/RAW 画像デコード経路で、platform/external/dng_sdk が整数オーバーフロー UBSan を有効にしているにもかかわらず、修正前は UBSan 検知が recoverable な画像デコード失敗ではなく process abort になっていたことによる persistent local DoS である。

攻撃者が細工した DNG/RAW 系画像を端末上に置き、それを MediaProvider/サムネイル生成/アプリの ImageDecoder/NDK AImageDecoder などが繰り返しデコードすると、DNG SDK 内の signed/unsigned integer overflow が UBSan runtime に捕捉され、修正前はプロセスが hard abort する。画像が残り続ける限り、同じスキャンや表示処理で再クラッシュし得るため OSV の説明どおり persistent local DoS になる。

原因

根本原因は、DNG SDK が入力由来の DNG メタデータ、寸法、タイル領域、sample/plane 数、opcode、レンダリング寸法などを使って多数の整数演算を行うにもかかわらず、整数オーバーフロー検知時の失敗モードが画像デコード API のエラー処理と整合していなかった点である。

DNG SDK 自体には dng_exception、ThrowProgramError、ThrowBadFormat などの例外ベースのエラー処理があり、Skia 側もそれを前提に catch (...) で DNG 読み込み・レンダリング失敗を recoverable な不正入力として扱っている。一方、UBSan の overflow 検知はこの例外モデルを迂回してプロセスを終了していた。つまり、入力検証不足によって overflow 可能な経路が存在することに加え、sanitizer が「安全な検出」ではなく「DoS primitive」になっていた。

どこから特定したか

パッチ解析: OSV の ASB-A-470966318.json には以下の詳細が記載されている。

> In multiple functions of ubsan_throwing_runtime.cpp, there is a possible persistent denial of service due to an integer overflow.

保存した証拠・付帯ファイル: ・artifacts/ASB-A-470966318.json
- Android OSV JSON。
・artifacts/*.patch, artifacts/*.diff.b64
- 取得できた Gitiles patch/diff。OSV listed commit のうち 404 だったものは 0 byte patch として残っている。
・artifacts/dng_sdk.git/
- platform/external/dng_sdk の公開 Git clone。
・artifacts/skia.git/
- platform/external/skia の sparse clone。DNG codec 確認用。
・artifacts/frameworks-base-snips…

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://osv.dev/vulnerability/ASB-A-470966318 / https://android.googlesource.com/platform/external/dng_sdk/+/81ded662eee07fc…

validated.md を表示
# CVE-2026-0079 検証結果

## 結論

特定できた。CVE-2026-0079 は Android の DNG/RAW 画像デコード経路で、`platform/external/dng_sdk` が整数オーバーフロー UBSan を有効にしているにもかかわらず、修正前は UBSan 検知が recoverable な画像デコード失敗ではなく process abort になっていたことによる persistent local DoS である。

攻撃者が細工した DNG/RAW 系画像を端末上に置き、それを MediaProvider/サムネイル生成/アプリの `ImageDecoder`/NDK `AImageDecoder` などが繰り返しデコードすると、DNG SDK 内の signed/unsigned integer overflow が UBSan runtime に捕捉され、修正前はプロセスが hard abort する。画像が残り続ける限り、同じスキャンや表示処理で再クラッシュし得るため OSV の説明どおり persistent local DoS になる。

修正は、`libdng_sdk` の通常 UBSan runtime を無効化しつつ `-fsanitize=signed-integer-overflow,unsigned-integer-overflow` を明示し、`ubsan-replacement/ubsan_throwing_runtime.cpp` を追加して UBSan overflow handler を C++ `std::runtime_error` に変換するもの。Skia の DNG codec は DNG SDK 呼び出しを `catch (...)` で囲んでおり、例外化された overflow は `SkCodec::kInvalidInput` / `kIncompleteInput` 等に落ち、framework の `ImageDecoder` 側では `DecodeException` になる。つまり「不正画像で該当プロセスを落とす」挙動が「不正画像として失敗する」挙動に変わる。

## 基本情報

- CVE: CVE-2026-0079
- Android bug: A-470966318
- Component/Subcomponent: System / `platform/external/dng_sdk`
- 種別: DoS
- Severity: High
- Bulletin: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- OSV: https://osv.dev/vulnerability/ASB-A-470966318
- 影響版: Android 14, 15, 16, 16-qpr2, 17-next
- Security patch level: 2026-06-01

## パッチ解析

OSV の `ASB-A-470966318.json` には以下の詳細が記載されている。

> In multiple functions of ubsan_throwing_runtime.cpp, there is a possible persistent denial of service due to an integer overflow.

実際の修正 commit の件名は一貫して `Replace ubsan-minimal with throw`。commit message には「C++ exceptions are enabled in this library and are a much, much better solution for ubsan errors than a hard abort is.」とあり、パッチの狙いは DNG SDK 内の個別算術式を修正することではなく、UBSan overflow 検知時の処理を abort から例外に差し替えることだと分かる。

主な公開修正 commit:

- `81ded662eee07fcbb830e6b6c83d1a3d85227ceb` / Android 17-next 系
  - https://android.googlesource.com/platform/external/dng_sdk/+/81ded662eee07fcbb830e6b6c83d1a3d85227ceb
- `7f197e818cbb7b5bc7b9ee5017a36a23650c29de` / Android 14 系として OSV に掲載
  - https://android.googlesource.com/platform/external/dng_sdk/+/7f197e818cbb7b5bc7b9ee5017a36a23650c29de
- `74a5a91d169a341db58d57e0bf018d0a8b784cce` / Android 16 security branch に存在する同一 Change-Id の cherrypick
  - https://android.googlesource.com/platform/external/dng_sdk/+/74a5a91d169a341db58d57e0bf018d0a8b784cce

OSV には `475c8cce973f56488cc9f37d00cf0a4069f0e4fe`、`1337d2e14a412ec81a4a32f6251063091922a9e9`、`690688f3b522dc80de007d5c3ac8b8ce61da8870` も listed fixes として載っているが、調査時点では単独 Gitiles URL が 404 だった。公開 clone では同じ `Change-Id: I7b8414e4b5c2f2ca44f572fb72e625d1907f7902` の関連 commit として `1ec41401b3d40b9165367953b662ab9189885b4b` が `origin/android15-security-release`、`42e65547eb33a30fd8b751dcb711bdd951310149` が `origin/android14-security-release`、`74a5a91d169a341db58d57e0bf018d0a8b784cce` が `origin/android16-security-release` に存在した。

修正差分の本質:

- 修正前:
  - `cc_defaults` で `sanitize.misc_undefined` に `unsigned-integer-overflow` と `signed-integer-overflow` が有効。
  - `libdng_sdk` は通常の sanitizer runtime を使うため、overflow 検知時に process abort する。
- 修正後:
  - `libdng_sdk` に `sanitize: { never: true }` を設定。
  - `cflags` に `-fsanitize=signed-integer-overflow,unsigned-integer-overflow` と `-fno-sanitize-link-runtime` を追加。
  - `ubsan-replacement/ubsan_throwing_runtime.cpp` を `srcs` に追加。
  - 独自 handler が `__ubsan_handle_add_overflow`、`sub_overflow`、`mul_overflow`、`negate_overflow`、`divrem_overflow` で `std::runtime_error("ubsan: ...")` を投げる。

この設計は、通常の sanitizer link runtime を使わず、同一ライブラリ内の hidden symbol として UBSan handler を解決させることで、overflow を C++ 例外として上位に戻す。

## 脆弱性の根本原因

根本原因は、DNG SDK が入力由来の DNG メタデータ、寸法、タイル領域、sample/plane 数、opcode、レンダリング寸法などを使って多数の整数演算を行うにもかかわらず、整数オーバーフロー検知時の失敗モードが画像デコード API のエラー処理と整合していなかった点である。

DNG SDK 自体には `dng_exception`、`ThrowProgramError`、`ThrowBadFormat` などの例外ベースのエラー処理があり、Skia 側もそれを前提に `catch (...)` で DNG 読み込み・レンダリング失敗を recoverable な不正入力として扱っている。一方、UBSan の overflow 検知はこの例外モデルを迂回してプロセスを終了していた。つまり、入力検証不足によって overflow 可能な経路が存在することに加え、sanitizer が「安全な検出」ではなく「DoS primitive」になっていた。

個別の overflow 箇所は OSV でも「multiple functions」とされており、単一の算術式修正ではない。パッチが個別演算を直していないことからも、問題の security boundary は「DNG SDK で発生し得る整数 overflow を、フレームワークの不正画像エラーに変換できないこと」だったと判断できる。

## 到達経路

確認した到達経路は以下。

1. Java/NDK の `ImageDecoder` は DNG/RAW 系 MIME type をサポートする。`ImageDecoder.java` には `image/x-adobe-dng` などが supported MIME として列挙されている。
2. `ImageDecoder.cpp` は `SkCodec::MakeFromStream` で codec を作り、作成失敗や decode 失敗を `DecodeException` に変換する。
3. Skia の `SkRawCodec.cpp` は DNG/RAW decode で `libdng_sdk` を呼び出す。
4. `SkDngImage::readDng()`、`SkDngImage::render()`、`SkRawCodec::onGetPixels()` は DNG SDK 呼び出しを `catch (...)` で囲み、失敗時に `false` / `nullptr` / `kIncompleteInput` を返す。
5. 修正前の UBSan abort はこの `catch (...)` に到達しないため、画像デコードを行ったプロセス自体が落ちる。
6. 修正後は UBSan handler が例外を投げるため、Skia の catch に到達し、不正画像として `DecodeException` に変換される。

この経路はソースで確認できたため、PoC 入力が手元になくても脆弱性の発生条件は十分説明できる。

## 面白い点・調査メモ

- CVE/OSV の説明だけ読むと `ubsan_throwing_runtime.cpp` にバグがあるように見えるが、このファイルは修正で新規追加された mitigation runtime であり、脆弱な実体は「修正前にこの runtime が存在しなかったこと」。
- commit message の Bug 番号は `470966846` など複数で、`A-470966318` は OSV/bulletin 側の集約 ID と見られる。
- パッチは DNG SDK の算術ロジックを細かく直していない。クラッシュを引き起こす malformed DNG は複数あり、Android 側は overflow を検知した時点で安全にデコード失敗へ変換する方針を取っている。
- `libdng_sdk_validate` や validator 系 target ではなく、実際に framework/Skia 経由で使われる `libdng_sdk` に対して sanitizer runtime 差し替えが入っている。
- Skia の `SkDngHost::PerformAreaTask()` は worker 内の `dng_exception` とその他例外を集め、最初の例外を再 throw する設計になっていた。DNG SDK はもともと例外を使う前提なので、UBSan を例外化する修正は既存設計に沿っている。

## 保存した証拠・付帯ファイル

- `artifacts/ASB-A-470966318.json`
  - Android OSV JSON。
- `artifacts/*.patch`, `artifacts/*.diff.b64`
  - 取得できた Gitiles patch/diff。OSV listed commit のうち 404 だったものは 0 byte patch として残っている。
- `artifacts/dng_sdk.git/`
  - `platform/external/dng_sdk` の公開 Git clone。
- `artifacts/skia.git/`
  - `platform/external/skia` の sparse clone。DNG codec 確認用。
- `artifacts/frameworks-base-snips/ImageDecoder.java`
  - `platform/frameworks/base` の `ImageDecoder.java` 抜粋保存。
- `artifacts/frameworks-base-snips/ImageDecoder.cpp`
  - `platform/frameworks/base` の JNI `ImageDecoder.cpp` 抜粋保存。
- `artifacts/commit-summary.txt`
  - 主要公開 commit の summary。
- `artifacts/related-commits.txt`
  - 同一件名の関連公開 commit 一覧。
- `artifacts/main-fix-full.patch`
  - `81ded662...` の full patch。
- `artifacts/android16-security-fix-full.patch`
  - `74a5a91...` の full patch。

## 判定

`ok`。ソースコードとパッチ差分から、脆弱性の性質、根本原因、修正の効果、Android framework への到達経路を説明できた。
069 OK

CVE-2026-0085

069-ok-contactsprovider-case-mismatched-simple-field-size-dos

cve.md の Android/Pixel 脆弱性情報

BulletinAndroid Security Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/2026/2026-06-01
Published/updatedJune 1, 2026; updated June 3, 2026
Security patch level2026-06-01 or later
ComponentSystem
TypeDoS
SeverityHigh
Updated AOSP versions14, 15, 16, 16-qpr2
ReferencesA-414389102
IncludedAndroid Security Rewards candidate: AOSP Framework/System item, not a Linux kernel, OSS upstream, chipset, or other-vendor section.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0085 is listed in the Android Security Bulletin as a High severity DoS issue in System.

特定した具体的な脆弱性

CVE-2026-0085 は、ContactsProvider の Data 行に対する単純文字列フィールド長制限を、大小文字を変えた列名で迂回できる DoS 脆弱性だった。

根本原因は、ContactsProvider が ContentValues 上の列名を Java の大小文字区別あり containsKey() / getAsString() で検査していた一方、最終的に値を書き込む SQLite の列名解決は大小文字非依存である、という名前解決ルールの不一致である。攻撃者は data1 の代わりに DaTa1 / DATA1 / daTa1 のようなキーで巨大文字列を渡すことで、applySimpleFieldMaxSize() の 10 KiB 制限を通さずに data1 などへ保存させられる。

この挙動は公開 AOSP ソースの修正 commit と追加テストで確認できたため、脆弱性は特定済みとして ok 判定とする。

原因

根本原因は 2 つの層で同じ「列名」の扱いが揃っていなかったこと。

・Java 側の ContentValues は key を case-sensitive に扱う。
・SQLite 側の column identifier は通常 case-insensitive に解決される。

ContactsProvider は ContentValues の exact key lookup で長さ制限済みと判断してから、その同じ ContentValues を SQLite に渡していた。結果として、検査層では別名として扱われた DaTa1 が、保存層では data1 として受理された。

修正はこの差を findKey() で吸収し、検査層でも保存層と同じく大小文字非依存で該当キーを見つけるようにしたもの。

どこから特定したか

URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01 / https://android.googlesource.com/platform/packages/providers/ContactsProvider/+/0d925d762547a49821187702948de39e4b05bf40

validated.md を表示
# CVE-2026-0085 解析結果

## 結論

CVE-2026-0085 は、ContactsProvider の Data 行に対する単純文字列フィールド長制限を、大小文字を変えた列名で迂回できる DoS 脆弱性だった。

根本原因は、ContactsProvider が `ContentValues` 上の列名を Java の大小文字区別あり `containsKey()` / `getAsString()` で検査していた一方、最終的に値を書き込む SQLite の列名解決は大小文字非依存である、という名前解決ルールの不一致である。攻撃者は `data1` の代わりに `DaTa1` / `DATA1` / `daTa1` のようなキーで巨大文字列を渡すことで、`applySimpleFieldMaxSize()` の 10 KiB 制限を通さずに `data1` などへ保存させられる。

この挙動は公開 AOSP ソースの修正 commit と追加テストで確認できたため、脆弱性は特定済みとして `ok` 判定とする。

## 確認した既存情報

- CVE: CVE-2026-0085
- Android bug reference: A-414389102
- Component: System
- Type / Severity: DoS / High
- Bulletin: Android Security Bulletin, 2026-06-01
- Bulletin URL: https://source.android.com/docs/security/bulletin/2026/2026-06-01
- Bulletin 上の AOSP fix: https://android.googlesource.com/platform/packages/providers/ContactsProvider/+/0d925d762547a49821187702948de39e4b05bf40
- 対象 AOSP version: 14, 15, 16, 16-qpr2

Bulletin の該当行では `CVE-2026-0085 A-414389102 DoS High 14, 15, 16, 16-qpr2` とされており、リンク先は ContactsProvider の commit `0d925d762547a49821187702948de39e4b05bf40` だった。

## パッチ

主要 commit:

- repository: `platform/packages/providers/ContactsProvider`
- commit: `0d925d762547a49821187702948de39e4b05bf40`
- parent: `164078c92d23d173f0f0c986e298dd236d66279b`
- author date: 2026-02-02
- commit date: 2026-04-09
- subject: `Fix size check bypass for case-mismatched columns`
- Bug: `414389102`
- Test: `atest ContactsProviderTests`

commit message は、`applySimpleFieldMaxSize` が exact string matching に依存していたため、`DaTa1` のような入力が最大サイズ制限を迂回できた、と明記している。

変更点は `DataRowHandler.java` と `ContactsProvider2Test.java` の 2 ファイル。修正前は以下のように、指定された正規の列名だけで値を取得していた。

```java
String v = cv.getAsString(column);
```

修正後は `findKey()` が追加され、`ContentValues` 内に正規名がなければ `equalsIgnoreCase()` で大小文字違いのキーを探し、そのキーの値を長さ制限対象にする。

```java
String key = findKey(cv, column);
String v = cv.getAsString(key);
```

注意点として、値の書き戻しは `cv.put(column, truncated)` で正規列名に対して行われる。`ContentValues` に大小文字違いの元キーが残っていても、SQLite 更新時には同じ列名として扱われるため、後続の正規キーで上書きされる形になる。

## 脆弱な処理フロー

`applySimpleFieldMaxSize()` は `ContactsDatabaseHelper.getSimpleFieldMaxSize()` の値を使う。デフォルトは `10 * 1024` で、DeviceConfig key は `simple_field_max_size`。

この制限は次の DataRowHandler で insert/update 前に適用される。

- `DataRowHandlerForStructuredName`: `data1`, `data2`, `data3`, `data4`, `data5`, `data6`, `data7`, `data8`, `data9`
- `DataRowHandlerForPhoneNumber`: `data1`, `data4`
- `DataRowHandlerForEmail`: `data1`
- `DataRowHandlerForOrganization`: `data1`, `data4`
- `DataRowHandlerForNickname`: `data1`

代表的な update 経路:

1. アプリが `ContactsContract.Data.CONTENT_URI` などへ `ContentResolver.update()` を投げる。
2. `ContactsProvider2.updateData()` が入力 `ContentValues` をコピーし、対象 Data 行ごとに MIME type 対応の `DataRowHandler` を選ぶ。
3. 各 handler が `applySimpleFieldMaxSize(values)` を呼ぶ。
4. 修正前は `cv.getAsString("data1")` のような exact key lookup だけなので、`"DaTa1"` の巨大値は見えない。
5. そのまま `DataRowHandler.update()` が `db.update(Tables.DATA, values, ...)` を実行する。
6. SQLite は列名を大小文字非依存で解決するため、`DaTa1` は `data1` として保存される。

修正後のテスト `testCaseMismatchingFieldUpdatesAreTruncatedToMaxSize()` は、`data1`, `daTa1`, `DATA1`, `Data1` の各 variant に対して、`maxSize + 100` 文字の値が `maxSize` へ切り詰められることを検証している。

## 再現条件

脆弱性を起こすには、ContactsProvider の単純フィールドに対して、大小文字違いの列名で最大サイズを超える文字列を渡す。

例:

- 既存の StructuredName Data 行を作る。
- `ContentValues` に `daTa1 = "D" * (simple_field_max_size + N)` を入れる。
- update を成立させるため、テストと同様に少なくとも 1 つ正規大小文字の列、例 `data14 = "Sample Data"` を一緒に渡す。

追加テストから分かる面白い点:

- `daTa1` だけを渡した update は「変更なし」と判断され、更新件数 0 になる。
- `data14` のような正規大小文字の列を 1 つ混ぜると更新処理が進み、大小文字違いの `daTa1` も SQLite により `data1` として保存される。
- これは `DataRowHandler.getAugmentedValues()` が変更有無の判定に `update.containsKey(key)` を使っており、ここも大小文字区別ありであるため。

手元でも SQLite の列名解決が大小文字非依存であることを確認した。`artifacts/sqlite_case_insensitive_column_demo.txt` に保存した実験では、`insert into data(DaTa1, data14)` で `data1` に 12000 文字が入り、`update data set DATA1=...` でも同じ `data1` が更新された。

## DoS としての意味

この修正が守っているのは名前、電話番号、メールアドレス、会社名、肩書、ニックネームなど「単純フィールド」のサイズ上限である。上限を迂回して巨大文字列を ContactsProvider DB に保存できると、以下のようなリソース消費に繋がる。

- `contacts2.db` の肥大化
- 連絡先検索・集約・表示名更新・同期・バックアップなど、Data 行を読む処理でのメモリ/CPU/IO 消費増加
- 連絡先 UI や system_server/ContactsProvider 呼び出し側の応答悪化

commit message は「oversized data from bypassing checks」と表現しており、Bulletin の分類も System DoS High である。RCE/EoP ではなく、制限対象フィールドへ過大な文字列を書き込ませることによるサービス妨害が本質と判断する。

## 根本原因

根本原因は 2 つの層で同じ「列名」の扱いが揃っていなかったこと。

- Java 側の `ContentValues` は key を case-sensitive に扱う。
- SQLite 側の column identifier は通常 case-insensitive に解決される。

ContactsProvider は `ContentValues` の exact key lookup で長さ制限済みと判断してから、その同じ `ContentValues` を SQLite に渡していた。結果として、検査層では別名として扱われた `DaTa1` が、保存層では `data1` として受理された。

修正はこの差を `findKey()` で吸収し、検査層でも保存層と同じく大小文字非依存で該当キーを見つけるようにしたもの。

## 付帯ファイル

- `artifacts/ContactsProvider.git/`: 解析用に clone した ContactsProvider
- `artifacts/git_show_0d925d762547a49821187702948de39e4b05bf40.patch`: 対象 commit の `git show`
- `artifacts/0d925d762547a49821187702948de39e4b05bf40.diff`: Gitiles から取得した diff
- `artifacts/DataRowHandler_pre.java`: parent commit の `DataRowHandler.java`
- `artifacts/DataRowHandler_post.java`: fixed commit の `DataRowHandler.java`
- `artifacts/ContactsProvider2Test_post.java`: fixed commit の `ContactsProvider2Test.java`
- `artifacts/applySimpleFieldMaxSize_callers.txt`: `applySimpleFieldMaxSize()` 呼び出し元一覧
- `artifacts/related_commits.txt`: 同名修正 commit の一覧
- `artifacts/sqlite_case_insensitive_column_demo.txt`: SQLite 列名大小文字非依存の確認結果

## 解析ログ

- `cve.md` を確認し、CVE 番号、A-414389102、System/DoS/High、Bulletin URL を確認。
- Android Security Bulletin 2026-06-01 の該当リンクから ContactsProvider commit `0d925d762547a49821187702948de39e4b05bf40` を特定。
- Gitiles diff と修正前後の `DataRowHandler.java`、修正後テストを保存。
- ContactsProvider を clone し、`git show`、呼び出し元検索、関連 commit 検索を実施。
- SQLite の `DaTa1` / `DATA1` が `data1` に解決されることを `sqlite3 :memory:` で確認。
070 NG

CVE-2026-0126

070-ng-wc-radio-wifi-firmware-wlc-join-oob-write

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentWC-Radio
TypeRCE
SeverityCritical
ReferencesA-472711335
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0126 is listed in the Pixel Update Bulletin as a Critical severity RCE issue in Pixel / WC-Radio.

NG 判定の要点

CVE-2026-0126 は Pixel Update Bulletin 2026-06-01 において Pixel / WC-Radio の Critical RCE として公開されている。CVE/NVD/OSV 側の説明は「WC-Radio に missing bounds check による out-of-bounds write があり、ユーザー操作なしで RCE につながる可能性」という内容だった。

今回のパッチ差分では、Pixel 8 (shiba) の 2026-05 factory image と 2026-06 factory image を比較し、vendor.img 内の Broadcom Wi-Fi firmware fw_bcmdhd.bin_4398_d0 が更新され、その map file 上で June 版のみ wlc_join が hot patch 化されていることを確認した。これは、攻撃者が制御する AP/ビーコン/Probe Response/Association 関連 IE から得た BSS 情報を join 処理へ渡す経路に境界チェックが追加された可能性が高い。

ただし、対象は proprietary firmware binary であり、今回の環境では Ghidra/BinDiff 等の逆コンパイルによる具体的なコピー先バッファ、長さフィールド、境界値までは確定できなかった。したがって「脆弱性が起きる状況を完璧に説明できる」水準には達していないため、このフォルダは ng と判定する。

未確定の理由 / 原因候補

ng。パッチ対象は fw_bcmdhd.bin_4398_d0 の wlc_join 周辺まで絞れたが、ソースコードまたは完全な逆コンパイルにより具体的な OOB write 条件を確定できていないため。

どこから特定したか

確認した公開情報: ・既存 cve.md の内容:
- CVE: CVE-2026-0126
- 参照 ID: A-472711335
- Component/Subcomponent: Pixel / WC-Radio
- Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- Type/Severity: RCE / Critical
・Pixel Bulletin 該当行: CVE-2026-0126 A-472711335 * RCE Critical WC-Radio
・Android OSV: https://storage.googleapis.com/android-osv/…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https://storage.googleapis.com/android-osv/PUB-A-472711335.json` / https://nvd.nist.gov/vuln/detail/CVE-2026-0126` / https://dl.google.com/dl/android/aosp/shiba-cp1a.260505.005.a1-factory-09dcebf9.zip`

validated.md を表示
# CVE-2026-0126 検証メモ

## 結論

CVE-2026-0126 は Pixel Update Bulletin 2026-06-01 において `Pixel / WC-Radio` の Critical RCE として公開されている。CVE/NVD/OSV 側の説明は「WC-Radio に missing bounds check による out-of-bounds write があり、ユーザー操作なしで RCE につながる可能性」という内容だった。

今回のパッチ差分では、Pixel 8 (`shiba`) の 2026-05 factory image と 2026-06 factory image を比較し、`vendor.img` 内の Broadcom Wi-Fi firmware `fw_bcmdhd.bin_4398_d0` が更新され、その map file 上で June 版のみ `wlc_join` が hot patch 化されていることを確認した。これは、攻撃者が制御する AP/ビーコン/Probe Response/Association 関連 IE から得た BSS 情報を join 処理へ渡す経路に境界チェックが追加された可能性が高い。

ただし、対象は proprietary firmware binary であり、今回の環境では Ghidra/BinDiff 等の逆コンパイルによる具体的なコピー先バッファ、長さフィールド、境界値までは確定できなかった。したがって「脆弱性が起きる状況を完璧に説明できる」水準には達していないため、このフォルダは `ng` と判定する。

## 確認した公開情報

- 既存 `cve.md` の内容:
  - CVE: `CVE-2026-0126`
  - 参照 ID: `A-472711335`
  - Component/Subcomponent: `Pixel / WC-Radio`
  - Bulletin URL: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
  - Type/Severity: `RCE / Critical`
- Pixel Bulletin 該当行: `CVE-2026-0126 A-472711335 * RCE Critical WC-Radio`
- Android OSV: `https://storage.googleapis.com/android-osv/PUB-A-472711335.json`
- NVD: `https://nvd.nist.gov/vuln/detail/CVE-2026-0126`
- OSV/NVD の説明: `possible out of bounds write due to a missing bounds check`、ユーザー操作不要、追加権限不要で RCE の可能性。

## 使用した firmware / image

Google factory image ページは TOS acknowledgement cookie がないと ZIP リンクが HTML に展開されないため、以下の URL を取得して解析した。

- May 2026 Pixel 8 factory image:
  - `https://dl.google.com/dl/android/aosp/shiba-cp1a.260505.005.a1-factory-09dcebf9.zip`
- June 2026 Pixel 8 factory image:
  - `https://dl.google.com/dl/android/aosp/shiba-cp2a.260605.012-factory-ada9841e.zip`

保存先:

- `../binaries/pixel_shiba_wc_radio/radio-shiba-g5300i-251202-260127-b-14784800.img`
- `../binaries/pixel_shiba_wc_radio/radio-shiba-g5300i-260317-260505-b-15346003.img`
- `../binaries/pixel_shiba_wc_radio/may_radio/vendor.img`
- `../binaries/pixel_shiba_wc_radio/june_radio/vendor.img`
- 抽出 firmware:
  - `../binaries/pixel_shiba_wc_radio/may_firmware_extract/firmware__fw_bcmdhd.bin_4398_d0`
  - `../binaries/pixel_shiba_wc_radio/june_firmware_extract/firmware__fw_bcmdhd.bin_4398_d0`
  - `../binaries/pixel_shiba_wc_radio/may_firmware_extract/firmware__fw_bcmdhd.map_4398_d0`
  - `../binaries/pixel_shiba_wc_radio/june_firmware_extract/firmware__fw_bcmdhd.map_4398_d0`

SHA-256:

- May radio image: `db5a0c8161d9cc674ec348c07460495f36ef9209740c03f44c14386501c2f80d`
- June radio image: `5bee584549ee24ce7b5465831c007277fd9c1ab73d618a53e607c8d9ade6fdd5`
- May `fw_bcmdhd.bin_4398_d0`: `fa49971a65d08177e52d6092d6f405249a29c603d7c8ea1b69e4e3fda8334ffd`
- June `fw_bcmdhd.bin_4398_d0`: `2f1a08b0aa2848720bbdf766f6229b18938400ee12364b0494cde004869cea68`
- May `fw_bcmdhd.map_4398_d0`: `ca377471d0d25cd6ef30cf2854fccf77b7e109888291cfc72c781b4e4791d7ac`
- June `fw_bcmdhd.map_4398_d0`: `1bb30784c7c30f8c90ea6af829e0dbce020457eb4e2220e4832811baae936315`

## 実施した差分解析

### 1. Factory ZIP の Range 抽出

全 ZIP を落とすと 3.6-3.8 GiB になるため、`range_zip_extract.py` を作成し HTTP Range で central directory と対象 entry のみを取得した。

成果物:

- `range_zip_extract.py`
- `shiba_may_factory_entries.txt`
- `shiba_june_factory_entries.txt`
- `shiba_may_inner_image_entries.txt`
- `shiba_inner_image_entries.txt`

### 2. radio image の確認

Top-level には以下の radio image があった。

- May: `radio-shiba-g5300i-251202-260127-b-14784800.img`
- June: `radio-shiba-g5300i-260317-260505-b-15346003.img`

radio image は `FBPK` header + tar 構造で、`skip=140` から tar として読めた。中身は modem ext4 であり、Bulletin に別途 `Modem` CVE が複数あるため、`WC-Radio` そのものと断定しない方がよいと判断した。

### 3. `vendor.img` 内 firmware 差分

`vendor.img` の `/firmware` で wireless connectivity 系候補を比較した。成果物: `shiba_firmware_top_hashes.tsv`。

主な差分:

- Changed:
  - `/firmware/fw_bcmdhd.bin_4398_d0`
  - `/firmware/fw_bcmdhd.map_4398_d0`
  - `/firmware/brcm/BCM.hcd`
  - `/firmware/brcm/BTFW_B.hcd`
  - `gxp_callisto_fw_core*` も更新されているが WC-Radio とは無関係と判断。
- Unchanged:
  - `bcmdhd.cal_*`
  - `bcmdhd_clm.blob_*`
  - `bcmdhd_txcap.blob_*`
  - `google_wifi_firmware_config_info.pb`

Bluetooth HCD は May の `BCM.hcd` と June の `BTFW_B.hcd` が同一 SHA-256 になるなど、ファイル入れ替え/更新が見える。しかし CVE が `WC-Radio` かつ OOB write/RCE であり、map file 付きの Wi-Fi firmware に関数レベルの security patch 候補があるため、最重要候補は Broadcom Wi-Fi firmware とした。

### 4. `fw_bcmdhd.map_4398_d0` の正規化 diff

通常 diff は `tcpatched_N` の連番ずれが大量に出るため、`__関数名__tcpatched_番号` から番号を除いて set 差分を取った。成果物: `fw_bcmdhd_4398_d0_tcpatched_delta.txt`。

結果:

```text
may patched 1202
june patched 1203

ADDED in June
0015667c wlc_bsscfg$wlc_bsscfg_init_int
0013e5a4 wlc_join

REMOVED in June
00137888 wlc_assoc$wlc_join_attempt_info_init
```

重要なのは June 版だけで `wlc_join` が hot patch 化された点。`wlc_join` は scan/join 対象 BSS 情報、SSID、capability、IE など、リモート AP が供給できる情報を処理して接続処理へ進める入口である。CVE 説明の「remote / user interaction not needed / missing bounds check / OOB write」と整合する。

## 推定される脆弱性の性質

確度の高い推定:

- 脆弱コンポーネントは Pixel 8 の Broadcom Wi-Fi firmware `fw_bcmdhd.bin_4398_d0` 系。
- 攻撃面は Wi-Fi management frame、特に AP 側が供給する BSS/association/join 関連情報。
- June patch で `wlc_join` が hot patch 化されているため、接続対象 BSS の情報を `wlc_join` が処理する際、配列 index、IE 長、リンク数、または BSS/MLD/MLO 関連フィールドの上限チェックが不足し、firmware memory へ OOB write できた可能性が高い。
- `wlc_bsscfg$wlc_bsscfg_init_int` も June で新規 patch 化されているため、join 経路で初期化される BSS config / multi-link config の配列・cubby 領域の初期化またはサイズ管理が関連している可能性がある。

確定できなかった点:

- どの入力 IE/field が直接 trigger になるか。
- どの destination buffer または array が OOB write されるか。
- 境界値、例えば link 数、IE 長、SSID 長、join target index 等の具体的な上限。
- OOB write 後の PC 制御可能性や exploit primitive。

## 面白い点 / 調査メモ

- `developers.google.com/android/images` は TOS acknowledgement cookie なしだと ZIP URL が HTML に出ない。`Cookie: devsite_wall_acks=nexus-image-tos` を付けるとリンク一覧を取得できた。
- Factory ZIP 全体を落とさず、central directory と entry data だけを HTTP Range で取ると、3-4 GiB の ZIP から `radio.img` や `vendor.img` だけを抽出できた。
- `radio-*.img` は先頭 `FBPK` header の後ろに tar があり、`dd ... skip=140 | tar -tvf -` で `*.ext4` を列挙できた。
- `vendor.img` 内 `/firmware/fw_bcmdhd.map_4398_d0` は symbol map として非常に有用で、Broadcom firmware の patched ROM function 名を直接確認できた。
- May firmware string: `24.100.671.82.2 (g998bb28 d0 release2)` / build path date `2025.11.21.0`
- June firmware string: `24.100.671.86.1` / build path date `2026.2.5.0`

## 付帯ファイル

- `range_zip_extract.py`: HTTP Range で ZIP/nested ZIP entry を抽出するスクリプト。
- `ext4_manifest.py`: ext4 image から manifest を作る試行用スクリプト。
- `shiba_may_factory_entries.txt`, `shiba_june_factory_entries.txt`: factory ZIP top-level entries。
- `shiba_may_inner_image_entries.txt`, `shiba_inner_image_entries.txt`: inner `image-*.zip` entries。
- `shiba_firmware_top_hashes.tsv`: `/firmware` の wireless candidate hash 比較。
- `fw_bcmdhd_4398_d0_map.diff`: map file の raw diff。
- `fw_bcmdhd_4398_d0_tcpatched_delta.txt`: `tcpatched` 正規化差分。
- `fw_bcmdhd_4398_d0_cmp_head.txt`: binary cmp の先頭差分。
- `fw_bcmdhd_june_relevant_strings.txt`, `fw_bcmdhd_may_relevant_strings.txt`: 関連 string 抽出。
- `wlc_join_hex_may_june.txt`, `wlc_bsscfg_init_int_hex_may_june.txt`, `patch_table_region.txt`: 候補アドレス周辺 hex dump。

## 判定

`ng`。パッチ対象は `fw_bcmdhd.bin_4398_d0` の `wlc_join` 周辺まで絞れたが、ソースコードまたは完全な逆コンパイルにより具体的な OOB write 条件を確定できていないため。
071 NG

CVE-2026-0132

071-ng-pixel-modem-heap-overflow-unattributed

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentModem
TypeRCE
SeverityCritical
ReferencesA-449160232
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0132 is listed in the Pixel Update Bulletin as a Critical severity RCE issue in Pixel / Modem.

NG 判定の要点

判定: ng

CVE-2026-0132 は Pixel / Modem の Critical RCE として公開されており、NVD/CISA 側の説明では「heap buffer overflow による out-of-bounds write」で、ユーザー操作不要、追加権限不要のリモートコード実行につながる可能性がある。

ただし、今回の検証では CVE-2026-0132 に対応する具体的な修正箇所、関数名、入力メッセージ、またはクラッシュ条件を一意に特定できなかった。Pixel bulletin の A-449160232 は非公開で、公開ソース commit も提示されていない。手元で比較できた Pixel 8 shiba の modem/radio firmware は firmware 全体の再ビルド差分であり、同じ bulletin には Modem RCE が複数件あるため、この差分だけから CVE-2026-0132 固有の根本原因を切り出すのは不十分。

未確定の理由 / 原因候補

このフォルダの基準では、ok とするにはソースコード、または脆弱性が起きる状況を完璧に説明できる必要がある。今回は以下の理由で満たせない。

・A-449160232 が非公開。
・Pixel Modem は closed-source firmware で、公開 commit / diff がない。
・June 2026 の該当 radio image を取得できず、Jan -> May の既存 image 比較に留まった。
・手元の Jan -> May 差分は firmware 全体に広がり、同じ bulletin の複数 Modem RCE と切り分けられない。
・strings 上の候補領域はあるが、CVE-2026-0132 固有の root cause として断定できない。

どこから特定したか

確認した公開情報: ・CVE: CVE-2026-0132
・Android bug ID: A-449160232
・Component: Pixel
・Subcomponent: Modem
・Type: RCE
・Severity: Critical
・Bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
・Bulletin published: 2026-06-16
・NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-0132
・NVD description: Modem に heap buffer overflow 起因の out-of-bounds write が…

解析したバイナリ: 既存の binaries/ と ../binaries/ を確認し、Pixel 8 shiba の radio image を使用した。

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01 / https://nvd.nist.gov/vuln/detail/CVE-2026-0132

validated.md を表示
# CVE-2026-0132 Pixel Modem RCE Critical 検証メモ

## 結論

判定: **ng**

CVE-2026-0132 は Pixel / Modem の Critical RCE として公開されており、NVD/CISA 側の説明では「heap buffer overflow による out-of-bounds write」で、ユーザー操作不要、追加権限不要のリモートコード実行につながる可能性がある。

ただし、今回の検証では **CVE-2026-0132 に対応する具体的な修正箇所、関数名、入力メッセージ、またはクラッシュ条件を一意に特定できなかった**。Pixel bulletin の `A-449160232` は非公開で、公開ソース commit も提示されていない。手元で比較できた Pixel 8 `shiba` の modem/radio firmware は firmware 全体の再ビルド差分であり、同じ bulletin には Modem RCE が複数件あるため、この差分だけから CVE-2026-0132 固有の根本原因を切り出すのは不十分。

## 確認した公開情報

- CVE: `CVE-2026-0132`
- Android bug ID: `A-449160232`
- Component: `Pixel`
- Subcomponent: `Modem`
- Type: `RCE`
- Severity: `Critical`
- Bulletin: <https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01>
- Bulletin published: 2026-06-16
- NVD: <https://nvd.nist.gov/vuln/detail/CVE-2026-0132>
- NVD description: Modem に heap buffer overflow 起因の out-of-bounds write があり、RCE になり得る。
- CWE: `CWE-122 Heap-based Buffer Overflow`

Pixel bulletin では `A-449160232` に `*` が付いており、これは Android bug ID / 修正が公開されていないことを示す。bulletin の FAQ も、この種の問題は通常 Pixel 用 binary drivers / firmware に含まれると説明している。

## 解析したバイナリ

既存の `binaries/` と `../binaries/` を確認し、Pixel 8 `shiba` の radio image を使用した。

- `binaries/pixel_shiba_wc_radio/radio-shiba-g5300i-251202-260127-b-14784800.img`
  - sha256: `db5a0c8161d9cc674ec348c07460495f36ef9209740c03f44c14386501c2f80d`
  - inner payload: `g5300i-251202-260127-B-14784800.ext4`
  - payload sha256: `0d64899c121a4478142823284ce397ee14b8743cd9c851e72b327329040404a6`
- `binaries/pixel_shiba_wc_radio/radio-shiba-g5300i-260317-260505-b-15346003.img`
  - sha256: `5bee584549ee24ce7b5465831c007277fd9c1ab73d618a53e607c8d9ade6fdd5`
  - inner payload: `g5300i-260317-260505-B-15346003.ext4`
  - payload sha256: `b5f0d965add5b160a719c89d84a9fed67bdbbbaed02b0b4bb0301fb164965a88`

June 2026 の安定版 AOSP build は `CP2A.260605.016` として build numbers に掲載されているが、調査時点で `shiba` の June factory/radio zip は通常検索、factory image HTML、binary transparency の範囲では取得できなかった。手元で解析できた最新寄りの比較対象は Jan -> May の `g5300i` firmware だった。

## 実施した解析

OriginHQ の patch diffing pipeline に沿って、次を実施した。

1. `cve.md` を読み、CVE、Bug ID、component/subcomponent、bulletin URL を確認。
2. Pixel Update Bulletin、NVD、AOSP build numbers、Pixel factory/binary transparency ページを確認。
3. 既存 radio image を展開。
4. `FBPK` コンテナの 0x8c 以降が tar として読めることを確認し、inner payload を抽出。
5. inner payload を比較し、4KB ブロック単位の差分と printable strings 差分を生成。
6. 長さ検証、境界チェック、malloc/copy、LCS/PRS、ROHC、USIM/USAT、IMS/RCS など脆弱性に関係し得るログ文字列を抽出。

付帯ファイル:

- `analysis/analyze_radio_diff.py`: 差分生成スクリプト
- `analysis/image_inventory.md`: 解析対象 image / payload の hash とサイズ
- `analysis/block_diff_4k.txt`: 4KB ブロック単位の差分範囲
- `analysis/strings_added.txt`, `analysis/strings_removed.txt`: strings 差分
- `analysis/strings_diff_summary.md`: strings 差分概要
- `analysis/interesting_added.txt`, `analysis/interesting_removed.txt`: 境界・長さ・メモリ・プロトコル関連に絞った strings
- `analysis/fbpk/`: `FBPK` から切り出した tar と inner payload

## 観察結果

`radio-*.img` は先頭に `FBPK` magic を持つコンテナで、内部に tar header があり、`g5300i-...ext4` という名前の payload を持つ。ただし、この payload は mount 可能な通常 ext4 superblock ではなく、先頭に `PIXELMODEM` を持つ Pixel modem 独自形式だった。

4KB ブロック差分では、Jan -> May の変更はほぼ全域に広がる。

```text
changed_blocks=27413
changed_ranges:
  0x00000000-0x00000fff
  0x00002000-0x00002fff
  0x00005000-0x00062fff
  0x000fa000-0x06ba8fff
  0x06bba000-0x06bbffff
```

これは単一関数だけの局所パッチではなく、firmware 全体の再配置・再ビルド・複数機能変更が混ざった差分に見える。

strings 差分では、以下のような領域のログが大量に増減した。

- LCS / NR positioning / PRS: `EUTRAN_LCS_*`, `LBS_ConvertNR_*`, `NR_DL_PRS_*`
- IMS/RCS/SIP: `RCSSH_SessMgr_*`, `IMSPL_Xml*`
- ROHC: `ROHC-COMP`, `ROHC-FEEDBACK`, `SROHC_TCP`
- USIM/USAT: `USIM_%d`, `USAT_%d`
- 3G/UMTS lower layer: `uhal_Hmcp*`, `uphy_CDedicatedModeResources.c`

興味深い点として、May 側には NR/LCS/PRS まわりの `data length is wrong`、`out of range`、`MALLOC FAIL`、`FAIL to copy ...`、`NULL Pointer` 系ログがまとまって見える。例:

- `EUTRAN_LCS_DecodeFacilityInformationElement() - data length is wrong`
- `EUTRAN_LCS_DecodeInvokeComponent() - data length is wrong`
- `LBS_CopyNR_DL_PRS_AssistanceDataList() - MALLOC FAIL!!!`
- `FAIL to copy NR_DL_PRS_BeamInfo`
- `resultsSSB_Indexes[%d].ssb_Index(%d) is out of range`
- `nr-cellidentity.length(%d)`

この領域は「リモートから到達する radio/network supplied data を decode/copy する」「長さ・個数・index を扱う」「heap allocation 後の copy がある」という点で、NVD の heap overflow / OOB write 説明と整合し得る。ただし、同じ image 差分には ROHC、IMS/RCS、USIM/USAT、lower layer の多数の変更も含まれており、CVE-2026-0132 に固有と断定できない。

## 根本原因について

公開情報から確実に言える根本原因は以下まで。

- Modem firmware 内で外部入力を処理する処理に heap buffer overflow が存在した。
- その overflow により heap 上の確保領域外へ書き込む可能性があった。
- 攻撃面は modem component で、ユーザー操作なしにリモートから到達し得る。

今回の binary diff から推測できる候補としては、LCS/NR positioning/PRS などの可変長 ASN.1/通信メッセージ decode 後に、要素数・長さ・index の検証不足のまま heap buffer へ copy するタイプの欠陥が考えられる。しかし、これは strings 差分からの推測であり、`A-449160232` と対応付ける証拠ではない。

したがって、現時点では「どういう脆弱性だったか」は NVD レベルの heap-based buffer overflow / OOB write までは確認できたが、「どの入力フィールドが、どの関数で、どのサイズ計算を誤り、どの buffer を overflow したか」は特定できていない。

## ok にしなかった理由

このフォルダの基準では、ok とするにはソースコード、または脆弱性が起きる状況を完璧に説明できる必要がある。今回は以下の理由で満たせない。

- `A-449160232` が非公開。
- Pixel Modem は closed-source firmware で、公開 commit / diff がない。
- June 2026 の該当 radio image を取得できず、Jan -> May の既存 image 比較に留まった。
- 手元の Jan -> May 差分は firmware 全体に広がり、同じ bulletin の複数 Modem RCE と切り分けられない。
- strings 上の候補領域はあるが、CVE-2026-0132 固有の root cause として断定できない。

## 追加で分かったこと

- `radio-shiba-*.img` は単純な ext4 ではなく、`FBPK` -> tar -> `PIXELMODEM` payload という構造だった。
- `PIXELMODEM` payload には carrier profile 名や SHA-1 風 ID が大量に含まれる。
- strings だけでも Samsung/Pixel modem firmware 内部のモジュール名やログがかなり見える。
- LCS/NR positioning/PRS 周辺は、可変長データ、copy、malloc、out-of-range ログが多く、今後 Ghidra/radare2/BinDiff などで深掘りする価値がある。

## 次に必要なもの

CVE-2026-0132 を ok に近づけるには、少なくとも以下が必要。

- June 2026 の対象 Pixel modem/radio image と直前版の同一デバイス・同一系列 image。
- `PIXELMODEM` payload を分割する専用 parser、または既知の Samsung modem image unpacker。
- Ghidra / radare2 / BinDiff / Diaphora などによる関数単位 diff。
- `A-449160232` に関する追加公開情報、クラッシュログ、vendor advisory、または PoC。
072 NG

CVE-2026-0135

072-ng-modem-oob-read-unattributed

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentModem
TypeRCE
SeverityCritical
ReferencesA-449725960
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0135 is listed in the Pixel Update Bulletin as a Critical severity RCE issue in Pixel / Modem.

NG 判定の要点

この CVE は Pixel Update Bulletin June 2026 の Pixel / Modem / RCE / Critical、参照 ID A-449725960 の非公開修正であることを確認した。NVD と OSV の説明では、根本原因は「missing bounds check による out-of-bounds read」で、追加権限やユーザー操作なしに RCE につながる可能性がある。

ただし、公開ソースコードや公開 bug tracker の差分はなく、取得できた Pixel modem firmware の差分も June リリース全体の大きなバイナリ差分で、A-449725960 に対応する関数、プロトコルメッセージ、入力フィールド、境界条件を一意に切り出せなかった。したがって、このフォルダは ng 判定とする。

未確定の理由 / 原因候補

ng

理由: 根本原因の種類は missing bounds check -> out-of-bounds read と確認できたが、ソースコード差分または脆弱性が起きる状況を完全に説明できるだけの個別パッチ特定には至っていない。

どこから特定したか

確認した公開情報: ・既存 cve.md: CVE-2026-0135, A-449725960, Component Pixel, Subcomponent Modem, Type RCE, Severity Critical, Bulletin https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
・Pixel Update Bulletin June 2026:
- Published: 2026-06-16
- CVE-2026-0135 A-449725960 * RCE Critical Modem
- * 付き Android bug ID は非公開で、修正は Pixel binary drivers に含まれると…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https://nvd.nist.gov/vuln/detail/CVE-2026-0135` / https://osv.dev/vulnerability/PUB-A-449725960` / https://www.originhq.com/research/patch-diffing-pipeline`

validated.md を表示
# CVE-2026-0135 検証メモ

## 結論

この CVE は Pixel Update Bulletin June 2026 の Pixel / Modem / RCE / Critical、参照 ID `A-449725960` の非公開修正であることを確認した。NVD と OSV の説明では、根本原因は「missing bounds check による out-of-bounds read」で、追加権限やユーザー操作なしに RCE につながる可能性がある。

ただし、公開ソースコードや公開 bug tracker の差分はなく、取得できた Pixel modem firmware の差分も June リリース全体の大きなバイナリ差分で、`A-449725960` に対応する関数、プロトコルメッセージ、入力フィールド、境界条件を一意に切り出せなかった。したがって、このフォルダは `ng` 判定とする。

## 確認した公開情報

- 既存 `cve.md`: `CVE-2026-0135`, `A-449725960`, Component `Pixel`, Subcomponent `Modem`, Type `RCE`, Severity `Critical`, Bulletin `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- Pixel Update Bulletin June 2026:
  - Published: 2026-06-16
  - `CVE-2026-0135 A-449725960 * RCE Critical Modem`
  - `*` 付き Android bug ID は非公開で、修正は Pixel binary drivers に含まれると説明されている。
- NVD:
  - URL: `https://nvd.nist.gov/vuln/detail/CVE-2026-0135`
  - Description: Modem で missing bounds check による out-of-bounds read があり、追加権限なし・ユーザー操作なしで RCE につながる可能性。
  - CWE: `CWE-125 Out-of-bounds Read`
- OSV:
  - URL: `https://osv.dev/vulnerability/PUB-A-449725960`
  - Alias: `CVE-2026-0135`, `A-449725960`
  - Fixed: `Pixel-family specific:2026-06-05`
  - 取得 JSON: `artifacts/osv-PUB-A-449725960.json`

## 使用したバイナリ

既存の shiba factory/radio artifacts を再利用した。保存済みの modem 本体は `../binaries/pixel_shiba_modem_0135/` に抽出した。

- May radio image: `binaries/pixel_shiba_wc_radio/radio-shiba-g5300i-251202-260127-b-14784800.img`
- June radio image: `binaries/pixel_shiba_wc_radio/radio-shiba-g5300i-260317-260505-b-15346003.img`
- May modem.bin: `../binaries/pixel_shiba_modem_0135/modem_shiba_may_g5300i-251202-260127-B-14784800.bin`
  - SHA256: `072eb34d8140a74f6d2508256ad4361175f388eafd7d5efcab8c8ea2b0891308`
- June modem.bin: `../binaries/pixel_shiba_modem_0135/modem_shiba_june_g5300i-260317-260505-B-15346003.bin`
  - SHA256: `95dd7a59690f17ecfc43a8ccee381850c37787169b1442c1841074b9828b018a`

## 解析内容

ユーザー指定の参考手法として `https://www.originhq.com/research/patch-diffing-pipeline` のように、公開 advisory の確認、対象成果物の収集、前後バージョンの差分、文字列・構造情報の絞り込み、根拠と限界の記録、という順で確認した。

radio image から切り出されていた ext4 payload は通常 ext4 と異なり superblock がファイル先頭にあり、読み取り時に 1024 bytes のゼロを前置した一時ビューで `ext4` Python パッケージから列挙した。

生成した主な付帯ファイル:

- `artifacts/may_ext4_file_hashes.jsonl`
- `artifacts/june_ext4_file_hashes.jsonl`
- `artifacts/ext4_file_diff_normalized.tsv`
- `artifacts/modem_bin_sha256.txt`
- `artifacts/toc_sections.tsv`
- `artifacts/toc_section_hashes.tsv`
- `artifacts/modem_diff_offsets_summary.txt`
- `artifacts/modem_strings_added.txt`
- `artifacts/modem_strings_removed.txt`
- `artifacts/modem_strings_added_security_keywords.txt`
- `artifacts/modem_strings_removed_security_keywords.txt`
- `artifacts/changed_string_keyword_clusters.txt`

## バイナリ差分から分かったこと

- ext4 内の重要な実行系ファイルは `/images/<version>/modem.bin`。May/June で同サイズだが SHA256 が変化している。
- `modem.bin` は `TOC` 形式で、主な section は `BOOT`, `MAIN`, `VSS`, `APM`, `INFO`。
- TOC 上の主要 section:
  - `BOOT`: offset `0x410`, size `0x16800`
  - `MAIN`: offset `0x16c10`, load address `0x40010000`, size `0x5da0c00`
  - `VSS`: offset `0x5db7810`, load address `0x4f900000`, size `0x47cc0c`
  - `APM`: offset `0x623441c`, load address `0x0202e000`, size `0xb498`
  - `INFO`: offset `0x623f8b4`, load address `0x40009000`, size `0xd0`
- `strings` には Samsung/Exynos modem 系と思われる `S5300`, `S5123`, `PALCommon`, `HEDGE`, `LTE_RRC`, `NR_RRC`, `NAS`, `IMSSH`, `STLS`, `SROHC` などの内部ログが多数含まれる。
- June 追加文字列には `out of bounds`, `Invalid length`, `decode error`, `Exceeded TempBuffer Size` など、境界検査・長さ検査に関係するログが多数ある。ただし May 側にも類似文字列が多く、リビルド差分・ログテーブル差分・複数修正が混在している。
- `A-449725960` 以外にも同じ Bulletin に Modem RCE が複数あるため、June の modem.bin 差分全体から CVE-2026-0135 だけを分離する根拠はない。

## 推定される脆弱性像

公開情報から確実に言える範囲では、Modem が外部入力由来の長さ・インデックス・要素数を使って読み取りを行う箇所で境界チェックが不足し、out-of-bounds read が発生する。Modem の attack surface であるため、ネットワーク側から到達する制御プレーン/データプレーン/IMS 等の入力を処理する閉源 firmware 内の問題と考えられる。

ただし、今回の解析では以下を特定できなかった。

- 具体的な parser または handler 名
- 悪性入力のプロトコル、メッセージ種別、フィールド
- OOB read の読み取り元バッファ、境界値、読み取りサイズ
- RCE に至るメモリ破壊または制御フロー到達条件
- `A-449725960` と一致する個別 patch hunk

## 面白い点・注意点

- Pixel Bulletin の `*` は実際に公開 changelist がないことを意味し、このケースでは Android ソース差分ではなく firmware 差分の問題になる。
- radio image は tar としては開けないが、先頭に TOC らしきメタデータを持ち、内部に ext4 payload が入っている。
- ext4 payload は通常の 0x400 superblock ではなく先頭 superblock 配置だったため、一般的な ext4 reader ではそのまま読めなかった。
- carrier configuration (`confpack`, `manifests`, `uecap`) も大量に変わっているが、CVE の「Modem RCE / OOB read」と直接結び付ける根拠は得られなかった。
- NVD の CVSS 表示は CISA-ADP が `AV:L/PR:L` を付けているが、Google/OSV の説明は「追加権限不要・ユーザー操作不要」。Modem attack surface の文脈では後者の説明を優先して記録した。

## 判定

`ng`

理由: 根本原因の種類は `missing bounds check -> out-of-bounds read` と確認できたが、ソースコード差分または脆弱性が起きる状況を完全に説明できるだけの個別パッチ特定には至っていない。
073 NG

CVE-2026-0139

073-ng-CVE-2026-0139-Pixel-Modem-OOB-write-RCE

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentModem
TypeRCE
SeverityCritical
ReferencesA-449726527
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0139 is listed in the Pixel Update Bulletin as a Critical severity RCE issue in Pixel / Modem.

NG 判定の要点

本件は ng と判定する。公開情報上は脆弱性の性質を確認できたが、手元のPixel modemバイナリ差分から CVE-2026-0139単独の修正箇所、関数、入力メッセージ形式を一意に特定できなかった。

公開CVE/OSV情報で確認できる脆弱性は、Pixel Modem内の missing bounds check による out-of-bounds write である。影響はremote code execution、追加権限不要、ユーザー操作不要とされる。CISA ADPの付加情報ではCWE-119、CVSS v3.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H、base score 8.8である。

ただし、今回比較した shiba modem firmwareでは、2026-01-27 buildから2026-05-05 buildへの更新で modem.bin の MAIN セクションが約80MB分変化しており、同じJune 2026 bulletin内の複数Modem RCE修正や通常更新が混在している。CVE-2026-0139のbug ID A-449726527 は非公開で、bulletin上の * 付きAndroid bug IDであるため、公開commitやAOSP diffには紐付かない。このため「どのbounds checkが追加されたか」までは検証不能だった。

未確定の理由 / 原因候補

公開情報から確定できる根本原因:

・Modem内のどこかの入力処理でbounds checkが不足していた。
・その結果、入力に由来する長さ、個数、index、またはTLV/IE/PDU field等が出力先バッファ容量を超えても書き込みが行われ、out-of-bounds writeが可能だった。
・攻撃面はnetwork経由で、追加権限不要、ユーザー操作不要。CVSS上はPR:Lだが、Pixel modem文脈ではbaseband/network側入力の処理で発火する類型と解釈できる。

今回のバイナリ解析から確定できない点:

・対象プロトコル層がLTE/NR RRC、NAS、IMS/SIP、TLS、MAC/RLC/PDCP等のどれか。
・具体的な脆弱関数名。
・追加されたbounds checkの条件式。
・OOB write先の構造体/heap/stack/共有メモリ領域。
・exploitに必要な具体的メッセージ列。

したがって、「missing bounds checkによるOOB write」という根本原因カテゴリは確認できたが、「脆弱性が起きる状況を完璧に説明できる」水準には達していない。

どこから特定したか

保存した付帯ファイル: ・artifacts/analysis/PUB-A-449726527.json
・artifacts/analysis/PUB-A-449726527.pretty.json
・artifacts/analysis/CVE-2026-0139.cve5.json
・artifacts/analysis/CVE-2026-0139.cve5.pretty.json
・artifacts/analysis/pixel-2026-06-01-bulletin.html
・artifacts/analysis/ext4_list_extract.py
・artifacts/analysis/old_file_manifest.txt
・artifacts/analysis/new_file_manifest.txt…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https://storage.googleapis.com/android-osv/PUB-A-449726527.json` / https://cveawg.mitre.org/api/cve/CVE-2026-0139`

validated.md を表示
# CVE-2026-0139 Pixel Modem RCE 解析結果

## 結論

本件は **ng** と判定する。公開情報上は脆弱性の性質を確認できたが、手元のPixel modemバイナリ差分から **CVE-2026-0139単独の修正箇所、関数、入力メッセージ形式を一意に特定できなかった**。

公開CVE/OSV情報で確認できる脆弱性は、Pixel Modem内の **missing bounds check による out-of-bounds write** である。影響はremote code execution、追加権限不要、ユーザー操作不要とされる。CISA ADPの付加情報ではCWE-119、CVSS v3.1 `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H`、base score 8.8である。

ただし、今回比較した `shiba` modem firmwareでは、2026-01-27 buildから2026-05-05 buildへの更新で `modem.bin` の `MAIN` セクションが約80MB分変化しており、同じJune 2026 bulletin内の複数Modem RCE修正や通常更新が混在している。CVE-2026-0139のbug ID `A-449726527` は非公開で、bulletin上の `*` 付きAndroid bug IDであるため、公開commitやAOSP diffには紐付かない。このため「どのbounds checkが追加されたか」までは検証不能だった。

## 確認したCVE情報

- CVE: `CVE-2026-0139`
- Android bug reference: `A-449726527`
- Component/Subcomponent: `Pixel / Modem`
- Type/Severity: `RCE / Critical`
- Bulletin: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- OSV: `https://storage.googleapis.com/android-osv/PUB-A-449726527.json`
- CVE v5: `https://cveawg.mitre.org/api/cve/CVE-2026-0139`

公開説明:

> In Modem, there is a possible out of bounds write due to a missing bounds check. This could lead to remote code execution with no additional execution privileges needed. User interaction is not needed for exploitation.

## 使用したバイナリ

既存の `../binaries/pixel_shiba_wc_radio/` を使用した。

- 修正前候補: `../binaries/pixel_shiba_wc_radio/radio-shiba-g5300i-251202-260127-b-14784800.img`
  - SHA-256: `db5a0c8161d9cc674ec348c07460495f36ef9209740c03f44c14386501c2f80d`
  - build.info: `date = 2026-01-27T11:35:17+00:00`
  - modem hash: `71397974fd703fea590e831e69d92cb9e5d0f5c9`
  - config hash: `c87159a9ea07a366804999cee760c67dc170e348`
- 修正後候補: `../binaries/pixel_shiba_wc_radio/radio-shiba-g5300i-260317-260505-b-15346003.img`
  - SHA-256: `5bee584549ee24ce7b5465831c007277fd9c1ab73d618a53e607c8d9ade6fdd5`
  - build.info: `date = 2026-05-05T10:11:26+00:00`
  - modem hash: `fe52cf9910f9040c2c92e8fe7c17cdd0ae0d13c9`
  - config hash: `7c5fed7de84c16c9dd146214add1809c2fa9e7ff`

## 抽出手順と構造

radio imageは `FBPK` ヘッダを持ち、オフセット `140` からtar streamが始まる。tarには0バイトのバージョンマーカーと `.ext4` が含まれていた。

- old tar list: `artifacts/analysis/old_tar_list.txt`
- new tar list: `artifacts/analysis/new_tar_list.txt`
- ext4抽出スクリプト: `artifacts/analysis/ext4_list_extract.py`
- file manifest:
  - `artifacts/analysis/old_file_manifest.txt`
  - `artifacts/analysis/new_file_manifest.txt`

`.ext4` はsuperblockが通常の1024バイトオフセットではなく先頭にある形式だったため、1024バイトのゼロを前置した作業コピーをPython `ext4` moduleで読んだ。

ext4内の主な構造:

- `/images/<version>/modem.bin`
- `/images/<version>/uecap/*.binarypb`
- `/images/<version>/confpack/`
- `/images/<version>/confpack/cfg.db`
- `/images/<version>/confpack/confseqs/`
- `/images/<version>/confpack/manifests/`

## 差分結果

バージョン名だけを正規化して比較した結果:

- added: 316 files
- removed: 316 files
- changed: 7 files

詳細は `artifacts/analysis/normalized_file_diff.txt`。

同名で変化した主なファイル:

- `/images/VERSION/modem.bin`
- `/images/VERSION/confpack/cfg.db`
- `/images/VERSION/confpack/cfg.sha2`
- `/images/VERSION/confpack/build.info`
- `/images/VERSION/confpack/release-label`
- `/images/VERSION/confpack/confseqs_symbolic_link_mapping`
- `/images/VERSION/confpack/manifests_symbolic_link_mapping`

`modem.bin` は先頭に `TOC` を持つコンテナで、`BOOT`, `MAIN`, `VSS`, `APM`, `NV_NORM`, `NV_PROT`, `REPLAY` のエントリが見えた。TOC差分は `artifacts/analysis/modem_toc_diff.tsv` に保存した。

主要セクション差分:

| section | file offset | size | diff bytes |
| --- | ---: | ---: | ---: |
| BOOT | `0x410` | `0x16800` | 138 |
| MAIN | `0x16c10` | `0x5da0c00` | 79,886,565 |
| VSS | `0x5db7810` | `0x47cc0c` | 130 |
| APM | `0x623441c` | `0xb498` | 130 |

`MAIN` の差分が極めて大きく、単純な関数単位のpatch diffではなく、モデムMAINイメージ全体が大規模に差し替わっている。この中にはCVE-2026-0132, CVE-2026-0135, CVE-2026-0139, CVE-2026-0154, CVE-2026-0164などJune 2026 bulletinに同時掲載されたModem RCE修正が混在している可能性が高い。

## 文字列差分で分かったこと

`modem.bin` から `strings -a -n 5` を取り、前後で追加/削除された文字列を保存した。

- added strings: `artifacts/analysis/added_modem_strings.txt`
- removed strings: `artifacts/analysis/removed_modem_strings.txt`
- suspicious added strings: `artifacts/analysis/added_modem_strings_suspicious.txt`
- suspicious removed strings: `artifacts/analysis/removed_modem_strings_suspicious.txt`

追加文字列にはTLS handshake、IMS/SIP、LTE/RRC/TLP、MAC/PDU、decode/length/invalid系のログが多数含まれていた。例:

- `Error - Invalid len for server certificate:%d!!`
- `Error - pBuff decode error!!`
- `Received msg: Invalid message %d in Active state`
- `MAC Header Length`
- `MAC Invalid PDU Count`

しかし、これらは広範なログ/コード差分であり、`A-449726527` または `CVE-2026-0139` に対応する固有の修正とは判断できない。

## 脆弱性と根本原因の評価

公開情報から確定できる根本原因:

- Modem内のどこかの入力処理でbounds checkが不足していた。
- その結果、入力に由来する長さ、個数、index、またはTLV/IE/PDU field等が出力先バッファ容量を超えても書き込みが行われ、out-of-bounds writeが可能だった。
- 攻撃面はnetwork経由で、追加権限不要、ユーザー操作不要。CVSS上はPR:Lだが、Pixel modem文脈ではbaseband/network側入力の処理で発火する類型と解釈できる。

今回のバイナリ解析から確定できない点:

- 対象プロトコル層がLTE/NR RRC、NAS、IMS/SIP、TLS、MAC/RLC/PDCP等のどれか。
- 具体的な脆弱関数名。
- 追加されたbounds checkの条件式。
- OOB write先の構造体/heap/stack/共有メモリ領域。
- exploitに必要な具体的メッセージ列。

したがって、「missing bounds checkによるOOB write」という根本原因カテゴリは確認できたが、「脆弱性が起きる状況を完璧に説明できる」水準には達していない。

## 面白い点・調査メモ

- Pixel bulletinの `*` 付きAndroid bug IDは非公開で、bulletinのFAQ上も最新binary driverに修正が入る類型と説明されている。今回のCVEも公開commitはなかった。
- `cve.md` のPublished/updatedはJune 16, 2026。OSV JSONのpublishedは`2026-06-01T00:00:00Z`、modifiedは`2026-06-22T15:18:41Z`だった。
- CVE v5上のCNA affected versionは `Android kernel` と記載されているが、Pixel bulletinでは `Pixel / Modem` であり、実際の修正候補はradio/modem binaryに入っている。
- `modem.bin` のTOC offsetは上位32bitに属性/ロードアドレスのような値が混ざっており、ファイル内オフセットとしては下位32bitを使う必要があった。
- ext4抽出時、Python `ext4` moduleの `inode.size` がこのイメージでは実サイズとして使えず、抽出ファイルが1MiB単位に見える挙動があった。差分検出は同一手法の前後比較として利用した。
- confpack側はmanifest/confseqsが大量に入れ替わっており、設定DB更新も同時に含まれている。CVE修正が設定で緩和された可能性も完全には除外できないが、公開CVEの「out-of-bounds write due to missing bounds check」はコード側修正を示唆する。

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

- `artifacts/analysis/PUB-A-449726527.json`
- `artifacts/analysis/PUB-A-449726527.pretty.json`
- `artifacts/analysis/CVE-2026-0139.cve5.json`
- `artifacts/analysis/CVE-2026-0139.cve5.pretty.json`
- `artifacts/analysis/pixel-2026-06-01-bulletin.html`
- `artifacts/analysis/ext4_list_extract.py`
- `artifacts/analysis/old_file_manifest.txt`
- `artifacts/analysis/new_file_manifest.txt`
- `artifacts/analysis/old_extracted_sha256.txt`
- `artifacts/analysis/new_extracted_sha256.txt`
- `artifacts/analysis/normalized_file_diff.txt`
- `artifacts/analysis/old_modem_toc.json`
- `artifacts/analysis/new_modem_toc.json`
- `artifacts/analysis/modem_toc_diff.tsv`
- `artifacts/analysis/added_modem_strings.txt`
- `artifacts/analysis/removed_modem_strings.txt`
- `artifacts/analysis/added_modem_strings_suspicious.txt`
- `artifacts/analysis/removed_modem_strings_suspicious.txt`

074 OK

CVE-2026-0149

074-ok-rtcp-mtu-mismatch-heap-oob-write

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
Subcomponentlibpixelimsmedia
TypeRCE
SeverityCritical
ReferencesA-481311295
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0149 is listed in the Pixel Update Bulletin as a Critical severity RCE issue in Pixel / libpixelimsmedia.

特定した具体的な脆弱性

CVE-2026-0149 は Pixel の libpixelimsmedia.so に含まれる RtpSession::rtpSendRtcpPacket() の heap out-of-bounds write である。根本原因は、RTCP compound packet のサイズ計算が RtpStackProfile::getMtuSize()、デフォルトでは RTP_CONF_MTU_SIZE = 3000 を基準に行われる一方、実際に formRtcpPacket() へ渡す送信バッファは RTP_DEF_MTU_SIZE = 1350 固定で確保されていたこと。

May 2026 の shiba OTA では rtpSendRtcpPacket() が常に 1350 バイトを new[] して RtpBuffer::setBufferInfo(1350, pcBuff) していた。June 2026 の OTA ではここが m_pobjRtpStack->getStackProfile()->getMtuSize() を取得し、その値で new[] と setBufferInfo() を行う実装に変わっている。RtpStackProfile が取れない場合だけ 1350 に fallback する。

原因

記載なし。

どこから特定したか

解析対象バイナリ: ・vulnerable 側: ../binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip
- SHA256: 71cbe004f1d76a981bbc65587465d5b36af22d85c7c7b18ee214c05488aee6fc
- 抽出 SO: blobs/libpixelimsmedia_may_cp1a.260505.005.a1.so
- SO SHA256: 805eb3e4af5ec05989ed0a8f95452962a8b59b7f16958f0adf9315467779407a
- BuildID: 04d1927fb8d90a6a235602b626d2bd2c
・patched 側:…

パッチ差分の要点: symbol_size_diff_may_june.txt で関連関数のサイズ変化を確認した。

保存した主な成果物: ・PUB-A-481311295.json: OSV の公開 CVE JSON
・payload_properties.txt: May/June OTA payload metadata (ota_may/, ota_june/)
・blobs/libpixelimsmedia_may_cp1a.260505.005.a1.so
・blobs/libpixelimsmedia_june_cp2a.260605.012.so
・symbol_size_diff_may_june.txt
・RtpSession_rtpSendRtcpPacket_RtcpPacketp_may.objdump.txt
・RtpSession_r…

validated.md を表示
# CVE-2026-0149 / A-481311295 検証メモ

## 結論

CVE-2026-0149 は Pixel の `libpixelimsmedia.so` に含まれる `RtpSession::rtpSendRtcpPacket()` の heap out-of-bounds write である。根本原因は、RTCP compound packet のサイズ計算が `RtpStackProfile::getMtuSize()`、デフォルトでは `RTP_CONF_MTU_SIZE = 3000` を基準に行われる一方、実際に `formRtcpPacket()` へ渡す送信バッファは `RTP_DEF_MTU_SIZE = 1350` 固定で確保されていたこと。

May 2026 の shiba OTA では `rtpSendRtcpPacket()` が常に 1350 バイトを `new[]` して `RtpBuffer::setBufferInfo(1350, pcBuff)` していた。June 2026 の OTA ではここが `m_pobjRtpStack->getStackProfile()->getMtuSize()` を取得し、その値で `new[]` と `setBufferInfo()` を行う実装に変わっている。`RtpStackProfile` が取れない場合だけ 1350 に fallback する。

このため、デフォルト構成では compound RTCP 生成側が最大 3000 バイト程度まで有効と判断した packet を、1350 バイト heap buffer に `memcpy()` 等で形成できる。RTCP feedback の FCI や RTCP XR report block は `RtcpFbPacket::formRtcpFbPacket()` / `RtcpXrPacket::formRtcpXrPacket()` で出力先の残容量確認なしに compound buffer へコピーされるため、RCE につながる heap overflow として扱われたと判断する。

判定: ok。公開ソース相当の旧実装と Pixel May/June バイナリ差分から、脆弱な状況と修正意図を説明できる。

## cve.md から確認した情報

- CVE: CVE-2026-0149
- 参照 ID: A-481311295
- Component / subcomponent: Pixel / `libpixelimsmedia`
- Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- Bulletin 公開/更新日: 2026-06-16
- 種別/深刻度: RCE / Critical

OSV/NVD では `RtpSession::rtpSendRtcpPacket` における heap buffer overflow による OOB write と説明されている。OSV JSON は `PUB-A-481311295.json` に保存した。

## 解析対象バイナリ

- vulnerable 側: `../binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip`
  - SHA256: `71cbe004f1d76a981bbc65587465d5b36af22d85c7c7b18ee214c05488aee6fc`
  - 抽出 SO: `blobs/libpixelimsmedia_may_cp1a.260505.005.a1.so`
  - SO SHA256: `805eb3e4af5ec05989ed0a8f95452962a8b59b7f16958f0adf9315467779407a`
  - BuildID: `04d1927fb8d90a6a235602b626d2bd2c`
- patched 側: `../binaries/pixel_shiba_ota/shiba-ota-cp2a.260605.012-b315a1a2.zip`
  - SHA256: `b315a1a292e0fec4ddfa9a527f99fe0569bbfead09ff49f5fd3d156863b6baa9`
  - 抽出 SO: `blobs/libpixelimsmedia_june_cp2a.260605.012.so`
  - SO SHA256: `22a5ff6cb128f68a9fbba7b96535c3732297a32a6e2fddb51d2c009e39e8df9d`
  - BuildID: `9805086f2f4b604be8076a9be5740ed6`

OTA URL:

- https://dl.google.com/dl/android/aosp/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip
- https://dl.google.com/dl/android/aosp/shiba-ota-cp2a.260605.012-b315a1a2.zip

抽出は `bsdtar` で `payload.bin` を取り出し、`payload-dumper` で `system_ext` のみ dump、Python `ext4` package で `lib64/libpixelimsmedia.so` を抽出した。`payload-dumper` は protobuf 互換性のため `PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python` と `run_payload_dumper_fork.py` を使った。

## パッチ差分の要点

`symbol_size_diff_may_june.txt` で関連関数のサイズ変化を確認した。

- `RtpSession::rtpSendRtcpPacket(RtcpPacket*)`: 448 -> 480 bytes
- `RtcpFbPacket::formRtcpFbPacket(RtpBuffer*)`: 304 -> 352 bytes
- `RtcpXrPacket::formRtcpXrPacket(RtpBuffer*)`: 288 -> 336 bytes
- `RtpSession::numberOfReportBlocks(unsigned int, unsigned int)`: 64 -> 96 bytes
- `RtpSession::rtpMakeCompoundRtcpPacket(RtcpPacket*)`: 1296 -> 1344 bytes

主修正は `RtpSession::rtpSendRtcpPacket()`。

May disassembly (`RtpSession_rtpSendRtcpPacket_RtcpPacketp_may.objdump.txt`):

- `0x173e38`: `mov w0, #0x546`、つまり 1350 バイトを `new[]`
- `0x173e48`: `mov w1, #0x546` を `RtpBuffer::setBufferInfo()` に渡す
- `0x173e58`: `RtcpPacket::formRtcpPacket(pRtcpBuf)` を呼ぶ

June disassembly (`RtpSession_rtpSendRtcpPacket_RtcpPacketp_june.objdump.txt`):

- `0x17f274` 以降で `m_pobjRtpStack` と `getStackProfile()` を null check
- `0x17f28c`: `RtpStackProfile::getMtuSize()` を呼び、その結果を `w22` に保持
- `0x17f298`: profile が無い場合のみ `w22 = 0x546`
- `0x17f29c`: `w22` で `new[]`
- `0x17f2ac`: `w22` を `RtpBuffer::setBufferInfo()` に渡す

つまり、送信バッファ容量が固定 1350 から stack profile MTU に修正された。

## 脆弱性が起きる状況

旧ソース相当の AOSP `RtpSession.cpp` では次の不整合がある。

- `RtpService.cpp:209-213`: `populateRtpProfile()` が `setMtuSize(RTP_CONF_MTU_SIZE)` を呼ぶ。
- `RtpGlobal.h:38`: `RTP_CONF_MTU_SIZE` は 3000。
- `RtpGlobal.h:50`: `RTP_DEF_MTU_SIZE` は 1350。
- `RtpSession.cpp:477-536`: `rtpMakeCompoundRtcpPacket()` は `getMtuSize()` を使い、packet 全体が MTU に収まるかを判断する。
- `RtpSession.cpp:590-615`: `rtpSendRtcpPacket()` は `new RtpDt_UChar[RTP_DEF_MTU_SIZE]` と `setBufferInfo(RTP_DEF_MTU_SIZE, pcBuff)` で 1350 バイトしか確保しない。

その後 `RtcpPacket::formRtcpPacket()` が SR/RR/SDES/feedback/XR などを同じ `RtpBuffer` に順に形成する。`RtcpFbPacket.cpp:109-169` では FCI を `memcpy(pucBuffer, pFCI->getBuffer(), pFCI->getLength())` でコピーし、`RtcpXrPacket.cpp:68-124` では XR report block を `memcpy(pucBuffer, pReportBlk->getBuffer(), pReportBlk->getLength())` でコピーする。どちらも `RtpBuffer` の capacity との比較が無い。

したがって、profile MTU に基づく compound RTCP が 1350 バイトを超えると、`rtpSendRtcpPacket()` が確保した heap buffer の末尾を越えて書く。RTCP feedback 送信 API (`IRtpSession::SendRtcpFeedback`) や XR 送信 API (`IRtpSession::SendRtcpXr`) は IMS media stack の上位から呼ばれ、OSV が示す通り追加権限や user interaction は不要な RCE 条件になり得る。

## 付随して分かったこと

- June では `RtcpFbPacket::formRtcpFbPacket()` と `RtcpXrPacket::formRtcpXrPacket()` に null check が追加されている。`strings` に `[formRtcpFbPacket] invalid FCI` があり、disassembly でも FCI/report block と内部 buffer の null check が増えている。ただし長さ境界チェックではない。
- `numberOfReportBlocks()` も June で hardening されている。May は `uiMtuSize - uiEstRtcpSize` を unsigned のまま計算するが、June は `subs` と `b.ls` で `uiMtuSize <= uiEstRtcpSize` の場合に 0 を返す分岐が追加されている。これは別の underflow/過大計算防止に見える。
- 公開 vendor blob mirror (`TheMuppets/proprietary_vendor_google_shiba`) の `lineage-23.2` は `BP4A.260205.001` ベースで、June 2026 の CVE 修正確認には古かった。参考差分として一部ファイルは残したが、結論には使っていない。
- macOS 標準 `unzip` と Python `zipfile` は May OTA の central directory で失敗したが、`bsdtar` は必要ファイルを抽出できた。
- `rtpSendRtcpPacket()` は `formRtcpPacket()` が失敗しても最後に `RTP_SUCCESS` を返す構造が残っている。今回の OOB の直接原因ではないが、エラー伝播としては弱い。

## 保存した主な成果物

- `PUB-A-481311295.json`: OSV の公開 CVE JSON
- `payload_properties.txt`: May/June OTA payload metadata (`ota_may/`, `ota_june/`)
- `blobs/libpixelimsmedia_may_cp1a.260505.005.a1.so`
- `blobs/libpixelimsmedia_june_cp2a.260605.012.so`
- `symbol_size_diff_may_june.txt`
- `RtpSession_rtpSendRtcpPacket_RtcpPacketp_may.objdump.txt`
- `RtpSession_rtpSendRtcpPacket_RtcpPacketp_june.objdump.txt`
- `RtcpFbPacket_formRtcpFbPacket_RtpBufferp_may.objdump.txt`
- `RtcpFbPacket_formRtcpFbPacket_RtpBufferp_june.objdump.txt`
- `RtcpXrPacket_formRtcpXrPacket_RtpBufferp_may.objdump.txt`
- `RtcpXrPacket_formRtcpXrPacket_RtpBufferp_june.objdump.txt`
- `RtpSession_rtpMakeCompoundRtcpPacket_RtcpPacketp_may.objdump.txt`
- `RtpSession_rtpMakeCompoundRtcpPacket_RtcpPacketp_june.objdump.txt`
- `RtpSession_numberOfReportBlocks_unsigned_int_unsigned_int_may.objdump.txt`
- `RtpSession_numberOfReportBlocks_unsigned_int_unsigned_int_june.objdump.txt`
- `run_payload_dumper_fork.py`
- `pip_payload_dumper_install.txt`, `pip_ext4_install.txt`

巨大な `payload.bin` と `system_ext.img` は OTA ZIP から再生成可能なため削除した。

## 参照 URL / リポジトリ

- Pixel bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- OSV: https://osv.dev/vulnerability/ASB-A-481311295
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-0149
- AOSP source mirror used locally: https://android.googlesource.com/platform/packages/modules/ImsMedia
  - local HEAD: `6da37b8 [automerger skipped] Merge 24Q3 to AOSP main am: d81dbf1b55 -s ours am: 12309eccde -s ours`
- 参考にした手法: https://www.originhq.com/research/patch-diffing-pipeline
075 NG

CVE-2026-0154

075-ng-sip-refer-memory-corruption

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentModem
TypeRCE
SeverityCritical
ReferencesA-449725859
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0154 is listed in the Pixel Update Bulletin as a Critical severity RCE issue in Pixel / Modem.

NG 判定の要点

この CVE は Pixel Update Bulletin June 2026 の Pixel / Modem / RCE / Critical、参照 ID A-449725859 の非公開修正である。公開情報から、脆弱性は modem の SIP REFER request 処理中に発生する memory corruption で、追加権限やユーザー操作なしに RCE につながる可能性があることを確認した。

根本原因として最も妥当なのは、IMS/SIP スタック内で REFER または Refer-To ヘッダ由来の入力を扱う際のサイズ検証不足、すなわち CWE-120 Buffer Copy without Checking Size of Input 相当の境界検査不足である。ただし、Google の bug ID と patch は非公開で、取得できた May/June の modem firmware 差分もリビルド差分を大量に含むため、個別の修正関数、修正命令、壊れる具体フィールド長までは特定できなかった。したがって、このフォルダは ng 判定とする。

未確定の理由 / 原因候補

ng

理由: 脆弱性の種類、attack surface、到達メッセージは SIP REFER request として説明できるが、ソースコードまたは個別バイナリ patch hunk に基づいて、脆弱性が起きる状況を完全に説明するところまでは到達していない。

どこから特定したか

確認した公開情報: ・既存 cve.md: CVE-2026-0154, A-449725859, Component Pixel, Subcomponent Modem, Type RCE, Severity Critical
・Pixel Update Bulletin June 2026:
- URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- Published: 2026-06-16
- 該当行: CVE-2026-0154 A-449725859 * RCE Critical Modem
- * は Android bug ID が非公開で、修正は Pixel binary drivers に含ま…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https://osv.dev/vulnerability/PUB-A-449725859` / https://nvd.nist.gov/vuln/detail/CVE-2026-0154` / https://www.originhq.com/research/patch-diffing-pipeline`

validated.md を表示
# CVE-2026-0154 検証メモ

## 結論

この CVE は Pixel Update Bulletin June 2026 の `Pixel / Modem / RCE / Critical`、参照 ID `A-449725859` の非公開修正である。公開情報から、脆弱性は modem の SIP `REFER` request 処理中に発生する memory corruption で、追加権限やユーザー操作なしに RCE につながる可能性があることを確認した。

根本原因として最も妥当なのは、IMS/SIP スタック内で `REFER` または `Refer-To` ヘッダ由来の入力を扱う際のサイズ検証不足、すなわち `CWE-120 Buffer Copy without Checking Size of Input` 相当の境界検査不足である。ただし、Google の bug ID と patch は非公開で、取得できた May/June の modem firmware 差分もリビルド差分を大量に含むため、個別の修正関数、修正命令、壊れる具体フィールド長までは特定できなかった。したがって、このフォルダは `ng` 判定とする。

## 確認した公開情報

- 既存 `cve.md`: `CVE-2026-0154`, `A-449725859`, Component `Pixel`, Subcomponent `Modem`, Type `RCE`, Severity `Critical`
- Pixel Update Bulletin June 2026:
  - URL: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
  - Published: `2026-06-16`
  - 該当行: `CVE-2026-0154 A-449725859 * RCE Critical Modem`
  - `*` は Android bug ID が非公開で、修正は Pixel binary drivers に含まれることを示す。
- OSV:
  - URL: `https://osv.dev/vulnerability/PUB-A-449725859`
  - Alias: `A-449725859`, `CVE-2026-0154`
  - Details: modem で SIP REFER request 中に memory corruption により crash を誘発でき、RCE につながり得る。
  - Fixed: `Pixel-family specific:2026-06-05`
  - 保存: `artifacts/public/osv-PUB-A-449725859.json`
- NVD:
  - URL: `https://nvd.nist.gov/vuln/detail/CVE-2026-0154`
  - Description: OSV と同じ SIP REFER request / memory corruption / no user interaction の説明。
  - CWE: `CWE-120`
  - CISA-ADP CVSS: `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H`
  - 保存: `artifacts/public/nvd-CVE-2026-0154.json`

## 使用したバイナリ

既存の Pixel shiba radio/modem artifacts を再利用した。ユーザー指定方針に合わせ、主な modem 本体は `../binaries` の既存抽出物を使った。

- May modem.bin: `../binaries/pixel_shiba_modem_0135/modem_shiba_may_g5300i-251202-260127-B-14784800.bin`
  - SHA256: `072eb34d8140a74f6d2508256ad4361175f388eafd7d5efcab8c8ea2b0891308`
- June modem.bin: `../binaries/pixel_shiba_modem_0135/modem_shiba_june_g5300i-260317-260505-B-15346003.bin`
  - SHA256: `95dd7a59690f17ecfc43a8ccee381850c37787169b1442c1841074b9828b018a`
- May radio image: `./binaries/pixel_shiba_wc_radio/radio-shiba-g5300i-251202-260127-b-14784800.img`
- June radio image: `./binaries/pixel_shiba_wc_radio/radio-shiba-g5300i-260317-260505-b-15346003.img`
- ハッシュ一覧: `artifacts/modem/input_sha256.txt`

## 解析内容

`https://www.originhq.com/research/patch-diffing-pipeline` の流れに合わせ、advisory 確認、対象成果物の収集、前後バージョン差分、文字列・構造情報の抽出、候補 attack surface の絞り込み、根拠と限界の記録を行った。参照ページ自体も `artifacts/public/originhq-patch-diffing-pipeline.html` に保存した。

生成した主な付帯ファイル:

- `artifacts/public/pixel-bulletin-2026-06-01.html`
- `artifacts/public/osv-PUB-A-449725859.pretty.json`
- `artifacts/public/nvd-CVE-2026-0154.pretty.json`
- `artifacts/modem/may_strings_offsets.txt`
- `artifacts/modem/june_strings_offsets.txt`
- `artifacts/analysis/toc_sections.tsv`
- `artifacts/analysis/binary_diff_by_section.tsv`
- `artifacts/analysis/binary_diff_runs_summary.tsv`
- `artifacts/analysis/may_refer_key_strings.txt`
- `artifacts/analysis/june_refer_key_strings.txt`
- `artifacts/analysis/strings_added_precise_sip_refer.txt`
- `artifacts/analysis/strings_removed_precise_sip_refer.txt`
- `artifacts/analysis/refer_string_pointer_xrefs.txt`
- `artifacts/analysis/capstone_refer_xref_disasm.txt`
- `artifacts/analysis/*window*.xxd`

## バイナリ差分から分かったこと

- `modem.bin` は `TOC` 形式で、主な section は `BOOT`, `MAIN`, `VSS`, `APM`, `INFO`。
- 実行コードとログ文字列の大半は `MAIN` にある。
- May/June の `MAIN` section は同サイズだが SHA256 が異なる。
- 差分集計では `MAIN` に約 3,530,108 個の差分ラン、約 79,886,565 bytes の差分があり、単一 CVE の patch hunk として直接読める差分ではなかった。
- `VSS`, `APM`, `BOOT`, `INFO` も SHA256 は変わるが、差分 bytes は非常に少なく、SIP REFER の説明と直接結び付く材料は得られなかった。

## SIP REFER 周辺の手掛かり

June modem の文字列には、SIP/IMS stack の `REFER` 処理に関係する以下の文字列が存在する。

- `IMSSH <== [REFER_SIP_METHOD_REQ]`
- `IMSSH ==> [REFER_SIP_METHOD_REQ]`
- `IMSCH <== [REFER_SIP_METHOD_REQ]`
- `IMSCOMM_SIP_HDR_REFER_TO`
- `INT_CC_CCM_REFER_REQ_RCVD`
- `[CONF_CALL][CC>>CCM]INT_CC_CCM_REFER_REQ_RCVD: CallId[%d]`
- `Alert> Invalid Refer To Header = %d`
- `Refer-To Mandatory header Missing`
- `Call ID, To Tag are Matching, REFER Received for existing Session`
- `[CONF_CALL]ReferRsp or Notify to Refer received, SipStatusCode[%d],CallId[%d]`

これらは `IMSSH`, `IMSCH`, `IMSCOMM`, `CCM`, conference call handling など、VoLTE/IMS の SIP call-control 周辺に集中している。NVD/OSV の「SIP REFER request 中の memory corruption」という説明と整合する。

ただし、これらの文字列自体は May 側にも存在する。June で新たに `REFER` parser が追加されたわけではなく、既存の REFER 処理に対する閉源修正と見るのが自然である。文字列の前置ログタグや配置は変わっているが、リビルド・ログテーブル再配置・複数 CVE 修正が混在しており、`A-449725859` の個別修正箇所を一意に切り出す根拠にはならない。

## 推定される脆弱性像

攻撃者が IMS/VoLTE 経路で細工した SIP `REFER` request を modem に処理させる。modem 内の IMS/SIP call-control 実装は `Refer-To` など REFER 固有ヘッダ、dialog/call ID/tag、conference-call 関連状態を解析する。その過程で、外部入力由来の長さまたは文字列を固定長バッファへコピー・構成する処理に十分な境界チェックがなく、メモリ破壊が発生し modem crash、条件次第で modem コンテキストの RCE につながる。

公開情報とバイナリ文字列からはここまでが妥当な説明である。一方で、以下は未特定である。

- 問題の正確な関数名または C/C++ ソース位置
- 悪性 `REFER` request の具体的なヘッダ、長さ、文字種、状態遷移条件
- overflow 先のバッファ、破壊される構造体、制御フロー到達条件
- May/June 差分中で `A-449725859` だけに対応する命令列
- RCE 化に必要な heap/layout 条件

## 面白い点・注意点

- Pixel Bulletin の `*` 付き bug ID なので、AOSP commit ではなく Pixel firmware/binary driver 側の修正である。
- OSV の advisory reference は Android Security Bulletin 形式の URL を指しているが、この CVE 自体は Pixel Update Bulletin 側に掲載されている。
- NVD の affected には `Android kernel` と出ているが、component/subcomponent と説明文はいずれも modem/SIP REFER を示しており、解析対象は Pixel modem firmware と見るべきである。
- 2026-06 の Pixel / Modem には複数の Critical RCE が同時に掲載されているため、June modem.bin 全体差分からこの CVE だけを抜き出すには、公開 bug tracker、シンボル、vendor patch note、またはより細かい中間ビルドが必要になる。
- `REFER` は SIP の call transfer / conference 関連で使われ、文字列上も `CONF_CALL`, `CCM`, `ReferRsp or Notify` などと隣接している。単なる radio-layer RRC/NAS ではなく IMS call-control attack surface の問題である点が特徴的だった。
- `objdump` はこの環境では raw binary 指定に対応しておらず失敗した。Capstone で一部 literal 参照周辺を試したが、見つかった参照はログ/テーブルらしく、実関数の逆アセンブル根拠にはならなかった。

## 判定

`ng`

理由: 脆弱性の種類、attack surface、到達メッセージは `SIP REFER request` として説明できるが、ソースコードまたは個別バイナリ patch hunk に基づいて、脆弱性が起きる状況を完全に説明するところまでは到達していない。
076 OK

CVE-2026-0160

076-ok-gims-t140-red-payload-oob-write-rce

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentgIMS
TypeRCE
SeverityCritical
ReferencesA-476108161
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0160 is listed in the Pixel Update Bulletin as a Critical severity RCE issue in Pixel / gIMS.

特定した具体的な脆弱性

特定できた。CVE-2026-0160 は Pixel/gIMS として公開されているが、実体は IMS media の RTT/T.140 受信経路にある TextRtpPayloadDecoderNode::DecodeT140 の out-of-bounds write である。

根本原因は、RFC 4103 の text/red RTP payload に含まれる redundant block length と primary payload length を、固定長バッファ mPayload[MAX_RTT_LEN] へコピーする前に MAX_RTT_LEN 以下へ制限していないこと。MAX_RTT_LEN は RTT_MAX_CHAR_PER_SEC * RTT_MAX_UNICODE_UTF8 = 30 * 4 = 120 バイトだが、RED header の block length は 10 bit で最大 1023 バイトを表せる。細工した RTP packet で redundantLength > 120、または RED header 後の primary data が 120 バイト超になると、mBitReader.ReadByteBuffer(mPayload, ... * 8) が mPayload の末尾を越えて書き込む。

原因

記載なし。

どこから特定したか

参照情報: ・Pixel bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- Pixel 表の該当行: CVE-2026-0160 A-476108161 * RCE Critical gIMS
・OSV: https://osv.dev/vulnerability/PUB-A-476108161
- 保存: analysis/PUB-A-476108161.json
- fixed: Pixel-family specific:2026-06-05
・NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-0160
- 説明文で TextRtpPayl…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https://osv.dev/vulnerability/PUB-A-476108161` / https://nvd.nist.gov/vuln/detail/CVE-2026-0160`

validated.md を表示
# CVE-2026-0160 検証メモ

## 結論

特定できた。CVE-2026-0160 は Pixel/gIMS として公開されているが、実体は IMS media の RTT/T.140 受信経路にある `TextRtpPayloadDecoderNode::DecodeT140` の out-of-bounds write である。

根本原因は、RFC 4103 の `text/red` RTP payload に含まれる redundant block length と primary payload length を、固定長バッファ `mPayload[MAX_RTT_LEN]` へコピーする前に `MAX_RTT_LEN` 以下へ制限していないこと。`MAX_RTT_LEN` は `RTT_MAX_CHAR_PER_SEC * RTT_MAX_UNICODE_UTF8 = 30 * 4 = 120` バイトだが、RED header の block length は 10 bit で最大 1023 バイトを表せる。細工した RTP packet で `redundantLength > 120`、または RED header 後の primary data が 120 バイト超になると、`mBitReader.ReadByteBuffer(mPayload, ... * 8)` が `mPayload` の末尾を越えて書き込む。

## 既存 cve.md から確認した情報

- CVE: `CVE-2026-0160`
- Bulletin: Pixel Update Bulletin
- Bulletin URL: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- Published/updated: 2026-06-16
- Security patch level: 2026-06-05 or later
- Component/Subcomponent: Pixel / gIMS
- Type/Severity: RCE / Critical
- Reference: `A-476108161`

## 参照情報

- Pixel bulletin: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
  - Pixel 表の該当行: `CVE-2026-0160 A-476108161 * RCE Critical gIMS`
- OSV: `https://osv.dev/vulnerability/PUB-A-476108161`
  - 保存: `analysis/PUB-A-476108161.json`
  - `fixed`: `Pixel-family specific:2026-06-05`
- NVD: `https://nvd.nist.gov/vuln/detail/CVE-2026-0160`
  - 説明文で `TextRtpPayloadDecoderNode::DecodeT140` / `TextRtpPayloadDecoderNode.cpp` / missing bounds check / OOB write が明記されている。
- AOSP source clone:
  - `../binaries/platform_packages_modules_ImsMedia.git`
  - HEAD: `6da37b8ef8bde01956e630bb42a31a40fc1ddba3`
  - 該当ソース保存: `analysis/TextRtpPayloadDecoderNode.cpp`, `analysis/TextRtpPayloadDecoderNode.h`, `analysis/ImsMediaBitReader.cpp`
- ローカルバイナリ:
  - `074-CVE-2026-0149-Pixel-libpixelimsmedia-RCE-Critical/blobs/libpixelimsmedia_lineage-23.1.so`
  - `074-CVE-2026-0149-Pixel-libpixelimsmedia-RCE-Critical/blobs/libpixelimsmedia_lineage-23.2.so`
  - 逆アセンブル保存: `analysis/DecodeT140_lineage-23.1.objdump.txt`, `analysis/DecodeT140_lineage-23.2.objdump.txt`

## ソースコード上の問題点

`TextRtpPayloadDecoderNode.h`:

```cpp
uint8_t mPayload[MAX_RTT_LEN];
ImsMediaBitReader mBitReader;
```

`ImsMediaDefine.h`:

```cpp
#define RTT_MAX_CHAR_PER_SEC (30)
#define RTT_MAX_UNICODE_UTF8 (4)
#define MAX_RTT_LEN (RTT_MAX_CHAR_PER_SEC * RTT_MAX_UNICODE_UTF8)
```

つまり `mPayload` は 120 バイト。

`TextRtpPayloadDecoderNode.cpp` の `DecodeT140` は RED header から 10bit の `length` を読み、`listLength` へ保存する。

```cpp
uint32_t length = mBitReader.Read(10);
listLength.push_back(length);
```

その後、保存した長さを上限確認なしで `mPayload` にコピーする。

```cpp
uint32_t redundantLength = listLength.front();
mBitReader.ReadByteBuffer(mPayload, redundantLength * 8);
SendDataToRearNode(..., mPayload, redundantLength, ...);
```

primary data も同じく `size - readByte` を上限確認なしで `mPayload` にコピーする。

```cpp
if (size - readByte > 0) {
    mBitReader.ReadByteBuffer(mPayload, (size - readByte) * 8);
}
SendDataToRearNode(..., mPayload, (size - readByte), ...);
```

`ImsMediaBitReader::ReadByteBuffer` は宛先サイズを引数に取らず、`memcpy(pbDst, mBuffer + mBytePos, nByteSize)` または 1 バイトずつ `pbDst[dst_pos] = Read(8)` するだけで、宛先 `mPayload` の長さを知らない。したがって bounds check は呼び出し側に必要だが、`DecodeT140` に存在しない。

## バイナリ確認

ローカルの `libpixelimsmedia_lineage-23.1.so` / `23.2.so` に以下のシンボルが存在した。

```text
TextRtpPayloadDecoderNode::DecodeT140(unsigned char*, unsigned int, ImsMediaSubType, unsigned int, bool, unsigned int)
```

逆アセンブルでは、RED block length を保持した値を `lsl w2, w27, #3` で bit length にし、`x1 = x22 + 0xe8` の固定メンバ領域へ `ImsMediaBitReader::ReadByteBuffer` を呼んでいる。`w27` と 120 バイト相当を比較する命令は周辺にない。

該当箇所の対応:

- `x22`: `this`
- `x22 + 0xe8`: `mPayload`
- `x22 + 0x160`: `mBitReader`
- `w27`: `redundantLength`
- `lsl w2, w27, #3`: `redundantLength * 8`
- call: `ImsMediaBitReader::ReadByteBuffer`

`23.1` と `23.2` の `DecodeT140` は、アドレスや PLT 参照、文字列位置の違いを除き、脆弱な長さ処理は同じだった。差分は `analysis/DecodeT140_23.1_vs_23.2.normalized.diff` と `analysis/DecodeT140_23.1_vs_23.2.opcodes.diff` に保存した。

## 攻撃条件の復元

1. 端末が IMS RTT/T.140 の受信経路を有効にし、`MEDIASUBTYPE_BITSTREAM_T140_RED` を `DecodeT140` に渡す。
2. 攻撃者が RTP `text/red` payload を送る。
3. RED header の redundant flag を 1 にして redundant block を作り、10bit `length` を 121 以上にする。最大 1023 まで指定できる。
4. 関数は `mPayload[120]` へ `redundantLength` バイト分をコピーしようとするため、隣接メンバまたはオブジェクト領域を破壊する。
5. 同様に、RED header 後の primary data が 120 バイトを超えても `size - readByte` による OOB write が起こる。

この経路は受信 RTP packet の処理なので network-triggered で、UI 操作は不要。NVD/CISA の CVSS は `AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H` で、IMS セッション参加者/低権限相当のネットワーク到達性を前提にしていると解釈できる。

## 面白い点・調査メモ

- Bulletin は subcomponent を `gIMS` としているが、CVE 詳細の関数名とローカルバイナリから見る限り、処理実体は `libpixelimsmedia` の text RTP payload decoder。
- AOSP 履歴の `4ecaf65` (`Fix to handle empty redundant payload in RTT decoder`, Bug `274881848`) の古い差分には、削除されたコメントとして `// here should compare mPayload size red length` が残っていた。つまり開発履歴上も `nRedLength` と `mPayload` サイズ比較が必要だと認識されていた形跡があるが、その変更では bounds check は追加されていない。
- `DecodeT140` は `uint32_t readByte` に RED header 分と redundant payload 分を足し、最後に `size - readByte` を計算する。`readByte > size` になる malformed packet では unsigned underflow により巨大な primary length になり得るため、primary 側も長さ整合性チェックが必要。
- 手元の `../binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip` と `../binaries/pixel_shiba_wc_radio/shiba-cp1a.260505.005.a1-factory-09dcebf9.zip` は zip としては不完全/中央ディレクトリ欠落だった。ただし今回の特定には、OSV/NVD の関数名、AOSP ソース、既存 `libpixelimsmedia` バイナリで十分だった。

## 修正方針

安全な修正は以下を満たす必要がある。

- RED header 読み取り中に、header 数と `readByte` が入力 `size` を超えないことを確認する。
- `redundantLength <= MAX_RTT_LEN` を確認してから `ReadByteBuffer(mPayload, redundantLength * 8)` する。
- `readByte + redundantLength <= size` を確認する。
- primary data は `size >= readByte` を確認した上で、`primaryLength = size - readByte` が `MAX_RTT_LEN` 以下であることを確認する。
- 不正な length の場合は packet を破棄し、`SendDataToRearNode` へ過大 length を渡さない。

## 判定

`ok`: ソースコードとバイナリ逆アセンブルから、固定 120 バイトバッファへの未検証コピーという根本原因と、脆弱性が起きる RTP/T.140 RED 条件を説明できる。
077 NG

CVE-2026-0164

077-ng-pixel-modem-oob-write-unattributed

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentModem
TypeRCE
SeverityCritical
ReferencesA-449159763
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0164 is listed in the Pixel Update Bulletin as a Critical severity RCE issue in Pixel / Modem.

NG 判定の要点

判定: ng

公開情報から、CVE-2026-0164 は Pixel / Modem の missing bounds check による out-of-bounds write で、Remote Code Execution に至り得る Critical 脆弱性であることを確認した。CVE v5 の CISA ADP 付加情報では CWE-120 と CWE-787 が付与されており、OSV では Pixel-family specific:2026-06-05 で修正済みとされている。

ただし、今回の解析では CVE-2026-0164 / A-449159763 に対応する具体的な関数、プロトコルメッセージ、入力フィールド、追加された境界チェックを一意に特定できなかった。Pixel Bulletin の A-449159763 は * 付きの非公開 Android bug ID で、公開 AOSP commit やソース diff はない。手元で比較できる Pixel 8 shiba の modem firmware 差分は MAIN セクション全体に広がっており、同じ June 2026 Bulletin に複数の Modem RCE が同時掲載されているため、この差分だけから CVE-2026-0164 固有の root cause を切り出す根拠が足りない。

このフォルダの ok 基準である「ソースコード、または脆弱性が起きる状況を完璧に説明できる」には達していないため、ng とする。

未確定の理由 / 原因候補

・A-449159763 が非公開で、公開 issue / patch / AOSP commit がない。
・対象は closed-source Pixel/Samsung modem firmware で、ソースコード diff が取れない。
・比較した modem.bin の MAIN セクション差分が約 79.9 MiB と大きく、単一修正の局所差分ではない。
・同じ Bulletin に複数の Modem RCE が同時掲載されており、CVE-2026-0164 固有の修正を他 CVE と切り分けられない。
・文字列差分には OOB write と整合する候補が多数あるが、どれも A-449159763 との対応付け証拠にならない。
・Ghidra/BinDiff/Diaphora 等で関数単位 diff まで行うためのシンボル、既知 loader、対応するクラッシュログ、PoC、vendor note がない。

どこから特定したか

確認した公開情報: ・CVE: CVE-2026-0164
・Android bug reference: A-449159763
・Component/Subcomponent: Pixel / Modem
・Type/Severity: RCE / Critical
・Bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
・Bulletin 掲載行: CVE-2026-0164 A-449159763 * RCE Critical Modem
・OSV: https://storage.googleapis.com/android-osv/PUB-A-449159763.json
・CVE v5: https://c…

保存した付帯ファイル: ・artifacts/analysis/PUB-A-449159763.json
・artifacts/analysis/PUB-A-449159763.pretty.json
・artifacts/analysis/CVE-2026-0164.cve5.json
・artifacts/analysis/CVE-2026-0164.cve5.pretty.json
・artifacts/analysis/pixel-2026-06-01-bulletin.html
・artifacts/analysis/binary_sha256.txt
・artifacts/analysis/old_modem_toc.json
・artifacts/analysis/new_modem_toc.json
・artifac…

URL: https://…

validated.md を表示
# CVE-2026-0164 Pixel Modem RCE 解析結果

## 結論

判定: **ng**

公開情報から、CVE-2026-0164 は Pixel / Modem の **missing bounds check による out-of-bounds write** で、Remote Code Execution に至り得る Critical 脆弱性であることを確認した。CVE v5 の CISA ADP 付加情報では `CWE-120` と `CWE-787` が付与されており、OSV では `Pixel-family specific:2026-06-05` で修正済みとされている。

ただし、今回の解析では **CVE-2026-0164 / A-449159763 に対応する具体的な関数、プロトコルメッセージ、入力フィールド、追加された境界チェックを一意に特定できなかった**。Pixel Bulletin の `A-449159763` は `*` 付きの非公開 Android bug ID で、公開 AOSP commit やソース diff はない。手元で比較できる Pixel 8 `shiba` の modem firmware 差分は `MAIN` セクション全体に広がっており、同じ June 2026 Bulletin に複数の Modem RCE が同時掲載されているため、この差分だけから CVE-2026-0164 固有の root cause を切り出す根拠が足りない。

このフォルダの ok 基準である「ソースコード、または脆弱性が起きる状況を完璧に説明できる」には達していないため、`ng` とする。

## 確認した公開情報

- CVE: `CVE-2026-0164`
- Android bug reference: `A-449159763`
- Component/Subcomponent: `Pixel / Modem`
- Type/Severity: `RCE / Critical`
- Bulletin: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- Bulletin 掲載行: `CVE-2026-0164 A-449159763 * RCE Critical Modem`
- OSV: `https://storage.googleapis.com/android-osv/PUB-A-449159763.json`
- CVE v5: `https://cveawg.mitre.org/api/cve/CVE-2026-0164`
- NVD: `https://nvd.nist.gov/vuln/detail/CVE-2026-0164`

公開説明は以下の内容。

> In Modem, there is a possible out of bounds write due to a missing bounds check. This could lead to remote code execution with no additional execution privileges needed. User interaction is not needed for exploitation.

OSV の要点:

- `published`: `2026-06-01T00:00:00Z`
- `modified`: `2026-06-22T15:18:41.032815418Z`
- `aliases`: `CVE-2026-0164`, `A-449159763`
- `fixed`: `Pixel-family specific:2026-06-05`
- `severity`: `Critical`
- `types`: `RCE`

CVE v5 / CISA ADP の要点:

- `CWE-120`: Buffer Copy without Checking Size of Input
- `CWE-787`: Out-of-bounds Write
- CVSS v3.1: `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H`
- base score: `8.8`

## 使用したバイナリ

既存の Pixel 8 `shiba` radio / modem artifacts を使用した。`../binaries` 側に抽出済み modem 本体があったため再利用した。

- 修正前候補 modem:
  - `../binaries/pixel_shiba_modem_0135/modem_shiba_may_g5300i-251202-260127-B-14784800.bin`
  - SHA-256: `072eb34d8140a74f6d2508256ad4361175f388eafd7d5efcab8c8ea2b0891308`
- 修正後候補 modem:
  - `../binaries/pixel_shiba_modem_0135/modem_shiba_june_g5300i-260317-260505-B-15346003.bin`
  - SHA-256: `95dd7a59690f17ecfc43a8ccee381850c37787169b1442c1841074b9828b018a`
- 元 radio image:
  - `binaries/pixel_shiba_wc_radio/radio-shiba-g5300i-251202-260127-b-14784800.img`
  - SHA-256: `db5a0c8161d9cc674ec348c07460495f36ef9209740c03f44c14386501c2f80d`
  - `FBPK` container -> tar -> modem payload
- 更新後 radio image:
  - `binaries/pixel_shiba_wc_radio/radio-shiba-g5300i-260317-260505-b-15346003.img`
  - SHA-256: `5bee584549ee24ce7b5465831c007277fd9c1ab73d618a53e607c8d9ade6fdd5`
  - `FBPK` container -> tar -> modem payload

ハッシュは `artifacts/analysis/binary_sha256.txt` に保存した。

## 実施した解析

参考に指定された OriginHQ の patch diffing pipeline と同じ方向で、advisory の確認、前後 artifact の収集、バイナリ構造の把握、差分生成、CVE 説明に合う候補の絞り込み、限界の明記を行った。

主な作業:

1. 既存 `cve.md` を読み、CVE、参照 ID、component/subcomponent、bulletin URL を確認。
2. Pixel Update Bulletin、OSV、CVE v5、NVD を確認。
3. 既存 `shiba` radio image / modem.bin を利用し、前後版の SHA-256 を記録。
4. `modem.bin` の TOC を解析し、主要セクション単位で差分量とセクション SHA-256 を算出。
5. `strings -a -n 5` で前後 modem の文字列を抽出し、追加/削除文字列を比較。
6. `bound|length|invalid|overflow|decode|copy|write|range|index|size|malloc|pdu|tlv|rrc|nas|sip|ims|rohc` などで、境界チェック・可変長 parser・copy 処理に関係し得るログを抽出。

## バイナリ差分の結果

`modem.bin` は `TOC` を持つコンテナで、主要セクションは `BOOT`, `MAIN`, `VSS`, `APM`, `INFO` として見えた。クリーンな TOC 差分は `artifacts/analysis/modem_toc_diff_clean.tsv` に保存した。

主要結果:

| section | file offset | size | diff bytes |
| --- | ---: | ---: | ---: |
| `TOC` | `0x0` | `0x410` | 139 |
| `BOOT` | `0x410` | `0x16800` | 138 |
| `MAIN` | `0x16c10` | `0x5da0c00` | 79,886,565 |
| `VSS` | `0x5db7810` | `0x47cc0c` | 130 |
| `APM` | `0x623441c` | `0xb498` | 130 |
| `INFO` | `0x623f8b4` | `0xd0` | 14 |

`MAIN` は約 98 MiB のうち約 79.9 MiB が byte 単位で変化しており、64 KiB 粒度でも広範囲に変更が散っている。これは単一関数だけの局所 patch ではなく、firmware の再ビルド、再配置、複数機能更新、複数 CVE 修正が混在した差分と見るべき状態だった。

同じ June 2026 Pixel Bulletin には Modem RCE が少なくとも以下のように複数ある。

- `CVE-2026-0132` / `A-449160232` / Modem RCE
- `CVE-2026-0135` / `A-449725960` / Modem RCE
- `CVE-2026-0139` / `A-449726527` / Modem RCE
- `CVE-2026-0154` / `A-449725859` / Modem RCE
- `CVE-2026-0164` / `A-449159763` / Modem RCE

そのため、`MAIN` セクション差分から `A-449159763` だけを機械的に対応付けることはできなかった。

## 文字列差分で見えた候補領域

文字列差分の件数:

- old modem strings: 734,100 行
- new modem strings: 732,935 行
- added strings: 67,916 行
- removed strings: 68,060 行
- suspicious added strings: 10,044 行
- suspicious removed strings: 10,013 行

保存ファイル:

- `artifacts/analysis/old_modem_strings.txt`
- `artifacts/analysis/new_modem_strings.txt`
- `artifacts/analysis/added_modem_strings.txt`
- `artifacts/analysis/removed_modem_strings.txt`
- `artifacts/analysis/added_modem_strings_suspicious.txt`
- `artifacts/analysis/removed_modem_strings_suspicious.txt`
- `artifacts/analysis/modem_strings_counts.txt`

CVE 説明に合い得る追加文字列として、例えば以下が見える。

- `Error - Invalid len for server certificate:%d!!`
- `Error - pBuff decode error!!`
- `m_PacketArrCount = %x`
- `[SROHC_TCP_C] TcpV4IRPacket cPktTotalLength = %d`
- `[SROHC_TCP_C] [WARN] OrginalHeaderLen:%d ComprHeaderLen:%d`
- `uhal_HmcpDlCctrchUpdateStaticInfo Array out of bound tfc_num %d`
- `uhal_HmcpDlCctrchUpdateStaticInfo Array out of bound trch_num %d`
- `uhal_HmcpDlCctrchCalcStaticPars:Array index out of bound hmcpCctrchPtr->static_pars.trch_num=%d`
- `DLA: nRl_total (%d) is over range`
- `Received msg: Invalid message %d in Active state`
- `MAC Header Length`
- `MAC Invalid PDU Count`

これらは、可変長入力、PDU/header length、decode、copy、array index、out-of-bound といった語を含み、公開情報の「missing bounds check による OOB write」と整合し得る。ただし、同じ差分には ROHC、IMS/SIP/TLS、LTE/NR/UMTS RRC/NAS、MAC/RLC/PDCP、LCS/PRS など多数の領域が混在しており、どのログ群が CVE-2026-0164 に対応するかは決められなかった。

## 脆弱性像と根本原因

確実に言える根本原因は以下。

- Modem firmware 内の入力処理に境界チェック不足があった。
- 外部入力由来の長さ、個数、index、header length、TLV/IE/PDU field などを使って buffer copy または構造体/配列への書き込みを行う際、出力先の容量を超える可能性があった。
- その結果、out-of-bounds write が発生し、modem 上での RCE につながり得る。
- ユーザー操作は不要で、追加実行権限も不要とされている。

推測としては、baseband が処理する network supplied data、IMS/SIP/TLS、ROHC compressed packet、RRC/NAS/MAC PDU、LCS/PRS などの可変長 parser/copy 処理のいずれかで、length/count/index の検証が不足していた可能性がある。CVE v5 の `CWE-120` は「入力サイズを確認しない buffer copy」を示しており、`CWE-787` は OOB write を示すため、単なる OOB index 参照よりも copy/serialize/decode 系の欠陥を示唆する。

ただし、これは公開説明と文字列差分からの分類であり、`A-449159763` に固有の脆弱関数や入力条件を特定したものではない。

## ok にしなかった理由

- `A-449159763` が非公開で、公開 issue / patch / AOSP commit がない。
- 対象は closed-source Pixel/Samsung modem firmware で、ソースコード diff が取れない。
- 比較した `modem.bin` の `MAIN` セクション差分が約 79.9 MiB と大きく、単一修正の局所差分ではない。
- 同じ Bulletin に複数の Modem RCE が同時掲載されており、CVE-2026-0164 固有の修正を他 CVE と切り分けられない。
- 文字列差分には OOB write と整合する候補が多数あるが、どれも `A-449159763` との対応付け証拠にならない。
- Ghidra/BinDiff/Diaphora 等で関数単位 diff まで行うためのシンボル、既知 loader、対応するクラッシュログ、PoC、vendor note がない。

## 面白い点・調査メモ

- Pixel Bulletin の `*` は、この Android bug ID が公開されていないことを示す。FAQ では、この種の問題の修正は通常 Pixel device の最新 binary driver / firmware に含まれると説明されている。
- OSV の advisory reference は `https://source.android.com/security/bulletin/2026-06-01` だが、実際に該当行を確認できる Pixel Bulletin は `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`。
- CVE v5 の CNA `affected` は `Android kernel` と書かれているが、Pixel Bulletin 上の分類は `Pixel / Modem` で、実際の解析対象は radio/modem firmware になる。
- CVE v5 / CISA ADP は `CWE-120` と `CWE-787` を付けており、単なる read 側バグではなく write/copy 側の典型的なメモリ破壊として扱っている。
- `strings` だけでも Samsung/Exynos modem 由来と思われる内部ログが大量に見えるが、ログ文字列は firmware 全体のリビルド差分の影響を強く受けるため、CVE attribution には弱い。
- `MAIN` 以外の `BOOT`, `VSS`, `APM`, `INFO` は差分が小さい一方、`MAIN` はほぼ全域が変わる。脆弱性修正は `MAIN` 内にある可能性が高いが、再配置・最適化差分でノイズが大きい。

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

- `artifacts/analysis/PUB-A-449159763.json`
- `artifacts/analysis/PUB-A-449159763.pretty.json`
- `artifacts/analysis/CVE-2026-0164.cve5.json`
- `artifacts/analysis/CVE-2026-0164.cve5.pretty.json`
- `artifacts/analysis/pixel-2026-06-01-bulletin.html`
- `artifacts/analysis/binary_sha256.txt`
- `artifacts/analysis/old_modem_toc.json`
- `artifacts/analysis/new_modem_toc.json`
- `artifacts/analysis/modem_toc_diff.tsv`
- `artifacts/analysis/modem_toc_diff_clean.tsv`
- `artifacts/analysis/main_changed_ranges_64k.txt`
- `artifacts/analysis/old_modem_strings.txt`
- `artifacts/analysis/new_modem_strings.txt`
- `artifacts/analysis/added_modem_strings.txt`
- `artifacts/analysis/removed_modem_strings.txt`
- `artifacts/analysis/added_modem_strings_suspicious.txt`
- `artifacts/analysis/removed_modem_strings_suspicious.txt`
- `artifacts/analysis/modem_strings_counts.txt`
078 OK

CVE-2026-0153

078-ok-tachyon-fmq-beginwrite-bounds-check

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentEdgeTPU
TypeEoP
SeverityCritical
ReferencesA-494629585
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0153 is listed in the Pixel Update Bulletin as a Critical severity EoP issue in Pixel / EdgeTPU.

特定した具体的な脆弱性

判定: ok

CVE-2026-0153 は Pixel EdgeTPU の Tachyon compute service にある FMQ 書き込み処理の境界チェック不備による out-of-bounds write。公式 OSV では Write of msg_to_host_buffer.cc の incorrect bounds check と説明されており、May 2026 版から June 2026 版への Pixel vendor binary diff では com.google.edgetpu.tachyon-service に FMQ 書き込み用の共通ヘルパ android::edgetpu::tachyon::BeginWrite<ResponseMessage> が新規追加され、旧実装の直接書き込み callback がこのヘルパ経由に置換されていることを確認した。

原因

根本原因は、FMQ response 書き込み処理が「実際の要求サイズに対して host buffer/FMQ の空き容量と領域境界を検証する」抽象を持たず、callback ごとに queue pointer と固定サイズを直接扱っていたこと。特に wrap-around する ring buffer では、論理的な空き容量、連続領域長、2分割領域長、write pointer alignment、pending transaction の整合性を同時に満たす必要がある。旧実装の incorrect bounds check により、このどれかが崩れた入力で host buffer 外書き込みが可能だったと判断できる。

どこから特定したか

解析対象バイナリ: 既存の別調査で保存済みだった shiba vendor image を再利用した。

パッチ差分の要点: artifacts/june.gnu_debugdata.elf から mini-symbols を復元できた。June 版に以下の関数が見える。

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01 / https://storage.googleapis.com/android-osv/PUB-A-494629585.json / https://dl.google.com/dl/android/aosp/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip` / https://dl.google.com/dl/android/aosp/shiba-ota-cp2a.260605.012-b315a1a2.zip`

validated.md を表示
# CVE-2026-0153 Pixel EdgeTPU EoP 解析結果

## 判定

判定: ok

CVE-2026-0153 は Pixel EdgeTPU の Tachyon compute service にある FMQ 書き込み処理の境界チェック不備による out-of-bounds write。公式 OSV では `Write` of `msg_to_host_buffer.cc` の incorrect bounds check と説明されており、May 2026 版から June 2026 版への Pixel vendor binary diff では `com.google.edgetpu.tachyon-service` に FMQ 書き込み用の共通ヘルパ `android::edgetpu::tachyon::BeginWrite<ResponseMessage>` が新規追加され、旧実装の直接書き込み callback がこのヘルパ経由に置換されていることを確認した。

## Advisory 確認

- CVE: CVE-2026-0153
- Android bug: A-494629585
- Component/subcomponent: Pixel / EdgeTPU
- Type/severity: EoP / Critical
- Bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- Bulletin 行: Pixel セクションに `CVE-2026-0153 A-494629585 * EoP Critical EdgeTPU`
- `*` の意味: bug は公開されておらず、修正は Pixel binary driver 側に含まれる扱い
- OSV: https://storage.googleapis.com/android-osv/PUB-A-494629585.json
- OSV details: `In Write of msg_to_host_buffer.cc, there is a possible out of bounds write due to an incorrect bounds check. This could lead to local escalation of privilege with no additional execution privileges needed. User interaction is not needed for exploitation.`
- Fixed SPL: Pixel-family specific: 2026-06-05

## 解析対象バイナリ

既存の別調査で保存済みだった `shiba` vendor image を再利用した。

- May: `binaries/pixel_shiba_wc_radio/may_radio/vendor.img`
- June: `binaries/pixel_shiba_wc_radio/june_radio/vendor.img`
- May build URL候補: `https://dl.google.com/dl/android/aosp/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip`
- June build URL候補: `https://dl.google.com/dl/android/aosp/shiba-ota-cp2a.260605.012-b315a1a2.zip`
- Factory metadata sources:
  - `shiba-cp1a.260505.005.a1-factory-09dcebf9.zip`
  - `shiba-cp2a.260605.012-factory-ada9841e.zip`

抽出物:

- `artifacts/extracted/may__bin__hw__com.google.edgetpu.tachyon-service`
- `artifacts/extracted/june__bin__hw__com.google.edgetpu.tachyon-service`
- `artifacts/extracted_sha256.txt`
- `artifacts/extracted_file.txt`

`com.google.edgetpu.tachyon-service` の差分:

- May: 103,408 bytes, BuildID `f41d4569b1fae8f57883db77cf1b296f`
- June: 120,368 bytes, BuildID `b9219b03444f26cfe28c5053e5e6050d`
- `vendor.google.edgetpu_vendor_service@1.0-service` と `/etc/edgetpu/custom_kernel.pbtxt` はサイズ・内容が同一
- `android.hardware.edgetpu.logging@service-edgetpu-logging` も変化しているが、CVE本文の `msg_to_host_buffer.cc`/`Write` とは一致しない

## パッチ差分の要点

`artifacts/june.gnu_debugdata.elf` から mini-symbols を復元できた。June 版に以下の関数が見える。

- `android::edgetpu::tachyon::BeginWrite<IComputeSession::ResponseMessage>(...)` at `0xe6a0`, size `0x4a8`
- `android::edgetpu::tachyon::BeginRead<IComputeSession::CommandMessage>(...)` at `0xe360`, size `0x33c`
- `android::MessageQueueBase<...ResponseMessage...>::availableToWriteBytes()` at `0x12830`, size `0x328`
- `TachyonComputeSession::Create(...)::$_38::__invoke(...)` at `0xf0a0`
- `TachyonComputeSession::Create(...)::$_68::__invoke(...)` at `0xf5e0`

May 版には同名の `BeginWrite`/`BeginRead` 共通ヘルパが存在せず、旧 callback が FMQ の read/write pointer と grantor region を直接処理していた。

重要な strings 差分:

- June で追加: `BeginWrite failed: Requested size is 0.`
- June で追加: `BeginWrite failed: Cannot start a new write operation while there is a pending write operation.`
- June で追加: `BeginWrite failed: Failed to begin write transaction.`
- June で追加: `Queue size is too large. Message size:`
- June で追加: `Requested message queue size too large. Size of elements:`
- June で追加: `Unable to write to the FMQ. FMQ regions are empty.`
- June で追加: `The provided command buffer or size is invalid.`

## 逆アセンブルで確認した修正内容

`artifacts/june_BeginWrite_ResponseMessage_disasm.txt` の `0xe6a0` からの処理:

- 既に pending write がある場合は失敗する。
- requested size が 0 の場合は失敗する。
- FMQ element size を `0x80` として、requested size から必要スロット数を計算する。
- `availableToWriteBytes()` の戻り値を `>> 7` して、必要スロット数より少なければ失敗する。
- FMQ grantor/region が空、または write pointer が `0x7f` 境界に misaligned の場合は失敗する。
- region の残量を見て、1つ目の連続領域と wrap-around 後の2つ目の領域に分け、呼び出し元へ pointer/length を返す。
- 成功時に pending write slot count を保存し、commit 側で使用できる状態にする。

旧 May callback (`artifacts/may_lambda38_write_callback_disasm.txt`) は、session 取得後に queue 内部の pointer 差分、固定サイズ `0x10008`、region 残量を直接見て `memcpy` 相当へ進む。処理は特定の固定レスポンスサイズを前提にしており、要求サイズをパラメータとして汎用的に検査する `BeginWrite` のような入口がない。

June callback (`artifacts/june_lambda38_response_write_callback_disasm.txt`) は、session 取得後に `x0 = [session + 0x80]`, `x1 = session + 0x130`, `x2 = requested_size`, `x3..x6 = output pointers` をセットして `BeginWrite` を呼び出すだけになっている。つまり修正は、外部/ファームウェア側から要求される response buffer 書き込みサイズを共通境界チェックに通す構造変更である。

## 脆弱性の状況

Tachyon compute session は AIDL service `com.google.edgetpu.tachyon.IComputeService/default` として公開され、EdgeTPU core と Android 側プロセスの間で command/response FMQ を共有する。脆弱な May 実装では、EdgeTPU 側から host response buffer へ書く経路で、書き込みサイズ・必要スロット数・wrap-around 後の領域分割・pending transaction 状態の検査が不十分だった。

攻撃条件は OSV の通り local、追加 execution privileges 不要、user interaction 不要。攻撃者が Tachyon/EdgeTPU compute session に到達し、response FMQ 書き込みサイズまたは関連 pointer 状態を不正に誘導できると、host 側 buffer の範囲外に書き込める。サービスは vendor/hal 側の高権限コンテキストで動くため、memory corruption が local EoP に繋がる。

## 根本原因

根本原因は、FMQ response 書き込み処理が「実際の要求サイズに対して host buffer/FMQ の空き容量と領域境界を検証する」抽象を持たず、callback ごとに queue pointer と固定サイズを直接扱っていたこと。特に wrap-around する ring buffer では、論理的な空き容量、連続領域長、2分割領域長、write pointer alignment、pending transaction の整合性を同時に満たす必要がある。旧実装の incorrect bounds check により、このどれかが崩れた入力で host buffer 外書き込みが可能だったと判断できる。

## 面白い点・調査メモ

- CVE 本文の `msg_to_host_buffer.cc` というファイル名はバイナリ内 strings には出ないが、June 版で追加された `BeginWrite` と FMQ helper のログ文字列が `Write`/host buffer/FMQ の修正と一致する。
- Patch は firmware blob ではなく `vendor/bin/hw/com.google.edgetpu.tachyon-service` に入っている。CVE-2026-0150 は EdgeTPU firmware の ExecuteGraph と説明されているため、同じ EdgeTPU でも 0153 は host-side Tachyon service、0150 は device firmware 側と切り分けられる。
- `.gnu_debugdata` が残っていたため、stripped ELF でも関数名とサイズを復元できた。これがなければ `strings` とサイズ差だけでかなり曖昧になっていた。
- `dl.google.com` の OTA 再ダウンロードは数 KB/s まで低下したため中断した。既存の `vendor.img` 抽出物を利用して解析を継続した。

## 付帯ファイル

- `artifacts/PUB-A-494629585.json`: OSV JSON
- `artifacts/edgetpu_vendor_manifest_diff.tsv`: May/June の EdgeTPU 関連 vendor manifest 差分
- `artifacts/extracted/`: 抽出した EdgeTPU 関連バイナリ
- `artifacts/extracted_sha256.txt`: 抽出物 SHA-256
- `artifacts/tachyon_strings_comm_diff.txt`: May/June strings 差分
- `artifacts/tachyon_keyword_strings.txt`: キーワード抽出
- `artifacts/may.gnu_debugdata.elf`, `artifacts/june.gnu_debugdata.elf`: `.gnu_debugdata` 復元 ELF
- `artifacts/may_gnu_debugdata_symbols.txt`, `artifacts/june_gnu_debugdata_symbols.txt`: mini-symbols
- `artifacts/june_BeginWrite_ResponseMessage_disasm.txt`: 修正後 `BeginWrite<ResponseMessage>` 逆アセンブル
- `artifacts/may_lambda38_write_callback_disasm.txt`: 修正前 write callback 逆アセンブル
- `artifacts/june_lambda38_response_write_callback_disasm.txt`: 修正後 callback 逆アセンブル

079 OK

CVE-2026-0161

079-ok-rtcp-report-block-count-integer-overflow-eop

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentReal-time Transport Protocol
TypeEoP
SeverityCritical
ReferencesA-481652507
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0161 is listed in the Pixel Update Bulletin as a Critical severity EoP issue in Pixel / Real-time Transport Protocol.

特定した具体的な脆弱性

特定できた。CVE-2026-0161 は Pixel / Real-time Transport Protocol として公開されたが、実体は IMS media の RTP/RTCP スタックにある RtpSession::numberOfReportBlocks() の unsigned integer wraparound から、RTCP compound packet 生成時に 1350 バイトの送信バッファを越えて書き込む脆弱性である。

根本原因は、MTU から既存 RTCP 要素サイズと SR 固定部分サイズを引く計算で、残りサイズが不足する場合を先に検査していないこと。RtpDt_UInt32 の減算が 32bit で wrap し、実際には report block を 0 個しか入れられないケースで 178956969 などの巨大な report block 数が返る。その値が formSrList() / formRrList() に渡ると、多数の SR/RR packet が組み立てられ、後段の RtcpReportBlock::formReportBlock() が RtpBuffer の容量を確認せず 24 バイト単位で直接書くため out-of-bounds write になる。

原因

記載なし。

どこから特定したか

参照情報: ・Pixel bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- 保存: analysis/pixel_2026-06-01.html
- 該当行: CVE-2026-0161 A-481652507 * EoP Critical Real-time Transport Protocol
・OSV: https://osv.dev/vulnerability/PUB-A-481652507
- 保存: analysis/PUB-A-481652507.json
- details: In numberOfReportBlocks of RtpSession.cpp, there…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https://osv.dev/vulnerability/PUB-A-481652507` / https://nvd.nist.gov/vuln/detail/CVE-2026-0161`

validated.md を表示
# CVE-2026-0161 検証メモ

## 結論

特定できた。CVE-2026-0161 は Pixel / Real-time Transport Protocol として公開されたが、実体は IMS media の RTP/RTCP スタックにある `RtpSession::numberOfReportBlocks()` の unsigned integer wraparound から、RTCP compound packet 生成時に 1350 バイトの送信バッファを越えて書き込む脆弱性である。

根本原因は、MTU から既存 RTCP 要素サイズと SR 固定部分サイズを引く計算で、残りサイズが不足する場合を先に検査していないこと。`RtpDt_UInt32` の減算が 32bit で wrap し、実際には report block を 0 個しか入れられないケースで `178956969` などの巨大な report block 数が返る。その値が `formSrList()` / `formRrList()` に渡ると、多数の SR/RR packet が組み立てられ、後段の `RtcpReportBlock::formReportBlock()` が `RtpBuffer` の容量を確認せず 24 バイト単位で直接書くため out-of-bounds write になる。

## 既存 cve.md から確認した情報

- CVE: `CVE-2026-0161`
- Bulletin: Pixel Update Bulletin
- Bulletin URL: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- Published/updated: 2026-06-16
- Security patch level: 2026-06-05 or later
- Component/Subcomponent: Pixel / Real-time Transport Protocol
- Type/Severity: EoP / Critical
- Reference: `A-481652507`

## 参照情報

- Pixel bulletin: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
  - 保存: `analysis/pixel_2026-06-01.html`
  - 該当行: `CVE-2026-0161 A-481652507 * EoP Critical Real-time Transport Protocol`
- OSV: `https://osv.dev/vulnerability/PUB-A-481652507`
  - 保存: `analysis/PUB-A-481652507.json`
  - details: `In numberOfReportBlocks of RtpSession.cpp, there is a possible out of bounds write due to an integer overflow...`
  - fixed: `Platform:2026-06-05`
- NVD: `https://nvd.nist.gov/vuln/detail/CVE-2026-0161`
  - 説明文で `numberOfReportBlocks` / `RtpSession.cpp` / integer overflow / OOB write / remote EoP が明記されている。
- CVE Record API:
  - 保存: `analysis/CVE-2026-0161_cveawg.json`
  - CISA ADP 側で `CWE-190 Integer Overflow or Wraparound` と `CWE-787 Out-of-bounds Write` が付与されている。
- AOSP source clone:
  - `../binaries/platform_packages_modules_ImsMedia.git`
  - HEAD: `analysis/ImsMedia_HEAD.txt`
  - 該当ソース保存: `analysis/RtpSession.cpp`, `analysis/RtcpRrPacket.cpp`, `analysis/RtcpReportBlock.cpp`, `analysis/RtpBuffer.cpp`
- ローカルバイナリ:
  - `074-CVE-2026-0149-Pixel-libpixelimsmedia-RCE-Critical/blobs/libpixelimsmedia_lineage-23.1.so`
  - `074-CVE-2026-0149-Pixel-libpixelimsmedia-RCE-Critical/blobs/libpixelimsmedia_lineage-23.2.so`
  - シンボル保存: `analysis/symbols_23.1.txt`, `analysis/symbols_23.2.txt`
  - 逆アセンブル保存: `analysis/numberOfReportBlocks_23.1.objdump.txt`, `analysis/numberOfReportBlocks_23.2.objdump.txt`, `analysis/rtpMakeCompoundRtcpPacket_23.1.objdump.txt`, `analysis/rtpMakeCompoundRtcpPacket_23.2.objdump.txt`, `analysis/RtcpReportBlock_formReportBlock_23.1.objdump.txt`, `analysis/RtcpReportBlock_formReportBlock_23.2.objdump.txt`

## ソースコード上の問題点

`RtpSession::rtpMakeCompoundRtcpPacket()` は、RTCP packet の推定サイズと sender 数から compound RTCP packet サイズを計算する。MTU に収まらない場合だけ `numberOfReportBlocks(uiMtuSize, uiEstRtcpSize)` を呼び、MTU に入る report block 数へ減らそうとしている。

問題の `numberOfReportBlocks()`:

```cpp
RtpDt_UInt32 uiReportDefSize = RTCP_FIXED_HDR_LEN + RTP_DEF_SR_SPEC_SIZE;
RtpDt_UInt32 uiRemTotalSize = uiMtuSize - uiEstRtcpSize;
RtpDt_UInt32 uiReportMaxSize = uiReportDefSize + (RTP_MAX_RECEP_REP_CNT * RTP_DEF_REP_BLK_SIZE);

RtpDt_UInt32 uiTotalNumofReport = uiRemTotalSize / uiReportMaxSize;

uiRemTotalSize = uiRemTotalSize - (uiReportMaxSize * uiTotalNumofReport);
uiRemTotalSize = uiRemTotalSize - uiReportDefSize;
RtpDt_UInt32 uiRemRepBlkNum = uiRemTotalSize / RTP_DEF_REP_BLK_SIZE;
uiRemRepBlkNum += uiTotalNumofReport * RTP_MAX_RECEP_REP_CNT;
```

定数は以下の通り。

```text
RTP_DEF_MTU_SIZE      = 1350
RTCP_FIXED_HDR_LEN   = 8
RTP_DEF_SR_SPEC_SIZE = 20
RTP_DEF_REP_BLK_SIZE = 24
RTP_MAX_RECEP_REP_CNT = 31
```

`uiReportDefSize` は 28、31 個の report block を含む SR packet は `28 + 31 * 24 = 772` バイトになる。ところが、`uiMtuSize - uiEstRtcpSize` が 28 未満の場合でも、`uiRemTotalSize = uiRemTotalSize - uiReportDefSize` を実行する。たとえば MTU 1350、既存 RTCP 要素推定値 1323 の場合、残りは 27 バイトしかなく SR 固定部分すら置けない。しかし unsigned 減算により `27 - 28 = 0xffffffff` になり、`0xffffffff / 24 = 178956970` 個の report block が返る。

算術再現は `analysis/numberOfReportBlocks_arithmetic.txt` に保存した。

```text
1350 1322 -> returned_report_blocks 0
1350 1323 -> returned_report_blocks 178956970
1350 1350 -> returned_report_blocks 178956969
1350 1400 -> returned_report_blocks 172466300
```

`uiEstRtcpSize` 自体が MTU 以上の場合、最初の `uiMtuSize - uiEstRtcpSize` でも wrap する。

## OOB write へつながる経路

`numberOfReportBlocks()` の返り値は、SR 経路では `formSrList(uiRemRepBlkNum, objRtcpPkt)`、RR 経路では `formRrList(uiRemRepBlkNum, objRtcpPkt)` に渡される。

`formSrList()` / `formRrList()` は、引数が 31 より大きい間、31 report block 入りの RTCP packet を追加し続ける。つまり `178956970` のような値は本来あり得ない数の RTCP packet 生成要求になる。

最終的な書き込みは `rtpSendRtcpPacket()` から呼ばれる `RtcpPacket::formRtcpPacket()` で行われる。送信バッファは固定で `new RtpDt_UChar[RTP_DEF_MTU_SIZE]`、つまり 1350 バイト。

```cpp
RtpDt_UChar* pcBuff = new RtpDt_UChar[RTP_DEF_MTU_SIZE];
pRtcpBuf->setBufferInfo(RTP_DEF_MTU_SIZE, pcBuff);
eEncRes = objRtcpPkt->formRtcpPacket(pRtcpBuf);
```

`RtcpRrPacket::formRrPacket()` は report block list を全て走査し、各 report block について `formReportBlock()` を呼ぶ。

```cpp
for (auto& pobjRepBlk : m_objReportBlkList) {
    pobjRepBlk->formReportBlock(pobjRtcpPktBuf);
}
```

`RtcpReportBlock::formReportBlock()` は `pobjRtcpPktBuf->getLength()` を現在位置として、`pobjRtcpPktBuf->getBuffer() + uiCurPos` に 32bit word を 6 個、合計 24 バイト書き込む。ここに容量チェックはない。`RtpBuffer` も容量と現在長を分けて保持しておらず、`setLength()` は整数を更新するだけなので、1350 バイトの実バッファ末尾を越えることを止められない。

## バイナリ確認

ローカルの `libpixelimsmedia_lineage-23.1.so` / `23.2.so` には以下のシンボルが存在した。

```text
RtpSession::numberOfReportBlocks(unsigned int, unsigned int)
RtpSession::rtpMakeCompoundRtcpPacket(RtcpPacket*)
RtpSession::formSrList(unsigned int, RtcpPacket*)
RtpSession::formRrList(unsigned int, RtcpPacket*)
RtcpPacket::formRtcpPacket(RtpBuffer*)
RtcpReportBlock::formReportBlock(RtpBuffer*)
```

`23.2` の `numberOfReportBlocks` 逆アセンブルでは、`uiMtuSize - uiEstRtcpSize` と `uiRemTotalSize - 28` がそのまま 32bit 減算されている。

```text
172838: sub w8, w1, w2       ; uiMtuSize - uiEstRtcpSize
...
172858: sub w8, w8, #0x1c    ; uiRemTotalSize - 28
...
172868: add w0, w8, w9, lsl #5
```

この周辺に `uiMtuSize <= uiEstRtcpSize`、または `uiRemTotalSize < 28` を検査して 0 を返す分岐はない。`23.1` と `23.2` の差分はアドレス差が中心で、同じ弱い算術が残っている。差分は `analysis/numberOfReportBlocks_23.1_vs_23.2.diff` に保存した。

`RtcpReportBlock::formReportBlock` の逆アセンブルも、`RtpBuffer::getLength()` で得た位置へ word store を並べるだけで、1350 バイト上限との比較は見えない。

## 攻撃条件の復元

1. 端末で IMS media の RTP/RTCP セッションが成立し、RTCP 送信タイマーまたは BYE/衝突処理などで `rtpMakeCompoundRtcpPacket()` が呼ばれる。
2. 攻撃者は RTP/RTCP セッション参加者として、複数 SSRC/CSRC や SDES/APP/BYE/RTCP-XR などの状態を増やし、`estimateRtcpPktSize()` が MTU に近い値または MTU 以上になる状態を作る。
3. `calculateTotalRtcpSize()` が MTU 超過を検出し、report block 数を絞るため `numberOfReportBlocks()` を呼ぶ。
4. 残りサイズが SR 固定部分 28 バイト未満、または `uiEstRtcpSize > uiMtuSize` になると unsigned integer wraparound が起き、巨大な report block 数が返る。
5. その値に基づいて SR/RR packet list が過大に構築され、`formRtcpPacket()` が 1350 バイト固定の `pcBuff` を越えて RTCP report block を書く。

NVD/OSV が remote EoP、no user interaction としているのは、この処理が IMS/RTP ネットワーク入力から到達する RTCP セッション状態に依存し、ユーザー操作なしで RTCP packet 生成側に到達できるためだと解釈できる。

## 面白い点・調査メモ

- Bulletin の subcomponent は `Real-time Transport Protocol` だが、コード実体は `packages/modules/ImsMedia` の `libimsmedia` / `libpixelimsmedia` RTP/RTCP 実装。
- `RtpBuffer::setBufferInfo(RTP_DEF_MTU_SIZE, pcBuff)` は初期長を 1350 にしており、`formRtcpPacket()` 側は packet 生成中に `setLength(RTP_ZERO)` などで現在位置としても使っている。容量と現在長が分離されていない設計が、境界チェックの欠落を見えにくくしている。
- `populateReportPacket()` は `uiTmpRecpCount <= uiRecepCount` で比較しており、通常の小さい値でも意図より 1 個多く report block を追加し得る off-by-one 疑いがある。ただし今回の CVE 説明は `numberOfReportBlocks` の integer overflow を指しており、主因は unsigned wraparound。
- `numberOfReportBlocks()` は RR 経路でも SR 固定部分込みの `uiReportDefSize = 28` を使っている。RR 固定部分は `RTCP_FIXED_HDR_LEN = 8` なので、RR では保守的ではあるが、wraparound 条件の判定をしていない点は同じ。
- 手元の `lineage-23.1` と `lineage-23.2` バイナリはこの関数に修正が入っていないため、修正済み Pixel バイナリそのものの patch diff は取れていない。公開 OSV は `Platform:2026-06-05` fixed としているが、修正 commit は公開検索では見つからなかった。

## 修正方針

安全な修正は、少なくとも以下を満たす必要がある。

- `uiMtuSize <= uiEstRtcpSize` の場合は report block 数を 0 にする。
- `uiMtuSize - uiEstRtcpSize < uiReportDefSize` の場合も 0 にする。
- 残りサイズ計算は `uint64_t` など広い型、または事前条件チェック付きの減算で行う。
- `formSrList()` / `formRrList()` に渡す数は、実際の sender 数と MTU から導いた上限の小さい方に丸める。
- `RtpBuffer` に capacity を持たせ、`formReportBlock()` / `formRrPacket()` / `formSrPacket()` の全書き込み前に残容量を検査する。

## 判定

`ok`: 公開情報で関数名と原因が明示され、AOSP ソースとローカル `libpixelimsmedia` 逆アセンブルから、`numberOfReportBlocks()` の 32bit unsigned wraparound、巨大 report block 数の伝播、固定 1350 バイト RTCP 送信バッファへの未検証書き込みという根本原因と発生条件を説明できる。
080 NG

CVE-2026-0162

080-ng-audiosdpparser-parsepayloads-type-confusion-unconfirmed

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentIP Multimedia Subsystem
TypeDoS
SeverityCritical
ReferencesA-481652714
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0162 is listed in the Pixel Update Bulletin as a Critical severity DoS issue in Pixel / IP Multimedia Subsystem.

NG 判定の要点

脆弱性の完全特定には至らなかったため ng と判定する。

OSV/CVE 詳細は AudioSdpParser.cpp の ParsePayloads における type confusion による memory corruption としているが、今回取得できた固定済み Pixel OTA からは、該当 C++ ソース、該当関数名、修正前後の同一バイナリ差分を確認できなかった。したがって、根本原因を「ソースコード」または「脆弱性が起きる状況の完全説明」として確定する条件を満たさない。

ただし、固定済み June OTA の ShannonIms.apk には SDP payload/IMS media のシリアライズ処理が存在し、APSdpDialogue.deSerialize() が APSdpInfoBase の実体として通常版 APSdpInfo と withfmtp.APSdpInfo を外部フラグ isMultipleFmtp で切り替える構造を確認した。両者は同じ基底型として扱われるが、バイト列の読み取り順が異なるため、誤った型を選ぶと SDP payload の読み取り位置とフィールド解釈がずれる。この構造は「type confusion」という CVE 説明と整合するが、これが AudioSdpParser.cpp::ParsePayloads の脆弱箇所そのものだとは断定できない。

未確定の理由 / 原因候補

ng: CVE 詳細が示す AudioSdpParser.cpp::ParsePayloads のソースコードまたは修正前後 diff を取得できず、type confusion の exact な根本原因を確定できなかった。ShannonIms.apk の SDP 型分岐は有力な関連構造だが、脆弱性そのものとして断定するには足りない。

どこから特定したか

取得・解析したバイナリ: ・OTA: ../binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip
- SHA-256: 71cbe004f1d76a981bbc65587465d5b36af22d85c7c7b18ee214c05488aee6fc
- ZIP central directory は欠落しており unzip -t は失敗するが、local header から payload.bin は store 方式で完全切り出しできた。
・Payload: ../binaries/pixel_shiba_ota/partial_extract/payload.bin.part
- SHA-256: 6ec094f8b120519c138f5…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https://api.osv.dev/v1/vulns/PUB-A-481652714`

validated.md を表示
# CVE-2026-0162 検証メモ

## 結論

脆弱性の完全特定には至らなかったため `ng` と判定する。

OSV/CVE 詳細は `AudioSdpParser.cpp` の `ParsePayloads` における type confusion による memory corruption としているが、今回取得できた固定済み Pixel OTA からは、該当 C++ ソース、該当関数名、修正前後の同一バイナリ差分を確認できなかった。したがって、根本原因を「ソースコード」または「脆弱性が起きる状況の完全説明」として確定する条件を満たさない。

ただし、固定済み June OTA の `ShannonIms.apk` には SDP payload/IMS media のシリアライズ処理が存在し、`APSdpDialogue.deSerialize()` が `APSdpInfoBase` の実体として通常版 `APSdpInfo` と `withfmtp.APSdpInfo` を外部フラグ `isMultipleFmtp` で切り替える構造を確認した。両者は同じ基底型として扱われるが、バイト列の読み取り順が異なるため、誤った型を選ぶと SDP payload の読み取り位置とフィールド解釈がずれる。この構造は「type confusion」という CVE 説明と整合するが、これが `AudioSdpParser.cpp::ParsePayloads` の脆弱箇所そのものだとは断定できない。

## 既存 cve.md から確認した情報

- CVE: `CVE-2026-0162`
- Bulletin: Pixel Update Bulletin
- Bulletin URL: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- Published/updated: 2026-06-16
- Security patch level: 2026-06-05 or later
- Component/Subcomponent: Pixel / IP Multimedia Subsystem
- Type/Severity: DoS / Critical
- Reference: `A-481652714`

## 外部情報

- OSV: `https://api.osv.dev/v1/vulns/PUB-A-481652714`
  - 保存: `analysis/PUB-A-481652714.json`
  - Details: `In ParsePayloads of AudioSdpParser.cpp, there is a possible memory corruption due to type confusion.`
  - `fixed`: `Pixel-family specific:2026-06-05`
  - `ecosystem_specific.types`: `DoS`
- Pixel bulletin: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
  - 該当行: `CVE-2026-0162 A-481652714 * DoS Critical IP Multimedia Subsystem`

## 取得・解析したバイナリ

- OTA: `../binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip`
  - SHA-256: `71cbe004f1d76a981bbc65587465d5b36af22d85c7c7b18ee214c05488aee6fc`
  - ZIP central directory は欠落しており `unzip -t` は失敗するが、local header から `payload.bin` は store 方式で完全切り出しできた。
- Payload: `../binaries/pixel_shiba_ota/partial_extract/payload.bin.part`
  - SHA-256: `6ec094f8b120519c138f5047767271cd6d7981cd5166d3b25e8aae8bfad653e7`
  - manifest 保存: `analysis/payload_manifest_summary.txt`
- 展開した partition:
  - `product.img`
  - `system.img`
  - `system_ext.img`
  - `vendor.img`
- 主な抽出ファイル:
  - `analysis/analysis_system_ext_extract/ShannonIms.apk`
    - SHA-256: `cd6439fe5cd65d58ab276bb24ee604a2f180383a3f162f05aac5419ebf4efccc`
  - `analysis/analysis_system_ext_extract/libpixelimsmedia.so`
    - SHA-256: `805eb3e4af5ec05989ed0a8f95452962a8b59b7f16958f0adf9315467779407a`
  - `analysis/analysis_system_ext_extract/PixelImsMediaService.apk`
  - `analysis/analysis_system_ext_extract/ShannonRcs.apk`
  - `analysis/analysis_vendor_extract/*`

## 調査結果

`system_ext.img` に IMS 関連の本体があった。

- `ShannonIms.apk`
- `ShannonRcs.apk`
- `PixelImsMediaService.apk`
- `libpixelimsmedia.so`

`ShannonIms.apk` の strings には以下の SDP/payload 関連クラスや文字列が残っていた。

- `APSdpDialogue.java`
- `APSdpInfo.java`
- `APSdpInfoBase.java`
- `APSdpSessionInfo.java`
- `mPayloadType`
- `mSdpSessionType`
- `payload-type`
- `sdp-info`
- `sdp-length`
- `Failed to de-serialize sdp`

軽量 DEX 解析結果は `analysis/dex_sdp_method_table.txt` に保存した。主な関係クラスは以下。

- `Lcom/shannon/imsservice/call/media/serial/dialogue/APSdpDialogue;`
- `Lcom/shannon/imsservice/call/media/serial/APSdpInfo;`
- `Lcom/shannon/imsservice/call/media/serial/withfmtp/APSdpInfo;`
- `Lcom/shannon/imsservice/call/media/serial/base/APSdpInfoBase;`

`analysis/androguard_key_disasm.txt` で確認した `APSdpDialogue.deSerialize()` は、`isMultipleFmtp` によって同じ SDP 情報を別型へ分岐している。

- `isMultipleFmtp == true`: `com.shannon.imsservice.call.media.serial.withfmtp.APSdpInfo`
- `isMultipleFmtp == false`: `com.shannon.imsservice.call.media.serial.APSdpInfo`

両者の `deSerialize()` は wire order が異なる。

- 通常版 `APSdpInfo.deSerialize()`:
  - `APSdpSessionInfo`
  - `NegotiatedVideoProfile`
  - `mLocalVideoPort`
- `withfmtp.APSdpInfo.deSerialize()`:
  - `mLocalVideoPort`
  - `APSdpSessionInfo`
  - `withfmtp.NegotiatedVideoProfile`

このため、入力 SDP/payload の実際の形式と `isMultipleFmtp` がずれると、同じ `APSdpInfoBase` として扱われるデータを別レイアウトで読むことになり、以降のフィールド境界が崩れる。これは OSV の「type confusion」説明と整合する興味深い構造だった。

一方、`AudioSdpParser.cpp` や `ParsePayloads` の名前は、`ShannonIms.apk`、`ShannonRcs.apk`、`PixelImsMediaService.apk`、`libpixelimsmedia.so`、vendor 側 IMS/RIL 関連 so の strings/symbols では見つからなかった。

## 固定済み挙動として確認できた長さチェック

`ShannonIms.apk` の RIL indication parser には SDP 長の上限チェックが入っていた。保存先は `analysis/androguard_key_disasm.txt`。

- `RilIndCallModify.update([B, I)`
- `RilIndCallModifyRsp.update([B, I)`
- `RilIndCallRing.update([B, I)`

例として `RilIndCallModify.update` は `mSdpLength` を `getShortAsInt()` で読み、`1750` を超える場合はログ出力後に `mSdpLength = 1750` へ丸めてから `getBytes(mSdpLength)` している。これは DoS/memory corruption 対策としては妥当だが、`ParsePayloads` の type confusion 修正そのものかは不明。

## 面白い点・調査メモ

- Bulletin は DoS / Critical だが、OSV details の定型文は RCE と書いている。OSV の `ecosystem_specific.types` は DoS なので、bulletin の DoS を優先した。
- `libpixelimsmedia.so` には `AudioSdpParser` はなく、RTCP/RTP/T.140 等のメディア処理シンボルが中心だった。CVE-2026-0160/0161 近傍とは別レイヤの IMS SDP 処理と見える。
- `ShannonIms.apk` は `com.shannon.imsservice` で、Pixel の IP Multimedia Subsystem という subcomponent と整合する。
- `product` には `ImsServiceEntitlement.apk` と `WfcActivation.apk` があったが、entitlement/WFC UI 系で、`AudioSdpParser` にはつながらなかった。
- `system` には framework の `ims-common.jar` / `telephony-common.jar` はあったが、Pixel 固有の SDP parser 本体は見つからなかった。
- OTA zip は中央ディレクトリ欠落の状態だが、local file header では `payload.bin` が offset `4507`、method `0`、size `2996622980` と読めたため、payload 解析は可能だった。

## 付帯ファイル

- `analysis/PUB-A-481652714.json`: OSV JSON
- `analysis/payload_manifest_summary.txt`: OTA payload manifest と partition data offset
- `analysis/extract_partition_single.py`: macOS の multiprocessing 問題を避けるために作った単一プロセス payload extractor
- `analysis/product_file_hits.txt`
- `analysis/system_file_hits.txt`
- `analysis/system_ext_file_hits.txt`
- `analysis/vendor_file_hits.txt`
- `analysis/dex_sdp_method_table.txt`: DEX の class/method table から抽出した SDP/Payload 関連一覧
- `analysis/androguard_key_disasm.txt`: 主要 SDP/Payload/RIL indication メソッドの DEX 命令列
- `analysis/androguard_sdp_methods.txt`: androguard の SDP/Payload 関連メソッド一覧。ログ込みで大きい。
- `analysis/analysis_system_ext_extract/*`: system_ext から抽出した IMS 関連 APK/so
- `analysis/analysis_vendor_extract/*`: vendor から抽出した IMS/RIL 関連 so

## 判定

`ng`: CVE 詳細が示す `AudioSdpParser.cpp::ParsePayloads` のソースコードまたは修正前後 diff を取得できず、type confusion の exact な根本原因を確定できなかった。`ShannonIms.apk` の SDP 型分岐は有力な関連構造だが、脆弱性そのものとして断定するには足りない。
081 OK

CVE-2026-0148

081-ok-video-rtp-payload-decoder-integer-overflow-rce

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentIP Multimedia Subsystem
TypeRCE
SeverityHigh
ReferencesA-480123693
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0148 is listed in the Pixel Update Bulletin as a High severity RCE issue in Pixel / IP Multimedia Subsystem.

特定した具体的な脆弱性

特定できた。CVE-2026-0148 は Pixel / IP Multimedia Subsystem の video RTP payload decoder にある RCE で、実体は VideoRtpPayloadDecoderNode.cpp の AVC/H.264 および HEVC/H.265 RTP payload 復元処理における整数 wraparound と境界検査不足である。

根本原因は、受信 RTP payload 長 nDataSize に Annex-B start code や FU header 復元分の固定バイト数を足す/引く前に、MAX_RTP_PAYLOAD_BUFFER_SIZE および最小 header 長との整合を検証していないこと。脆弱な公開ソースでは mBuffer を MAX_RTP_PAYLOAD_BUFFER_SIZE で確保した後、memcpy(mBuffer + 4, pData, nDataSize)、memcpy(mBuffer + 5, pData + 2, nDataSize - 2)、memcpy(mBuffer + 6, pData + 3, nDataSize - 3) などをそのまま実行し、後段へ nDataSize + 4 / nDataSize + 3 を渡す。nDataSize が大きい場合は加算後のサイズが buffer 容量を超え、極端な値では uint32_t の加算が wrap する。FU packet が短すぎる場合は nDataSize - 2 / nDataSize - 3 が unsigned underflow して巨大な copy length になる。

原因

記載なし。

どこから特定したか

参照情報: ・Pixel bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- 該当行: CVE-2026-0148 A-480123693 * RCE High IP Multimedia Subsystem
・OSV: https://osv.dev/vulnerability/PUB-A-480123693
- 保存: artifacts/public/osv-PUB-A-480123693.json
- Details: In multiple functions of VideoRtpPayloadDecoderNode.cpp, there is a possible out of b…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https://osv.dev/vulnerability/PUB-A-480123693` / https://nvd.nist.gov/vuln/detail/CVE-2026-0148` / https://www.originhq.com/research/patch-diffing-pipeline`

validated.md を表示
# CVE-2026-0148 検証メモ

## 結論

特定できた。CVE-2026-0148 は Pixel / IP Multimedia Subsystem の video RTP payload decoder にある RCE で、実体は `VideoRtpPayloadDecoderNode.cpp` の AVC/H.264 および HEVC/H.265 RTP payload 復元処理における整数 wraparound と境界検査不足である。

根本原因は、受信 RTP payload 長 `nDataSize` に Annex-B start code や FU header 復元分の固定バイト数を足す/引く前に、`MAX_RTP_PAYLOAD_BUFFER_SIZE` および最小 header 長との整合を検証していないこと。脆弱な公開ソースでは `mBuffer` を `MAX_RTP_PAYLOAD_BUFFER_SIZE` で確保した後、`memcpy(mBuffer + 4, pData, nDataSize)`、`memcpy(mBuffer + 5, pData + 2, nDataSize - 2)`、`memcpy(mBuffer + 6, pData + 3, nDataSize - 3)` などをそのまま実行し、後段へ `nDataSize + 4` / `nDataSize + 3` を渡す。`nDataSize` が大きい場合は加算後のサイズが buffer 容量を超え、極端な値では `uint32_t` の加算が wrap する。FU packet が短すぎる場合は `nDataSize - 2` / `nDataSize - 3` が unsigned underflow して巨大な copy length になる。

## 既存 cve.md から確認した情報

- CVE: `CVE-2026-0148`
- Bulletin: Pixel Update Bulletin
- Bulletin URL: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- Published/updated: 2026-06-16
- Security patch level: 2026-06-05 or later
- Component/Subcomponent: Pixel / IP Multimedia Subsystem
- Type/Severity: RCE / High
- Reference: `A-480123693`

## 参照情報

- Pixel bulletin: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
  - 該当行: `CVE-2026-0148 A-480123693 * RCE High IP Multimedia Subsystem`
- OSV: `https://osv.dev/vulnerability/PUB-A-480123693`
  - 保存: `artifacts/public/osv-PUB-A-480123693.json`
  - Details: `In multiple functions of VideoRtpPayloadDecoderNode.cpp, there is a possible out of bounds write due to an integer overflow.`
  - Fixed: `Pixel-family specific:2026-06-05`
- NVD: `https://nvd.nist.gov/vuln/detail/CVE-2026-0148`
  - 保存: `artifacts/public/nvd-CVE-2026-0148.html`
  - CWE: `CWE-190 Integer Overflow or Wraparound`, `CWE-787 Out-of-bounds Write`
  - CVSS v3.1 ADP: `8.8 HIGH`, `AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H`
- Patch diffing 参考: `https://www.originhq.com/research/patch-diffing-pipeline`
  - 保存: `artifacts/public/originhq-patch-diffing-pipeline.html`

## ソースコード確認

使用した AOSP checkout:

- Path: `/Users/eric/workspace/android/binaries/platform_packages_modules_ImsMedia.git`
- HEAD: `6da37b8ef8bde01956e630bb42a31a40fc1ddba3`
- 保存:
  - `artifacts/source/VideoRtpPayloadDecoderNode_local.cpp`
  - `artifacts/source/VideoRtpPayloadDecoderNode_local.h`
  - `artifacts/source/ImsMediaVideoUtil_local.h`

`ImsMediaVideoUtil.h` では video payload decoder の heap buffer は次のサイズである。

```cpp
#define MAX_VIDEO_WIDTH             1920
#define MAX_VIDEO_HEIGHT            1920
#define MAX_RTP_PAYLOAD_BUFFER_SIZE (MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT * 3 >> 1)
```

つまり `MAX_RTP_PAYLOAD_BUFFER_SIZE = 1920 * 1920 * 3 / 2 = 5,529,600` bytes。

`VideoRtpPayloadDecoderNode::Start()` はこのサイズで `mBuffer` を確保する。

問題箇所は `DecodeAvc` と `DecodeHevc` の複数経路にある。

- AVC single NAL: `memcpy(mBuffer + 4, pData, nDataSize)` の後、`nDataSize + 4` を後段へ渡す。
- AVC FU-A start: `memcpy(mBuffer + 5, pData + 2, nDataSize - 2)` の後、`nDataSize + 3` を渡す。
- HEVC single NAL: `memcpy(mBuffer + 4, pData, nDataSize)` の後、`nDataSize + 4` を渡す。
- HEVC FU-A start: `memcpy(mBuffer + 6, pData + 3, nDataSize - 3)` の後、`nDataSize + 3` を渡す。

公開ソースには以下の確認がない。

- `nDataSize <= MAX_RTP_PAYLOAD_BUFFER_SIZE - 4`
- AVC FU-A で `nDataSize >= 2` かつ `nDataSize <= MAX_RTP_PAYLOAD_BUFFER_SIZE - 3`
- HEVC FU-A で `nDataSize >= 3` かつ `nDataSize <= MAX_RTP_PAYLOAD_BUFFER_SIZE - 3`
- `nDataSize + 3/4` が `uint32_t` で wrap しないこと

したがって、過大な RTP payload 長が内部ノードへ到達すると `mBuffer + 4/5/6` から heap OOB write になる。短すぎる FU packet でも `nDataSize - 2` / `nDataSize - 3` が unsigned underflow し、`memcpy` の第三引数が巨大化し得る。

危険箇所の grep は `artifacts/analysis/source_risky_operations.txt` に保存した。

## バイナリ確認

既存の `libpixelimsmedia` バイナリを使い、`VideoRtpPayloadDecoderNode` シンボルと逆アセンブルを確認した。

- `074-CVE-2026-0149-Pixel-libpixelimsmedia-RCE-Critical/blobs/libpixelimsmedia_lineage-23.1.so`
- `074-CVE-2026-0149-Pixel-libpixelimsmedia-RCE-Critical/blobs/libpixelimsmedia_lineage-23.2.so`
- Symbols: `artifacts/analysis/video_decoder_symbols_lineage-23.1.txt`, `artifacts/analysis/video_decoder_symbols_lineage-23.2.txt`
- Disassembly:
  - `artifacts/analysis/DecodeAvc_lineage-23.1.objdump.txt`
  - `artifacts/analysis/DecodeAvc_lineage-23.2.objdump.txt`
  - `artifacts/analysis/DecodeHevc_lineage-23.1.objdump.txt`
  - `artifacts/analysis/DecodeHevc_lineage-23.2.objdump.txt`

Lineage 23.2 の `DecodeAvc` / `DecodeHevc` には、single NAL と FU start の `memcpy` 前に `0x545ffd` 近辺、つまり `MAX_RTP_PAYLOAD_BUFFER_SIZE - 3` 近辺との比較が存在した。これは公開ソースにはない上限チェックであり、修正の方向性が「start code/FU header を足した後に `mBuffer` を超えないよう、加算前の `nDataSize` を制限する」ことを示す。

例:

- AVC single NAL: `cmp w24, 0x545ffd; b.hs ...; memcpy(mBuffer + 4, pData, nDataSize)`
- AVC FU-A start: `cmp w24, 0x545ffe; b.hs ...; memcpy(mBuffer + 5, pData + 2, nDataSize - 2)`
- HEVC single NAL: `cmp w23, 0x545ffd; b.hs ...; memcpy(mBuffer + 4, pData, nDataSize)`
- HEVC FU-A start: `cmp w23, 0x545ffe; b.hs ...; memcpy(mBuffer + 6, pData + 3, nDataSize - 3)`

抜粋は `artifacts/analysis/binary_memcpy_checks_excerpt.txt` に保存した。

注意: この Lineage バイナリ差分は Pixel 2026-06 OTA の直接 diff ではない。Google の bug ID は `*` 付きで、Pixel binary driver 側の修正として公開 CL はない。実際の Pixel patch hunk そのものは取得できなかったが、OSV/NVD が具体ファイル名を公開しており、AOSP ソース上の根本原因と、同関数バイナリに現れる上限チェックの形は整合している。

## 攻撃条件の復元

1. Pixel の IMS video call / video RTP 受信経路で、`VideoRtpPayloadDecoderNode` が AVC または HEVC payload を処理する。
2. 攻撃者が、IMS/RTP セッションで細工した video RTP payload を送る。
3. AVC/HEVC single NAL の場合、`nDataSize` が `MAX_RTP_PAYLOAD_BUFFER_SIZE - 4` を超える、または `nDataSize + 4` が `uint32_t` wrap する値になる。
4. AVC FU-A start の場合、`nDataSize + 3` が buffer 容量を超える、または短すぎる packet により `nDataSize - 2` が underflow する。
5. HEVC FU-A start の場合、同様に `nDataSize + 3` が buffer 容量を超える、または `nDataSize - 3` が underflow する。
6. decoder は `mBuffer` 末尾を越えて `memcpy` し、heap metadata または隣接 object を破壊する。IMS media process の文脈で RCE につながり得る。

CVSS の `PR:L` は、任意のインターネット到達ではなく、IMS/RTP セッションに参加できる相手または低権限相当の到達性を前提にしていると解釈できる。`UI:N` なので、セッション成立後のユーザー操作は不要。

## 面白い点・調査メモ

- Bulletin の subcomponent は `IP Multimedia Subsystem` だが、公開 CVE 詳細は `VideoRtpPayloadDecoderNode.cpp` と明記しており、実処理は `libpixelimsmedia` の video RTP payload decoder にある。
- 同じ June 2026 の IMS 周辺には `libpixelimsmedia` / `gIMS` / `Real-time Transport Protocol` の CVE が多く、`CVE-2026-0160` は text RTP/T.140、`CVE-2026-0149` や `CVE-2026-0161` は RTCP/RTP 周辺だった。0148 は video RTP payload 復元側。
- AOSP gitiles の `main`, `android16-release`, `android16-security-release`, `android17-release` から取得した `VideoRtpPayloadDecoderNode.cpp` はローカルソースと同一だった。`local_vs_*.diff` は空で、公開 AOSP ブランチ上では Pixel 修正差分を確認できなかった。
- 既存 Lineage バイナリには、公開 AOSP ソースにない上限チェックが入っていた。Pixel 2026-06 修正そのものではないが、CVE 説明と一致する hardening の例として有用だった。
- AVC STAP-A の NAL length は 16 bit なので単体 NAL は最大 65,535 bytes で、5.5MB の `mBuffer` には収まる。CVE の主対象は STAP-A より、`nDataSize + start-code` や FU start の `nDataSize - header` 算術を使う複数関数/経路と見るのが妥当。

## 修正方針

安全な修正は以下を満たす必要がある。

- `DecodeAvc` / `DecodeHevc` の入口で、packet type ごとの最小 header 長を確認する。
- `memcpy` 前に、宛先 offset と copy length の加算が `MAX_RTP_PAYLOAD_BUFFER_SIZE` 以下であることを確認する。
- `SendDataToRearNode` に渡す `nDataSize + 3/4` は、wrap しないことを加算前に確認する。
- 不正な RTP payload は drop し、後段へ不整合な長さを渡さない。

## 生成した付帯ファイル

- `artifacts/public/pixel-bulletin-2026-06-01.html`
- `artifacts/public/osv-PUB-A-480123693.pretty.json`
- `artifacts/public/nvd-CVE-2026-0148.html`
- `artifacts/source/VideoRtpPayloadDecoderNode_local.cpp`
- `artifacts/source/ImsMediaVideoUtil_local.h`
- `artifacts/analysis/source_risky_operations.txt`
- `artifacts/analysis/binary_memcpy_checks_excerpt.txt`
- `artifacts/analysis/DecodeAvc_lineage-23.2.objdump.txt`
- `artifacts/analysis/DecodeHevc_lineage-23.2.objdump.txt`
- `artifacts/artifacts_sha256.txt`

## 判定

`ok`

理由: OSV/NVD が具体的に `VideoRtpPayloadDecoderNode.cpp` の integer overflow / OOB write と公開しており、AOSP ソースから `mBuffer` の固定容量、未検証の `nDataSize +/- const` 算術、`memcpy` による OOB write 条件を説明できる。Pixel の非公開 patch hunk は取得できなかったが、脆弱性が起きる状況と根本原因はソースコードで特定できた。
082 OK

CVE-2026-0131

082-ok-rtp-decodepacket-extension-len-overflow

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
Subcomponentlibpixelimsmedia
TypeEoP
SeverityHigh
ReferencesA-476459432
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0131 is listed in the Pixel Update Bulletin as a High severity EoP issue in Pixel / libpixelimsmedia.

特定した具体的な脆弱性

CVE-2026-0131 は、Pixel libpixelimsmedia の RtpPacket::decodePacket が RTP header extension length を境界チェック前に 16-bit 幅で加算・乗算することに起因する integer overflow / length validation bypass である。攻撃者制御の extension length により parser のバッファ位置と残長管理が破綻し、out-of-bounds access を起こす。根本原因は外部入力長の narrow integer arithmetic と、overflow を考慮しない境界チェックである。

原因

RtpPacket::decodePacket は RTP fixed header を decode した後、RTP header extension bit が立っている場合に extension header の 16-bit length field を読み、extension 全体のバイト長へ変換する。

問題のある処理は以下。

``cpp
RtpDt_UInt32 uiByte4Data = RtpOsUtil::Ntohl(*(reinterpret_cast<RtpDt_UInt32*>(pcRtpBuf)));
RtpDt_UInt16 uXHdrLen =
(RtpDt_UInt16)(uiByte4Data & RTP_HEX_16_BIT_MAX);

uXHdrLen += 1;
uXHdrLen *= RTP_WORD_SIZE;

if ((uXHdrLen <= 0) || ((uiRtpBufPos + uXHdrLen) > uiRtpUtlBufLen)) {
return eRTP_FAILURE;
}
`

どこから特定したか

確認した公開情報: ・既存 cve.md: CVE-2026-0131 / A-476459432 / Pixel / libpixelimsmedia / EoP High / Pixel Update Bulletin 2026-06-01。
・Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
・Bulletin の Pixel セクションでは CVE-2026-0131 A-476459432 * EoP High libpixelimsmedia と記載。* は Android bug が非公開で、通常は Pixel binary driver 側で修正されることを示す。
・OSV: https://…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01 / https://osv.dev/vulnerability/PUB-A-476459432 / https://storage.googleapis.com/android-osv/PUB-A-476459432.json / https://android.googlesource.com/platform/packages/modules/ImsMedia`

validated.md を表示
# CVE-2026-0131 検証結果

## 判定

ok: 脆弱性の発生条件と根本原因をソースコードレベルで特定した。

タイトル: `rtp-decodepacket-extension-len-overflow`

## 確認した公開情報

- 既存 `cve.md`: CVE-2026-0131 / A-476459432 / Pixel / libpixelimsmedia / EoP High / Pixel Update Bulletin 2026-06-01。
- Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- Bulletin の Pixel セクションでは `CVE-2026-0131 A-476459432 * EoP High libpixelimsmedia` と記載。`*` は Android bug が非公開で、通常は Pixel binary driver 側で修正されることを示す。
- OSV: https://osv.dev/vulnerability/PUB-A-476459432
- OSV JSON: https://storage.googleapis.com/android-osv/PUB-A-476459432.json
- OSV の詳細: `RtpPacket::decodePacket` に integer overflow 起因の out-of-bounds access があり、local EoP、追加権限不要、ユーザー操作あり。

取得した OSV JSON は `PUB-A-476459432.json` としてこのフォルダに保存した。

## 調査対象ソース

- Repository: `https://android.googlesource.com/platform/packages/modules/ImsMedia`
- Local path: `/Users/eric/workspace/android/binaries/platform_packages_modules_ImsMedia.git`
- HEAD: `6da37b8ef8bde01956e630bb42a31a40fc1ddba3`
- 対象ファイル: `service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtpPacket.cpp`
- 対象関数: `RtpPacket::decodePacket(RtpBuffer*)`
- 型定義確認: `RtpPfDatatypes.h` で `RtpDt_UInt16` は `uint16_t`、`RtpGlobal.h` で `RTP_WORD_SIZE` は `4`、`RTP_HEX_16_BIT_MAX` は `0xFFFF`。

## 根本原因

`RtpPacket::decodePacket` は RTP fixed header を decode した後、RTP header extension bit が立っている場合に extension header の 16-bit length field を読み、extension 全体のバイト長へ変換する。

問題のある処理は以下。

```cpp
RtpDt_UInt32 uiByte4Data = RtpOsUtil::Ntohl(*(reinterpret_cast<RtpDt_UInt32*>(pcRtpBuf)));
RtpDt_UInt16 uXHdrLen =
        (RtpDt_UInt16)(uiByte4Data & RTP_HEX_16_BIT_MAX);

uXHdrLen += 1;
uXHdrLen *= RTP_WORD_SIZE;

if ((uXHdrLen <= 0) || ((uiRtpBufPos + uXHdrLen) > uiRtpUtlBufLen)) {
    return eRTP_FAILURE;
}
```

RTP extension length は「4 byte word 数」で、extension header 自身の 1 word を足してから 4 倍してバイト数にする必要がある。ところが中間値を `RtpDt_UInt16` に保持してから `+ 1` しているため、攻撃者が length field に `0xffff` を入れると 16-bit 加算で 0 に wrap し得る。これにより正しい拡張ヘッダ長 `0x40000` bytes が短い値として扱われ、以後の `memcpy`、`pcRtpBuf` 更新、payload/padding 長計算が実際の受信バッファ境界とずれる。

根本原因は、外部入力由来の 16-bit RTP extension length を、境界チェック前に狭い整数型で加算・乗算していること。正しい修正方針は、32-bit 以上の型で `((uint32_t)len + 1) * 4` を計算し、加算/乗算 overflow と `uiRtpBufPos + extLen > packetLen` を先に検査してから allocate/copy/カーソル更新すること。

## 脆弱性の発生条件

次のような RTP packet が `libpixelimsmedia` の IMS/RTP 受信処理に到達すると成立する。

- RTP version が 2。
- RTP header extension bit が 1。
- extension length field が 16-bit 境界値、特に `0xffff`。
- 実際の受信 packet length は正しい extension byte length より短い。

この条件では、本来なら extension header が packet 内に収まらないため即時 reject すべきだが、長さ計算が wrap/truncate すると、短い extension として処理が続く。結果として parser の読み取り位置と残り payload 長が不正になり、out-of-bounds access につながる。

## 影響

OSV は local escalation of privilege としている。`libpixelimsmedia` は Pixel の IMS media/RTP 処理に関与するため、細工した RTP media 入力をローカル経路またはユーザー操作を伴う IMS/media 経路で処理させることで、Pixel 側の media/telephony 関連プロセス文脈で境界外アクセスを起こせる問題と考えられる。

## バイナリ解析メモ

同じ `libpixelimsmedia` の既存調査フォルダにあった LineageOS shiba vendor blob を利用した。

- 入力: `074-CVE-2026-0149-Pixel-libpixelimsmedia-RCE-Critical/blobs/libpixelimsmedia_lineage-23.1.so`
- 入力: `074-CVE-2026-0149-Pixel-libpixelimsmedia-RCE-Critical/blobs/libpixelimsmedia_lineage-23.2.so`
- 保存先: `artifacts/libpixelimsmedia_lineage-23.1.so`, `artifacts/libpixelimsmedia_lineage-23.2.so`
- `RtpPacket::decodePacket` address:
  - 23.1: `0x171400`
  - 23.2: `0x170560`

逆アセンブルでは両方とも `Ntohl` 後に `lsl w8, w0, #2; add w8, w8, #0x4; ands w22, w8, #0xfffc` という計算が見え、`decodePacket` の該当ロジック自体に有意な差分はなかった。AArch64 のこの mask は下位 16-bit の word-aligned 値を残す形で、`0xffff` では `(0xffff << 2) + 4 = 0x40000` が最終的に 0 へ truncate される。つまりこの Lineage 23.1/23.2 blob は June 2026 Pixel security patch の pre/post としては使えなかったが、AOSP ソースで見た 16-bit wrap 条件とは整合している。

保存した付帯ファイル:

- `artifacts/RtpPacket_decodePacket_23.1.objdump.txt`
- `artifacts/RtpPacket_decodePacket_23.2.objdump.txt`
- `artifacts/RtpPacket_decodePacket_23.1_vs_23.2.diff`
- `artifacts/rootcause_notes.md`
- `artifacts/libpixelimsmedia_lineage-23.1.so`
- `artifacts/libpixelimsmedia_lineage-23.2.so`

## 公式 OTA 取得メモ

Google の OTA URL リストから以下を確認した。

- May pre-patch candidate: `https://dl.google.com/dl/android/aosp/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip`
- June fixed candidate: `https://dl.google.com/dl/android/aosp/shiba-ota-cp2a.260605.012-b315a1a2.zip`

HTTP HEAD で確認した公式サイズ:

- May: `2996632121` bytes
- June: `3243662423` bytes

既存の May OTA は `/Users/eric/workspace/android/binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip` にあったが、中央ディレクトリがなく `unzip`/`zipinfo` で壊れた ZIP と判定された。`curl -C -` で再開を試みたが、元ファイルが壊れていたため最終的にも公式サイズと一致しない不整合ファイルになっており、使用不可。速度も数十 KB/s まで落ち、完了見込みが数時間から十数時間になったため停止した。June OTA も同様に取得を開始したが未完了。

したがって、この調査では CP1A.260505.005.A1 と CP2A.260605.012 の完全な公式 binary diff は未完了。脆弱性判定は OSV が明示した関数名と、AOSP に存在する同一 `RtpPacket::decodePacket` のソースコード上の整数 overflow 条件に基づく。

## 面白い点・調査中に分かったこと

- Bulletin の `*` 付き Android bug は非公開で、公開 Gerrit commit は見つからなかった。
- AOSP `platform/packages/modules/ImsMedia` の公開履歴では、`RtpPacket.cpp` の最近の security fix commit は確認できなかった。Pixel 固有 blob 側で修正された可能性が高い。
- OSV は Bulletin より具体的で、`RtpPacket::decodePacket` と integer overflow OOB まで公開している。Pixel bulletin の表だけではここまで絞れない。
- LineageOS の `libpixelimsmedia` blob には dynamic symbol が残っており、stripped でも `RtpPacket::decodePacket` は `llvm-nm -D -C` で特定できた。
- ただし Lineage 23.1/23.2 の `decodePacket` はほぼ同じで、June 2026 security patch の検証には不十分だった。

## 結論

CVE-2026-0131 は、Pixel `libpixelimsmedia` の `RtpPacket::decodePacket` が RTP header extension length を境界チェック前に 16-bit 幅で加算・乗算することに起因する integer overflow / length validation bypass である。攻撃者制御の extension length により parser のバッファ位置と残長管理が破綻し、out-of-bounds access を起こす。根本原因は外部入力長の narrow integer arithmetic と、overflow を考慮しない境界チェックである。
083 NG

CVE-2026-0133

083-ng-pixel-iommu-bootclass-signing-unidentified

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentIommu
TypeEoP
SeverityHigh
ReferencesA-373409261
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0133 is listed in the Pixel Update Bulletin as a High severity EoP issue in Pixel / Iommu.

NG 判定の要点

判定: ng

CVE-2026-0133 は Pixel Update Bulletin / OSV / NVD では Pixel / Iommu の High EoP とされ、公開説明は「smmu_attach_dev / arm-smmu-v3.c に missing permission check があり、悪意ある Android Runtime bootclass artifacts を署名できる可能性」となっている。しかし、今回確認できた公開ソース差分および shiba(Pixel 8) May/June OTA の kernel/vendor kernel boot バイナリ差分からは、該当する権限チェック追加や attach_dev 実コード変更を特定できなかった。

ok とするには、修正コード、または脆弱性が起きる状況を完全に説明できる証拠が必要だが、現状はそこまで到達していない。

未確定の理由 / 原因候補

記載なし。

どこから特定したか

公開情報: ・Bulletin: Pixel Update Bulletin 2026-06-01
・SPL: 2026-06-05
・Component/Subcomponent: Pixel / Iommu
・Type/Severity: EoP / High
・Reference: A-373409261
・OSV/NVD description:
- smmu_attach_dev of arm-smmu-v3.c
- missing permission check
- malicious Android Runtime bootclass artifacts を署名できる可能性
- local EoP, no additional execution privileges, no user i…

validated.md を表示
# CVE-2026-0133 Pixel Iommu EoP 検証メモ

## 結論

判定: **ng**

CVE-2026-0133 は Pixel Update Bulletin / OSV / NVD では Pixel / Iommu の High EoP とされ、公開説明は「`smmu_attach_dev` / `arm-smmu-v3.c` に missing permission check があり、悪意ある Android Runtime bootclass artifacts を署名できる可能性」となっている。しかし、今回確認できた公開ソース差分および shiba(Pixel 8) May/June OTA の kernel/vendor kernel boot バイナリ差分からは、該当する権限チェック追加や `attach_dev` 実コード変更を特定できなかった。

`ok` とするには、修正コード、または脆弱性が起きる状況を完全に説明できる証拠が必要だが、現状はそこまで到達していない。

## 公開情報

- Bulletin: Pixel Update Bulletin 2026-06-01
- SPL: 2026-06-05
- Component/Subcomponent: Pixel / Iommu
- Type/Severity: EoP / High
- Reference: A-373409261
- OSV/NVD description:
  - `smmu_attach_dev` of `arm-smmu-v3.c`
  - missing permission check
  - malicious Android Runtime bootclass artifacts を署名できる可能性
  - local EoP, no additional execution privileges, no user interaction
- CWE: CWE-862

根本原因候補としては「IOMMU domain attach の権限境界不備により、通常到達できない保護メモリ/署名経路/ART artifact signing に影響するデバイス経路へローカル権限で到達できる」筋が考えられるが、これは公開説明からの推測であり、検証済みの原因ではない。

## ソース差分調査

`artifacts/` に Gitiles から取得した `drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c` を保存した。

確認した主な ref:

- `android14-6.1-2026-03` -> `android14-6.1-2026-06`
- `android15-6.6-2026-04` -> `android15-6.6-2026-07`
- `android-gs-shusky-5.15-android15-qpr1`
- `android-gs-shusky-6.1-android15-qpr2`
- `android-gs-shusky-6.1-android16`
- `android-gs-shusky-6.1-android16-beta-3`
- `android-gs-*` 系 refs の広域一覧: `artifacts/kernel_common_relevant_refs.txt`

`android14-6.1-2026-03_to_2026-06_arm-smmu-v3.diff` で見つかった実差分は `arm_smmu_cmdq_shared_lock()` / exclusive unlock 周辺の rwlock/cmdq ロック修正だった。これは `smmu_attach_dev` の permission check 追加ではなく、CVE の公開説明とは一致しない。

`arm_smmu_attach_dev()` 本体は、取得できた `android14-6.1-2026-03` と `android14-6.1-2026-06`、および shusky 6.1 Android 15/16 系で実質同一だった。関数内に `capable()`、SELinux/security hook、uid/gid、Android Runtime/bootclass/signing に関係する新規チェックは確認できなかった。

## バイナリ差分調査

Pixel 8 / shiba の OTA を利用した。

対象:

- May: `shiba-ota-cp1a.260505.005-a604326e.zip`
- June: `shiba-ota-cp2a.260605.012-b315a1a2.zip`

フル OTA 全体は巨大なため、payload manifest と必要 byte range のみ取得した。range 情報は `artifacts/vendor_kernel_boot_ranges.txt` に保存した。取得した range バイナリは `../binaries/pixel_shiba_full_ota/` に保存した。

抽出したもの:

- `boot.img`
- `vendor_kernel_boot.img`
- `vendor_kernel_boot` ramdisk
- `samsung_iommu_v9.ko`
- `samsung-iommu-group.ko`
- `iovad-vendor-hooks.ko`
- `exynos-pcie-iommu.ko`
- `samsung-secure-iova.ko`
- `pkvm-s2mpu-v9.ko`
- `vendor_kernel_boot.dtb`

### boot.img

May boot kernel:

- `Linux version 6.1.145-android14-11-gfa1d6308d1fe-ab14691759`
- build time: `Fri Jan 9 16:33:46 UTC 2026`

June boot kernel:

- `Linux version 6.1.157-android14-11-gbd23337e42e7-ab14791245`
- build time: `Wed Jan 28 05:34:14 UTC 2026`

GKI boot image 側には `arm-smmu-v3` の明確な文字列や `arm_smmu_attach_dev` のシンボルは確認できなかった。

### vendor_kernel_boot / IOMMU modules

shiba の IOMMU 実体は `arm-smmu-v3.c` ではなく、vendor ramdisk 内の Samsung System MMU 系モジュールに見える。

重要な確認結果:

- `samsung_iommu_v9.ko` は未 strip ELF で、`samsung_sysmmu_attach_dev` シンボルを含む。
- May/June とも `samsung_sysmmu_attach_dev` は `0x1940`、サイズ `0x4d0`。
- `artifacts/may_samsung_sysmmu_attach_dev.bin` と `artifacts/june_samsung_sysmmu_attach_dev.bin` の SHA-256 は同一。
- `samsung_sysmmu_attach_dev` の objdump 差分も、ファイル名以外に実差分なし。

IOMMU 関連モジュールの `.text` / `.rodata` / relocation 比較結果は `artifacts/iommu_module_section_hashes.tsv` に保存した。以下のモジュールはいずれも `.text` が May/June で同一だった。

- `samsung_iommu_v9.ko`
- `samsung-iommu-group.ko`
- `iovad-vendor-hooks.ko`
- `exynos-pcie-iommu.ko`
- `samsung-secure-iova.ko`
- `pkvm-s2mpu-v9.ko`

ファイル全体の SHA-256 は変わっているが、差分は主に `.modinfo` の `vermagic` / `scmversion` / build-id などで、実コード差分ではない。

### DTB

`vendor_kernel_boot.dtb` は May/June で SHA-256 が同一だった。

`sysmmu@...`、`iommu_group_*`、`samsung,sysmmu-v9`、`gsa`、`tpu`、`aoc` など IOMMU 関連ノードは見えるが、May/June 差分はなかった。

## 面白い点・注意点

- 公開 OSV/NVD は `arm-smmu-v3.c` / `smmu_attach_dev` と書いているが、Pixel 8 shiba の該当 IOMMU 実装は Samsung System MMU vendor module 側に見える。
- shiba の May/June OTA では IOMMU 関連 vendor modules の実コードと DTB が一致しており、CVE 修正を直接示す差分は確認できなかった。
- `arm-smmu-v3.c` の公開差分には cmdq lock 修正があったが、missing permission check ではない。
- `android15-6.6-2026-07` の `arm-smmu-v3.c` 取得は 404 になり、既存 `artifacts/android15-6.6-2026-07_arm-smmu-v3.c` は空ファイルだった。そのため同 diff は信頼できない。
- May/June の boot image は kernel version が変わっているが、CVE 説明に直結する文字列/シンボルは boot 側では見つからなかった。

## 残した主な成果物

- `artifacts/PUB-A-373409261.json`: OSV 公開情報
- `artifacts/nvd_CVE-2026-0133.json`: NVD 公開情報
- `artifacts/android14_6.1_2026-03_to_2026-06_arm-smmu-v3.diff`: 公開 common kernel 差分
- `artifacts/ref_survey/`: 複数 ref の `arm-smmu-v3.c`
- `artifacts/vendor_kernel_boot_ranges.txt`: OTA range 取得情報
- `artifacts/full_ota_extract/`: May/June の boot/vendor_kernel_boot 抽出結果
- `artifacts/vendor_kernel_boot_ramdisk_may/`
- `artifacts/vendor_kernel_boot_ramdisk_june/`
- `artifacts/iommu_related_module_hashes.tsv`
- `artifacts/iommu_module_section_hashes.tsv`
- `artifacts/may_samsung_sysmmu_attach_dev.objdump.txt`
- `artifacts/june_samsung_sysmmu_attach_dev.objdump.txt`
- `artifacts/may_samsung_sysmmu_attach_dev.bin`
- `artifacts/june_samsung_sysmmu_attach_dev.bin`

## 未解決事項

次に進めるなら、以下が必要。

1. 別 Pixel 機種/別ビルドで同じ range 抽出を実施し、IOMMU 関連 module/DTB に実コード差分があるか確認する。
2. Google 内部/partner branch 由来の非公開 `smmu_attach_dev` 修正が公開 branch に落ちていない可能性を前提に、factory image の boot/vendor_boot/vendor_dlkm 全体を対象に再探索する。
3. ART bootclass artifact signing 経路、特に `odsign` / fs-verity / ART artifact key material と IOMMU デバイス割当の接点を別途調査する。

現時点では、脆弱性が発生する完全な条件や根本原因を証拠付きで説明できない。
084 OK

CVE-2026-0150

084-ok-edgetpu-executegraph-integer-overflow-oob-write

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentEdgeTPU
TypeEoP
SeverityHigh
ReferencesA-494623587
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0150 is listed in the Pixel Update Bulletin as a High severity EoP issue in Pixel / EdgeTPU.

特定した具体的な脆弱性

OK。Pixel 8 (shiba) の 2026年5月版と 2026年6月版の vendor.img を比較し、EdgeTPUファームウェア firmware/google/edgetpu-rio.fw に、OSVが説明する ExecuteGraph コマンドハンドラの整数オーバーフロー対策と見られる境界チェック追加を確認した。

脆弱性は、EdgeTPU firmware の ExecuteGraph コマンド処理で、ホストから渡されるグラフ/実行要求内のバッファ数またはバッファサイズを十分に検証せずに合計・変換していたため、整数オーバーフローにより小さすぎる管理領域が作られ、その後の input/output buffer descriptor 登録処理で範囲外書き込みに到達できるものだったと判断する。

原因

根本原因は、ExecuteGraph が受け取るグラフ実行要求の buffer count / buffer size が信頼境界を越えているにもかかわらず、firmware側で安全に合計・変換・上限制約していなかったこと。

特に input_count + output_count のような合計、または64-bit/flatbuffer由来のサイズ値から size_t/内部配列サイズへの変換でオーバーフローが起きると、firmwareは実際より小さい descriptor/metadata 領域を確保または参照する。その後、各 input/output buffer を登録するループが攻撃者指定の個数分だけ書き込み、確保済み領域の外へ書く。

June firmwareで追加された Too many input ... output ... buffers は buffer数合計側の上限チェック、Buffer size is greater than ... size_t はサイズ変換側の上限チェックに対応すると見てよい。

どこから特定したか

解析対象: Factory image URLは artifacts/factory_image_urls.txt に保存した。

パッチ解析: edgetpu-rio.fw にはシンボルではないが、ソースパスとエラー文字列が多く残っている。May/Juneの文字列差分で、Juneにのみ次の2つの防御系エラー文字列が追加されていた。

・Buffer size is greater than the maximum value of \size_t\: %lld
- 近傍ソース文字列: third_party/darwinn/firmware/interpreter/ops/tpu_offload_op.cc
・Too many input %lu and output %lu buffers.
- 近傍ソース文字列: third_party/darwinn/firmware/driver/graph/command.cc

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01 / https://osv.dev/vulnerability/PUB-A-494623587 / https://dl.google.com/dl/android/aosp/shiba-cp1a.260505.005-factory-3f3bd85e.zip` / https://dl.google.com/dl/android/aosp/shiba-cp2a.260605.012-factory-ada9841e.zip`

validated.md を表示
# CVE-2026-0150 / A-494623587 検証メモ

## 判定

OK。Pixel 8 (`shiba`) の 2026年5月版と 2026年6月版の `vendor.img` を比較し、EdgeTPUファームウェア `firmware/google/edgetpu-rio.fw` に、OSVが説明する `ExecuteGraph` コマンドハンドラの整数オーバーフロー対策と見られる境界チェック追加を確認した。

脆弱性は、EdgeTPU firmware の `ExecuteGraph` コマンド処理で、ホストから渡されるグラフ/実行要求内のバッファ数またはバッファサイズを十分に検証せずに合計・変換していたため、整数オーバーフローにより小さすぎる管理領域が作られ、その後の input/output buffer descriptor 登録処理で範囲外書き込みに到達できるものだったと判断する。

## 基本情報

- CVE: CVE-2026-0150
- 参照ID: A-494623587 / PUB-A-494623587
- Component / Subcomponent: Pixel / EdgeTPU
- 種別: EoP
- Severity: High
- Bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- OSV: https://osv.dev/vulnerability/PUB-A-494623587
- Patch level: 2026-06-05 fixed

OSV JSONには次の内容が記載されていた: `ExecuteGraph command handler of EdgeTPU firmware` に整数オーバーフロー由来の out-of-bounds write があり、root権限を持つローカル攻撃者がUIなしで権限昇格できる。

## 解析対象

Factory image URLは `artifacts/factory_image_urls.txt` に保存した。

- May/pre: `shiba-cp1a.260505.005-factory-3f3bd85e.zip`
  - URL: `https://dl.google.com/dl/android/aosp/shiba-cp1a.260505.005-factory-3f3bd85e.zip`
  - factory SHA-256: `3f3bd85e3d8a80c93b69a2d53b8b11547e0aa0ef7d14e9428c6203e63ce03cf7`
  - 抽出済み: `../binaries/pixel_factory/shiba-cp1a.260505.005/vendor.img`
  - `vendor.img` SHA-256: `4c06a3df5dbd92bb1bdf6cf06a616d4234111d22dfcf6f3f637061736ab5e8ba`
- June/post: `shiba-cp2a.260605.012-factory-ada9841e.zip`
  - URL: `https://dl.google.com/dl/android/aosp/shiba-cp2a.260605.012-factory-ada9841e.zip`
  - factory SHA-256: `ada9841ee75cfc81490b4d16bcce209b0f1b8a59478395e14f06d2d70f7ac87f`
  - 抽出済み: `../binaries/pixel_factory/shiba-cp2a.260605.012/vendor.img`
  - `vendor.img` SHA-256: `927e78fe4c97b9532a6f3df8e33051cca559290e1eb766e8e99cc69c49d7da4c`

## 差分の要点

`vendor.img` 内で `tpu`/`edgetpu` を含むファイルを列挙した結果、主要差分は次の通り。

- `firmware/google/edgetpu-rio.fw`: `1,135,488` -> `1,137,344` bytes
- `bin/hw/com.google.edgetpu.tachyon-service`: `103,408` -> `120,368` bytes
- `lib64/libedgetpu_tachyon.google.so`: `116,848` -> `133,232` bytes
- `lib64/libedgetpu_client.google.so`: `168,856` -> `169,008` bytes
- `lib64/libedgetpu_tflite_compiler.so`: `67,107,088` -> `68,653,744` bytes
- `lib64/libedgetpu_util.so`: `10,738,520` -> `10,360,768` bytes

設定ファイルやinit/vintf manifestは実質同一で、修正はコード/ファームウェア側に集中している。

## パッチ解析

`edgetpu-rio.fw` にはシンボルではないが、ソースパスとエラー文字列が多く残っている。May/Juneの文字列差分で、Juneにのみ次の2つの防御系エラー文字列が追加されていた。

- `Buffer size is greater than the maximum value of \`size_t\`: %lld`
  - 近傍ソース文字列: `third_party/darwinn/firmware/interpreter/ops/tpu_offload_op.cc`
- `Too many input %lu and output %lu buffers.`
  - 近傍ソース文字列: `third_party/darwinn/firmware/driver/graph/command.cc`

同じファームウェア内には、脆弱性説明と一致する実行経路の文字列も残っている。

- `Inactive power state (%d) was specified in ExecuteGraph command.`
- `Could not parse Command flatbuffer.`
- `Flatbuffer verification failed (address=%p, size=%u).`
- `Size of buffers (%d) does not match size of metadata (%d).`
- `Tensor length (%lu) causes overflow for %s.`
- `Resolved tensor shape will require a larger buffer (%u bytes) than set (%u bytes).`

このため、修正は単なるホスト側API変更ではなく、EdgeTPU firmwareのグラフ実行コマンド処理における入力バッファ検証強化と判断した。

## 根本原因

根本原因は、`ExecuteGraph` が受け取るグラフ実行要求の buffer count / buffer size が信頼境界を越えているにもかかわらず、firmware側で安全に合計・変換・上限制約していなかったこと。

特に `input_count + output_count` のような合計、または64-bit/flatbuffer由来のサイズ値から `size_t`/内部配列サイズへの変換でオーバーフローが起きると、firmwareは実際より小さい descriptor/metadata 領域を確保または参照する。その後、各 input/output buffer を登録するループが攻撃者指定の個数分だけ書き込み、確保済み領域の外へ書く。

June firmwareで追加された `Too many input ... output ... buffers` は buffer数合計側の上限チェック、`Buffer size is greater than ... size_t` はサイズ変換側の上限チェックに対応すると見てよい。

## 攻撃条件と影響

OSVによると攻撃にはroot権限が必要で、ユーザー操作は不要。root権限を得たローカル攻撃者が、EdgeTPU/tachyonサービスまたはデバイスインターフェース経由で細工した graph execution command / flatbuffer / buffer metadata をfirmwareへ渡すことで、EdgeTPU firmware側のメモリ破壊を起こせる。

Androidアプリから直接到達する通常の権限昇格ではなく、rootからPixel固有firmware/EdgeTPU実行環境へ境界を越えるタイプのEoPと考える。

## 面白い点・調査メモ

- `vendor.img` はAndroid sparseではなく、そのまま読めるext系イメージだった。ローカルに `debugfs` はなかったため、Pythonの既存 `ext4` モジュールで抽出した。
- GoogleのFactory Imagesページは同意後に表を動的表示する形式だったため、`wuxianlin/get_android_data` のCSVで完全なFactory ZIP名とSHA-256を確認し、公式 `dl.google.com` URLへ置換して使った。
- `edgetpu-rio.fw` は `file` では正しく識別されないが、文字列には `third_party/darwinn/firmware/...` のパスと詳細なassert/errorが残っており、パッチ箇所の推定に有用だった。
- `libedgetpu_tachyon.google.so` にはJuneで `BeginCommandQueueWrite/CommitCommandQueueWrite/BeginResponseQueueRead` などのFMQ APIが追加されているが、OSVがfirmwareの`ExecuteGraph` handlerを指していること、またfirmware側に上記の整数/個数チェック文字列が追加されていることから、CVE本体は `edgetpu-rio.fw` 側と判断した。

## 付帯ファイル

- `artifacts/PUB-A-494623587.osv.json`: OSV JSON
- `artifacts/factory_image_urls.txt`: 解析に使ったFactory image URL/SHA-256
- `artifacts/range_nested_zip.py`: Factory ZIPのRange抽出補助
- `artifacts/ext4_extract.py`: `vendor.img` からのファイル抽出補助
- `artifacts/shiba_vendor_tpu_filelist.diff`: EdgeTPU関連ファイル一覧diff
- `artifacts/extracted_edgetpu_sha256.txt`: 抽出したEdgeTPU関連ファイルのSHA-256
- `artifacts/edgetpu-rio_strings.diff`: firmware文字列diff
- `artifacts/edgetpu-rio_strings_added.txt`: Juneで追加されたfirmware文字列
- `artifacts/edgetpu-rio_strings_diff_executegraph_region.txt`: `ExecuteGraph` 近傍の差分抜粋
- `artifacts/edgetpu-rio_binary_delta_summary.txt`: `edgetpu-rio.fw` のサイズ/差分範囲概要
- `artifacts/libedgetpu_tachyon_strings.diff`: tachyonライブラリ文字列diff
- `../binaries/pixel_factory/shiba-cp1a.260505.005/vendor.img`: May `vendor.img`
- `../binaries/pixel_factory/shiba-cp2a.260605.012/vendor.img`: June `vendor.img`
085 OK

CVE-2026-0128

085-ok-rtcp-feedback-fci-length-underflow-id

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
Subcomponentlibpixelimsmedia
TypeID
SeverityHigh
ReferencesA-481300795
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0128 is listed in the Pixel Update Bulletin as a High severity ID issue in Pixel / libpixelimsmedia.

特定した具体的な脆弱性

特定できた。CVE-2026-0128 は Pixel libpixelimsmedia の RTCP feedback packet decode 処理にある remote information disclosure で、実体は RtcpFbPacket::decodeRtcpFbPacket() の 16-bit 長さ underflow による out-of-bounds read である。

根本原因は、RTCP feedback packet body が必須フィールドである media SSRC 4 バイトを含むか確認する前に、RtpDt_UInt16 usRtcpFbLen から RTP_WORD_SIZE を減算していること。usRtcpFbLen < 4 の malformed RTPFB/PSFB packet では usRtcpFbLen -= 4 が 16-bit wrap し、RtpBuffer(usRtcpFbLen, pucRtcpFbBuf + 4) が実際の packet 境界を越えて最大 65535 バイト近くを memcpy で読み出す。

原因

記載なし。

どこから特定したか

参照情報: ・Pixel bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- 保存: artifacts/public/pixel-bulletin-2026-06-01.html
- 該当行: CVE-2026-0128 A-481300795 * ID High libpixelimsmedia
- * は Android bug が非公開で、更新は通常 Pixel binary driver 側に含まれるという説明あり。
・OSV: https://osv.dev/vulnerability/PUB-A-481300795
- 保存: artifacts/public/PUB-A-48…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https://osv.dev/vulnerability/PUB-A-481300795` / https://cveawg.mitre.org/api/cve/CVE-2026-0128` / https://nvd.nist.gov/vuln/detail/CVE-2026-0128`

validated.md を表示
# CVE-2026-0128 検証メモ

## 結論

特定できた。CVE-2026-0128 は Pixel `libpixelimsmedia` の RTCP feedback packet decode 処理にある remote information disclosure で、実体は `RtcpFbPacket::decodeRtcpFbPacket()` の 16-bit 長さ underflow による out-of-bounds read である。

根本原因は、RTCP feedback packet body が必須フィールドである `media SSRC` 4 バイトを含むか確認する前に、`RtpDt_UInt16 usRtcpFbLen` から `RTP_WORD_SIZE` を減算していること。`usRtcpFbLen < 4` の malformed RTPFB/PSFB packet では `usRtcpFbLen -= 4` が 16-bit wrap し、`RtpBuffer(usRtcpFbLen, pucRtcpFbBuf + 4)` が実際の packet 境界を越えて最大 65535 バイト近くを `memcpy` で読み出す。

## 既存 cve.md から確認した情報

- CVE: `CVE-2026-0128`
- Bulletin: Pixel Update Bulletin
- Bulletin URL: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- Published/updated: 2026-06-16
- Security patch level: 2026-06-05 or later
- Component/Subcomponent: Pixel / `libpixelimsmedia`
- Type/Severity: ID / High
- Reference: `A-481300795`

## 参照情報

- Pixel bulletin: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
  - 保存: `artifacts/public/pixel-bulletin-2026-06-01.html`
  - 該当行: `CVE-2026-0128 A-481300795 * ID High libpixelimsmedia`
  - `*` は Android bug が非公開で、更新は通常 Pixel binary driver 側に含まれるという説明あり。
- OSV: `https://osv.dev/vulnerability/PUB-A-481300795`
  - 保存: `artifacts/public/PUB-A-481300795.json`, `artifacts/public/PUB-A-481300795.pretty.json`
  - Details: `In RtcpFbPacket::decodeRtcpFbPacket, there is a possible out of bounds read due to an integer overflow...`
  - Fixed: `Pixel-family specific:2026-06-05`
- CVE Record API: `https://cveawg.mitre.org/api/cve/CVE-2026-0128`
  - 保存: `artifacts/public/CVE-2026-0128-cveawg.json`, `artifacts/public/CVE-2026-0128-cveawg.pretty.json`
  - OSV と同じ関数名・原因・影響が記載されている。
- NVD: `https://nvd.nist.gov/vuln/detail/CVE-2026-0128`
  - 保存: `artifacts/public/nvd-CVE-2026-0128.html`
  - 取得時点では軽量 HTML だけで詳細文字列は確認できなかった。
- Patch diffing 参考: `https://www.originhq.com/research/patch-diffing-pipeline`
  - 保存: `artifacts/public/originhq-patch-diffing-pipeline.html`

## 調査対象

- AOSP source clone: `/Users/eric/workspace/android/binaries/platform_packages_modules_ImsMedia.git`
- HEAD: `6da37b8ef8bde01956e630bb42a31a40fc1ddba3`
- 保存したソース:
  - `artifacts/source/RtcpFbPacket.cpp`
  - `artifacts/source/RtcpPacket.cpp`
  - `artifacts/source/RtpBuffer.cpp`
  - `artifacts/source/RtpBuffer.h`
  - `artifacts/source/ImsMedia_HEAD.txt`
- 既存ローカル blob:
  - `074-CVE-2026-0149-Pixel-libpixelimsmedia-RCE-Critical/blobs/libpixelimsmedia_lineage-23.1.so`
  - `074-CVE-2026-0149-Pixel-libpixelimsmedia-RCE-Critical/blobs/libpixelimsmedia_lineage-23.2.so`
  - SHA-256 は `artifacts/analysis/blob_sha256.txt` に保存。

## ソースコード上の問題点

`RtcpPacket::decodeRtcpPacket()` は RTCP common header を読んだ後、RTCP packet length から common header 4 バイトを引いた値を `usPktLen` として各 packet decoder へ渡す。

```cpp
RtpDt_UInt16 usPktLen = m_objHeader.getLength();
usPktLen -= RTP_WORD_SIZE;
if (usPktLen > iTrackCompLen) {
    return RTP_INVALID_MSG;
}
...
case RTCP_RTPFB:
case RTCP_PSFB:
    eDecodeRes = pobjFbPkt->decodeRtcpFbPacket(pucBuffer, usPktLen);
```

`RtcpFbPacket::decodeRtcpFbPacket()` は、その `usRtcpFbLen` が `media SSRC` 4 バイトを含むか検査せずに読み取りと減算を行う。

```cpp
RtpDt_UInt32 uiMediaSsrc = RtpOsUtil::Ntohl(*(reinterpret_cast<RtpDt_UInt32*>(pucRtcpFbBuf)));
setMediaSsrc(uiMediaSsrc);
pucRtcpFbBuf += RTP_WORD_SIZE;
usRtcpFbLen -= RTP_WORD_SIZE;

if (usRtcpFbLen > 0) {
    RtpBuffer* pFCI = new RtpBuffer(usRtcpFbLen, reinterpret_cast<RtpDt_UChar*>(pucRtcpFbBuf));
    setFCI(pFCI);
}
```

`RtpBuffer` のコンストラクタは指定長で heap buffer を確保し、入力 pointer からその長さをそのまま `memcpy` する。

```cpp
m_uiLength = uiLength;
m_pBuffer = new RtpDt_UChar[m_uiLength];
memcpy(m_pBuffer, pBuffer, m_uiLength);
```

したがって `usRtcpFbLen` が 0, 1, 2, 3 の状態で `decodeRtcpFbPacket()` に入ると、減算後の値は 65532, 65533, 65534, 65535 になる。算術メモは `artifacts/analysis/underflow_arithmetic.txt` に保存した。

## 攻撃条件の復元

1. Pixel の IMS media RTP/RTCP 受信経路で `RtcpPacket::decodeRtcpPacket()` が呼ばれる。
2. 攻撃者が RTCP packet type `RTCP_RTPFB` 205 または `RTCP_PSFB` 206 の packet を送る。
3. RTCP common header の length field を短くし、feedback body が `media SSRC` 4 バイト未満になるようにする。
4. 上位 parser は `while (iTrackCompLen >= RTCP_FIXED_HDR_LEN)` のため、実 packet が少なくとも 8 バイトあれば feedback decoder へ到達できる。
5. `RtcpFbPacket::decodeRtcpFbPacket()` は `media SSRC` を読むために 4 バイト読み、その後 `usRtcpFbLen -= 4` を実行する。`usRtcpFbLen` が 0 の代表例では 65532 へ wrap する。
6. `RtpBuffer` が `pucRtcpFbBuf + 4` から 65532 バイトを `memcpy` し、受信 RTCP packet 末尾を大きく越えてプロセス内メモリを読み出す。

RTCP feedback packet の仕様上は sender SSRC と media SSRC が必要で、実装内でも `RtcpHeader::decodeRtcpHeader()` が sender SSRC を common body として読む設計になっている。`RTCP_RTPFB` / `RTCP_PSFB` では少なくとも common header 4 バイト + sender SSRC 4 バイト + media SSRC 4 バイトが必要だが、実装は feedback decoder 入口で `media SSRC` 分の最小長を確認していない。

## バイナリ確認

`nm -D -C` で既存 blob に以下の dynamic symbol が残っていることを確認した。

- `RtcpFbPacket::decodeRtcpFbPacket(unsigned char*, unsigned short)`
- `RtcpFbPacket::formRtcpFbPacket(RtpBuffer*)`
- `RtcpPacket::addFbPacketData(RtcpFbPacket*)`
- `RtpSession::populateRtcpFbPacket(...)`

保存:

- `artifacts/analysis/symbols_23.1.txt`
- `artifacts/analysis/symbols_23.2.txt`
- `artifacts/analysis/symbol_addresses.txt`

逆アセンブル:

- `artifacts/analysis/RtcpFbPacket_decode_23.1.objdump.txt`
- `artifacts/analysis/RtcpFbPacket_decode_23.2.objdump.txt`
- `artifacts/analysis/RtcpFbPacket_decode_23.1_vs_23.2.diff`

`lineage-23.2` の該当部分:

```text
16c794: ldr w0, [x1]                 ; media SSRC を読む
16c798: mov w21, w2                  ; usRtcpFbLen
16c7a4: sub w22, w21, #0x4           ; usRtcpFbLen - 4
16c7ac: tst w22, #0xffff             ; 下位16bitが0なら FCI なし
16c7bc: and w1, w22, #0xffff         ; wrapped length を RtpBuffer 長へ
16c7c0: add x2, x20, #0x4            ; copy source = packet body + 4
16c7c8: bl RtpBuffer::RtpBuffer(unsigned int, unsigned char*)
```

`usRtcpFbLen < 4` を弾く `cmp w21, #4; b.lo error` のような分岐はない。`23.1` と `23.2` の差分はアドレスや PLT 参照差が中心で、この関数の脆弱な算術は同じだった。これは Pixel 2026-06 の公式 pre/post patch diff ではないが、OSV/CVE Record が示す関数と AOSP ソースの弱点が、実 blob の機械語にも存在することを確認する材料になる。

## 面白い点・調査メモ

- 公開 bulletin の subcomponent は `libpixelimsmedia` だけだが、OSV/CVE Record は `RtcpFbPacket::decodeRtcpFbPacket` まで具体化している。Pixel binary driver 側の `*` 非公開 bug でも、OSV から root cause にかなり近い情報を取れる。
- `RtcpHeader::decodeRtcpHeader()` は length field を `word count * 4` として保存しており、RTCP 仕様の “minus one” を完全には反映していないように見える。既存実装全体では `formPartialRtcpHeader()` 側も独自に `length / 4 - 1` しており、受信側では `decodeRtcpPacket()` がさらに `RTP_WORD_SIZE` を引く。長さの意味が複数箇所で変換されるため、最小長検査漏れが起きやすい構造になっている。
- `RtcpFbPacket::decodeRtcpFbPacket()` は関数冒頭で `pucRtcpFbBuf` 自体の null check もなく、長さ 0 でも `ldr/Net-to-host` 相当で 4 バイトを読む。OOB read は FCI copy だけでなく、media SSRC 読み取り時点でも起き得る。
- `RtpBuffer` は `(length, pointer)` を受けると必ず private copy を作るが、入力 pointer の実残長は受け取らない。境界検査責務が全て caller にある設計で、今回のような caller 側の underflow が直接 OOB read になる。
- 手元の Lineage 23.1/23.2 blob は本関数については修正済み差分を含んでいなかった。Pixel 2026-06 の公式 fixed blob diff は取得できていないため、patch hunk そのものではなく、公開 details + ソース + バイナリ挙動からの特定である。

## 修正方針

安全な修正は少なくとも以下を満たす必要がある。

- `RtcpPacket::decodeRtcpPacket()` で RTCP length field と実 compound packet 残長の整合を、underflow しない広い型で検査する。
- `RTCP_RTPFB` / `RTCP_PSFB` は `decodeRtcpFbPacket()` に渡す前、または同関数冒頭で `usRtcpFbLen >= RTP_WORD_SIZE` を必ず確認する。
- `RtcpFbPacket::decodeRtcpFbPacket()` は `pucRtcpFbBuf == nullptr` と `usRtcpFbLen < RTP_WORD_SIZE` を reject してから `media SSRC` を読む。
- `RtpBuffer(length, pointer)` のような copy API は、可能なら入力の実残長も受け取り、caller の長さ算術だけに依存しない形にする。

## 生成した付帯ファイル

- `artifacts/public/PUB-A-481300795.json`
- `artifacts/public/CVE-2026-0128-cveawg.json`
- `artifacts/public/pixel-bulletin-2026-06-01.html`
- `artifacts/public/originhq-patch-diffing-pipeline.html`
- `artifacts/source/RtcpFbPacket.cpp`
- `artifacts/source/RtcpPacket.cpp`
- `artifacts/source/RtpBuffer.cpp`
- `artifacts/analysis/RtcpFbPacket_decode_23.1.objdump.txt`
- `artifacts/analysis/RtcpFbPacket_decode_23.2.objdump.txt`
- `artifacts/analysis/underflow_arithmetic.txt`
- `artifacts/analysis/rtcp_feedback_minlen_notes.txt`
- `artifacts/artifacts_sha256.txt`

## 判定

`ok`

理由: OSV/CVE Record が具体関数 `RtcpFbPacket::decodeRtcpFbPacket` と integer overflow / OOB read / remote ID を明示しており、AOSP ソースと既存 `libpixelimsmedia` blob の逆アセンブルから、短い RTCP feedback packet による 16-bit underflow、巨大長 `RtpBuffer` copy、packet 境界外読み取りという脆弱性発生条件と根本原因を説明できた。
086 OK

CVE-2026-0129

086-ok-rtcp-bye-reason-oob-read-id

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
Subcomponentlibpixelimsmedia
TypeID
SeverityHigh
ReferencesA-481287452
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0129 is listed in the Pixel Update Bulletin as a High severity ID issue in Pixel / libpixelimsmedia.

特定した具体的な脆弱性

CVE-2026-0129 は、Pixel libpixelimsmedia の RtcpByePacket::decodeByePacket がRTCP BYE reason lengthを検証せず、かつ1バイトlength fieldを4バイトロードで読むことに起因する out-of-bounds read / remote information disclosure である。細工したRTCP BYE packetで理由文字列長を実データより大きくすると、packet末尾を越えたメモリが memcpy で RtpBuffer に取り込まれる。根本原因は、外部入力由来の可変長フィールドに対する残長チェック欠落である。

原因

RtcpByePacket::decodeByePacket(unsigned char*, unsigned short) は RTCP BYE packet body を decode する。BYE body は SSRC/CSRC list の後ろに、任意で 1 byte reason length + reason string を持てる。

問題のコードは以下。

どこから特定したか

参照情報と保存物: ・Pixel bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- 保存: artifacts/pixel-bulletin-2026-06-01.html
- 該当行: CVE-2026-0129 A-481287452 * ID High libpixelimsmedia
- Bulletin上の * は Android bug が非公開で、修正が通常 Pixel binary driver 側に含まれることを示す。
・OSV JSON: https://storage.googleapis.com/android-osv/PUB-A-481287452.json
- 保存:…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https://storage.googleapis.com/android-osv/PUB-A-481287452.json` / https://nvd.nist.gov/vuln/detail/CVE-2026-0129` / https://www.originhq.com/research/patch-diffing-pipeline`

validated.md を表示
# CVE-2026-0129 検証結果

## 判定

`ok`: 脆弱性の発生条件と根本原因を、公開OSV/NVD説明、AOSPソース、ローカル `libpixelimsmedia` 逆アセンブルから特定できた。

タイトル: `rtcp-bye-reason-oob-read-id`

## 既存 cve.md から確認した情報

- CVE: `CVE-2026-0129`
- Reference: `A-481287452`
- Bulletin: Pixel Update Bulletin
- Bulletin URL: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- Published/updated: `June 16, 2026`
- Security patch level: `2026-06-05 or later`
- Component/Subcomponent: `Pixel / libpixelimsmedia`
- Type/Severity: `ID / High`

## 参照情報と保存物

- Pixel bulletin: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
  - 保存: `artifacts/pixel-bulletin-2026-06-01.html`
  - 該当行: `CVE-2026-0129 A-481287452 * ID High libpixelimsmedia`
  - Bulletin上の `*` は Android bug が非公開で、修正が通常 Pixel binary driver 側に含まれることを示す。
- OSV JSON: `https://storage.googleapis.com/android-osv/PUB-A-481287452.json`
  - 保存: `PUB-A-481287452.json`, `artifacts/PUB-A-481287452.json`
  - details: `In RtcpByePacket::decodeByePacket, there is a possible due to a missing bounds check... remote information disclosure...`
- NVD: `https://nvd.nist.gov/vuln/detail/CVE-2026-0129`
  - HTML保存は403で失敗したが、検索結果およびページ概要でOSVと同じ `RtcpByePacket::decodeByePacket` / missing bounds check / remote information disclosure が確認できた。
- Origin patch-diffing pipeline: `https://www.originhq.com/research/patch-diffing-pipeline`
  - 保存: `artifacts/origin-patch-diffing-pipeline.html`
- AOSP source clone: `/Users/eric/workspace/android/binaries/platform_packages_modules_ImsMedia.git`
  - remote: `https://android.googlesource.com/platform/packages/modules/ImsMedia`
  - HEAD: `6da37b8ef8bde01956e630bb42a31a40fc1ddba3`
  - 保存: `artifacts/ImsMedia_HEAD.txt`, `artifacts/RtcpByePacket.cpp`, `artifacts/RtcpPacket.cpp`, `artifacts/RtpBuffer.cpp`, `artifacts/RtpBuffer.h`
- ローカルバイナリ:
  - `074-CVE-2026-0149-Pixel-libpixelimsmedia-RCE-Critical/blobs/libpixelimsmedia_lineage-23.1.so`
  - `074-CVE-2026-0149-Pixel-libpixelimsmedia-RCE-Critical/blobs/libpixelimsmedia_lineage-23.2.so`
  - 保存: `artifacts/libpixelimsmedia_lineage-23.1.so`, `artifacts/libpixelimsmedia_lineage-23.2.so`
- 逆アセンブル:
  - `artifacts/RtcpByePacket_decodeByePacket_23.1.objdump.txt`
  - `artifacts/RtcpByePacket_decodeByePacket_23.2.objdump.txt`
  - `artifacts/RtcpByePacket_decodeByePacket_23.1_vs_23.2.diff`
- 発生条件メモ:
  - `artifacts/rtcp_bye_oob_read_conditions.txt`
- 推定修正差分:
  - `artifacts/inferred_fix_RtcpByePacket_decodeByePacket.diff`
- 全成果物ハッシュ:
  - `artifacts/SHA256SUMS.txt`

## 根本原因

`RtcpByePacket::decodeByePacket(unsigned char*, unsigned short)` は RTCP BYE packet body を decode する。BYE body は SSRC/CSRC list の後ろに、任意で `1 byte reason length + reason string` を持てる。

問題のコードは以下。

```cpp
if (usByeLen >= RTP_ONE) {
    RtpDt_UInt32 uiByte4Data = RtpOsUtil::Ntohl(*(reinterpret_cast<RtpDt_UInt32*>(pucByeBuf)));
    pucByeBuf = pucByeBuf + RTP_ONE;
    uiByte4Data = uiByte4Data >> RTP_24;  // length of "Reason for leaving"
    if (uiByte4Data > RTP_ZERO) {
        RtpDt_UChar* pucReason = new RtpDt_UChar[uiByte4Data];
        ...
        memcpy(pucReason, pucByeBuf, uiByte4Data);
        m_pReason->setBufferInfo(uiByte4Data, pucReason);
    }
}
```

境界チェックの欠落は2つある。

- reason length は1バイトなのに、`usByeLen >= 1` だけで `*(uint32_t*)pucByeBuf` を読み、残りが1から3バイトでも4バイト読んでしまう。
- length byte を消費した後、`uiByte4Data <= usByeLen - 1` を確認せず `memcpy(pucReason, pucByeBuf, uiByte4Data)` する。

そのため、短いBYE packetの末尾に大きい reason length を置くと、受信packet境界を越えてメモリを読み、`RtpBuffer` に保存する。根本原因は、外部入力である BYE reason length と残りpacket長の整合性を検証していないこと、および1バイトフィールド取得に4バイトロードを使っていること。

## 脆弱性の発生条件

最小条件は以下。

1. `RtcpPacket::decodeRtcpPacket()` が RTCP packet type `RTCP_BYE` を処理し、`RtcpByePacket::decodeByePacket(pucBuffer, usPktLen)` にBYE body pointerとbody長を渡す。
2. BYE body内のSSRC/CSRC処理後、残り `usByeLen` が1以上ある。
3. その先頭1バイトが reason length として0より大きい。
4. 実際の残り reason bytes がその length より短い。

具体例:

- `usByeLen = 1`, `body[0] = 0xff`: 4バイトロード自体がpacket末尾を越え、さらに255バイトを `memcpy` しようとする。
- `usByeLen = 2`, `body = {0x02, 'A'}`: reason bytes は1バイトしかないのに2バイトコピーする。
- SSRC list後でも同じで、例えば1個SSRCを読んだ後に残り1バイトだけ reason length を置けば成立する。

このOOB read結果は `m_pReason` の `RtpBuffer` として保持される。OSV/NVDが remote information disclosure としているのは、IMS/RTCP経路で細工したBYE packetを処理させることで、packet隣接メモリを理由文字列として取り込ませられるためだと解釈できる。User interaction required は、IMS media session成立などユーザー操作を伴う通信状態が必要という意味と考えられる。

## バイナリ確認

`nm -D -C` で両方の `libpixelimsmedia` に以下のdynamic symbolを確認した。

- 23.1: `0x16eee0 RtcpByePacket::decodeByePacket(unsigned char*, unsigned short)`
- 23.2: `0x16e040 RtcpByePacket::decodeByePacket(unsigned char*, unsigned short)`

23.2の逆アセンブルでは該当部分が次の流れになっていた。

```text
16e0f8: tst w21, #0xffff        ; usByeLen != 0 だけを見る
16e100: ldr w0, [x19]           ; 4バイトロード
16e108: lsr w21, w0, #24        ; 先頭1バイトをreason lengthにする
16e10c: cbz w21, ...
16e110: mov x0, x21
16e114: bl _Znam                ; reason length分を確保
16e140: add x1, x19, #0x1       ; コピー元はlength byteの次
16e148: mov x2, x21
16e14c: bl memcpy               ; 残り長との比較なし
```

この間に `reason_len <= usByeLen - 1` 相当の比較分岐はない。23.1も同じ構造だった。Lineage 23.1/23.2 はPixel June 2026公式pre/postそのものではないため、ここで見えた差分はアドレス差中心で、修正済みPixelバイナリのpatch diffではない。ただし、公開ソースの脆弱な実装と同じ機械語パターンが `libpixelimsmedia` に存在することは確認できた。

## 公開ブランチ確認

`RtcpByePacket.cpp` は以下の参照で同じSHA256だった。

- `origin/android16-release`
- `origin/android16-security-release`
- `origin/android17-release`
- `origin/main`
- `android-16.0.0_r4`
- `android-security-16.0.0_r7`

保存: `artifacts/RtcpByePacket_branch_sha256.txt`, `artifacts/RtcpByePacket_branch_excerpt.txt`

公開AOSPブランチ上にはこの修正は確認できなかった。Bulletinの `*` 注記どおり、CVE-2026-0129 の実修正はPixel-family specific binary update側に含まれた可能性が高い。

## 推定される修正

安全な修正は以下。

- SSRC/CSRC count分の4バイト要素を処理する前に、body残長が足りなければ reject する。
- reason length は1バイトとして読む。4バイトロードしない。
- length byteを消費した後、`reason_len <= remaining_body_len` を検査する。
- `memcpy` は検査後にだけ実行する。

`artifacts/inferred_fix_RtcpByePacket_decodeByePacket.diff` に最小修正案を保存した。これは非公開Pixelパッチそのものではなく、確認した根本原因を塞ぐための推定差分である。

## 面白い点・調査メモ

- OSVのdetailsは `possible  due to` のように種別名が欠落しているが、CVE typeはIDで、関数名とmissing bounds checkは明示されている。
- `RtcpByePacket::decodeByePacket` のSSRC loop条件が `ucSsrcCnt > RTP_ONE` になっており、RTCP BYEのsource countが1のときSSRCを読まないように見える。今回のIDの主因ではないが、RTCP BYE parser全体の入力検証が弱い兆候として気になる。
- `RtpBuffer::setBufferInfo()` は長さとポインタを保存するだけで、元packet境界の概念を持たない。decode時に境界を失う設計なので、各packet decoder側で厳密に残長を管理する必要がある。
- 近傍の同月 `libpixelimsmedia` CVE群は、RTCP/RTP decoderの整数・境界チェック不備が多い。今回も同じクラスの parser bug だった。

## 結論

CVE-2026-0129 は、Pixel `libpixelimsmedia` の `RtcpByePacket::decodeByePacket` がRTCP BYE reason lengthを検証せず、かつ1バイトlength fieldを4バイトロードで読むことに起因する out-of-bounds read / remote information disclosure である。細工したRTCP BYE packetで理由文字列長を実データより大きくすると、packet末尾を越えたメモリが `memcpy` で `RtpBuffer` に取り込まれる。根本原因は、外部入力由来の可変長フィールドに対する残長チェック欠落である。
087 OK

CVE-2026-0130

087-ok-libpixelimsmedia-rtcp-sdes-oob-read

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
Subcomponentlibpixelimsmedia
TypeID
SeverityHigh
ReferencesA-479203197
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0130 is listed in the Pixel Update Bulletin as a High severity ID issue in Pixel / libpixelimsmedia.

特定した具体的な脆弱性

特定できた。CVE-2026-0130 は Pixel の libpixelimsmedia.so に含まれる RtcpChunk::decodeRtcpChunk の RTCP SDES chunk parser における境界チェック不足で、細工された RTCP SDES item により入力 RTCP packet の末尾を越えて heap buffer から読み出す脆弱性だった。

根本原因は、呼び出し元 RtcpSdesPacket::decodeSdesPacket() が SDES packet 残り長 usSdesLen を保持しているにもかかわらず、旧 RtcpChunk::decodeRtcpChunk() の API が「消費済み長 usChunkLen」しか受け取らず、type、length、value[length] を読む時点で入力残量と照合できない設計になっていたこと。特に length byte を信頼して memcpy(pcSdesBuf, pucChunkBuf, pstSdesItem->ucLength) を実行するため、ucLength > remaining の SDES item で OOB read が起きる。

原因

記載なし。

どこから特定したか

公開情報: ・対象: 087-ok-libpixelimsmedia-rtcp-sdes-oob-read/cve.md
・Bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
・OSV: https://storage.googleapis.com/android-osv/PUB-A-479203197.json
・CVE: CVE-2026-0130
・Bug/Ref: A-479203197
・Component/Subcomponent: Pixel / libpixelimsmedia
・Type/Severity: ID / High
・SPL fixed: 2026-06-05
・OSV detai…

解析対象と保存物: ・既存 OTA:
- ../binaries/pixel_shiba_ota/shiba-ota-cp2a.260605.012-b315a1a2.zip
- ../binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip は central directory 不整合があり、May 版 system_ext 抽出には使えなかった。
・抽出した June partition image:
- ../binaries/pixel_shiba_imsmedia_cve0130/june/system_ext.img
- ../binaries/pixel_shiba_imsmedia_cve0130/june/produc…

URL: https://source…

validated.md を表示
# CVE-2026-0130 / A-479203197 検証メモ

## 結論

特定できた。CVE-2026-0130 は Pixel の `libpixelimsmedia.so` に含まれる `RtcpChunk::decodeRtcpChunk` の RTCP SDES chunk parser における境界チェック不足で、細工された RTCP SDES item により入力 RTCP packet の末尾を越えて heap buffer から読み出す脆弱性だった。

根本原因は、呼び出し元 `RtcpSdesPacket::decodeSdesPacket()` が SDES packet 残り長 `usSdesLen` を保持しているにもかかわらず、旧 `RtcpChunk::decodeRtcpChunk()` の API が「消費済み長 `usChunkLen`」しか受け取らず、`type`、`length`、`value[length]` を読む時点で入力残量と照合できない設計になっていたこと。特に `length` byte を信頼して `memcpy(pcSdesBuf, pucChunkBuf, pstSdesItem->ucLength)` を実行するため、`ucLength > remaining` の SDES item で OOB read が起きる。

## 公開情報

- 対象: `087-ok-libpixelimsmedia-rtcp-sdes-oob-read/cve.md`
- Bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- OSV: https://storage.googleapis.com/android-osv/PUB-A-479203197.json
- CVE: `CVE-2026-0130`
- Bug/Ref: `A-479203197`
- Component/Subcomponent: `Pixel / libpixelimsmedia`
- Type/Severity: `ID / High`
- SPL fixed: `2026-06-05`
- OSV detail: `RtcpChunk::decodeRtcpChunk` で heap buffer overflow による out-of-bounds read。追加権限不要、悪用には user interaction が必要。

保存した公開情報:

- `bulletin_extract.txt`
- `osv_PUB-A-479203197.json`
- `osv_PUB-A-479203197.pretty.json`

## 解析対象と保存物

- 既存 OTA:
  - `../binaries/pixel_shiba_ota/shiba-ota-cp2a.260605.012-b315a1a2.zip`
  - `../binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip` は central directory 不整合があり、May 版 `system_ext` 抽出には使えなかった。
- 抽出した June partition image:
  - `../binaries/pixel_shiba_imsmedia_cve0130/june/system_ext.img`
  - `../binaries/pixel_shiba_imsmedia_cve0130/june/product.img`
  - `../binaries/pixel_shiba_imsmedia_cve0130/june/vendor.img`
- 抽出した June library:
  - `libs/june/libpixelimsmedia.so`
  - SHA-256: `22a5ff6cb128f68a9fbba7b96535c3732297a32a6e2fddb51d2c009e39e8df9d`
  - ELF: ARM64 shared object, BuildID `9805086f2f4b604be8076a9be5740ed6`
- 解析出力:
  - `june_symbols.txt`
  - `june_strings_rtcpchunk.txt`
  - `source_RtcpChunk_android16-release_vulnerable.cpp`
  - `source_RtcpChunk_android16-release_vulnerable.h`
  - `inferred_patch_decodeRtcpChunk.diff`

## 脆弱コード

公開 `packages/modules/ImsMedia` の `origin/android16-release` では `RtcpChunk::decodeRtcpChunk` は次の形になっている。

- `decodeRtcpChunk(RtpDt_UChar* pucChunkBuf, RtpDt_UInt16& usChunkLen, RtcpConfigInfo* pobjRtcpCfgInfo)`
- ループ回数は packet 内の SDES END ではなく `pobjRtcpCfgInfo->getSdesItemCount()` に依存。
- `type` を 1 byte 読む前に残量確認なし。
- `length` を 1 byte 読む前に残量確認なし。
- `length` byte 分を `new RtpDt_UChar[length]` で確保した後、`memcpy(pcSdesBuf, pucChunkBuf, length)` するが、`length <= remaining` の確認がない。

該当箇所は `source_RtcpChunk_android16-release_vulnerable.cpp` に保存した。重要行は以下。

- `73`: `pstSdesItem->ucType = *pucChunkBuf`
- `82`: `pstSdesItem->ucLength = *pucChunkBuf`
- `97`: `memcpy(pcSdesBuf, pucChunkBuf, pstSdesItem->ucLength)`

呼び出し元 `RtcpSdesPacket::decodeSdesPacket()` には `usSdesLen` があり、`pucSdesBuf += usChunkSize; usSdesLen -= usChunkSize;` で chunk 単位の消費管理をしている。しかし旧 API は `usSdesLen` を `RtcpChunk` に渡さないため、item 単位では境界を検証できない。

## June バイナリで見えた修正

June OTA の `system_ext.img` から抽出した `/lib64/libpixelimsmedia.so` では、動的シンボルが次のように変わっていた。

- 旧公開ソース相当: `RtcpChunk::decodeRtcpChunk(unsigned char*, unsigned short&, RtcpConfigInfo*)`
- June バイナリ: `RtcpChunk::decodeRtcpChunk(unsigned char*, unsigned short, unsigned short&, RtcpConfigInfo*)`

つまり、追加の `unsigned short` 引数が増えており、これは `RtcpSdesPacket::decodeSdesPacket()` が持つ `usSdesLen` を渡すための修正と一致する。

さらに June バイナリには以下の修正ログ文字列が入っていた。

- `[decodeRtcpChunk] OOB read : SDES item type length, available: %d, needed: %d`
- `[decodeRtcpChunk] OOB read: SDES item value, available: %d, needed: %d`
- `[decodeRtcpChunk] invalid arguments`
- `[decodeRtcpChunk] SDES End`

このため修正内容は、`type/length` の 2 bytes を読む前の残量チェック、`value[length]` をコピーする前の残量チェック、null/invalid argument チェック、SDES END item 処理追加だと判断した。復元した推定差分は `inferred_patch_decodeRtcpChunk.diff` に保存した。

## 攻撃条件と再現し得る入力

RTCP が有効な IMS media session で、攻撃者が受信側に細工した RTCP SDES packet を届けられる状況が必要。OSV の user interaction 条件から、通話/ビデオ通話/RCS 等の media session 確立が必要なリモート入力として扱われていると考えられる。

最小条件は以下。

- RTCP packet type が `RTCP_SDES`。
- SDES payload 長は小さいが、SDES item header の `length` が残り payload より大きい。
- 例: `type = 1` (`CNAME`), `length = 0xff`, 実際の残り bytes は 0 または数 byte。

旧コードでは `length` を信頼して 255 bytes を `memcpy` するため、RTCP packet 用 heap buffer の末尾を越えた領域を新規 SDES item buffer にコピーする。`type/length` そのものも、payload が 1 byte で終端する SDES END などでは残量不足のまま読まれ得る。

## 面白かった点・注意点

- Bulletin では `libpixelimsmedia` の ID High とだけ出ているが、OSV には関数名 `RtcpChunk::decodeRtcpChunk` が出ており、ソース探索の決め手になった。
- 公開 AOSP `packages/modules/ImsMedia` の `origin/android16-release` には脆弱な形の `RtcpChunk.cpp` が残っている。一方、Pixel June の `libpixelimsmedia.so` は `vendor/google/services/ImsMedia/.../RtcpChunk.cpp` パスを文字列に含み、Pixel vendor 側で修正されている。
- 修正後バイナリの関数シグネチャは、既存 API に入力全長を足す最小修正になっている。これは root cause が単なる `memcpy` のミスではなく、parser 関数に bounds 情報が渡っていない API 設計だったことを示す。
- June バイナリには `SDES End` 文字列も追加されている。旧公開ソースは `RTCP_SDES_END` を特別扱いせず、END item の後に length を読む作りだったため、SDES 終端処理も修正範囲に含まれる可能性が高い。
- May OTA の既存ファイルは壊れており完全な May バイナリ diff は取れなかった。ただし、公開ソースの脆弱実装、OSV の関数名、June バイナリの追加引数と OOB ログ文字列が一致しているため、脆弱性の根本原因は十分に特定できた。

## 判定

`ok`。ソースコード上の脆弱箇所と、修正後 Pixel バイナリの境界チェック痕跡が一致し、脆弱性が起きる状況と根本原因を説明できる。
088 OK

CVE-2026-0140

088-ok-rtp-extension-length-overflow-oob-read

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
Subcomponentlibpixelimsmedia
TypeID
SeverityHigh
ReferencesA-479211693
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0140 is listed in the Pixel Update Bulletin as a High severity ID issue in Pixel / libpixelimsmedia.

特定した具体的な脆弱性

CVE-2026-0140 は、Pixel libpixelimsmedia の RtpPacket::decodePacket が RTP header extension length を 16-bit 幅のまま加算・乗算し、境界チェック前に truncate/wrap させることに起因する out-of-bounds read / remote information disclosure である。攻撃者が巨大な extension length を宣言した RTP packet を処理させると、本来 reject すべき packet が短い extension として受理され、parser の読み取り位置と payload 切り出しが RTP packet 構造からずれる。根本原因は、外部入力長に対する narrow integer arithmetic と、残長ベースでない境界チェックである。

原因

RtpPacket::decodePacket(RtpBuffer*) は RTP fixed header を decode した後、RTP header extension bit が立っている場合に extension header の 16-bit length field を読み、extension 全体のバイト長へ変換する。

問題の処理は以下。

``cpp
RtpDt_UInt32 uiByte4Data = RtpOsUtil::Ntohl(*(reinterpret_cast<RtpDt_UInt32*>(pcRtpBuf)));
RtpDt_UInt16 uXHdrLen =
(RtpDt_UInt16)(uiByte4Data & RTP_HEX_16_BIT_MAX);

uXHdrLen += 1;
uXHdrLen *= RTP_WORD_SIZE;

if ((uXHdrLen <= 0) || ((uiRtpBufPos + uXHdrLen) > uiRtpUtlBufLen)) {
return eRTP_FAILURE;
}
`

どこから特定したか

参照情報と保存物: ・Pixel bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- 保存: artifacts/pixel-bulletin-2026-06-01.html
- 該当行: CVE-2026-0140 A-479211693 * ID High libpixelimsmedia
- * は Android bug が非公開で、通常 Pixel binary driver 側で修正されることを示す。
・Android OSV JSON: https://storage.googleapis.com/android-osv/PUB-A-479211693.json
- 保存: PUB-A…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https://storage.googleapis.com/android-osv/PUB-A-479211693.json` / https://www.originhq.com/research/patch-diffing-pipeline` / https://android.googlesource.com/platform/packages/modules/ImsMedia`

validated.md を表示
# CVE-2026-0140 検証結果

## 判定

`ok`: 公開OSVが示す関数名と欠陥種別、AOSPソース、ローカル `libpixelimsmedia` 逆アセンブルから、脆弱性の発生条件と根本原因を特定できた。

タイトル: `rtp-extension-length-overflow-oob-read`

## 既存 cve.md から確認した情報

- CVE: `CVE-2026-0140`
- Reference: `A-479211693`
- Bulletin: Pixel Update Bulletin
- Bulletin URL: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- Published/updated: `June 16, 2026`
- Security patch level: `2026-06-05 or later`
- Component/Subcomponent: `Pixel / libpixelimsmedia`
- Type/Severity: `ID / High`

## 参照情報と保存物

- Pixel bulletin: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
  - 保存: `artifacts/pixel-bulletin-2026-06-01.html`
  - 該当行: `CVE-2026-0140 A-479211693 * ID High libpixelimsmedia`
  - `*` は Android bug が非公開で、通常 Pixel binary driver 側で修正されることを示す。
- Android OSV JSON: `https://storage.googleapis.com/android-osv/PUB-A-479211693.json`
  - 保存: `PUB-A-479211693.json`, `artifacts/PUB-A-479211693.json`
  - details: `RtpPacket::decodePacket` に integer overflow 起因の out-of-bounds read があり、remote information disclosure、追加権限不要、ユーザー操作あり。
- Origin patch-diffing pipeline: `https://www.originhq.com/research/patch-diffing-pipeline`
  - 保存: `artifacts/origin-patch-diffing-pipeline.html`
- AOSP source clone: `/Users/eric/workspace/android/binaries/platform_packages_modules_ImsMedia.git`
  - remote: `https://android.googlesource.com/platform/packages/modules/ImsMedia`
  - HEAD: `6da37b8ef8bde01956e630bb42a31a40fc1ddba3`
  - 保存: `artifacts/ImsMedia_HEAD.txt`, `artifacts/RtpPacket.cpp`, `artifacts/RtpHeader.cpp`, `artifacts/RtpGlobal.h`, `artifacts/RtpPfDatatypes.h`
- ローカルバイナリ:
  - `074-CVE-2026-0149-Pixel-libpixelimsmedia-RCE-Critical/blobs/libpixelimsmedia_lineage-23.1.so`
  - `074-CVE-2026-0149-Pixel-libpixelimsmedia-RCE-Critical/blobs/libpixelimsmedia_lineage-23.2.so`
  - 保存: `artifacts/libpixelimsmedia_lineage-23.1.so`, `artifacts/libpixelimsmedia_lineage-23.2.so`
- 逆アセンブル:
  - `artifacts/RtpPacket_decodePacket_23.1.objdump.txt`
  - `artifacts/RtpPacket_decodePacket_23.2.objdump.txt`
  - `artifacts/RtpPacket_decodePacket_23.1_vs_23.2.diff`
- 推定修正:
  - `artifacts/inferred_fix_RtpPacket_decodePacket.diff`
- 解析メモ:
  - `artifacts/rootcause_notes.md`

## 根本原因

`RtpPacket::decodePacket(RtpBuffer*)` は RTP fixed header を decode した後、RTP header extension bit が立っている場合に extension header の 16-bit length field を読み、extension 全体のバイト長へ変換する。

問題の処理は以下。

```cpp
RtpDt_UInt32 uiByte4Data = RtpOsUtil::Ntohl(*(reinterpret_cast<RtpDt_UInt32*>(pcRtpBuf)));
RtpDt_UInt16 uXHdrLen =
        (RtpDt_UInt16)(uiByte4Data & RTP_HEX_16_BIT_MAX);

uXHdrLen += 1;
uXHdrLen *= RTP_WORD_SIZE;

if ((uXHdrLen <= 0) || ((uiRtpBufPos + uXHdrLen) > uiRtpUtlBufLen)) {
    return eRTP_FAILURE;
}
```

RTP extension length は「4 byte word 数」で、extension header 自身の1 wordを足してから4倍する必要がある。最大値 `0xffff` なら正しい byte length は `0x40000` になる。ところが実装は中間結果を `RtpDt_UInt16` に保持しているため、`(len + 1) * 4` が 16-bit 幅で truncate/wrap する。

具体例:

- length `0x4000`: 正しい extension length は `0x10004` bytes だが、実装上の `uXHdrLen` は `0x0004` になる。
- length `0x8000`: 正しい extension length は `0x20004` bytes だが、実装上の `uXHdrLen` は `0x0004` になる。
- length `0xffff`: 正しい extension length は `0x40000` bytes だが、実装上の `uXHdrLen` は `0x0000` になり、この値だけはゼロ長として reject される。

つまり、ゼロに wrap しない値では、本来なら packet 内に収まらない巨大 extension を、数バイトの extension と誤認して境界チェックを通せる。以後 `pcRtpBuf` と `uiRtpBufPos` は攻撃者が宣言した RTP packet 構造とずれ、extension として拒否されるべき領域が後続の payload buffer に読み込まれる。根本原因は、外部入力由来の 16-bit length field に対し、境界チェック前に狭い整数型で加算・乗算していること。

## 脆弱性の発生条件

次の RTP packet が `libpixelimsmedia` の RTP 受信処理に到達すると成立する。

1. RTP version が 2。
2. RTP header extension bit が 1。
3. extension length field が `0x4000` 以上など、`(length + 1) * 4` が 16-bit で wrap/truncate する値。
4. 実際の受信 packet length は、正しい extension byte length より短いが、wrap 後の短い `uXHdrLen` 以上はある。

この条件では、仕様上は extension が packet 内に収まらないため reject すべきである。しかし実装は truncate 後の小さい length だけで `uiRtpBufPos + uXHdrLen <= uiRtpUtlBufLen` を判定し、`memcpy` と payload 切り出しへ進む。OSV の remote information disclosure は、この不正な長さ解釈により RTP 受信側が packet 構造外として扱うべき bytes を payload/extension buffer として取り込む点に対応すると判断した。

## バイナリ確認

`nm -D -C` で LineageOS shiba blob の dynamic symbol を確認した。

- 23.1: `0x171400 RtpPacket::decodePacket(RtpBuffer*)`
- 23.2: `0x170560 RtpPacket::decodePacket(RtpBuffer*)`

23.2 の逆アセンブルでは extension length 計算が以下の命令列になっている。

```text
170604: ldr w0, [x20]
170608: bl RtpOsUtil::Ntohl
17060c: lsl w8, w0, #2
170610: add w8, w8, #0x4
170614: ands w22, w8, #0xfffc
170620: add w8, w8, w22
170624: cmp w8, w21
```

23.1 も同じ構造だった。`lsl` と `add #4` の後に `#0xfffc` で mask されるため、上位bitが落ちる。この blob は Pixel June 2026 公式 pre/post ではなく、23.1/23.2 の差分もアドレス差中心だったため、修正済み Pixel binary diff としては使えない。ただし AOSP ソースにある narrow arithmetic が実際の `libpixelimsmedia` 機械語にも存在することは確認できた。

## 公開ブランチ確認

`RtpPacket.cpp` は以下の公開ブランチで同じ SHA256 だった。

- `origin/android16-release`
- `origin/android16-security-release`
- `origin/android16-qpr2-release`
- `origin/android17-release`
- `origin/main`

保存: `artifacts/RtpPacket_branch_check.txt`

公開AOSPブランチでは修正差分を確認できなかった。Bulletin の `*` 注記どおり、CVE-2026-0140 の実修正は Pixel-family specific binary update 側に含まれた可能性が高い。

## 推定される修正

安全な修正は以下。

- `RtpHeader::decodeHeader()` の返り値を確認し、失敗時は `decodePacket()` も失敗させる。
- extension bit が立っている場合、4 byte extension header を読む前に残長が `RTP_WORD_SIZE` 以上あることを確認する。
- extension length を `uint32_t` 以上で `((uint32_t)len + 1) * 4` として計算する。
- `uiRtpBufPos + uXHdrLen` の加算ではなく、`uXHdrLen <= uiRtpUtlBufLen - uiRtpBufPos` で overflow しない形にする。
- padding branch でも、payload残長が0の状態で `remaining - 1` を読まない。

`artifacts/inferred_fix_RtpPacket_decodePacket.diff` に推定修正案を保存した。これは非公開Pixelパッチそのものではなく、確認した根本原因を塞ぐための最小修正案である。

## 面白い点・調査メモ

- 同じ `RtpPacket::decodePacket` には CVE-2026-0131 / A-476459432 も割り当てられている。OSV上では CVE-0131 が `out of bounds access` / EoP、CVE-0140 が `out-of-bounds read` / ID と書き分けられている。
- `0xffff` は最も目立つ境界値だが、この実装ではゼロに wrap して reject される。実際に危険なのは `0x4000`, `0x8000`, `0xc001` など、wrap 後が非ゼロの小さい値になる length。
- `decodePacket` は `RtpHeader::decodeHeader()` の戻り値を無視している。現行 `RtpHeader::decodeHeader` は固定ヘッダ長と CSRC 長を検査するが、その失敗を上位が無視する設計は parser として危険。
- extension header を読む前に「残り4バイト以上」のチェックがない。これは OSV の integer overflow とは別の防御不足だが、同じ関数の残長管理が弱いことを示している。
- padding 処理にも `uiRtpUtlBufLen - 1` の unsigned underflow 候補がある。今回の主因ではないが、推定修正では同時に塞ぐべき箇所として記載した。

## 結論

CVE-2026-0140 は、Pixel `libpixelimsmedia` の `RtpPacket::decodePacket` が RTP header extension length を 16-bit 幅のまま加算・乗算し、境界チェック前に truncate/wrap させることに起因する out-of-bounds read / remote information disclosure である。攻撃者が巨大な extension length を宣言した RTP packet を処理させると、本来 reject すべき packet が短い extension として受理され、parser の読み取り位置と payload 切り出しが RTP packet 構造からずれる。根本原因は、外部入力長に対する narrow integer arithmetic と、残長ベースでない境界チェックである。
089 NG

CVE-2026-0141

089-ng-carriersettings-provider-added-unconfirmed

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentTelephony
TypeID
SeverityHigh
ReferencesA-479212863
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0141 is listed in the Pixel Update Bulletin as a High severity ID issue in Pixel / Telephony.

NG 判定の要点

判定: ng

CVE-2026-0141 は Pixel Update Bulletin 2026-06-01 の Pixel / Telephony / ID / High、参照 ID A-479212863 として掲載されている。参照 ID は非公開で、公開 AOSP commit は見つからなかった。

May (CP1A.260505.005.A1) と June (CP2A.260605.012) の Pixel 8 (shiba) OTA/factory image から Telephony 関連 APK を抽出して差分を見た。最も有力な差分は CarrierSettings.apk に June で com.google.android.carrier.CarrierSettingsProvider と com.google.android.carrier.permission.MANAGE_CARRIER_SETTINGS が追加された点だが、May には対応する無権限 provider が存在せず、これが CVE-2026-0141 の修正であると断定できない。

従って、脆弱性の根本原因を「完璧に説明できる」状態ではないため ng とする。

未確定の理由 / 原因候補

記載なし。

どこから特定したか

解析対象: ・May OTA: /Users/eric/workspace/android/binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip
- payload.bin offset 4548, size 2996622980
・June OTA: /Users/eric/workspace/android/binaries/pixel_shiba_ota/shiba-ota-cp2a.260605.012-b315a1a2.zip
- payload.bin offset 4596, size 3243653234
・May system_ext 既存抽出元: /Users/eric/workspace/android/2026…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01

validated.md を表示
# CVE-2026-0141 検証メモ

## 結論

判定: **ng**

CVE-2026-0141 は Pixel Update Bulletin 2026-06-01 の Pixel / Telephony / ID / High、参照 ID `A-479212863` として掲載されている。参照 ID は非公開で、公開 AOSP commit は見つからなかった。

May (`CP1A.260505.005.A1`) と June (`CP2A.260605.012`) の Pixel 8 (`shiba`) OTA/factory image から Telephony 関連 APK を抽出して差分を見た。最も有力な差分は `CarrierSettings.apk` に June で `com.google.android.carrier.CarrierSettingsProvider` と `com.google.android.carrier.permission.MANAGE_CARRIER_SETTINGS` が追加された点だが、May には対応する無権限 provider が存在せず、これが CVE-2026-0141 の修正であると断定できない。

従って、脆弱性の根本原因を「完璧に説明できる」状態ではないため `ng` とする。

## Bulletin 情報

- Bulletin: Pixel Update Bulletin - June 2026
- URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- CVE: `CVE-2026-0141`
- Reference: `A-479212863`
- Component / Subcomponent: `Pixel / Telephony`
- Type / Severity: `ID / High`
- Security patch level: `2026-06-05` or later

該当 HTML 抜粋は `analysis/bulletin_extract.txt` に保存した。

## 解析対象

- May OTA: `/Users/eric/workspace/android/binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip`
  - `payload.bin` offset `4548`, size `2996622980`
- June OTA: `/Users/eric/workspace/android/binaries/pixel_shiba_ota/shiba-ota-cp2a.260605.012-b315a1a2.zip`
  - `payload.bin` offset `4596`, size `3243653234`
- May system_ext 既存抽出元: `/Users/eric/workspace/android/2026-06/074-CVE-2026-0149-Pixel-libpixelimsmedia-RCE-Critical/ota_may/dump/system_ext.img`
- June vendor 既存抽出元: `/Users/eric/workspace/android/2026-06/binaries/pixel_factory/shiba-cp2a.260605.012/vendor.img`

ZIP 内の stored `payload.bin` をオフセット指定で読む補助スクリプト `analysis/payload_extract_offset.py` を作成し、`product` / `system_ext` の APK を抽出した。

## 主な差分

APK 差分サマリは `analysis/apk_diff_summary.tsv` に保存した。主な DEX 差分は以下。

- `CarrierSettings.apk`: `classes.dex`, `classes2.dex`, `classes3.dex` が変更。May 1,858,147 bytes、June 2,034,339 bytes。
- `CarrierSetup.apk`: `classes.dex` が変更。`VzwSetupActivity` に `SubscriptionInfo` 参照と `SecurityException while accessing SubscriptionInfo` の処理が追加。
- `ImsServiceEntitlement.apk`, `EuiccGoogle.apk`, `GoogleDialer.apk`, `CarrierLocation.apk` などにも DEX 差分あり。ただし R8/Kotlin/AndroidX 更新ノイズが多い。

## 有力候補: CarrierSettingsProvider

June の `CarrierSettings.apk` で以下が追加されていた。

- Declared permission: `com.google.android.carrier.permission.MANAGE_CARRIER_SETTINGS`
- Provider: `com.google.android.carrier.CarrierSettingsProvider`
- Authority: `com.google.android.carrier.settingsprovider`
- `android:exported="true"`
- `android:permission="com.google.android.carrier.permission.MANAGE_CARRIER_SETTINGS"`

`CarrierSettingsProvider.call()` は冒頭で `checkCallingPermission("com.google.android.carrier.permission.MANAGE_CARRIER_SETTINGS")` を実行し、権限がなければ `SecurityException` を投げる。対応する disasm は `analysis/carriersettings_provider_methods.txt` に保存した。

Provider が扱う method 名・返却キー:

- `get_applied_carrier_settings_versions`
- `get_ota_carrier_settings_versions`
- `is_ota_pending`
- `trigger_ota`
- Bundle key: `carrier_list`
- Bundle key: `subid_<subscriptionId>`
- Bundle key: `is_ota_pending`
- Bundle key: `ota_trigger_queued`

内部では `SubscriptionManager.getActiveSubscriptionInfoList()` と `SubscriptionInfo.getSimSlotIndex()` を使い、slot ごとの last carrier / carrier settings version / OTA pending 状態を返す。情報種別は Telephony/ID に近いが、June 版では provider レベル permission とメソッド内 permission check の二重で保護されている。

問題は、May 版にはこの provider 自体が存在しない点である。つまり「May で無権限に provider call でき、June で permission が追加された」という典型的な修正形ではない。新しい保護 API を導入して既存の別経路を置き換えた可能性はあるが、旧経路を特定できなかった。

## その他候補

`CarrierSetup.apk` では June で `VzwSetupActivity.lambda$showMaxAttemptsErrorUi$22()` が追加され、`SubscriptionManager.getActiveSubscriptionInfo(mSubId)`、`SubscriptionInfo.isEmbedded()`、`SecurityException while accessing SubscriptionInfo` が見える。Manifest 上の `VzwSetupActivity` は May/June とも exported true かつ permission なしだった。

ただし、この差分はエラー UI/例外処理の追加に見え、ID の根本原因としては弱い。少なくとも「無権限 caller がこの activity から subscriber identifier を取得できる」ことまでは説明できない。

## 付帯ファイル

- `analysis/apk_diff_summary.tsv`: APK/DEX 差分サマリ
- `analysis/carriersettings_manifest_diff.txt`: `CarrierSettings.apk` の manifest 差分
- `analysis/carriersettings_method_diff.txt`: `com.google.android.carrier.*` のメソッド差分
- `analysis/carriersettings_provider_disasm.txt`: `CarrierSettingsProvider` 関連 disasm
- `analysis/carriersettings_provider_methods.txt`: `CarrierSettingsProvider` 本体メソッド抜粋
- `analysis/carriersetup_subscription_disasm.txt`: `CarrierSetup` の `SubscriptionInfo` 関連 disasm
- `analysis/manifest_candidates.txt`: 候補 APK の exported component 一覧
- `analysis/new_strings_all_interesting.txt`: ID/Telephony/permission 関連の新旧 DEX 文字列差分
- `analysis/may_*`, `analysis/june_*`: 抽出した候補 APK

## 面白い点・注意点

- CP1A から CP2A への差分は単純な月例セキュリティ修正だけではなく、R8 バージョン、AndroidX/Kotlin、min-api、ライブラリ更新が大量に混ざる。DEX ハッシュ差分だけでは CVE 修正を特定しにくい。
- `CarrierSettingsProvider` は exported true だが独自 permission で保護され、さらに `call()` 内でも同じ permission をチェックしている。ここだけ見ると「脆弱なコード」ではなく「安全な新 API」に見える。
- `CarrierSettingsProvider` が返す `subid_<id>` は subscription ID を key 名に含むため ID 情報として扱えるが、保護 permission があるため未権限アプリへの情報漏えいとは言えない。
- `CarrierSetup` には exported true / permission なしの activity/receiver が複数あるが、May/June で manifest の保護強化は確認できなかった。
090 OK

CVE-2026-0142

090-ok-avb-rsa-key-oob-read

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentAndroid Bootloader
TypeID
SeverityHigh
ReferencesA-485031572
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0142 is listed in the Pixel Update Bulletin as a High severity ID issue in Pixel / Android Bootloader.

特定した具体的な脆弱性

判定: ok

CVE-2026-0142 / A-485031572 は、Pixel Android Bootloader に取り込まれている AVB RSA 公開鍵パーサ iavb_parse_key_data() の境界外読み出しである。根本原因は、RSA 公開鍵バッファの長さが AvbRSAPublicKeyHeader より短い場合でも、先に data を AvbRSAPublicKeyHeader* として avb_rsa_public_key_header_validate_and_byteswap() に渡していたこと。修正は、ヘッダを読む前に length < sizeof(AvbRSAPublicKeyHeader) を拒否する最小長チェックを追加するものだった。

この脆弱性は malformed な AVB RSA 公開鍵データを処理する経路で、入力バッファ末尾を越えてヘッダ分を読み得る。CVEの分類どおり、結果はローカル情報漏えいで、完全性・可用性より機密性への影響が主である。

原因

iavb_parse_key_data() は、AVB RSA公開鍵のシリアライズデータを次の順序で処理していた。

1. 入力 data を AvbRSAPublicKeyHeader* にキャストする。
2. avb_rsa_public_key_header_validate_and_byteswap() でヘッダを検証し、バイトオーダー変換する。
3. アルゴリズム種別から期待鍵長を決める。
4. length == sizeof(AvbRSAPublicKeyHeader) + 2 * h.key_num_bits / 8 を検証する。

問題は 4 の完全長チェックが 2 のヘッダ読み出しより後だった点。攻撃者が length < sizeof(AvbRSAPublicKeyHeader) の短い鍵データを与えると、ヘッダ検証関数が入力バッファ外を読む。修正は完全長チェックとは別に、最初に「ヘッダを安全に読めるだけの長さがあるか」を検証する。

どこから特定したか

参照情報: ・Bulletin: Pixel Update Bulletin, 2026-06-01
・Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
・CVE: CVE-2026-0142
・Android bug ID: A-485031572
・Component / Subcomponent: Pixel / Android Bootloader
・Type / Severity: ID / High
・CVE record: https://www.cve.org/CVERecord?id=CVE-2026-0142
・OSV: https://osv.dev/vulnerability/…

パッチ解析: 公開AOSP側で、参照ID Bug: 485031572 を持つ修正コミットを確認した。

・Repository: platform/external/avb
・Commit: 9670c9fa9f
・Commit URL: https://android.googlesource.com/platform/external/avb/+/9670c9fa9f
・Diff: aosp_avb_patch/9670c9fa9f.diff
・保存したソース:
- aosp_avb_patch/avb_rsa_before.c
- aosp_avb_patch/avb_rsa_after.c
- aosp_avb_patch/9670c9fa9f_commit.txt

URL: https://source.android.com/docs/secu…

validated.md を表示
# CVE-2026-0142 検証結果

## 結論

判定: ok

CVE-2026-0142 / A-485031572 は、Pixel Android Bootloader に取り込まれている AVB RSA 公開鍵パーサ `iavb_parse_key_data()` の境界外読み出しである。根本原因は、RSA 公開鍵バッファの長さが `AvbRSAPublicKeyHeader` より短い場合でも、先に `data` を `AvbRSAPublicKeyHeader*` として `avb_rsa_public_key_header_validate_and_byteswap()` に渡していたこと。修正は、ヘッダを読む前に `length < sizeof(AvbRSAPublicKeyHeader)` を拒否する最小長チェックを追加するものだった。

この脆弱性は malformed な AVB RSA 公開鍵データを処理する経路で、入力バッファ末尾を越えてヘッダ分を読み得る。CVEの分類どおり、結果はローカル情報漏えいで、完全性・可用性より機密性への影響が主である。

## 参照情報

- Bulletin: Pixel Update Bulletin, 2026-06-01
- Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- CVE: CVE-2026-0142
- Android bug ID: A-485031572
- Component / Subcomponent: Pixel / Android Bootloader
- Type / Severity: ID / High
- CVE record: https://www.cve.org/CVERecord?id=CVE-2026-0142
- OSV: https://osv.dev/vulnerability/PUB-A-485031572

## パッチ解析

公開AOSP側で、参照ID `Bug: 485031572` を持つ修正コミットを確認した。

- Repository: `platform/external/avb`
- Commit: `9670c9fa9f`
- Commit URL: https://android.googlesource.com/platform/external/avb/+/9670c9fa9f
- Diff: `aosp_avb_patch/9670c9fa9f.diff`
- 保存したソース:
  - `aosp_avb_patch/avb_rsa_before.c`
  - `aosp_avb_patch/avb_rsa_after.c`
  - `aosp_avb_patch/9670c9fa9f_commit.txt`

差分は `libavb/avb_rsa.c` の `iavb_parse_key_data()` に以下のチェックを追加するだけだった。

```c
if (length < sizeof(AvbRSAPublicKeyHeader)) {
  avb_error("Invalid key length.\n");
  goto fail;
}
```

修正前は `length` を確認する前に `avb_rsa_public_key_header_validate_and_byteswap((const AvbRSAPublicKeyHeader*)data, &h)` を呼ぶ。コミットメッセージにも、同関数が入力バッファから `sizeof(AvbRSAPublicKeyHeader)` バイトを読むため、入力がヘッダサイズ未満だとOOB readになる、と明記されていた。

## Pixel ABL バイナリでの確認

Pixel 8 (`shiba`) のOTA payloadからbootloader系パーティションを抽出して比較した。

- May OTA: `../binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip`
- June OTA: `../binaries/pixel_shiba_ota/shiba-ota-cp2a.260605.012-b315a1a2.zip`
- 抽出先:
  - `../binaries/pixel_shiba_bootloader_0142/may/`
  - `../binaries/pixel_shiba_bootloader_0142/june/`
- 抽出対象: `abl`, `bl1`, `bl2`, `bl31`, `pbl`, `gsa_bl1`
- 抽出ログ:
  - `may_payload_manifest.json`
  - `june_payload_manifest_from_incomplete_zip.json`
  - `may_bootloader_extract_summary.json`
  - `june_bootloader_extract_summary.json`
  - `bootloader_sha256.txt`

`abl.img` の文字列比較では、5月版に存在しなかった `Invalid key length.` が6月版に追加されていた。

- May ABL: `Key does not match expected length.`, `Signature length does not match key length.`, `Unexpected key length.`, `Invalid key.`
- June ABL: 上記に加えて `Invalid key length.`
- May version string: `ripcurrent-16.4-14540574`
- June version string: `ripcurrent-17.0-15199481`
- 証跡: `binary_evidence.txt`, `strings/may_abl_strings.txt`, `strings/june_abl_strings.txt`

追加文字列がAOSP修正コミットで追加されたエラーメッセージと一致するため、6月Pixel bootloaderにはこの修正が取り込まれていると判断できる。

## 脆弱性の根本原因

`iavb_parse_key_data()` は、AVB RSA公開鍵のシリアライズデータを次の順序で処理していた。

1. 入力 `data` を `AvbRSAPublicKeyHeader*` にキャストする。
2. `avb_rsa_public_key_header_validate_and_byteswap()` でヘッダを検証し、バイトオーダー変換する。
3. アルゴリズム種別から期待鍵長を決める。
4. `length == sizeof(AvbRSAPublicKeyHeader) + 2 * h.key_num_bits / 8` を検証する。

問題は 4 の完全長チェックが 2 のヘッダ読み出しより後だった点。攻撃者が `length < sizeof(AvbRSAPublicKeyHeader)` の短い鍵データを与えると、ヘッダ検証関数が入力バッファ外を読む。修正は完全長チェックとは別に、最初に「ヘッダを安全に読めるだけの長さがあるか」を検証する。

## 到達条件の推定

AVBのRSA公開鍵はvbmeta検証や署名検証で使われる。CVE本文は「local information disclosure, no additional execution privileges, no user interaction」としているため、想定される攻撃面はローカルから細工したAVBメタデータまたは署名検証対象をbootloaderに処理させる経路である。今回の公開情報とバイナリ差分だけでは、Pixel固有の具体的な入力経路までは完全には特定できないが、脆弱関数・不正入力条件・修正内容はソースコードで確認できた。

## 調査メモ

- Bulletin上の `A-485031572` は `*` 付きで、Android bug trackerの詳細は非公開。
- Pixelの更新はbootloaderバイナリ内に含まれており、AOSPの `external/avb` 修正とABL内の文字列追加が対応している。
- `abl.img` 以外の `bl1`, `bl2`, `bl31`, `pbl`, `gsa_bl1` も5月/6月でハッシュは変化していたが、CVE本文およびAOSPコミットと直接対応する証跡は `abl.img` の `Invalid key length.` だった。
- 6月OTAファイルは手元では完全zipとしては壊れていたが、先頭から始まるpayload manifestとbootloader系blobは読み出せた。抽出スクリプトはlocal zip headerから `payload.bin` を見つけ、必要な `REPLACE_XZ` blobだけを展開している。

## 付帯ファイル

- `analysis_tools/payload_manifest.py`: OTA payload manifestダンプ用スクリプト
- `analysis_tools/extract_payload_partitions.py`: OTA payloadから指定パーティションを抽出するスクリプト
- `analysis_tools/update_metadata.proto`: AOSP update_engine のpayload metadata定義
- `aosp_avb_patch/9670c9fa9f.diff`: 修正差分
- `aosp_avb_patch/9670c9fa9f_commit.txt`: コミットメッセージ
- `aosp_avb_patch/avb_rsa_before.c`: 修正前 `avb_rsa.c`
- `aosp_avb_patch/avb_rsa_after.c`: 修正後 `avb_rsa.c`
- `bootloader_sha256.txt`: 抽出したbootloaderパーティションのSHA-256
- `binary_evidence.txt`: ABL文字列証跡の要約
- `strings/*.txt`: 各bootloaderパーティションのstrings出力と差分
091 NG

CVE-2026-0145

091-ng-sharedsecret-fragment-split-unidentified

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
Subcomponentkeymint
TypeID
SeverityHigh
ReferencesA-434105398
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0145 is listed in the Pixel Update Bulletin as a High severity ID issue in Pixel / keymint.

NG 判定の要点

判定: ng。CVE-2026-0145 の対象が Pixel / keymint の Permission Bypass / local information disclosure であること、May/June の shiba vendor image で keymint/StrongBox 周辺に複数の差分があることは確認できた。しかし、脆弱性そのものをソースコードまたは完全な発生条件として特定するには至らなかった。

最初に有力に見えた差分は、Citadel StrongBox manifest から ISharedSecret/strongbox が消えたように見える点だった。だが追加調査で、June には別 fragment android.hardware.security.sharesecret-service.citadel.xml が追加され、そこに同じ android.hardware.security.sharedsecret.ISharedSecret/strongbox が宣言されていることが分かった。従って「StrongBox SharedSecret の公開削除」がパッチだとは言えない。

未確定の理由 / 原因候補

未特定。候補は以下。

・KeyMint/SharedSecret の fragment 同居によるサービス登録・列挙ロジックの誤り。
・keymint-service.rust.trusty の v4→v5 移行に伴う authorization/parameter 処理の修正。
・Pixel 固有 vendor/google_nos/host/android/hals/keymaster/aidl/strongbox/service.cpp または Trusty TA 側の非公開変更。

このうち、保存した diff で確実に説明できるのは fragment 分離と AOSP 登録 API の変更までで、CVE の Permission Bypass 条件は確定できていない。

どこから特定したか

解析対象: ・May factory/vendor image:
- /Users/eric/workspace/android/2026-06/binaries/pixel_factory/shiba-cp1a.260505.005/vendor.img
・June factory/vendor image:
- /Users/eric/workspace/android/2026-06/binaries/pixel_factory/shiba-cp2a.260605.012/vendor.img
・既存 OTA:
- /Users/eric/workspace/android/binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zi…

主要差分: 保存ファイル:

・artifacts/citadel_vintf_manifest.diff
・artifacts/extracted_may/etc/vintf/manifest/android.hardware.security.keymint-service.citadel.xml
・artifacts/extracted_june/etc/vintf/manifest/android.hardware.security.keymint-service-v3.citadel.xml

May:

保存した主な成果物: ・artifacts/ext4_extract.py, artifacts/ext4_manifest.py: ext4 vendor image 抽出/一覧化スクリプト。
・artifacts/shiba_may_vendor_mani…

validated.md を表示
# CVE-2026-0145 Pixel keymint ID High 検証メモ

## 結論

判定: ng。CVE-2026-0145 の対象が Pixel / keymint の Permission Bypass / local information disclosure であること、May/June の shiba vendor image で keymint/StrongBox 周辺に複数の差分があることは確認できた。しかし、脆弱性そのものをソースコードまたは完全な発生条件として特定するには至らなかった。

最初に有力に見えた差分は、Citadel StrongBox manifest から `ISharedSecret/strongbox` が消えたように見える点だった。だが追加調査で、June には別 fragment `android.hardware.security.sharesecret-service.citadel.xml` が追加され、そこに同じ `android.hardware.security.sharedsecret.ISharedSecret/strongbox` が宣言されていることが分かった。従って「StrongBox SharedSecret の公開削除」がパッチだとは言えない。

現時点で言える最も強い事実は、June で StrongBox KeyMint の VINTF fragment が分割されたこと、default/TEE KeyMint が v4 から v5 へ上がったこと、`android.hardware.security.keymint-service.rust.trusty` と keymint support library が大きく更新されたこと、AOSP `system/keymint` に HAL 登録対象を設定可能にする変更が入っていることまでである。CVE の root cause は、非公開の Pixel/Google NOS 実装または Trusty KeyMint 側の変更にある可能性が高いが、静的 diff だけでは確定できなかった。

## 既存 cve.md の確認

- CVE: CVE-2026-0145
- 参照 ID: A-434105398
- Component/Subcomponent: Pixel / keymint
- Type/Severity: ID / High
- Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- Bulletin 上の行: `CVE-2026-0145 A-434105398 * ID High keymint`
- `*` 付きなので Android bug は非公開。Pixel bulletin の FAQ では、`*` 付き問題の更新は通常 Pixel binary drivers に含まれると説明されている。

## 解析対象

- May factory/vendor image:
  - `/Users/eric/workspace/android/2026-06/binaries/pixel_factory/shiba-cp1a.260505.005/vendor.img`
- June factory/vendor image:
  - `/Users/eric/workspace/android/2026-06/binaries/pixel_factory/shiba-cp2a.260605.012/vendor.img`
- 既存 OTA:
  - `/Users/eric/workspace/android/binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip`
  - `/Users/eric/workspace/android/binaries/pixel_shiba_ota/shiba-ota-cp2a.260605.012-b315a1a2.zip`

## 主要差分

### Citadel StrongBox VINTF manifest

保存ファイル:

- `artifacts/citadel_vintf_manifest.diff`
- `artifacts/extracted_may/etc/vintf/manifest/android.hardware.security.keymint-service.citadel.xml`
- `artifacts/extracted_june/etc/vintf/manifest/android.hardware.security.keymint-service-v3.citadel.xml`

May:

```xml
<hal format="aidl">
    <name>android.hardware.security.keymint</name>
    <version>3</version>
    <fqname>IKeyMintDevice/strongbox</fqname>
</hal>
<hal format="aidl">
    <name>android.hardware.security.sharedsecret</name>
    <fqname>ISharedSecret/strongbox</fqname>
</hal>
```

June:

```xml
<hal format="aidl">
    <name>android.hardware.security.keymint</name>
    <version>3</version>
    <fqname>IKeyMintDevice/strongbox</fqname>
</hal>
```

この差分だけを見ると June では StrongBox KeyMint 自体は残し、SharedSecret の StrongBox インスタンス宣言だけを削除したように見える。

しかしこれは決定的な修正ではなかった。June vendor image には次の fragment が新規追加されていた。

保存ファイル:

- `artifacts/extracted_june_sharesecret_service/etc/vintf/manifest/android.hardware.security.sharesecret-service.citadel.xml`

内容:

```xml
<manifest version="9.0" type="device">
    <hal format="aidl">
        <name>android.hardware.security.sharedsecret</name>
        <fqname>ISharedSecret/strongbox</fqname>
    </hal>
</manifest>
```

つまり `ISharedSecret/strongbox` は June でも VINTF 宣言されている。May では KeyMint fragment 内に同居していたものが、June では `sharesecret-service.citadel.xml` へ分離された、というのが正確な観測結果。

### Trusty/default KeyMint manifest

保存ファイル:

- `artifacts/trusty_vintf_manifest.diff`

May から June で default/TEE KeyMint は `IKeyMintDevice/default` が v4 から v5 に上がったが、`ISharedSecret/default` は引き続き宣言されている。これは SharedSecret 全体の削除ではなく、StrongBox 側だけを公開面から外したことを示す。

### SELinux service context

保存ファイル:

- `artifacts/vendor_service_contexts.diff`
- `artifacts/selinux_context_keymint_hits.txt`

`vendor_service_contexts` には June でも `android.hardware.security.sharedsecret.ISharedSecret/strongbox` の service context が残っている。追加 fragment も存在するため、SharedSecret StrongBox インスタンス自体の撤去ではない。

### Citadel バイナリ

保存ファイル:

- `artifacts/extracted_keymint_file_types.txt`
- `artifacts/extracted_keymint_sha256.txt`
- `artifacts/citadel_registration_strings.txt`
- `artifacts/citadel_registration_disasm.diff`
- `artifacts/may_citadel_objdump_d.txt`
- `artifacts/june_citadel_objdump_d.txt`

`android.hardware.security.keymint-service.citadel` は May 52,088 bytes、June 52,096 bytes。両方とも `android.hardware.security.sharedsecret-V1-ndk.so` に依存し、`SharedSecret` コンストラクタや `ISharedSecret` descriptor 文字列を含む。したがって実装クラス自体は完全削除されていない。June の修正は「StrongBox SharedSecret 機能を実装から消す」よりも「公開/宣言/登録対象を絞る」性質が強い。

興味深い文字列差分:

- May: `Keymint HAL service starting`, `adding keymint service instance: `
- June: `Strongbox HAL service starting`, `adding service instance: `

### AOSP system/keymint の対応変更

保存ファイル:

- `artifacts/system_keymint_r3_r4_log.txt`
- `artifacts/system_keymint_hal_registration_commits.txt`
- `artifacts/system_keymint_hal_registration.diff`
- `artifacts/system_keymint_hal_lib_before_43f5727.rs`
- `artifacts/system_keymint_hal_lib_after_43f5727.rs`

`system/keymint` の `android-16.0.0_r3..android-16.0.0_r4` に以下が入っている。

- `dfcc4f8 Add common utils for HAL service registration`
- `43f5727 hal: Refactor HAL service registration to be configurable`

`43f5727` のコミット本文は、従来の登録ロジックが KeyMint 関連 4 サービスをハードコードで全登録しており、`ISharedSecret` を別 HAL へ移す upcoming change のため硬すぎる、と説明している。差分では `Hal` enum が導入され、`KeyMintDevice`、`RemotelyProvisionedComponent`、`SecureClock`、`SharedSecret` から登録対象を明示指定できる API に変わった。

この公開 AOSP 変更は、Pixel June の「KeyMint と SharedSecret の VINTF fragment を分離する」vendor 差分と方向性が一致する。ただし、これ自体が情報漏えい/permission bypass を修正するのか、単なる構成整理なのかは確定できない。

なお `Check nonce length for ISharedSecret` という古いコミットも検索で見つかったが、`android-16.0.0_r3` に既に含まれていたため、May→June の本 CVE パッチ候補からは外した。

## 有力だが未確定の仮説

`ISharedSecret` AIDL 仕様では、サービス群が起動時に shared HMAC key を合意するため、以下を公開する。

- `getSharedSecretParameters()`: seed/nonce を返す。
- `computeSharedSecret(params)`: 実装定義の pre-established secret `K` と呼び出し側 supplied の parameters から shared key `H` を計算し、検証用 32-byte `sharingCheck` を返す。

この HAL は通常、Android 起動時に KeyMint/認証器/secure clock などの内部参加者間で使うもので、一般的な KeyStore API の公開面ではない。仮に呼び出し制御に欠陥があると、呼び出し側 supplied の parameter list に対する StrongBox/TEE 由来の `sharingCheck`、および起動セッション内で安定する SharedSecretParameters が観測できる可能性がある。これは local information disclosure と整合する。

ただし June でも `ISharedSecret/strongbox` 自体は宣言されているため、「この HAL が見えていたこと」だけを根本原因とはできない。実際の問題は、どのサービスがどの SharedSecret インスタンスを登録/利用するか、または KeyMint v5 化で変わったパラメータ/権限チェックにある可能性がある。

## 根本原因

未特定。候補は以下。

- KeyMint/SharedSecret の fragment 同居によるサービス登録・列挙ロジックの誤り。
- `keymint-service.rust.trusty` の v4→v5 移行に伴う authorization/parameter 処理の修正。
- Pixel 固有 `vendor/google_nos/host/android/hals/keymaster/aidl/strongbox/service.cpp` または Trusty TA 側の非公開変更。

このうち、保存した diff で確実に説明できるのは fragment 分離と AOSP 登録 API の変更までで、CVE の Permission Bypass 条件は確定できていない。

## パッチとして確認できたこと

June では:

- StrongBox/Citadel の KeyMint manifest から `ISharedSecret/strongbox` を外す。
- ただし `android.hardware.security.sharesecret-service.citadel.xml` を新規追加し、`ISharedSecret/strongbox` は別 fragment で宣言する。
- default/TEE 側の `ISharedSecret/default` は残す。
- AOSP `system/keymint` では登録対象を選択可能にする API が入る。

このため、SharedSecret 公開面の削除ではなく、KeyMint と SharedSecret の構成分離が少なくとも一部のパッチである。

## 限界と補足

- A-434105398 は非公開で、Pixel 固有 `vendor/google_nos/.../strongbox/service.cpp` の完全なソースは公開されていない。
- June Citadel バイナリにも `ISharedSecret` の実装/依存文字列は残る。
- June には `ISharedSecret/strongbox` の別 manifest fragment が追加されるため、SharedSecret StrongBox インスタンス撤去説は否定された。
- 実機で `service list` / `cmd servicemanager check` を May/June 比較できれば、`ISharedSecret/strongbox` が runtime で見えるかをさらに確認できる。今回は factory vendor image と公開 AOSP からの静的解析。
- `system/security` の追加確認は、既存の部分 clone が promisor object 欠落で fetch 失敗したため断念した。失敗ログは会話ログに残っているが、今回の結論には必須ではない。

## 参照 URL

- Pixel Update Bulletin June 2026: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- OSV PUB-A-434105398: https://osv.dev/vulnerability/PUB-A-434105398
- CVE Record: https://www.cve.org/CVERecord?id=CVE-2026-0145
- AOSP ISharedSecret AIDL: https://android.googlesource.com/platform/hardware/interfaces/+/main/security/sharedsecret/aidl/android/hardware/security/sharedsecret/ISharedSecret.aidl
- AOSP KeyMint README/security overview: https://android.googlesource.com/platform/hardware/interfaces/+/main/security/
- AOSP system/keymint commit `43f5727`: `hal: Refactor HAL service registration to be configurable`
- AOSP system/keymint commit `dfcc4f8`: `Add common utils for HAL service registration`

## 保存した主な成果物

- `artifacts/ext4_extract.py`, `artifacts/ext4_manifest.py`: ext4 vendor image 抽出/一覧化スクリプト。
- `artifacts/shiba_may_vendor_manifest.tsv`, `artifacts/shiba_june_vendor_manifest.tsv`: vendor.img manifest。
- `artifacts/extracted_may/`, `artifacts/extracted_june/`: keymint 関連抽出物。
- `artifacts/extracted_may_contexts/`, `artifacts/extracted_june_contexts/`: service/file context 抽出物。
- `artifacts/citadel_vintf_manifest.diff`: StrongBox manifest の決定的差分。
- `artifacts/extracted_june_sharesecret_service/etc/vintf/manifest/android.hardware.security.sharesecret-service.citadel.xml`: June で追加された SharedSecret StrongBox fragment。
- `artifacts/trusty_vintf_manifest.diff`: default/TEE manifest 差分。
- `artifacts/vendor_service_contexts.diff`: service context 差分。
- `artifacts/extracted_keymint_sha256.txt`: 抽出 keymint ファイルの SHA-256。
- `artifacts/*strings.txt`, `artifacts/*objdump*.txt`: 文字列/ELF/逆アセンブル出力。
- `artifacts/system_keymint_hal_registration.diff`: AOSP `system/keymint` 登録 API 変更。
- `artifacts/public/ISharedSecret.aidl`: AOSP AIDL 仕様の保存コピー。
- `artifacts/public/pixel-bulletin-2026-06-01.html`, `artifacts/public/PUB-A-434105398.html`: 公開 advisory 保存コピー。
092 OK

CVE-2026-0155

092-ok-imsmediabitreader-readbytebuffer-oob-read

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
Subcomponentlibpixelimsmedia
TypeID
SeverityHigh
ReferencesA-476132502
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0155 is listed in the Pixel Update Bulletin as a High severity ID issue in Pixel / libpixelimsmedia.

特定した具体的な脆弱性

CVE-2026-0155 は Pixel の libpixelimsmedia.so に含まれる ImsMediaBitReader::ReadByteBuffer(unsigned char*, unsigned int) の out-of-bounds read である。根本原因は、byte-aligned 状態 (mBitPos == 32) の高速パスで、入力バッファの残量を確認せずに memcpy(pbDst, mBuffer + mBytePos, nByteSize) を実行していたこと。

May 2026 の shiba OTA の libpixelimsmedia.so では、nBitSize >> 3 で算出した nByteSize をそのまま memcpy の長さに使っていた。June 2026 の OTA では、remaining = mMaxBufferSize - mBytePos 相当を計算し、nByteSize > remaining の場合は "[ReadByteBuffer] exceed buffer size: pos[%d], req[%d], max[%d]" をログに出して mBufferEOF = true にし、コピーせず return する分岐が追加されている。

判定: ok。公開ソース相当の実装、OSV/NVD の説明、May/June の Pixel バイナリ差分が一致し、脆弱性が起きる状況も説明できる。

原因

記載なし。

どこから特定したか

解析対象: ・vulnerable 側: ../binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip
- OTA SHA256: 71cbe004f1d76a981bbc65587465d5b36af22d85c7c7b18ee214c05488aee6fc
- 抽出 SO: blobs/libpixelimsmedia_may_cp1a.260505.005.a1.so
- SO SHA256: 805eb3e4af5ec05989ed0a8f95452962a8b59b7f16958f0adf9315467779407a
- BuildID: 04d1927fb8d90a6a235602b626d2bd2c
・patche…

パッチ差分: 関連関数の dynamic symbol size:

・May: ImsMediaBitReader::ReadByteBuffer(...) は 320 bytes
・June: ImsMediaBitReader::ReadByteBuffer(...) は 416 bytes

May disassembly (analysis/ImsMediaBitReader_ReadByteBuffer_may.objdump.txt):

保存した成果物: ・PUB-A-476132502.json: OSV JSON
・blobs/libpixelimsmedia_may_cp1a.260505.005.a1.so
・blobs/libpixelimsmedia_june_cp2a.260605.012.so
・analysis/blob_sha256.t…

validated.md を表示
# CVE-2026-0155 / A-476132502 検証メモ

## 結論

CVE-2026-0155 は Pixel の `libpixelimsmedia.so` に含まれる `ImsMediaBitReader::ReadByteBuffer(unsigned char*, unsigned int)` の out-of-bounds read である。根本原因は、byte-aligned 状態 (`mBitPos == 32`) の高速パスで、入力バッファの残量を確認せずに `memcpy(pbDst, mBuffer + mBytePos, nByteSize)` を実行していたこと。

May 2026 の shiba OTA の `libpixelimsmedia.so` では、`nBitSize >> 3` で算出した `nByteSize` をそのまま `memcpy` の長さに使っていた。June 2026 の OTA では、`remaining = mMaxBufferSize - mBytePos` 相当を計算し、`nByteSize > remaining` の場合は `"[ReadByteBuffer] exceed buffer size: pos[%d], req[%d], max[%d]"` をログに出して `mBufferEOF = true` にし、コピーせず return する分岐が追加されている。

判定: ok。公開ソース相当の実装、OSV/NVD の説明、May/June の Pixel バイナリ差分が一致し、脆弱性が起きる状況も説明できる。

## cve.md から確認した情報

- CVE: `CVE-2026-0155`
- 参照 ID: `A-476132502`
- Component / subcomponent: Pixel / `libpixelimsmedia`
- Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- Bulletin 公開/更新日: 2026-06-16
- 種別/深刻度: ID / High

Pixel bulletin では `CVE-2026-0155 A-476132502 * ID High libpixelimsmedia` と記載されている。OSV/NVD では `ImsMediaBitReader::ReadByteBuffer` の missing bounds check による OOB read、remote information disclosure、追加権限不要、user interaction 不要と説明されている。OSV JSON は `PUB-A-476132502.json` に保存した。

## 解析対象

- vulnerable 側: `../binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip`
  - OTA SHA256: `71cbe004f1d76a981bbc65587465d5b36af22d85c7c7b18ee214c05488aee6fc`
  - 抽出 SO: `blobs/libpixelimsmedia_may_cp1a.260505.005.a1.so`
  - SO SHA256: `805eb3e4af5ec05989ed0a8f95452962a8b59b7f16958f0adf9315467779407a`
  - BuildID: `04d1927fb8d90a6a235602b626d2bd2c`
- patched 側: `../binaries/pixel_shiba_ota/shiba-ota-cp2a.260605.012-b315a1a2.zip`
  - OTA SHA256: `b315a1a292e0fec4ddfa9a527f99fe0569bbfead09ff49f5fd3d156863b6baa9`
  - 抽出 SO: `blobs/libpixelimsmedia_june_cp2a.260605.012.so`
  - SO SHA256: `22a5ff6cb128f68a9fbba7b96535c3732297a32a6e2fddb51d2c009e39e8df9d`
  - BuildID: `9805086f2f4b604be8076a9be5740ed6`

OTA URL:

- https://dl.google.com/dl/android/aosp/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip
- https://dl.google.com/dl/android/aosp/shiba-ota-cp2a.260605.012-b315a1a2.zip

`libpixelimsmedia.so` は既に `074-ok-rtcp-mtu-mismatch-heap-oob-write/blobs/` に抽出済みだったため再利用し、このフォルダの `blobs/` にコピーした。抽出元 OTA と payload metadata のハッシュは `analysis/ota_sha256.txt` と `analysis/payload_properties_*.txt` に残した。

## パッチ差分

関連関数の dynamic symbol size:

- May: `ImsMediaBitReader::ReadByteBuffer(...)` は 320 bytes
- June: `ImsMediaBitReader::ReadByteBuffer(...)` は 416 bytes

May disassembly (`analysis/ImsMediaBitReader_ReadByteBuffer_may.objdump.txt`):

- `0xd3f1c`: `nByteSize = nBitSize >> 3`
- `0xd3f24`: `mBitPos == 32` を確認
- `0xd3f2c`: `mBytePos` を読む
- `0xd3f34`: `x2 = nByteSize`
- `0xd3f38`: `x1 = mBuffer + mBytePos`
- `0xd3f3c`: `memcpy` 呼び出し
- ここまでに `mMaxBufferSize - mBytePos` と `nByteSize` の比較がない。

June disassembly (`analysis/ImsMediaBitReader_ReadByteBuffer_june.objdump.txt`):

- `0xd70a4`: `nByteSize = nBitSize >> 3`
- `0xd70b0`: `mMaxBufferSize` と `mBytePos` を読む
- `0xd70b4`: `remaining = mMaxBufferSize - mBytePos`
- `0xd70b8`: `cmp nByteSize, remaining`
- `0xd70bc`: `nByteSize <= remaining` の場合だけ `memcpy` 側へ分岐
- `0xd70c0` 以降: 超過時ログを出す
- `0xd70e8`-`0xd70ec`: `mBufferEOF = true`
- `0xd70f0`: `memcpy` せず return path へ

復元した差分は `analysis/ImsMediaBitReader_ReadByteBuffer_reconstructed.diff` に保存した。

```cpp
if (mBitPos == 32) {
    uint32_t remaining = mMaxBufferSize - mBytePos;
    if (nByteSize > remaining) {
        IMLOGE3("[ReadByteBuffer] exceed buffer size: pos[%d], req[%d], max[%d]",
                mBytePos, nByteSize, mMaxBufferSize);
        mBufferEOF = true;
        return;
    }
    memcpy(pbDst, mBuffer + mBytePos, nByteSize);
    ...
}
```

## 脆弱性が起きる状況

公開 AOSP 実装相当の `ImsMediaBitReader::SetBuffer()` は、外部から受け取った RTP payload 等を `mBuffer` と `mMaxBufferSize` に設定し、`mBitPos = 32` に初期化する。`ReadByteBuffer()` は `nBitSize` から byte 数を算出し、byte-aligned なら高速パスで `memcpy` する。

旧実装ではこの高速パスだけが `Read()` を経由しない。`Read()` は `mBytePos >= mMaxBufferSize` を確認して EOF にするが、高速パスの `memcpy` は May バイナリで残量を確認していない。そのため、呼び出し側が入力 payload の実残量より大きい `nBitSize` を渡すと、`mBuffer + mBytePos` から `nByteSize` バイトを読み、受信パケットバッファ末尾の先にあるメモリを `pbDst` にコピーする。

主な到達経路:

- `AudioRtpPayloadDecoderNode::DecodePayloadAmr()` は `SetBuffer(pData, nDataSize)` 後、AMR ToC の frame type から `dataBitSize` を計算して `ReadByteBuffer(mPayload + 1, dataBitSize)` を呼ぶ。octet-aligned では ToC 読み後も byte-aligned になりやすく、高速パスに入る。
- `AudioRtpPayloadDecoderNode::DecodePayloadEvs()` は EVS compact/header-full payload の frame type や payload 長から `nDataBitSize` を計算し、`ReadByteBuffer(mPayload, nDataBitSize)` または `ReadByteBuffer(mPayload + 1, nDataBitSize)` を呼ぶ。
- `TextRtpPayloadDecoderNode::DecodeT140()` は T.140 redundancy header の 10-bit block length を使い、`ReadByteBuffer(mPayload, redundantLength * 8)` を呼ぶ。

これらの入力は IMS media stack が処理する RTP payload 由来であり、細工された短い packet と大きい frame length/block length の組み合わせで、入力バッファ末尾の外側を読める。コピー先は decoder の `mPayload` で、その後 `SendDataToRearNode(...)` に渡されるため、OOB read した内容が上位の media processing に混入し得る。OSV/NVD の remote information disclosure という分類と整合する。

## 付随して分かったこと

- June では新しいログ文字列 `"[ReadByteBuffer] exceed buffer size: pos[%d], req[%d], max[%d]"` が追加されている。May には `"[ReadByteBuffer] End of buffer : byte position[%d], buffer size[%d]"` はあるが、これは null/EOF 入口のログで、`memcpy` 前のサイズ比較ではない。
- `ReadByteBuffer()` の非 byte-aligned 低速パスは `Read(8)` を繰り返すため、`Read()` 側の EOF チェックが働く。今回の根本原因は byte-aligned 高速パスだけにある。
- ローカルの AOSP checkout は partial clone で、古い blob を追加取得しようとした際に `android.googlesource.com` への接続が reset されることがあった。そのため最終判断は May/June Pixel バイナリ差分を主根拠にした。
- AOSP の `android-16.0.0_r4` から `android-17.0.0_r1` の公開差分は大きく、`ReadByteBuffer()` 単体の修正は現行 checkout には反映されていなかった。Pixel 固有 blob 側で修正済みである点が重要。
- 同じ June bulletin には `libpixelimsmedia` の CVE が複数あり、別フォルダの CVE-2026-0149 は RTCP 送信バッファサイズ不整合の RCE だった。本件は別関数の OOB read で、修正箇所も `ImsMediaBitReader` に限定される。

## 保存した成果物

- `PUB-A-476132502.json`: OSV JSON
- `blobs/libpixelimsmedia_may_cp1a.260505.005.a1.so`
- `blobs/libpixelimsmedia_june_cp2a.260605.012.so`
- `analysis/blob_sha256.txt`
- `analysis/ota_sha256.txt`
- `analysis/payload_properties_may.txt`
- `analysis/payload_properties_june.txt`
- `analysis/ImsMediaBitReader_ReadByteBuffer_may.objdump.txt`
- `analysis/ImsMediaBitReader_ReadByteBuffer_june.objdump.txt`
- `analysis/ImsMediaBitReader_ReadByteBuffer_may_vs_june.objdump.diff`
- `analysis/ImsMediaBitReader_ReadByteBuffer_reconstructed.diff`
- `analysis/symbol_size_diff_ImsMediaBitReader.txt`
- `analysis/ImsMediaBitReader_current_source_excerpt.txt`
- `analysis/AudioRtpPayloadDecoderNode_AMR_callers.txt`
- `analysis/AudioRtpPayloadDecoderNode_EVS_compact_callers.txt`
- `analysis/TextRtpPayloadDecoderNode_ReadByteBuffer_callers.txt`

## 参照 URL / commit

- Pixel Update Bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- OSV: https://osv.dev/vulnerability/PUB-A-476132502
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-0155
- CVE Record: https://www.cve.org/CVERecord?id=CVE-2026-0155
- 参考手法: https://www.originhq.com/research/patch-diffing-pipeline
- AOSP source mirror used locally: https://android.googlesource.com/platform/packages/modules/ImsMedia
  - local HEAD: `6da37b8ef8bde01956e630bb42a31a40fc1ddba3`
  - `android-16.0.0_r4`: `3b6e43311675c2d9450d1e46bfa2a21585dc1407`
  - `android-17.0.0_r1`: `9f827ea0d0d7543fb2b6839e7a7f287bdc4b2954`
093 OK

CVE-2026-0157

093-ok-rtcp-header-ssrc-oob-read-id

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
Subcomponentlibpixelimsmedia
TypeID
SeverityHigh
ReferencesA-481345618
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0157 is listed in the Pixel Update Bulletin as a High severity ID issue in Pixel / libpixelimsmedia.

特定した具体的な脆弱性

CVE-2026-0157 は、Pixel libpixelimsmedia の RtcpHeader::decodeRtcpHeader が、RTCP length fieldが非0のとき実入力長を8バイト以上と確認せずSSRC 4バイトを読むことに起因する out-of-bounds read / remote information disclosure である。May版PixelバイナリではSSRCロード前の長さチェックがなく、June版では length >= 8 ガードが追加されている。根本原因は、外部入力由来のRTCP header長と実バッファ長の整合性チェック欠落である。

原因

RtcpHeader::decodeRtcpHeader(unsigned char*, int) は RTCP common header を読む関数である。公開AOSPソースでは、入力長が RTP_WORD_SIZE、つまり4バイト以上であれば先頭4バイトを読み、RTCP length field を m_usLength に保存する。

問題は、m_usLength が非0の場合に、入力バッファがRTCP fixed header全体の8バイトを含むか確認せず、pRtcpBuffer + 4 からSSRC 4バイトを読む点である。

``cpp
if (length < RTP_WORD_SIZE)
return eRTP_FALSE;

どこから特定したか

参照情報と保存物: ・Pixel bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- 保存: artifacts/public/pixel-bulletin-2026-06-01.html
- 該当行: CVE-2026-0157 A-481345618 * ID High libpixelimsmedia
・OSV: https://storage.googleapis.com/android-osv/PUB-A-481345618.json
- 保存: artifacts/public/PUB-A-481345618.json, artifacts/public/PUB-A-481345618.pr…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https://storage.googleapis.com/android-osv/PUB-A-481345618.json` / https://cveawg.mitre.org/api/cve/CVE-2026-0157` / https://nvd.nist.gov/vuln/detail/CVE-2026-0157`

validated.md を表示
# CVE-2026-0157 検証結果

## 判定

`ok`: 脆弱性の発生条件、根本原因、Pixel May/June バイナリ上の修正点を特定できた。

タイトル: `rtcp-header-ssrc-oob-read-id`

## 既存 cve.md から確認した情報

- CVE: `CVE-2026-0157`
- Reference: `A-481345618`
- Bulletin: Pixel Update Bulletin
- Bulletin URL: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- Published/updated: `June 16, 2026`
- Security patch level: `2026-06-05 or later`
- Component/Subcomponent: `Pixel / libpixelimsmedia`
- Type/Severity: `ID / High`

## 参照情報と保存物

- Pixel bulletin: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
  - 保存: `artifacts/public/pixel-bulletin-2026-06-01.html`
  - 該当行: `CVE-2026-0157 A-481345618 * ID High libpixelimsmedia`
- OSV: `https://storage.googleapis.com/android-osv/PUB-A-481345618.json`
  - 保存: `artifacts/public/PUB-A-481345618.json`, `artifacts/public/PUB-A-481345618.pretty.json`
  - Details: `In RtcpHeader::decodeRtcpHeader, there is a possible OOB read due to a missing bounds check...`
- CVE Record API: `https://cveawg.mitre.org/api/cve/CVE-2026-0157`
  - 保存: `artifacts/public/CVE-2026-0157-cveawg.json`, `artifacts/public/CVE-2026-0157-cveawg.pretty.json`
  - ADP enrichment: `CWE-125 Out-of-bounds Read`, CVSS v3.1 `AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N`
- NVD: `https://nvd.nist.gov/vuln/detail/CVE-2026-0157`
  - 保存: `artifacts/public/nvd-CVE-2026-0157.html`
- Origin patch-diffing pipeline: `https://www.originhq.com/research/patch-diffing-pipeline`
  - 保存: `artifacts/public/originhq-patch-diffing-pipeline.html`

## 調査対象

- AOSP source clone: `/Users/eric/workspace/android/binaries/platform_packages_modules_ImsMedia.git`
- Remote: `https://android.googlesource.com/platform/packages/modules/ImsMedia`
- HEAD: `6da37b8ef8bde01956e630bb42a31a40fc1ddba3`
- 保存ソース:
  - `artifacts/source/RtcpHeader.cpp`
  - `artifacts/source/RtcpHeader.h`
  - `artifacts/source/RtcpPacket.cpp`
  - `artifacts/source/ImsMedia_HEAD.txt`
- Pixel pre/post バイナリ:
  - May: `074-ok-rtcp-mtu-mismatch-heap-oob-write/blobs/libpixelimsmedia_may_cp1a.260505.005.a1.so`
  - June: `074-ok-rtcp-mtu-mismatch-heap-oob-write/blobs/libpixelimsmedia_june_cp2a.260605.012.so`
  - SHA-256: `artifacts/analysis/blob_sha256.txt`
- 再検証ログ:
  - `artifacts/analysis/reverification_2026-06-23.txt`
  - `nm -D -C` でMay/Juneの `RtcpHeader::decodeRtcpHeader` と `RtcpPacket::decodeRtcpPacket` のアドレスを再確認した。
  - `rg` で保存済み逆アセンブル内のMay/Lineageの無条件SSRCロード、Juneの `cmp w19, #0x7; b.hi` ガードを再確認した。

## 根本原因

`RtcpHeader::decodeRtcpHeader(unsigned char*, int)` は RTCP common header を読む関数である。公開AOSPソースでは、入力長が `RTP_WORD_SIZE`、つまり4バイト以上であれば先頭4バイトを読み、RTCP length field を `m_usLength` に保存する。

問題は、`m_usLength` が非0の場合に、入力バッファがRTCP fixed header全体の8バイトを含むか確認せず、`pRtcpBuffer + 4` からSSRC 4バイトを読む点である。

```cpp
if (length < RTP_WORD_SIZE)
    return eRTP_FALSE;

RtpDt_UInt32 uiTemp4Data = RtpOsUtil::Ntohl(*(reinterpret_cast<RtpDt_UInt32*>(pRtcpBuffer)));
m_usLength = uiTemp4Data & 0x0000FFFF;
m_usLength *= RTP_WORD_SIZE;
...
if (m_usLength)
{
    pRtcpBuffer = pRtcpBuffer + RTP_WORD_SIZE;
    m_uiSsrc = RtpOsUtil::Ntohl(*(reinterpret_cast<RtpDt_UInt32*>(pRtcpBuffer)));
}
```

最小の発生条件は、実入力長が4バイトで、先頭RTCP header word内のlength fieldが非0であること。このとき先頭4バイトのロードは境界内だが、SSRC読み取りは bytes `[4..7]` を読むため完全に境界外になる。入力長5から7バイトでも部分的なOOB readになる。

根本原因は、RTCP header内の「length fieldが非0ならSSRCがあるはず」というプロトコル上の仮定を、実際の受信バッファ長で検証していないこと。`RtcpHeader` が受け取る `length` は実バッファ長なので、SSRCを読む前に `length >= RTCP_FIXED_HDR_LEN` を確認する必要があった。

## 呼び出し元の問題

`RtcpPacket::decodeRtcpPacket()` は4バイトだけのRTCP bufferを特別扱いしている。

```cpp
if (pobjRtcpPktBuf->getLength() == RTP_WORD_SIZE)
{
    m_objHeader.decodeRtcpHeader(pobjRtcpPktBuf->getBuffer(), pobjRtcpPktBuf->getLength());
    return RTP_SUCCESS;
}
```

この経路では `decodeRtcpHeader()` の戻り値を確認せず、常に `RTP_SUCCESS` を返す。したがって、4バイト長の細工RTCP packetでも `decodeRtcpHeader()` に到達し、May版ではSSRC OOB readが成立する。通常のcompound packet処理は `while (iTrackCompLen >= RTCP_FIXED_HDR_LEN)` で8バイト以上を要求するため、4バイト入力の到達経路としてこの特別扱いが重要だった。

## バイナリ差分

`nm -D -C` で May/June Pixel `libpixelimsmedia` に `RtcpHeader::decodeRtcpHeader(unsigned char*, int)` が残っていることを確認した。

- May address: `0x16eca0`
- June address: `0x179e30`
- 逆アセンブル:
  - `artifacts/analysis/RtcpHeader_decode_may.objdump.txt`
  - `artifacts/analysis/RtcpHeader_decode_june.objdump.txt`
  - `artifacts/analysis/RtcpHeader_decode_may_vs_june.diff`

May版では、先頭4バイトのチェック後、RTCP lengthが非0ならそのままSSRCを読む。

```text
16ed04: cbz w8, 0x16ed50
16ed08: ldr w0, [x20, #0x4]
16ed0c: bl  RtpOsUtil::Ntohl
16ed18: str w8, [x19, #0x10]
```

June版では、SSRCロード前に実入力長 `w19` が8バイト以上か確認するガードが追加されている。

```text
179e90: cbz w8, 0x179efc
179e94: cmp w19, #0x7
179e98: b.hi 0x179f04
...
179f04: ldr w0, [x21, #0x4]
179f08: bl  RtpOsUtil::Ntohl
179f14: str w8, [x20, #0x10]
```

`cmp w19, #0x7; b.hi` は unsigned `length > 7`、つまり `length >= 8` のときだけSSRCロードへ進む条件であり、CVE説明の missing bounds check を直接塞いでいる。

Lineage 23.2 の `libpixelimsmedia` も確認したが、同関数にはこのガードがなかった。今回の修正はPixel June 2026バイナリに入ったPixel-family specific patchと判断できる。

## 攻撃条件の復元

1. Pixel の IMS media / RTP-RTCP 受信経路で、攻撃者がRTCP packetを処理させる。
2. 実バッファ長4から7バイトの短いRTCP bufferを用意する。
3. 先頭4バイトのRTCP common header内で version を2にし、length fieldを非0にする。
4. `RtcpPacket::decodeRtcpPacket()` の4バイト特別経路、または同等に短い入力を `RtcpHeader::decodeRtcpHeader()` へ渡す経路に到達する。
5. May版では `m_usLength != 0` により `pRtcpBuffer + 4` から4バイトSSRCを読む。
6. 入力バッファ末尾を越えたメモリが `m_uiSsrc` として取り込まれる。周辺処理やログ、状態遷移でこの値が観測可能になると remote information disclosure になる。

CVE RecordのCVSSは `AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N` で、IMS/RTCP到達性は必要だがユーザー操作は不要という形と整合している。

## 公開ブランチ確認

`RtcpHeader.cpp` のSHA-256は以下の公開AOSPブランチで同一だった。

- `origin/android16-release`
- `origin/android16-security-release`
- `origin/android16-qpr2-release`
- `origin/android17-release`
- `origin/main`

保存: `artifacts/source/RtcpHeader_branch_sha256.txt`

公開AOSPブランチ上にJune Pixel修正相当のソース差分は確認できなかった。Bulletinの `*` 注記どおり、修正はPixel binary driver側に含まれたと見るのが妥当である。

## 推定される修正

最小修正は `RtcpHeader::decodeRtcpHeader()` で以下を行うこと。

- `pRtcpBuffer == nullptr` を拒否する。
- 先頭common headerを読む前に `length >= RTP_WORD_SIZE` を確認する。
- `m_usLength != 0` でSSRCを読む前に、実入力長が `RTCP_FIXED_HDR_LEN`、つまり8バイト以上あることを確認する。
- 呼び出し元 `RtcpPacket::decodeRtcpPacket()` は `decodeRtcpHeader()` の戻り値を無視しない。

推定ソース差分は `artifacts/analysis/inferred_fix_RtcpHeader_decodeRtcpHeader.diff` に保存した。これはJune Pixelバイナリで見えた `length >= 8` ガードをソースに戻したもので、非公開Googleパッチそのものではない。

## 面白い点・調査メモ

- 同じJune 2026の `libpixelimsmedia` にはRTCP/RTP parserの境界チェック不備が複数あった。今回の0157は最も入口に近い `RtcpHeader` のSSRC読み取り不備で、0128/0129のようなpacket subtype decoderより上流の問題だった。
- 公開AOSPソースでは `RtcpHeader::decodeRtcpHeader()` 冒頭に `pRtcpBuffer == nullptr` チェックがないが、Pixel May/Juneバイナリには `cbz x1` があり、少なくともnull checkはバイナリ側で追加済みだった。CVEの本質はnullではなく、4から7バイト入力でのSSRCロードである。
- `m_usLength` はRTCP length fieldを4倍した値として扱われる。RTCP仕様本来のlengthは「32-bit words minus one」だが、この実装では送信側の `formPartialRtcpHeader()` も独自変換を行っており、長さ概念が複数箇所でずれている。今回のように「field上は非0」と「実バッファに8バイトある」を分けて確認しないと境界外読み取りになる。
- `RtcpPacket::decodeRtcpPacket()` の4バイト特別経路は、戻り値無視と成功返却が重なっており、防御的には削除または厳密化すべきである。

## 生成した付帯ファイル

- `artifacts/public/PUB-A-481345618.json`
- `artifacts/public/CVE-2026-0157-cveawg.json`
- `artifacts/public/pixel-bulletin-2026-06-01.html`
- `artifacts/public/nvd-CVE-2026-0157.html`
- `artifacts/public/originhq-patch-diffing-pipeline.html`
- `artifacts/source/RtcpHeader.cpp`
- `artifacts/source/RtcpPacket.cpp`
- `artifacts/source/RtcpHeader_branch_sha256.txt`
- `artifacts/analysis/RtcpHeader_decode_may.objdump.txt`
- `artifacts/analysis/RtcpHeader_decode_june.objdump.txt`
- `artifacts/analysis/RtcpHeader_decode_may_vs_june.diff`
- `artifacts/analysis/RtcpPacket_decode_june.objdump.txt`
- `artifacts/analysis/rtcp_header_oob_read_conditions.txt`
- `artifacts/analysis/inferred_fix_RtcpHeader_decodeRtcpHeader.diff`
- `artifacts/analysis/reverification_2026-06-23.txt`
- `artifacts/artifacts_sha256.txt`

## 結論

CVE-2026-0157 は、Pixel `libpixelimsmedia` の `RtcpHeader::decodeRtcpHeader` が、RTCP length fieldが非0のとき実入力長を8バイト以上と確認せずSSRC 4バイトを読むことに起因する out-of-bounds read / remote information disclosure である。May版PixelバイナリではSSRCロード前の長さチェックがなく、June版では `length >= 8` ガードが追加されている。根本原因は、外部入力由来のRTCP header長と実バッファ長の整合性チェック欠落である。
094 OK

CVE-2026-0165

094-ok-rtcp-sdes-chunk-payload-oob-read-id

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
Subcomponentlibpixelimsmedia
TypeID
SeverityHigh
ReferencesA-491016892
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0165 is listed in the Pixel Update Bulletin as a High severity ID issue in Pixel / libpixelimsmedia.

特定した具体的な脆弱性

CVE-2026-0165 は、Pixel libpixelimsmedia のRTCP decoderにおいて、SDES chunk/itemの可変長フィールドを実受信バッファ残長で検証していなかった out-of-bounds read / remote information disclosure である。May版では RtcpSdesPacket::decodeSdesPacket() が残り長を RtcpChunk::decodeRtcpChunk() に渡さず、RtcpChunk はSDES item length を信じて memcpy する。June版では RtcpChunk::decodeRtcpChunk に残り長引数が追加され、type、length、value copyの各段階で境界チェックが入った。併せて RtcpRrPacket::decodeRrPacket のprofile extension長 underflowも修正されており、OSVの「RTCP packet decoderの複数関数」という説明と整合する。

原因

CVE-2026-0165 の主な実体は、RTCP SDES decoder が受信packetの残り長を RtcpChunk::decodeRtcpChunk() に渡しておらず、SDES itemの type、length、value を実バッファ長と照合せずに読むことだった。

公開AOSPソースの RtcpSdesPacket::decodeSdesPacket() は usSdesLen を持っているが、chunk decoderには渡していない。

``cpp
eChunkStatus = pobjRtcpChunk->decodeRtcpChunk(pucSdesBuf, usChunkSize, pobjRtcpCfgInfo);
`

RtcpChunk::decodeRtcpChunk() 側は RtcpConfigInfo::getSdesItemCount() の回数だけSDES itemを読む。各itemについて、1バイトtype、1バイトlength、lengthバイトvalueを順に読むが、どの段階でも残りpacket長を確認しない。

どこから特定したか

参照情報と保存物: ・Pixel bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- 保存: artifacts/public/pixel-bulletin-2026-06-01.html
- 該当抜粋: artifacts/public/pixel-bulletin-CVE-2026-0165-excerpt.txt
- 行内容: CVE-2026-0165 A-491016892 * ID High libpixelimsmedia
・OSV: https://storage.googleapis.com/android-osv/PUB-A-491016892.json
- 保存: artifa…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https://storage.googleapis.com/android-osv/PUB-A-491016892.json` / https://cveawg.mitre.org/api/cve/CVE-2026-0165` / https://www.originhq.com/research/patch-diffing-pipeline`

validated.md を表示
# CVE-2026-0165 検証結果

## 判定

`ok`: 脆弱性の発生条件、根本原因、Pixel May/June バイナリ上の修正点を特定できた。

タイトル: `rtcp-sdes-chunk-payload-oob-read-id`

## 既存 cve.md から確認した情報

- CVE: `CVE-2026-0165`
- Reference: `A-491016892`
- Bulletin: Pixel Update Bulletin
- Bulletin URL: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- Published/updated: `June 16, 2026`
- Security patch level: `2026-06-05 or later`
- Component/Subcomponent: `Pixel / libpixelimsmedia`
- Type/Severity: `ID / High`

## 参照情報と保存物

- Pixel bulletin: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
  - 保存: `artifacts/public/pixel-bulletin-2026-06-01.html`
  - 該当抜粋: `artifacts/public/pixel-bulletin-CVE-2026-0165-excerpt.txt`
  - 行内容: `CVE-2026-0165 A-491016892 * ID High libpixelimsmedia`
- OSV: `https://storage.googleapis.com/android-osv/PUB-A-491016892.json`
  - 保存: `artifacts/public/PUB-A-491016892.json`, `artifacts/public/PUB-A-491016892.pretty.json`
  - Details: RTCP packet decoder の複数関数で missing bounds check による out-of-bounds read、remote information disclosure、user interaction required。
- CVE Record API: `https://cveawg.mitre.org/api/cve/CVE-2026-0165`
  - 保存: `artifacts/public/CVE-2026-0165-cveawg.json`, `artifacts/public/CVE-2026-0165-cveawg.pretty.json`
  - ADP enrichment: `CWE-120`, `CWE-125`, CVSS v3.1 `AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N`
- Origin patch-diffing pipeline: `https://www.originhq.com/research/patch-diffing-pipeline`
  - 保存: `artifacts/public/originhq-patch-diffing-pipeline.html`

## 調査対象

- AOSP source clone: `/Users/eric/workspace/android/binaries/platform_packages_modules_ImsMedia.git`
- Remote: `https://android.googlesource.com/platform/packages/modules/ImsMedia`
- HEAD: `6da37b8ef8bde01956e630bb42a31a40fc1ddba3`
- 保存ソース:
  - `artifacts/source/RtcpPacket.cpp`
  - `artifacts/source/RtcpSdesPacket.cpp`
  - `artifacts/source/RtcpChunk.cpp`
  - `artifacts/source/RtcpRrPacket.cpp`
  - `artifacts/source/RtcpSrPacket.cpp`
  - `artifacts/source/ImsMedia_HEAD.txt`
- Pixel pre/post バイナリ:
  - May: `074-ok-rtcp-mtu-mismatch-heap-oob-write/blobs/libpixelimsmedia_may_cp1a.260505.005.a1.so`
  - June: `074-ok-rtcp-mtu-mismatch-heap-oob-write/blobs/libpixelimsmedia_june_cp2a.260605.012.so`
  - SHA-256: `artifacts/analysis/blob_sha256.txt`

## 根本原因

CVE-2026-0165 の主な実体は、RTCP SDES decoder が受信packetの残り長を `RtcpChunk::decodeRtcpChunk()` に渡しておらず、SDES itemの `type`、`length`、`value` を実バッファ長と照合せずに読むことだった。

公開AOSPソースの `RtcpSdesPacket::decodeSdesPacket()` は `usSdesLen` を持っているが、chunk decoderには渡していない。

```cpp
eChunkStatus = pobjRtcpChunk->decodeRtcpChunk(pucSdesBuf, usChunkSize, pobjRtcpCfgInfo);
```

`RtcpChunk::decodeRtcpChunk()` 側は `RtcpConfigInfo::getSdesItemCount()` の回数だけSDES itemを読む。各itemについて、1バイトtype、1バイトlength、lengthバイトvalueを順に読むが、どの段階でも残りpacket長を確認しない。

```cpp
pstSdesItem->ucType = *(reinterpret_cast<RtpDt_UChar*>(pucChunkBuf));
...
pstSdesItem->ucLength = *(reinterpret_cast<RtpDt_UChar*>(pucChunkBuf));
...
memcpy(pcSdesBuf, pucChunkBuf, pstSdesItem->ucLength);
```

したがって、RTCP SDES packetとしてdecoderに到達する最小長だけを満たし、SDES item lengthを実際の残りbytesより大きくした入力で、packet境界外のメモリが `memcpy` により `pcSdesBuf` へ読み込まれる。根本原因は、外部入力由来の可変長SDES item長と実受信バッファ残長の整合性チェック欠落である。

## 攻撃条件の復元

1. Pixel の IMS media / RTCP 受信経路で `RtcpPacket::decodeRtcpPacket()` にRTCP packetを処理させる。
2. RTCP packet typeを `RTCP_SDES` にし、`RC/source count` を非0にする。
3. RTCP header lengthはdecoderがSDES bodyに入る程度に整える。
4. SDES chunk内に `type=1`、つまりCNAMEを含める。CNAMEがないとdecode末尾で `RTP_DECODE_ERROR` になるが、OOB read自体はvalue copy時点で先に起きる。
5. SDES itemの `length` byteを、実際にpacket内に残っているvalue bytesより大きくする。
6. May版では `memcpy(pcSdesBuf, pucChunkBuf, ucLength)` がpacket末尾を越えて読み、周辺メモリをchunk item valueとして保存する。

代表例は、chunk残り長が2バイトだけで `type=1, length=18` を置くケースである。May版はtype/lengthを境界内で読んだ後、valueが0バイトしか残っていないにもかかわらず18バイトをコピーする。

詳細な条件メモは `artifacts/analysis/rtcp_decoder_oob_read_conditions.txt` に保存した。

## バイナリ差分

`nm -D -C -S` で May/June のRTCP decoder関数サイズとシンボルを比較した。保存:

- `artifacts/analysis/nm_may_decode_symbols.txt`
- `artifacts/analysis/nm_june_decode_symbols.txt`
- `artifacts/analysis/nm_may_decode_size.txt`
- `artifacts/analysis/nm_june_decode_size.txt`

重要な差分は以下。

- May: `RtcpChunk::decodeRtcpChunk(unsigned char*, unsigned short&, RtcpConfigInfo*)`, size `0x1bc`
- June: `RtcpChunk::decodeRtcpChunk(unsigned char*, unsigned short, unsigned short&, RtcpConfigInfo*)`, size `0x294`
- May: `RtcpSdesPacket::decodeSdesPacket(...)`, size `0x13c`
- June: `RtcpSdesPacket::decodeSdesPacket(...)`, size `0x210`
- May: `RtcpRrPacket::decodeRrPacket(...)`, size `0x140`
- June: `RtcpRrPacket::decodeRrPacket(...)`, size `0x168`

June版では `RtcpChunk::decodeRtcpChunk` のABIが変わり、2番目の `unsigned short` として残り長が渡される。関数内では以下のチェックが追加されている。

```text
17c7ac: ldrh w8, [x19]      ; consumed length
17c7b0: and  w20, w21, #0xffff ; remaining length argument
17c7b4: cmp  w8, w20
17c7b8: b.hs error
...
17c810: cmp  w9, w21, uxth  ; length byteを読む前の境界確認
17c814: b.hs error
...
17c854: add  w9, w8, w27    ; consumed + item_length
17c858: cmp  w9, w20
17c85c: b.hi error          ; value memcpy前の境界確認
```

May版では対応する境界チェックがなく、`ldrb [x21]`、`ldrb [x21,#1]`、`memcpy` がそのまま実行される。

```text
1714f0: ldrb w10, [x21]      ; type
171518: ldrb w9, [x21, #0x1] ; length
...
171560: mov  x1, x21
171564: mov  x27, x0
171568: bl   memcpy
```

逆アセンブル保存:

- `artifacts/analysis/RtcpChunk_decodeRtcpChunk_may.objdump.txt`
- `artifacts/analysis/RtcpChunk_decodeRtcpChunk_june.objdump.txt`
- `artifacts/analysis/RtcpChunk_decodeRtcpChunk_may_vs_june.diff`
- `artifacts/analysis/RtcpSdesPacket_decodeSdesPacket_may.objdump.txt`
- `artifacts/analysis/RtcpSdesPacket_decodeSdesPacket_june.objdump.txt`
- `artifacts/analysis/RtcpSdesPacket_decodeSdesPacket_may_vs_june.diff`

## 同じパッチで見えた追加修正

June版では `RtcpRrPacket::decodeRrPacket()` にも `usRrLen >= usProfExtLen` のチェックが追加されていた。公開ソースでは以下のように16-bitで減算するため、`usProfExtLen > usRrLen` ならwrapし、report block読み取りやprofile extension copyが実packet境界を越える。

```cpp
RtpDt_UInt16 usRepBlkLen = usRrLen - usProfExtLen;
...
memcpy(pcProfExtBuf, pucRrBuf, usProfExtLen);
```

June版の入口では以下が追加されている。

```text
17be54: ldrh w8, [x2]  ; usRrLen
17be58: mov  w19, w3   ; usProfExtLen
17be60: cmp  w8, w21
17be64: b.hs continue  ; usRrLen >= usProfExtLen の場合だけ継続
```

このため、OSVの「several functions of the RTCP packet decoder」という表現は、`RtcpSdesPacket`/`RtcpChunk` のSDES残長伝播修正に加えて、`RtcpRrPacket` のprofile-specific extension長検証も含む広いRTCP decoder hardeningを指している可能性が高い。

保存:

- `artifacts/analysis/RtcpRrPacket_decodeRrPacket_may.objdump.txt`
- `artifacts/analysis/RtcpRrPacket_decodeRrPacket_june.objdump.txt`
- `artifacts/analysis/RtcpRrPacket_decodeRrPacket_may_vs_june.diff`
- `artifacts/analysis/inferred_fix_rtcp_sdes_chunk_bounds.diff`

## 推定される修正

最小修正は以下。

- `RtcpSdesPacket::decodeSdesPacket()` がchunk decoderへ現在の残りSDES payload長を渡す。
- `RtcpChunk::decodeRtcpChunk()` の引数に `usRemainingLen` を追加する。
- type byteを読む前に `usChunkLen + 1 <= usRemainingLen` を確認する。
- length byteを読む前に `usChunkLen + 1 <= usRemainingLen` を確認する。
- valueをcopyする前に `usChunkLen + ucLength <= usRemainingLen` を確認する。
- `RtcpRrPacket::decodeRrPacket()` では `usRrLen < usProfExtLen` を拒否してから減算する。

推定ソース差分は `artifacts/analysis/inferred_fix_rtcp_sdes_chunk_bounds.diff` に保存した。これはMay/Juneバイナリ差分から復元した最小修正案であり、非公開Googleパッチそのものではない。

## 面白い点・調査メモ

- 公開AOSPの `RtcpChunkTest.cpp` には「decodeRtcpChunkでpayload lengthを検証するテストを追加する」「RtcpChunk.cppにSdes Payload Length検証のfixが必要」というTODOが残っていた。これは今回の根本原因とほぼ同じ問題意識で、既存テストからも弱点が見えていた。
- `RtcpSdesPacket::decodeSdesPacket()` は `usSdesLen -= usChunkSize` を行うが、May版では `usChunkSize` が実残長を超えても先に `RtcpChunk` 側でOOB readが起きる。呼び出し元で長さ変数を持っていても、calleeへ渡さない設計が脆弱性の直接原因になっていた。
- June版 `RtcpSdesPacket` は2個目以降のchunkで、残り長が4バイトを超える場合だけSSRCを読むようになっている。May版はchunk処理がより単純で、SDESの複数source/chunk処理も長さに対して脆かった。
- 同じJune 2026の `libpixelimsmedia` にはRTCP/RTP parserの境界チェック不備が多数あり、今回の0165は「単一関数」ではなく、RTCP decoder全体で残長をcalleeへ渡していなかった設計問題の修正として見える。
- `CVE-2026-0155` / `A-476132502` は別途OSVで `ImsMediaBitReader::ReadByteBuffer` と明示されており、今回のRTCP decoder問題とは切り分けられる。

## 生成した付帯ファイル

- `artifacts/public/PUB-A-491016892.json`
- `artifacts/public/PUB-A-491016892.pretty.json`
- `artifacts/public/CVE-2026-0165-cveawg.json`
- `artifacts/public/CVE-2026-0165-cveawg.pretty.json`
- `artifacts/public/pixel-bulletin-2026-06-01.html`
- `artifacts/public/pixel-bulletin-CVE-2026-0165-excerpt.txt`
- `artifacts/public/originhq-patch-diffing-pipeline.html`
- `artifacts/source/RtcpPacket.cpp`
- `artifacts/source/RtcpSdesPacket.cpp`
- `artifacts/source/RtcpChunk.cpp`
- `artifacts/source/RtcpRrPacket.cpp`
- `artifacts/source/RtcpSrPacket.cpp`
- `artifacts/source/ImsMedia_HEAD.txt`
- `artifacts/source/RtcpSdes_Chunk_git_log.txt`
- `artifacts/analysis/nm_may_decode_symbols.txt`
- `artifacts/analysis/nm_june_decode_symbols.txt`
- `artifacts/analysis/nm_may_decode_size.txt`
- `artifacts/analysis/nm_june_decode_size.txt`
- `artifacts/analysis/RtcpChunk_decodeRtcpChunk_may.objdump.txt`
- `artifacts/analysis/RtcpChunk_decodeRtcpChunk_june.objdump.txt`
- `artifacts/analysis/RtcpChunk_decodeRtcpChunk_may_vs_june.diff`
- `artifacts/analysis/RtcpSdesPacket_decodeSdesPacket_may.objdump.txt`
- `artifacts/analysis/RtcpSdesPacket_decodeSdesPacket_june.objdump.txt`
- `artifacts/analysis/RtcpSdesPacket_decodeSdesPacket_may_vs_june.diff`
- `artifacts/analysis/RtcpRrPacket_decodeRrPacket_may.objdump.txt`
- `artifacts/analysis/RtcpRrPacket_decodeRrPacket_june.objdump.txt`
- `artifacts/analysis/RtcpRrPacket_decodeRrPacket_may_vs_june.diff`
- `artifacts/analysis/rtcp_decoder_oob_read_conditions.txt`
- `artifacts/analysis/inferred_fix_rtcp_sdes_chunk_bounds.diff`
- `artifacts/artifacts_sha256.txt`

## 結論

CVE-2026-0165 は、Pixel `libpixelimsmedia` のRTCP decoderにおいて、SDES chunk/itemの可変長フィールドを実受信バッファ残長で検証していなかった out-of-bounds read / remote information disclosure である。May版では `RtcpSdesPacket::decodeSdesPacket()` が残り長を `RtcpChunk::decodeRtcpChunk()` に渡さず、`RtcpChunk` はSDES item `length` を信じて `memcpy` する。June版では `RtcpChunk::decodeRtcpChunk` に残り長引数が追加され、type、length、value copyの各段階で境界チェックが入った。併せて `RtcpRrPacket::decodeRrPacket` のprofile extension長 underflowも修正されており、OSVの「RTCP packet decoderの複数関数」という説明と整合する。
095 NG

CVE-2026-0136

095-ng-pixel-modem-oob-read-dos

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentModem
TypeDoS
SeverityHigh
ReferencesA-460779217
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0136 is listed in the Pixel Update Bulletin as a High severity DoS issue in Pixel / Modem.

NG 判定の要点

判定: ng

CVE-2026-0136 は Pixel / Modem の High severity DoS として公開されており、公開 OSV/CVE 情報では missing bounds check による out-of-bounds read と説明されている。リモートから到達可能で、追加権限不要、ユーザー操作不要、影響は denial of service とされる。

ただし、今回の検証では CVE-2026-0136 に対応する具体的な関数、入力メッセージ、追加された bounds check、またはクラッシュ条件を一意に特定できなかった。Pixel bulletin の A-460779217 は * 付きの非公開 bug ID で、AOSP/source commit へのリンクはない。手元の Pixel 8 shiba radio/modem firmware 差分は大規模な modem firmware 再ビルドで、同じ bulletin 内の複数 Modem RCE/DoS 修正や通常更新が混在しているため、この差分だけで本 CVE 固有の根本原因を切り出すには不十分だった。

未確定の理由 / 原因候補

この作業の基準では、ok とするにはソースコード、または脆弱性が起きる状況を完璧に説明できる必要がある。今回は以下の理由で満たせない。

・A-460779217 が非公開。
・Pixel Modem firmware は closed-source で、公開 commit/diff がない。
・手元の比較は firmware 全体の再ビルド差分で、関数単位 diff まで落とせていない。
・同じ bulletin の複数 Modem 脆弱性と通常更新が同じ modem.bin 差分に混在している。
・OOB read に整合する候補ログは複数あるが、CVE-2026-0136 固有の入力フィールド、関数、bounds check 条件式、クラッシュ条件を特定できていない。

どこから特定したか

公開情報で確認できた内容: 保存先:

・artifacts/public/pixel-2026-06-01-bulletin.html
・artifacts/public/PUB-A-460779217.json
・artifacts/public/PUB-A-460779217.pretty.json
・artifacts/public/CVE-2026-0136.cve5.json
・artifacts/public/CVE-2026-0136.cve5.pretty.json

Pixel bulletin の該当行は以下。

・CVE-2026-0136
・A-460779217*
・DoS
・High
・Modem

解析したバイナリ: 既存の ../binaries/pixel_shiba_wc_radio/ を使用した。CVE 固有に新規ダウンロードした firmware はない。

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`

validated.md を表示
# CVE-2026-0136 Pixel Modem DoS 解析結果

## 結論

判定: **ng**

CVE-2026-0136 は Pixel / Modem の High severity DoS として公開されており、公開 OSV/CVE 情報では **missing bounds check による out-of-bounds read** と説明されている。リモートから到達可能で、追加権限不要、ユーザー操作不要、影響は denial of service とされる。

ただし、今回の検証では **CVE-2026-0136 に対応する具体的な関数、入力メッセージ、追加された bounds check、またはクラッシュ条件を一意に特定できなかった**。Pixel bulletin の `A-460779217` は `*` 付きの非公開 bug ID で、AOSP/source commit へのリンクはない。手元の Pixel 8 `shiba` radio/modem firmware 差分は大規模な modem firmware 再ビルドで、同じ bulletin 内の複数 Modem RCE/DoS 修正や通常更新が混在しているため、この差分だけで本 CVE 固有の根本原因を切り出すには不十分だった。

## 最初に確認した cve.md 情報

- CVE: `CVE-2026-0136`
- Android bug reference: `A-460779217`
- Component/Subcomponent: `Pixel / Modem`
- Type/Severity: `DoS / High`
- Bulletin URL: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- Bulletin published/updated in cve.md: `June 16, 2026`
- Security patch level: `2026-06-05 or later`

## 公開情報で確認できた内容

保存先:

- `artifacts/public/pixel-2026-06-01-bulletin.html`
- `artifacts/public/PUB-A-460779217.json`
- `artifacts/public/PUB-A-460779217.pretty.json`
- `artifacts/public/CVE-2026-0136.cve5.json`
- `artifacts/public/CVE-2026-0136.cve5.pretty.json`

Pixel bulletin の該当行は以下。

- `CVE-2026-0136`
- `A-460779217*`
- `DoS`
- `High`
- `Modem`

OSV `PUB-A-460779217` の公開説明は、Modem に missing bounds check による possible out-of-bounds read があり、remote DoS につながり得る、追加権限不要、ユーザー操作不要、という内容だった。CVE v5 / CISA ADP では `CWE-125 Out-of-bounds Read` と `CWE-120 Buffer Copy without Checking Size of Input` が付与され、CVSS v3.1 は `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H` / 6.5 / Medium だった。Pixel bulletin 側の severity は High で、CVE ADP 側の CVSS severity と差がある。

## 解析したバイナリ

既存の `../binaries/pixel_shiba_wc_radio/` を使用した。CVE 固有に新規ダウンロードした firmware はない。

- 修正前候補: `../binaries/pixel_shiba_wc_radio/radio-shiba-g5300i-251202-260127-b-14784800.img`
  - SHA-256: `db5a0c8161d9cc674ec348c07460495f36ef9209740c03f44c14386501c2f80d`
  - build.info date: `2026-01-27T11:35:17+00:00`
- 修正後候補: `../binaries/pixel_shiba_wc_radio/radio-shiba-g5300i-260317-260505-b-15346003.img`
  - SHA-256: `5bee584549ee24ce7b5465831c007277fd9c1ab73d618a53e607c8d9ade6fdd5`
  - build.info date: `2026-05-05T10:11:26+00:00`

抽出した `modem.bin` はこのフォルダにも保存した。

- `artifacts/extract/old/images/g5300i-251202-260127-B-14784800/modem.bin`
- `artifacts/extract/new/images/g5300i-260317-260505-B-15346003/modem.bin`

## 実施した patch diffing

OriginHQ の patch diffing pipeline と同じ考え方で、公開 advisory から対象 bug ID を確認し、前後 firmware を収集済み binary から選び、コンテナ展開、ファイル manifest、hash、文字列差分、候補文字列オフセット確認を行った。

主な付帯ファイル:

- `artifacts/analysis/old_manifest.txt`, `artifacts/analysis/new_manifest.txt`
- `artifacts/analysis/old_extracted_sha256.txt`, `artifacts/analysis/new_extracted_sha256.txt`
- `artifacts/analysis/normalized_file_diff.txt`
- `artifacts/analysis/modem_toc_diff.tsv`
- `artifacts/analysis/old_modem_strings_offsets.txt`, `artifacts/analysis/new_modem_strings_offsets.txt`
- `artifacts/analysis/added_modem_strings_triage.txt`, `artifacts/analysis/removed_modem_strings_triage.txt`
- `artifacts/analysis/normalized_added_suspicious.txt`, `artifacts/analysis/normalized_removed_suspicious.txt`
- `artifacts/analysis/candidate_string_offsets.txt`
- `artifacts/artifacts_sha256.txt`

## バイナリ差分で分かったこと

Radio image は `FBPK` コンテナで、内部 tar から ext4 風 payload を取り出せる。ext4 には `/images/<version>/modem.bin`、`uecap/*.binarypb`、`confpack/`、`cfg.db`、`confseqs/`、`manifests/` などが含まれる。

`modem.bin` は TOC を持つコンテナで、`BOOT`, `MAIN`, `VSS`, `APM`, `NV_NORM`, `NV_PROT`, `REPLAY` などの entry が見える。前後差分では `MAIN` セクションが約 80 MiB 規模で変化しており、単一関数のパッチというより firmware 全体の大規模更新だった。

`normalized_file_diff.txt` 上、バージョン名を正規化しても `modem.bin`、`confpack/cfg.db`、`cfg.sha2`、`build.info`、`release-label`、symbolic link mapping 類が変化している。confpack / carrier config も多数入れ替わっており、コード差分だけでなく設定更新も混在している。

## OOB read に関係し得る候補

`strings` 差分から length / decode / invalid / range / read / copy / size などを含むログを抽出した。特に OOB read / insufficient length check と整合する候補は以下。

- `Fail due to Input length(%d bits) < unpackedLen(%d bits)` 系: LTE/UMTS/RRLP ProASN decode の入力長不足チェック。ASN.1 decode が入力 bit 長を超えて読む問題と整合し得る。
- `@[ERROR][MACTX][ENTITY:%d][ScheduleCCCH] remainGrantSize=%d < SchedDataSize=%d`: MAC TX の grant size と scheduled data size の不一致チェック。読み過ぎ/書き過ぎの防止に見える。
- `@[SrbId:0x%02x][ERROR] Integrity verification fail !!! Invalid SMC PDU (Length=%d Count=%d Algo=%d Key=0x%08x dir=%d)`: RRC/SMC PDU の長さ検証失敗ログ。
- `Warn>[IMSCH TPC] Integer overflow - Rcv pkt content len exceeds max value`: IMS/SIP header/content length の overflow 防止ログ。
- `BUILD*TABLE: input data size overflow`, `pData length is overflow`: RF calibration / AT 系の入力サイズ検証ログ。
- `LBS_SetEmcRequestLocationInfo() - Memory Allocation Failed!`, `Copied EMM Message!`: LBS/EMC location 周辺の可変長 EMM message copy 処理。

ただし、これらの多くは旧版にも同一本文またはログ prefix 違いで存在し、単純に「June 修正で追加された check」とは言えない。新旧 `modem.bin` は全体的に再配置されており、文字列オフセットも数 KiB 単位でずれる。`candidate_string_offsets.txt` に前後の候補文字列オフセットを保存したが、CVE-2026-0136 固有の関数境界や制御フロー差分までは確認できなかった。

## 脆弱性と根本原因の評価

公開情報から確実に言える根本原因は以下。

- Modem firmware の外部入力処理に bounds check 不足があった。
- 入力由来の length、index、count、TLV/IE/PDU/ASN.1 field などを検証しきれず、buffer の範囲外を読む可能性があった。
- 範囲外読み取りにより modem process / baseband firmware がクラッシュし、remote denial of service になる。
- 攻撃は network 経由で成立し得るとされ、ユーザー操作は不要。

今回のバイナリ差分から推測できる候補領域は、ASN.1/RRC decode、MAC/RLC PDU、IMS/SIP content length、LBS/EMM message copy、RF/AT table input など複数ある。しかし、`A-460779217` が非公開で、同じ firmware 更新に複数の Modem CVE が含まれるため、どれが CVE-2026-0136 かは断定できない。

したがって、根本原因カテゴリは **missing bounds check による OOB read** と確認できたが、「脆弱性が起きる状況を完璧に説明できる」水準には達していない。

## 面白い点・調査メモ

- `A-460779217` は bulletin 上で `*` 付き。Pixel の binary driver / firmware 側に修正があるが、bug tracker や commit は公開されていない類型と考えられる。
- CVE v5 の `affected.version` は `Android kernel` と記載されているが、bulletin では `Pixel / Modem`。Google Devices CVE の定型出力が実態より粗い可能性がある。
- Pixel bulletin severity は High、一方で CISA ADP CVSS base severity は Medium。DoS の実運用影響を Pixel 側が高めに評価している可能性がある。
- `modem.bin` の MAIN 差分は大規模で、同じ June 2026 bulletin の `CVE-2026-0132`, `CVE-2026-0135`, `CVE-2026-0139`, `CVE-2026-0154`, `CVE-2026-0164` など Modem RCE 修正と混在している可能性が高い。
- `strings` だけでも Samsung/Pixel modem 内部のモジュール名、RRC/ASN.1、IMS/SIP、LBS/PRS、RF calibration、AT command 周辺のログがかなり見えるが、これは証拠というより探索の入口に留まる。

## ok にしなかった理由

この作業の基準では、ok とするにはソースコード、または脆弱性が起きる状況を完璧に説明できる必要がある。今回は以下の理由で満たせない。

- `A-460779217` が非公開。
- Pixel Modem firmware は closed-source で、公開 commit/diff がない。
- 手元の比較は firmware 全体の再ビルド差分で、関数単位 diff まで落とせていない。
- 同じ bulletin の複数 Modem 脆弱性と通常更新が同じ `modem.bin` 差分に混在している。
- OOB read に整合する候補ログは複数あるが、CVE-2026-0136 固有の入力フィールド、関数、bounds check 条件式、クラッシュ条件を特定できていない。

## 追加で必要なもの

- 同一 Pixel device / 同一 modem branch の 2026-06-05 SPL 直前直後の radio image。
- `modem.bin` MAIN セクションを関数単位に分割できる loader / symbol recovery / Ghidra project。
- BinDiff/Diaphora 相当の関数 diff と、候補ログ文字列への xref。
- `A-460779217` に関する crash log、vendor advisory、PoC、または bug tracker の追加公開情報。
096 OK

CVE-2026-0137

096-ok-edgetpu-sync-fence-group-shutdown-uaf

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentEdgeTPU Kernel Driver
TypeEoP
SeverityModerate
ReferencesA-467353904
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0137 is listed in the Pixel Update Bulletin as a Moderate severity EoP issue in Pixel / EdgeTPU Kernel Driver.

特定した具体的な脆弱性

OK。Pixel EdgeTPU Kernel Driver の edgetpu_sync_fence_group_shutdown() における dma-fence lifetime 管理ミスによる use-after-free と特定した。

今回は公開ソースだけでなく、May/June 2026 の Pixel vendor_dlkm.img から rio.ko を抽出して比較した。June 側では同関数が 0x128 bytes から 0x314 bytes に増え、signal 前の fence refcount 取得、safe traversal、一時 list 退避、後段の dma_fence_put() 相当処理が追加されていた。これは OSV が名指しする UAF と一致する。

原因

記載なし。

どこから特定したか

解析対象: 公開ソース:

保存した付帯ファイル: ・artifacts/public/PUB-A-467353904.osv.json
・artifacts/public/PUB-A-467353904.pretty.json
・artifacts/public/pixel-bulletin-2026-06-01.html
・artifacts/public/origin-patch-diffing-pipeline.html
・artifacts/binary_inventory.txt
・artifacts/payload_may/vendor_dlkm.img
・artifacts/payload_june/vendor_dlkm.img
・artifacts/payload_may/extract/rio.ko
・artifacts/payload_…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01 / https://osv.dev/vulnerability/PUB-A-467353904 / https://storage.googleapis.com/android-osv/PUB-A-467353904.json / https://android.googlesource.com/kernel/google-modules/edgetpu/rio`

validated.md を表示
# CVE-2026-0137 / A-467353904 検証結果

## 判定

OK。Pixel EdgeTPU Kernel Driver の `edgetpu_sync_fence_group_shutdown()` における dma-fence lifetime 管理ミスによる use-after-free と特定した。

今回は公開ソースだけでなく、May/June 2026 の Pixel `vendor_dlkm.img` から `rio.ko` を抽出して比較した。June 側では同関数が 0x128 bytes から 0x314 bytes に増え、signal 前の fence refcount 取得、safe traversal、一時 list 退避、後段の `dma_fence_put()` 相当処理が追加されていた。これは OSV が名指しする UAF と一致する。

## 基本情報

- CVE: CVE-2026-0137
- 参照ID: A-467353904 / PUB-A-467353904
- Component / Subcomponent: Pixel / EdgeTPU Kernel Driver
- 種別: EoP
- Severity: Moderate
- Bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- OSV: https://osv.dev/vulnerability/PUB-A-467353904
- OSV raw JSON: https://storage.googleapis.com/android-osv/PUB-A-467353904.json
- 修正 SPL: 2026-06-05

OSV の説明は、`edgetpu_sync_fence_group_shutdown()` of `edgetpu-dmabuf.c` に UAF があり、System 実行権限が必要なローカル攻撃者がユーザー操作なしで権限昇格できる、という内容だった。

## 解析対象

公開ソース:

- repo: `https://android.googlesource.com/kernel/google-modules/edgetpu/rio`
- local clone: `../binaries/kernel_google_modules_edgetpu_rio.git`
- 主な確認 ref: `android-16.0.0_r0.3`
- commit: `833176f56239154c046a4c3fda0ab65a24230005`
- note: 公開ソースは構造確認用。May/June `rio.ko` では `edgetpu_sync_fence_group_shutdown()` 自体が `group->lock` を lock/unlock しており、公開 tag と完全一致ではない。最終判定はバイナリ差分を優先した。

バイナリ:

- May/pre OTA: `../binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.truncated.zip`
- June/post OTA: `../binaries/pixel_shiba_ota/shiba-ota-cp2a.260605.012-b315a1a2.zip`
- 抽出 partition: `artifacts/payload_may/vendor_dlkm.img`, `artifacts/payload_june/vendor_dlkm.img`
- 抽出 module: `artifacts/payload_may/extract/rio.ko`, `artifacts/payload_june/extract/rio.ko`

ハッシュと抽出手順は `artifacts/binary_inventory.txt` に保存した。

## 脆弱なコード構造

公開ソース `artifacts/source/edgetpu-dmabuf.android-16.0.0_r0.3.c` では、`struct edgetpu_dma_fence` が `struct gcip_dma_fence gfence` と `group->dma_fence_list` 用の `group_list` を持つ。

重要な箇所:

- `struct edgetpu_dma_fence`: lines 42-46
- `edgetpu_dma_fence_release()`: lines 200-212
- `edgetpu_dma_fence_after_init()`: lines 223-230
- `edgetpu_sync_fence_group_shutdown()`: lines 271-291
- `gcip_dma_fence_init()`: `artifacts/source/gcip-dma-fence.android-16.0.0_r0.3.c` lines 96-147
- `gcip_dma_fenceptr_signal()`: same file lines 183-186

脆弱版の流れ:

1. `edgetpu_sync_fence_create()` が `etfence` を `kzalloc()` し、`etfence->group = edgetpu_device_group_get(group)` で group 参照を持つ。
2. `gcip_dma_fence_init()` が `dma_fence_init()` と `sync_file_create()` を行い、sync_file が fence 参照を持つため初期参照を `dma_fence_put()` で落とす。
3. `after_init` callback の `edgetpu_dma_fence_after_init()` が `etfence->group_list` を `group->dma_fence_list` に追加する。
4. group teardown 時、`edgetpu_sync_fence_group_shutdown(group)` が未 signal の fence をエラー終了させる。公開ソースでは caller-held lock、May/June バイナリでは関数内 lock という差があるが、どちらも同じ `group->dma_fence_list` を走査する。
5. 脆弱版 shutdown は raw list cursor で `group->dma_fence_list` を歩き、`container_of(pos, struct edgetpu_dma_fence, group_list)` で `etfence` を得る。
6. その `etfence` / `gfence` に対する一時 `dma_fence_get()` を持たずに `gcip_dma_fenceptr_signal(&etfence->gfence, -EPIPE, true)` を呼ぶ。
7. `gcip_dma_fenceptr_signal()` は `dma_fence_signal_locked()` に到達し、fence の waiter/callback を同期的に起こす。
8. 起こされた側が sync_file fd close などで最後の外部 fence 参照を落とすと、`edgetpu_dma_fence_release()` が `group_list` を外し、group ref を落とし、`kfree(etfence)` する経路に入る。

根本原因は、`group->dma_fence_list` の list lock/mutex と dma-fence の refcount lifetime を混同したこと。shutdown は callback を実行し得る signal 操作をしているのに、対象 fence 自体の一時参照を取っていなかった。

## バイナリ差分で見えた修正

`rio.ko` は strip されておらず、`objdump -t` で該当関数を確認できた。

May/pre:

- `rio.ko` sha256: `a73a631d4509f9f5cc0f015b72566e47f406dbd2151f6b76670a4df92702f54e`
- BuildID: `3603ad808e532994cd283a19dc4c20e24a96df6f`
- `edgetpu_sync_fence_group_shutdown`: address `0x14954`, size `0x128`
- 実装: `mutex_lock` -> raw `group->dma_fence_list` walk -> `gcip_dma_fenceptr_signal` -> optional `_dev_warn` -> `mutex_unlock`

June/post:

- `rio.ko` sha256: `cd7009d7d75a0698e9895dc5beadb17b21d1bf4d4c6c819e54c0c2c1e44a5671`
- BuildID: `7b3ee7ca19984b4a5b63b30bfc52f37d4497ac9a`
- `edgetpu_sync_fence_group_shutdown`: address `0x150c8`, size `0x314`
- 追加された処理:
  - embedded `dma_fence` refcount の non-zero atomic increment
  - saved-next traversal
  - `gcip_dma_fenceptr_signal`
  - `__list_del_entry_valid` / `__list_add_valid` による一時 stack list への退避
  - `mutex_unlock` 後、退避 list を再走査
  - group list へ戻してから temporary ref を put
  - 最終 put では `dma_fence_release` に到達

保存した根拠:

- `artifacts/payload_may/edgetpu_sync_fence_group_shutdown.dr.txt`
- `artifacts/payload_june/edgetpu_sync_fence_group_shutdown.dr.txt`
- `artifacts/rio_symbol_relevant.diff`
- `artifacts/source/reconstructed_fix_from_rio_ko.diff`

June の修正は「signal 前に対象 fence の寿命を refcount で固定する」ことが中心で、脆弱版の根本原因と一致する。

## 攻撃条件と影響

OSV の条件どおり System 実行権限が必要。通常アプリが直接到達できる問題ではなく、EdgeTPU の sync fence 作成と group teardown に到達できる System 権限コンポーネント、またはその権限を得たローカル攻撃者が対象。

攻撃者が sync fence fd の寿命、waiter/callback、group shutdown のタイミングを合わせると、shutdown が raw list pointer として保持している `edgetpu_dma_fence` が release/free 経路に入る。カーネル driver 内 UAF なので、成功時は kernel memory corruption 経由の権限昇格につながる。

## 調査メモ

- 既存メモでは公開 GoogleSource の `android-16.0.0_r0.10` まで修正後ソースがないと書かれていたが、今回は Pixel OTA の `vendor_dlkm.img` から実際の `rio.ko` を取り出せたため、バイナリ差分で修正を確認できた。
- May の完全 OTA として置かれていた一部 zip は壊れていたが、`shiba-ota-cp1a.260505.005.a1-7c6aa727.truncated.zip` は `payload-dumper-go` で読め、`vendor_dlkm` と `rio.ko` を抽出できた。
- macOS では ext4 mount できなかったため、Docker `ubuntu:24.04` の `debugfs` で `/lib/modules/rio.ko` を抽出した。
- 非 rio repo `kernel/google-modules/edgetpu` に `51ec41e0208a9cf8456f9ae4374aa2217839c2db` (`edgetpu: dmabuf fix potential UAF`) があるが、これは 2021 年の `dmap->map` read-after-free 修正で、CVE-2026-0137 ではない。
- `originhq` の patch diffing pipeline 記事は `artifacts/public/origin-patch-diffing-pipeline.html` に保存済み。今回の作業も「公開情報の関数名 -> pre/post artifact 収集 -> symbol/function diff -> root cause 復元」の流れで進めた。

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

- `artifacts/public/PUB-A-467353904.osv.json`
- `artifacts/public/PUB-A-467353904.pretty.json`
- `artifacts/public/pixel-bulletin-2026-06-01.html`
- `artifacts/public/origin-patch-diffing-pipeline.html`
- `artifacts/binary_inventory.txt`
- `artifacts/payload_may/vendor_dlkm.img`
- `artifacts/payload_june/vendor_dlkm.img`
- `artifacts/payload_may/extract/rio.ko`
- `artifacts/payload_june/extract/rio.ko`
- `artifacts/payload_may/edgetpu_sync_fence_group_shutdown.dr.txt`
- `artifacts/payload_june/edgetpu_sync_fence_group_shutdown.dr.txt`
- `artifacts/payload_may/rio_symbols.txt`
- `artifacts/payload_june/rio_symbols.txt`
- `artifacts/rio_symbol_relevant.diff`
- `artifacts/source/public_source_refs.txt`
- `artifacts/source/tag_function_hashes.tsv`
- `artifacts/source/tag_shutdown_snippets.txt`
- `artifacts/source/edgetpu-dmabuf.android-16.0.0_r0.3.c`
- `artifacts/source/edgetpu-dmabuf.android-16.0.0_r0.3.h`
- `artifacts/source/edgetpu-device-group.android-16.0.0_r0.3.c`
- `artifacts/source/edgetpu-device-group.android-16.0.0_r0.3.h`
- `artifacts/source/gcip-dma-fence.android-16.0.0_r0.3.c`
- `artifacts/source/gcip-dma-fence.android-16.0.0_r0.3.h`
- `artifacts/source/root_cause_notes.md`
- `artifacts/source/reconstructed_fix_from_rio_ko.diff`
097 OK

CVE-2026-0138

097-ok-lwis-error-event-client-list-race-eop

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentLwis
TypeEoP
SeverityModerate
ReferencesA-486024286
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0138 is listed in the Pixel Update Bulletin as a Moderate severity EoP issue in Pixel / Lwis.

特定した具体的な脆弱性

CVE-2026-0138 は Pixel Update Bulletin 2026-06-01 に掲載された Pixel / Lwis の Moderate EoP。公開 Bug ID は A-486024286 だが、LWIS の公開 git 履歴にはこの Bug ID は直接出ていない。

検証結果として、097 は LWIS の error-event 配信経路 lwis_device_error_event_emit() が lwis_dev->clients をロックせずに走査していた競合脆弱性と判断した。修正候補は以下。

・commit: 575098bba7f8a8fdd0ea05262848afb0fdb5a93e
・title: Add protect when accessing lwis_dev->clients
・Bug: 385044747
・Change-Id: Id03120eb5860cd744ca40f27c907ff599648b0ac
・file: lwis_event.c
・保存パッチ: artifacts/source/575098bba7f8_clients_lock.patch

この修正は lwis_device_error_event_emit() の list_for_each_safe(p, n, &lwis_dev->clients) の前後に spin_lock_irqsave(&lwis_dev->lock, flags) / spin_unlock_irqrestore() を追加し、途中の kmalloc() 失敗や client_error_event_push_back() 失敗時にも unlock して戻るようにしている。

原因

記載なし。

どこから特定したか

パッチ解析: 修正前:

・lwis_device_error_event_emit() が lwis_dev->clients を無ロック走査。
・各 client に kmalloc(sizeof(struct lwis_event_entry) + payload_size, GFP_ATOMIC) した event を詰め、client_error_event_push_back() する。
・list_for_each_safe() は走査中の削除にはある程度耐えるが、別 CPU/IRQ context からの同時 list 操作や object free を同期しない。

修正後:

参照した公開情報: ・Pixel Update Bulletin: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
・Bulletin 行: CVE-2026-0138 / A-486024286 / EoP / Moderate / Lwis
・Gitiles repo: https://android.googlesource.com/kernel/google-modules/lwis
・主要 commit: 575098bba7f8a8fdd0ea05262848afb0fdb5a93e
・比較候補 commit: a1d547435f1eb021f57bbe40266397590d1d39d5, 9f8fa04be9ef16…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https…

validated.md を表示
# CVE-2026-0138 / A-486024286 検証メモ

## 結論

CVE-2026-0138 は Pixel Update Bulletin 2026-06-01 に掲載された Pixel / Lwis の Moderate EoP。公開 Bug ID は `A-486024286` だが、LWIS の公開 git 履歴にはこの Bug ID は直接出ていない。

検証結果として、097 は LWIS の error-event 配信経路 `lwis_device_error_event_emit()` が `lwis_dev->clients` をロックせずに走査していた競合脆弱性と判断した。修正候補は以下。

- commit: `575098bba7f8a8fdd0ea05262848afb0fdb5a93e`
- title: `Add protect when accessing lwis_dev->clients`
- Bug: `385044747`
- Change-Id: `Id03120eb5860cd744ca40f27c907ff599648b0ac`
- file: `lwis_event.c`
- 保存パッチ: `artifacts/source/575098bba7f8_clients_lock.patch`

この修正は `lwis_device_error_event_emit()` の `list_for_each_safe(p, n, &lwis_dev->clients)` の前後に `spin_lock_irqsave(&lwis_dev->lock, flags)` / `spin_unlock_irqrestore()` を追加し、途中の `kmalloc()` 失敗や `client_error_event_push_back()` 失敗時にも unlock して戻るようにしている。

## 脆弱性の内容

LWIS はユーザー空間から `/dev/lwis-*` を open した client を `lwis_dev->clients` にぶら下げる。open 側は `lwis_dev->lock` を取って `list_add(&lwis_client->node, &lwis_dev->clients)` している。

一方、修正前の `lwis_device_error_event_emit()` は error event を全 client に配るため同じ `lwis_dev->clients` を走査していたが、`lwis_dev->lock` を取っていなかった。error event は `client_event_push_back()` のイベントキュー overflow などから呼ばれるので、通常のユーザー操作、poll/read/ioctl、close と並行して発生し得る。

このため、client list の追加、削除、client オブジェクト解放と error-event broadcast が競合すると、list 破壊、解放済み `lwis_client` 参照、誤った client の event queue への push が起こり得る。カーネルドライバ内の UAF/list race なので、攻撃者が timing と heap 状態を制御できる場合は EoP に繋がる。

根本原因は `lwis_dev->clients` の所有ロック規約が一貫していないこと。`lwis_device.c` には `check_client_exists()` について「`lwis_dev->lock` を保持して呼ぶ」とコメントがあるが、少なくとも確認した `release_client()` 経路は `client_lock` の下で `check_client_exists()` / `list_del()` を実行しており、`lwis_dev->lock` とは別のロックになっている。今回の 575098b 修正は error-event 側の無ロック走査を塞ぐものだが、LWIS 全体としては client list のロック境界が分かりにくい。

## パッチ解析

修正前:

- `lwis_device_error_event_emit()` が `lwis_dev->clients` を無ロック走査。
- 各 client に `kmalloc(sizeof(struct lwis_event_entry) + payload_size, GFP_ATOMIC)` した event を詰め、`client_error_event_push_back()` する。
- `list_for_each_safe()` は走査中の削除にはある程度耐えるが、別 CPU/IRQ context からの同時 list 操作や object free を同期しない。

修正後:

- 走査前に `spin_lock_irqsave(&lwis_dev->lock, flags)` を追加。
- 走査完了後に `spin_unlock_irqrestore(&lwis_dev->lock, flags)` を追加。
- early return する 2 箇所にも unlock を追加。

重要な点として、098-CVE-2026-0143 側には別 commit `a1d547435f1eb021f57bbe40266397590d1d39d5` があり、通常 event / external event 経路でも同じ `lwis_dev->clients` の保護を追加している。つまり June 2026 Bulletin の 0138 と 0143 は、LWIS client list を複数の event 配信経路が無ロックで触っていた同系統の問題が 2 件として採番された可能性が高い。

## 参照した公開情報

- Pixel Update Bulletin: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- Bulletin 行: `CVE-2026-0138 / A-486024286 / EoP / Moderate / Lwis`
- Gitiles repo: `https://android.googlesource.com/kernel/google-modules/lwis`
- 主要 commit: `575098bba7f8a8fdd0ea05262848afb0fdb5a93e`
- 比較候補 commit: `a1d547435f1eb021f57bbe40266397590d1d39d5`, `9f8fa04be9ef162b006e09abfdfd434b402ad069`, `91d254295bd361c8b1b0716c7278c88b915f3421`

## バイナリ確認

June OTA 由来の `vendor_dlkm.img` から `lwis.ko` を抽出済み。

- `analysis/ota_june/vendor_dlkm.img`
- `analysis/ota_june/extracted/lwis.ko`
- 保存コピー: `artifacts/analysis/lwis_june_shiba_cp2a_260605_012.ko`
- `lwis.ko` sha256: `8a143034e4cec8114ef1b8de83ab25689fe8c6f8d0fa9274bbc5a5612f993101`

Docker 内の `debugfs` で `/lib/modules/lwis.ko` inode と sha256 を確認し、既存抽出物と一致した。June バイナリの strings には `lwis_device_error_event_emit`, `Failed to push error event to queue: ID 0x%llx`, `lwis_device_event_emit`, `lwis_device_external_event_emit` が含まれる。

May OTA は手元の `../binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005*.zip` が central directory を欠く壊れた zip として見え、`payload-dumper-go` / `unzip` で `vendor_dlkm` を抽出できなかった。そのため May/June の `lwis.ko` バイナリ diff は未実施。今回の判定は公開ソース差分と June バイナリの存在確認に基づく。

## 付帯ファイル

- `artifacts/public/pixel-bulletin-2026-06-01.html`
- `artifacts/source/575098bba7f8_clients_lock.patch`
- `artifacts/source/lwis_device_error_event_emit.before.txt`
- `artifacts/source/lwis_device_error_event_emit.after.txt`
- `artifacts/source/lwis_client_list_locking_context.txt`
- `artifacts/source/a1d547435f1e_clients_lock.patch`
- `artifacts/source/9f8fa04be9ef_device_reset_enabled.patch`
- `artifacts/source/91d254295bd3_ioctl_echo_overflow.patch`
- `artifacts/analysis/lwis_june_key_strings.txt`
- `artifacts/analysis/june_debugfs_lwis_extract.txt`
- `artifacts/analysis/artifacts_sha256.txt`

## 面白い点 / 調査メモ

- Bulletin では `Lwis` と `LWIS` の表記揺れで 0138 と 0143 が連続している。
- 公開 Bug ID `A-486024286` は Gitiles の公開 commit には出てこない。公開履歴上の実修正 Bug は `385044747` と `389685568`。
- `91d254295bd3` の `Ioctl: Fix echo msg overflow` は `msg.size + 1` の overflow を `MAX_ECHO_SIZE` で塞ぐ非常に分かりやすいバグだが、commit 本文は information disclosure と書いており、0138 の EoP とは整合しにくい。
- `9f8fa04be9e` の `DEVICE_RESET` enabled check は MMIO/IRQ mask 操作を disabled device で拒否する修正だが、これ単体で EoP 状況を完全に説明するには根拠が弱い。
- 575098b と a1d5474 はどちらも `lwis_dev->clients` 保護で、前者が error-event、後者が通常 event / external event。CVE-2026-0138 と CVE-2026-0143 は同じ根本原因の別到達経路として扱うのが自然。
098 OK

CVE-2026-0143

098-ok-lwis-external-event-clients-uaf

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentLWIS
TypeEoP
SeverityModerate
ReferencesA-486235633
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0143 is listed in the Pixel Update Bulletin as a Moderate severity EoP issue in Pixel / LWIS.

特定した具体的な脆弱性

CVE-2026-0143 は Pixel の LWIS (lwis_event.c) における lwis_dev->clients リスト走査の同期不備による use-after-free / memory corruption と判断する。公開 OSV (PUB-A-486235633) は問題箇所を lwis_device_external_event_emit() と明記しており、この関数は lwis_dev->lock を外した後に lwis_dev->clients を list_for_each_safe() で走査し、各 lwis_client に対して event_lock 取得、イベントキュー投入、transaction trigger を実行する。

根本原因は、デバイスにぶら下がる client リスト自体の寿命を保護せずに、イベント発火側が lwis_client ポインタを取得して使い続ける点である。別スレッドで client close/release が走り、同じ client がリストから削除・解放されると、イベント発火側は解放済み lwis_client の event_lock、event state、event queue、transaction state にアクセスできる。結果として kernel memory corruption になり、ローカル権限昇格に利用され得る。

原因

・lwis_dev->clients の所有権・寿命を守る lock と、個々の lwis_client の event state を守る event_lock が混同されていた。
・lwis_client->event_lock は client 内部の event queue/state を守るだけで、client が device の clients リストから外されて解放されることは防げない。
・event emit 系は IRQ/atomic context を意識して spin_lock_irqsave と GFP_ATOMIC を使っているが、リスト走査の全期間で device 側 lock を保持していなかった。
・修正パターンは、client リストから lwis_client を取り出して内部状態を読む区間を lwis_dev->lock で保護し、別 lock の IRQ flags を event_flags として分けること。

どこから特定したか

解析したソース / 差分: ・artifacts/PUB-A-486235633.json: OSV メタデータ。
・artifacts/pixel-bulletin-2026-06-01.html: Pixel Update Bulletin 保存物。
・artifacts/lwis_event.before_a1d547.c, artifacts/lwis_event.after_a1d547.c: a1d547435f1e 前後の lwis_event.c。
・artifacts/lwis_event.before_vs_after.diff: 上記 before/after のローカル diff。
・artifacts/a1d547435f1e_lwis_event.patch: 既存保存済みの公開 patch。
・artifa…

パッチ差分から見えたこと: a1d547435f1eb021f57bbe40266397590d1d39d5 のコミットメッセージは Event: Add protect when accessing lwis_dev->clients で、変更ファイルは lwis_event.c のみ。Bug は 389685568 で、CVE の参照 ID A-486235633 とは一致しない。

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https://storage.googleapis.com/android-osv/PUB-A-486235633.json`

validated.md を表示
# CVE-2026-0143 Pixel LWIS EoP 解析結果

## 結論

CVE-2026-0143 は Pixel の LWIS (`lwis_event.c`) における `lwis_dev->clients` リスト走査の同期不備による use-after-free / memory corruption と判断する。公開 OSV (`PUB-A-486235633`) は問題箇所を `lwis_device_external_event_emit()` と明記しており、この関数は `lwis_dev->lock` を外した後に `lwis_dev->clients` を `list_for_each_safe()` で走査し、各 `lwis_client` に対して `event_lock` 取得、イベントキュー投入、transaction trigger を実行する。

根本原因は、デバイスにぶら下がる client リスト自体の寿命を保護せずに、イベント発火側が `lwis_client` ポインタを取得して使い続ける点である。別スレッドで client close/release が走り、同じ client がリストから削除・解放されると、イベント発火側は解放済み `lwis_client` の `event_lock`、event state、event queue、transaction state にアクセスできる。結果として kernel memory corruption になり、ローカル権限昇格に利用され得る。

`ok` 判定にした理由: 公開 OSV が関数名と UAF を明示しており、手元の `lwis_event.c` 抜粋で `lwis_device_external_event_emit()` の無保護リスト走査を確認できた。また関連する公開修正コミット `a1d547435f1e...` では同じ `lwis_dev->clients` 走査に `lwis_dev->lock` を追加するパターンが確認でき、脆弱な設計と修正方針がソースコード上で説明できる。

## Advisory / ID

- CVE: `CVE-2026-0143`
- 参照 ID: `A-486235633`
- Component / Subcomponent: `Pixel / LWIS` (`cve.md` では `LWIS`、bulletin 表示では `Lwis`)
- Type / Severity: `EoP / Moderate`
- Bulletin URL: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- Pixel bulletin 確認箇所: 保存済み `artifacts/pixel-bulletin-2026-06-01.html` の grep で `CVE-2026-0143`, `A-486235633`, `LWIS` を確認。
- OSV URL: `https://storage.googleapis.com/android-osv/PUB-A-486235633.json`
- OSV details: `lwis_device_external_event_emit` の use-after-free による memory corruption。System 実行権限が必要、ユーザー操作不要、修正 SPL は `2026-06-05`。

## 解析したソース / 差分

- `artifacts/PUB-A-486235633.json`: OSV メタデータ。
- `artifacts/pixel-bulletin-2026-06-01.html`: Pixel Update Bulletin 保存物。
- `artifacts/lwis_event.before_a1d547.c`, `artifacts/lwis_event.after_a1d547.c`: `a1d547435f1e` 前後の `lwis_event.c`。
- `artifacts/lwis_event.before_vs_after.diff`: 上記 before/after のローカル diff。
- `artifacts/a1d547435f1e_lwis_event.patch`: 既存保存済みの公開 patch。
- `artifacts/a1d547435f1e_commit.json`: Gitiles の commit JSON。
- `artifacts/lwis_git_log_candidates.txt`: `clients` / race / Bug ID で候補化した git log。
- `artifacts/575098bba7f8_commit.cat-file.txt`: 関連候補 `575098bba7f8...` の commit object。こちらも「Add protect when accessing lwis_dev->clients」。
- `artifacts/external_event_emit_vulnerable_excerpt.c`: OSV が名指しする vulnerable function の抜粋。
- `artifacts/device_event_emit_impl_vulnerable_excerpt.c`, `artifacts/device_event_emit_impl_fixed_excerpt.c`: 同型の通常イベント経路に対する修正パターン抜粋。
- `artifacts/branches_contains_a1d547.txt`: `a1d547435f1e...` を含む remote branch。

## パッチ差分から見えたこと

`a1d547435f1eb021f57bbe40266397590d1d39d5` のコミットメッセージは `Event: Add protect when accessing lwis_dev->clients` で、変更ファイルは `lwis_event.c` のみ。Bug は `389685568` で、CVE の参照 ID `A-486235633` とは一致しない。

主な修正は `device_event_emit_impl()` の client 通知ループである。修正前は event state 更新後に `lwis_dev->lock` を解放したまま `list_for_each_safe(p, n, &lwis_dev->clients)` を実行していた。修正後は client リスト走査前に `spin_lock_irqsave(&lwis_dev->lock, flags)` を追加し、`lwis_transaction_event_trigger()` のような重い処理の前だけ一時的に device lock を解放して、次の iteration で再取得する形になった。また、ネストする `lwis_client->event_lock` 用に `event_flags` を別変数化し、外側の `lwis_dev->lock` 用 flags を壊さないようにしている。

一方で、OSV が名指しする `lwis_device_external_event_emit()` について、保存済み `a1d547` after では `event_flags` の分離は入っているが、`list_for_each_safe(p, n, &lwis_dev->clients)` 全体を `lwis_dev->lock` で保護する変更は入っていない。このため `a1d547` だけを CVE-2026-0143 の完全な直接修正と断定するのは危険である。CVE-2026-0143 の直接対象は external event 経路、`a1d547` は同型の通常 event 経路に入った公開修正・修正パターンとして扱う。

## 脆弱性が起きる状況

1. ある `lwis_device` に複数の `lwis_client` が接続され、各 client がイベント購読や transaction を持つ。
2. 外部デバイス由来のイベントが `lwis_device_external_event_emit(lwis_dev, event_id, event_counter, timestamp)` に入る。
3. この関数は `device_event_state->event_counter` 更新時だけ `lwis_dev->lock` を取るが、その後 `lwis_dev->lock` を解放する。
4. その状態で `lwis_dev->clients` を走査し、`lwis_client = list_entry(...)` で得たポインタに対して `lwis_client->event_lock`、`client_event_state_find_locked()`、`client_event_push_back()`、`lwis_transaction_event_trigger()` を呼ぶ。
5. 同時に別スレッドで同じ client の close/release が走り、`lwis_dev->clients` から削除され、`lwis_client` 本体または内部状態が解放される。
6. event emit 側はリスト要素の寿命を保証していないため、解放済み client に対する lock 取得や queue/transaction 操作が起きる。

`list_for_each_safe()` は「ループ中に自分で現在要素を削除する」場合に次要素ポインタを先取りするためのマクロであり、他スレッドが同時に list node や container を削除・解放する競合を解決しない。ここが元々の問題点である。

## 根本原因

- `lwis_dev->clients` の所有権・寿命を守る lock と、個々の `lwis_client` の event state を守る `event_lock` が混同されていた。
- `lwis_client->event_lock` は client 内部の event queue/state を守るだけで、client が device の clients リストから外されて解放されることは防げない。
- event emit 系は IRQ/atomic context を意識して `spin_lock_irqsave` と `GFP_ATOMIC` を使っているが、リスト走査の全期間で device 側 lock を保持していなかった。
- 修正パターンは、client リストから `lwis_client` を取り出して内部状態を読む区間を `lwis_dev->lock` で保護し、別 lock の IRQ flags を `event_flags` として分けること。

## 面白い点 / 注意点

- `a1d547435f1e...` の Bug ID は `389685568` で、CVE の `A-486235633` とは異なる。公開セキュリティ修正では、CVE の参照 ID と Gerrit/Git commit の Bug ID が一致しない、または関連 hardening commit として見えることがある。
- `lwis_git_log_candidates.txt` には `575098bba7f8...` も出ており、こちらは 2024-08-19 の `Add protect when accessing lwis_dev->clients` / Bug `385044747`。Gitiles patch 取得はタイムアウトしたが、commit object は保存した。
- `a1d547` after の `lwis_device_external_event_emit()` は `event_flags` 分離のみで、device lock による list protection は見えなかった。この差分だけを見ると external 経路の UAF は残るように見えるため、CVE-2026-0143 の直接修正は別系列・別ブランチの commit である可能性が高い。
- ただし、OSV の説明と vulnerable excerpt から、脆弱性そのものは `external_event_emit` の clients list UAF として説明できる。

## バイナリ / OTA について

- 既存作業で `analysis/ota_june/vendor_dlkm.img` が保存されていた。
- May 側 vendor_dlkm 抽出は `analysis/logs/extract_vendor_dlkm_may.txt` に `no space left on device` とあり失敗していた。
- `artifacts/bin/vendor_dlkm_sha256.txt` に vendor_dlkm の SHA256 が保存されている。
- 今回の最終判定はバイナリ diff ではなく、公開 OSV と LWIS ソース差分・関数抜粋に基づく。Pixel バイナリでの命令差分までは完了していない。

## 取得に失敗したもの

- NVD HTML は `403` で保存できなかった。
- Gitiles の `575098bba7f8...` patch / raw file 取得は SSL timeout / connection reset で完了しなかった。
- partial clone の `git show` は promisor blob の追加取得時に connection reset したため、一部の `*.git_show.patch` は空ファイルになっている。

## 最終判定

判定: `ok`

タイトル: `lwis-external-event-clients-uaf`

理由: CVE の公開説明が `lwis_device_external_event_emit()` の UAF を明示し、該当ソース抜粋で `lwis_dev->clients` の無保護走査を確認できた。関連公開差分で同じ `lwis_dev->clients` 走査に対する lock 追加パターンも確認でき、脆弱性の原因と発生条件をソースコードレベルで説明できる。
099 OK

CVE-2026-0134

099-ok-recovery-user-preferred-resolution-persistence

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentRecovery
TypeID
SeverityModerate
ReferencesA-438759342
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0134 is listed in the Pixel Update Bulletin as a Moderate severity ID issue in Pixel / Recovery.

特定した具体的な脆弱性

判定: ok

CVE-2026-0134 / A-438759342 は、Pixel Recovery の PostWipeData() が factory reset 後に /data 以外の永続領域へ保存されたユーザ設定を完全に消していなかった情報漏えい問題と判断した。公開CVE本文は「recovery_ui.cpp の PostWipeData における logic error により factory reset 後に data persistence が起き、local information disclosure になり得る」と説明している。

特定できた具体的な残存データは、/misc partition の vendor space に保存される user_preferred_resolution、つまりユーザが選択した表示解像度である。misc_writer はこれを mode=<value> として32バイト領域へ保存するが、修正前の PostWipeData() は Titan M、secure element hook、provisioned/dark theme flag、SOTA flag だけを処理し、display mode を消していなかった。factory reset は /data を消しても /misc vendor space を消さないため、前所有者の表示解像度設定が初期化後も残る。

原因

記載なし。

どこから特定したか

パッチ解析: 主な修正コミット:

・8b61d9d00d0e1cbf461934973cd6867bdf915b0d
・subject: recovery: wipe user preferred resolution on recovery factory reset
・project: platform/hardware/google/pixel
・file: recovery/recovery_ui.cpp
・Bug: 250788756
・Change-Id: I72eb68c4ad6082e31f16966d44131afc8b1d137a

保存した付帯ファイル: ・artifacts/PUB-A-438759342.json: OSV JSON
・artifacts/pixel-bulletin-2026-06-01.html: Pixel bulletin
・artifacts/8b61d9d0_recovery_ui_gitiles.patch: recovery側修正パッチ
・artifacts/8b61d9d0_recovery_ui.patch: local git show 版パッチ
・artifacts/46949743_display_mode_misc_writer.patch: display mode保存側パッチ
・artifacts/recovery_ui_before_8b61d9d0.cpp: 修正前 recovery_ui.cpp
・ar…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01 / https://api.osv.dev/v1/vu…

validated.md を表示
# CVE-2026-0134 検証メモ

## 結論

判定: ok

CVE-2026-0134 / A-438759342 は、Pixel Recovery の `PostWipeData()` が factory reset 後に `/data` 以外の永続領域へ保存されたユーザ設定を完全に消していなかった情報漏えい問題と判断した。公開CVE本文は「`recovery_ui.cpp` の `PostWipeData` における logic error により factory reset 後に data persistence が起き、local information disclosure になり得る」と説明している。

特定できた具体的な残存データは、`/misc` partition の vendor space に保存される `user_preferred_resolution`、つまりユーザが選択した表示解像度である。`misc_writer` はこれを `mode=<value>` として32バイト領域へ保存するが、修正前の `PostWipeData()` は Titan M、secure element hook、provisioned/dark theme flag、SOTA flag だけを処理し、display mode を消していなかった。factory reset は `/data` を消しても `/misc` vendor space を消さないため、前所有者の表示解像度設定が初期化後も残る。

## 確認したCVE情報

- CVE: `CVE-2026-0134`
- Android/Pixel reference: `A-438759342`
- Bulletin: Pixel Update Bulletin, 2026-06-01, published 2026-06-16
- Component/Subcomponent: `Pixel / Recovery`
- Type/Severity: `ID / Moderate`
- Security patch level: `2026-06-05`
- OSV: `PUB-A-438759342`, fixed `Pixel-family specific:2026-06-05`

## パッチ解析

主な修正コミット:

- `8b61d9d00d0e1cbf461934973cd6867bdf915b0d`
- subject: `recovery: wipe user preferred resolution on recovery factory reset`
- project: `platform/hardware/google/pixel`
- file: `recovery/recovery_ui.cpp`
- Bug: `250788756`
- Change-Id: `I72eb68c4ad6082e31f16966d44131afc8b1d137a`

このコミットは `WipeUserPreferredResolution()` を追加し、`PostWipeData()` の中で呼ぶようにしている。追加された処理は `MiscWriterActions::kClearDisplayMode` を実行し、失敗したら `totalSuccess = false` にする。

関連する保存側コミット:

- `4694974308e8ad924178399770e08a70e59eaf69`
- subject: `store display resolution in misc partition`
- project: `platform/hardware/google/pixel`

このコミットで `MiscWriterActions::kSetDisplayMode` / `kClearDisplayMode`、`kDisplayModeOffsetInVendorSpace = 456`、`kDisplayModePrefix = "mode="` が追加された。`kSetDisplayMode` は `mode=` + display mode を32バイトに詰めて `/misc` vendor space へ書き、`kClearDisplayMode` は同じ32バイトをゼロ化する。

根本原因は、`/misc` vendor space をユーザ設定の永続ストアとして使い始めた後、factory reset path の `PostWipeData()` にその新しい保存先のクリア処理を追加していなかったこと。`/data` 消去を factory reset の主処理とみなし、`/data` 外のPixel固有状態を個別に列挙して消す設計で、列挙漏れが起きた。

## 脆弱性の成立条件

1. ユーザがPixel上で表示解像度など、`misc_writer --set-display-mode` 相当で `/misc` vendor space に保存される設定を持つ。
2. recovery factory reset が実行される。
3. 修正前の `PostWipeData()` は `kClearDisplayMode` を呼ばない。
4. `/data` は消えるが `/misc` vendor space の `mode=<...>` は残る。
5. 初期化後の所有者またはローカルアクセス可能な主体が、ブートローダ/初期化処理/デバイス状態を通じて前所有者の設定値を観測できる可能性がある。

機密性影響は限定的だが、factory reset が「利用者データを残さない」ことを期待される操作であり、前所有者固有の設定が残るため ID と分類されたと考える。

## バイナリ確認

既存の Shiba OTA を使用した。

- May source: `../binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip`
- June source: `../binaries/pixel_shiba_ota/shiba-ota-cp2a.260605.012-b315a1a2.zip`

`payload.bin` から `boot`, `init_boot`, `vendor_boot`, `vendor_kernel_boot` を抽出し、`vendor_boot.img` の vendor ramdisk を展開した。recovery ramdisk 内の `system/lib64/librecovery_ui_ext.so` に以下の修正後文字列が存在することを確認した。

- `Failed to clear the user preferred resolution`
- `User preferred resolution wiped successful`
- `mode=`

面白い点として、Shiba の5月A1 OTAにも同じ修正後文字列が存在した。つまり、少なくともこのビルド系列では、2026年6月 bulletin 公開より前に recovery UI バイナリへ修正が入っている。CVE/OSV上の fixed SPL は `2026-06-05` だが、公開ソース上の対応コミット自体は2023年10月作成、2024年3月コミットで、CVE公開タイミングとは一致しない。Pixel bulletin では古い潜在問題が後からCVE化された、または対象端末/ブランチごとに取り込み時期が異なる可能性が高い。

## 解析時に見た別候補

2025年の `misc_writer` 履歴には flood control 用の `/misc` エントリ追加と `kWipeFloodStatus` 追加があった。

- `092e05030e0a3465189b32b7c069f4f4bb978d9e` `allocate 2240 bytes for flood control`
- `8b20e1c96cb65ccba161d7c508fa9efa74e5632f` `update flood entry in misc`
- `53fc9768be1721f2068d776e4bf45eb8ee94aa0c` `be able to wipe flood status`

これも `/misc` の data persistence という観点では近いが、公開CVE本文が `PostWipeData of recovery_ui.cpp` と明示している一方、公開履歴上は `recovery/recovery_ui.cpp` への flood status wipe 呼び出し追加は確認できなかった。そのため主因としては採用しない。

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

- `artifacts/PUB-A-438759342.json`: OSV JSON
- `artifacts/pixel-bulletin-2026-06-01.html`: Pixel bulletin
- `artifacts/8b61d9d0_recovery_ui_gitiles.patch`: recovery側修正パッチ
- `artifacts/8b61d9d0_recovery_ui.patch`: local git show 版パッチ
- `artifacts/46949743_display_mode_misc_writer.patch`: display mode保存側パッチ
- `artifacts/recovery_ui_before_8b61d9d0.cpp`: 修正前 `recovery_ui.cpp`
- `artifacts/recovery_ui_after_8b61d9d0.cpp`: 修正後 `recovery_ui.cpp`
- `artifacts/hardware_google_pixel_recovery_misc_log.txt`: recovery/misc_writer 関連履歴
- `artifacts/payload_extract/`: OTA payload から抽出した boot image 群
- `artifacts/vendor_boot_ramdisks/`: `vendor_boot.img` から抽出した LZ4 ramdisk と cpio
- `artifacts/vendor_boot_extracted/`: recovery ramdisk展開結果
- `artifacts/may_a1_recovery_ui_ext_relevant_strings.txt`
- `artifacts/june_recovery_ui_ext_relevant_strings.txt`
- `artifacts/artifacts_sha256.txt`: 抽出物のSHA-256
- `artifacts/tools/extract_vendor_boot_ramdisks.py`: `vendor_boot.img` ramdisk抽出用スクリプト
- `artifacts/extract_payload_partitions.py`: OTA payload partition抽出用スクリプト

## 参照URL

- https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- https://api.osv.dev/v1/vulns/PUB-A-438759342
- https://android.googlesource.com/platform/hardware/google/pixel/+/8b61d9d00d0e1cbf461934973cd6867bdf915b0d%5E%21/
- https://android.googlesource.com/platform/hardware/google/pixel/+/4694974308e8ad924178399770e08a70e59eaf69%5E%21/
100 NG

CVE-2026-0158

100-ng-pixel-camera-services-saw-appop-grant

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentCamera
TypeID
SeverityModerate
ReferencesA-420435325
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0158 is listed in the Pixel Update Bulletin as a Moderate severity ID issue in Pixel / Camera.

NG 判定の要点

CVE-2026-0158 は Pixel Update Bulletin では Pixel / Camera の ID、severity Moderate、参照 ID A-420435325 とされている。Android OSV (PUB-A-420435325) の説明は「Camera で permission check 欠落により photos へ不正アクセスできる可能性」となっている。

手元で May (CP1A.260505.005) と June (CP2A.260605.012) の Pixel system_ext / vendor を比較した結果、最も CVE 説明に近い差分は system_ext/app/PersistentBackgroundCameraServices/PersistentBackgroundCameraServices.apk の OverlayCameraCallback だった。May 版は camera open 時に com.google.android.apps.camera.services に対する AppOps OP_SYSTEM_ALERT_WINDOW (24) を MODE_ALLOWED (0) にし、camera close 時に MODE_DEFAULT (3) へ戻していた。June 版では close 時の戻し処理が削除され、CameraCallback.onCameraClosed() を呼ぶだけになっている。

未確定の理由 / 原因候補

判定: ng

タイトル: pixel-camera-services-saw-appop-grant

理由: May/June バイナリ差分から、PBCS の OverlayCameraCallback が com.google.android.apps.camera.services の SYSTEM_ALERT_WINDOW AppOps を camera open/close に連動して変更していたこと、June で close 時の revert が削除されたことまでは特定できた。一方で、公開説明にある「photos への不正アクセス」がどの API / service / UI 経路で成立するかを完全には説明できないため、ok 条件には届かない。

どこから特定したか

取得・解析したもの: ・artifacts/PUB-A-420435325.json: Android OSV。
・artifacts/pixel-bulletin-2026-06-01.html: Pixel bulletin 保存物。
・../binaries/pixel_shiba_full_ota/shiba-ota-cp1a.260505.005-a604326e.zip: May OTA の system_ext 抽出に必要な payload 範囲だけを range 取得した部分 zip。
・analysis/payload_extract_may/system_ext.img: May system_ext.img。
・../binaries/pixel_shiba_ota/june_system_ext/syste…

主要差分: PersistentBackgroundCameraServices.apk のハッシュ:

・May: 846ee11d51d3f0a56ccea2199f20c2273337c53b15f453caefaf2e1d534094aa
・June: 5427eec832e88d53805c8a5c1343ca7485132bfcb745a0702df3eab37ad16239

PersistentApplication の定数から、AppOps 操作対象は com.google.android.apps.camera.services である。

OverlayCameraCallback.compareAndSetMode(oldMode, newMode) は以下を行う。

URL: https://source.android.com/doc…

validated.md を表示
# CVE-2026-0158 Pixel Camera ID 解析結果

## 結論

CVE-2026-0158 は Pixel Update Bulletin では `Pixel / Camera` の `ID`、severity `Moderate`、参照 ID `A-420435325` とされている。Android OSV (`PUB-A-420435325`) の説明は「Camera で permission check 欠落により photos へ不正アクセスできる可能性」となっている。

手元で May (`CP1A.260505.005`) と June (`CP2A.260605.012`) の Pixel `system_ext` / `vendor` を比較した結果、最も CVE 説明に近い差分は `system_ext/app/PersistentBackgroundCameraServices/PersistentBackgroundCameraServices.apk` の `OverlayCameraCallback` だった。May 版は camera open 時に `com.google.android.apps.camera.services` に対する AppOps `OP_SYSTEM_ALERT_WINDOW` (`24`) を `MODE_ALLOWED` (`0`) にし、camera close 時に `MODE_DEFAULT` (`3`) へ戻していた。June 版では close 時の戻し処理が削除され、`CameraCallback.onCameraClosed()` を呼ぶだけになっている。

ただし、公開説明の「photos への不正アクセス」までを完全に再現・証明できる `com.google.android.apps.camera.services` 側の APK/product partition はこの作業フォルダ内に無く、今回の証拠だけでは「どの photo access API / UI / service が、どの caller から読めたか」までは断定できない。そのため最終判定は `ng` とする。

## Advisory / ID

- CVE: `CVE-2026-0158`
- 参照 ID: `A-420435325`
- Bulletin: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- OSV: `https://storage.googleapis.com/android-osv/PUB-A-420435325.json`
- Component / Subcomponent: `Pixel / Camera`
- Type / Severity: `ID / Moderate`
- 修正 SPL: `2026-06-05`

OSV details の要約: Camera 内の permission check 欠落により、追加実行権限やユーザー操作なしで photos へ不正アクセスでき、ローカル情報漏えいにつながる可能性がある。

## 取得・解析したもの

- `artifacts/PUB-A-420435325.json`: Android OSV。
- `artifacts/pixel-bulletin-2026-06-01.html`: Pixel bulletin 保存物。
- `../binaries/pixel_shiba_full_ota/shiba-ota-cp1a.260505.005-a604326e.zip`: May OTA の `system_ext` 抽出に必要な payload 範囲だけを range 取得した部分 zip。
- `analysis/payload_extract_may/system_ext.img`: May `system_ext.img`。
- `../binaries/pixel_shiba_ota/june_system_ext/system_ext.img`: 既存 June `system_ext.img`。
- `analysis/system_ext_may_extract/...`: May `system_ext` から抽出した camera 関連 APK/JAR。
- `artifacts/may_june_system_ext_camera_hashes.txt`: May/June camera 関連 APK/JAR の SHA-256。
- `artifacts/PBCS_may_target_classes.dexdump.txt`, `artifacts/PBCS_june_target_classes.dexdump.txt`: `PersistentBackgroundCameraServices.apk` の対象クラス Dex dump。
- `artifacts/PBCS_target_classes.diff`: 対象クラスの May/June diff。
- `artifacts/OverlayCameraCallback_onCameraClosed.diff`: 重要差分だけの抜粋。
- `analysis/apex_may/apex_payload.img`, `analysis/apex_june/apex_payload.img`: `com.google.pixel.camera.hal.apex` payload。
- `artifacts/camera_hal_apex_payload_file_diff.txt`: Camera HAL APEX の May/June file diff。

## 主要差分

`PersistentBackgroundCameraServices.apk` のハッシュ:

- May: `846ee11d51d3f0a56ccea2199f20c2273337c53b15f453caefaf2e1d534094aa`
- June: `5427eec832e88d53805c8a5c1343ca7485132bfcb745a0702df3eab37ad16239`

`PersistentApplication` の定数から、AppOps 操作対象は `com.google.android.apps.camera.services` である。

`OverlayCameraCallback.compareAndSetMode(oldMode, newMode)` は以下を行う。

- `com.google.android.apps.camera.services` の requested permissions に `android.permission.SYSTEM_ALERT_WINDOW` があるか確認する。
- 同 package の UID を取得する。
- `AppOpsManager.unsafeCheckOpRawNoThrow(24, uid, packageName)` で現在の SAW app-op mode を読む。
- 現在 mode が期待値と一致した場合だけ `AppOpsManager.setMode(24, uid, packageName, newMode)` を実行する。

May の `onCameraOpened(cameraId, packageId)`:

- `compareAndSetMode(3, 0)` を呼ぶ。
- つまり `MODE_DEFAULT` なら `MODE_ALLOWED` にする。

May の `onCameraClosed(cameraId, packageId)`:

- `compareAndSetMode(0, 3)` を呼ぶ。
- つまり `MODE_ALLOWED` なら `MODE_DEFAULT` に戻す。

June の `onCameraClosed(cameraId, packageId)`:

- 上記の `compareAndSetMode(0, 3)` が削除され、super 呼び出しだけになっている。

## 脆弱性として疑われる状況

`CameraClientTrackingService.shouldTriggerCameraCallbackFor(packageName)` は、camera を開いた package の UID を `PackageManager.getPackageUid()` で引き、`uid >= 10000` なら callback 対象にする。これは「サードパーティ app UID かどうか」の判定であり、Pixel Camera / Google Photos / trusted package / 特定 permission の確認ではない。

そのため May 版では、任意の通常 app が Camera2 API などで camera を開くだけで、PBCS の camera open callback が走り、`com.google.android.apps.camera.services` の `SYSTEM_ALERT_WINDOW` AppOps が一時的に `MODE_ALLOWED` に変更され得る。公開説明の「missing permission check」は、この callback 発火条件が「任意の通常 app の camera open」を許している点、または PCS service/app-op 操作に caller 権限確認が足りない点を指している可能性が高い。

ただし、今回取得できた partition には `com.google.android.apps.camera.services` 本体がなく、SAW app-op 一時許可から「photos への不正アクセス」へ至る直接経路は未確認である。考えられる方向性は overlay / artificial frame / Pixel Camera Services 側 service 連携だが、これは推測に留まる。

## 根本原因候補

根本原因候補は、PBCS が camera availability callback を信頼しすぎ、camera を開いた package に対する厳密な permission / identity check なしに、別 package (`com.google.android.apps.camera.services`) の強力な AppOps (`SYSTEM_ALERT_WINDOW`) を変更していたこと。

修正に見える差分は「camera close 時に `MODE_DEFAULT` へ戻す処理を削除する」ことで、少なくとも May の「camera open 中だけ SAW を一時許可する状態遷移」は無くなっている。ただし June でも `onCameraOpened()` の `compareAndSetMode(3, 0)` は残るため、これが完全な security fix なのか、別 partition の `com.google.android.apps.camera.services` 側修正と組み合わせた fix なのかは未確認。

## 面白い点 / 注意点

- `Pixel / Camera` だが、AOSP ソース差分ではなく Pixel proprietary APK の Dex 差分が中心だった。
- `system_ext` の `com.google.pixel.camera.services.cameraidremapper.jar`、`com.google.pixel.camera.connectivity.jar`、`com.google.android.camera.extensions.jar` も May/June で変わっているが、CVE 説明に直結する差分は見つからなかった。
- `vendor` の `com.google.pixel.camera.hal.apex` も大きく変わっているが、`photos` や permission check と直接結びつく証拠は得られなかった。
- `PersistentBackgroundCameraServices.apk` は `android.uid.system` の shared UID を使う persistent system app で、通常 app より強い権限文脈で AppOps を操作している。

## 最終判定

判定: `ng`

タイトル: `pixel-camera-services-saw-appop-grant`

理由: May/June バイナリ差分から、PBCS の `OverlayCameraCallback` が `com.google.android.apps.camera.services` の `SYSTEM_ALERT_WINDOW` AppOps を camera open/close に連動して変更していたこと、June で close 時の revert が削除されたことまでは特定できた。一方で、公開説明にある「photos への不正アクセス」がどの API / service / UI 経路で成立するかを完全には説明できないため、`ok` 条件には届かない。
101 NG

CVE-2026-0127

101-ng-nrmm-upu-transparent-context-oob-read-dos

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentPixel Modem
TypeDoS
SeverityModerate
ReferencesA-463414629
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0127 is listed in the Pixel Update Bulletin as a Moderate severity DoS issue in Pixel / Pixel Modem.

NG 判定の要点

判定: ng

CVE-2026-0127 は Pixel / Pixel Modem の Moderate severity DoS。公開 OSV / CVE / NVD 情報では、NrmmMsgCodec::DecodeUPUTransparentContext(cn_NrmmDecoder.cpp)に out-of-bounds read があり、通信プロセッサのクラッシュによる remote denial of service につながる、と説明されている。CISA ADP の分類は CWE-125 Out-of-bounds Read、CVSS v3.1 は CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H。

未確定の理由 / 原因候補

この作業の基準では、ok とするにはソースコード、または脆弱性が起きる状況を完璧に説明できる必要がある。今回は公開情報で関数名と脆弱性種別はかなり狭く特定できたが、以下が不足している。

・A-463414629 が非公開。
・Pixel Modem firmware は closed-source で、公開 commit/diff がない。
・modem.bin は大規模再ビルド差分で、複数CVE修正と通常更新が混在している。
・関数単位の逆アセンブルdiff、xref、追加された bounds check の命令列を確認できていない。
・malformed UPU transparent container のうち、どの subfield / length 条件で OOB read するかを確定できていない。

どこから特定したか

公開情報: 保存先:

・artifacts/public/PUB-A-463414629.json
・artifacts/public/PUB-A-463414629.pretty.json
・artifacts/public/CVE-2026-0127.cve.json
・artifacts/public/CVE-2026-0127.cve.pretty.json
・artifacts/public/pixel-2026-06-01.html

確認したURL:

解析したバイナリ: 既存の ../binaries/pixel_shiba_modem_0135/ を使用した。CVE-2026-0135 の調査で保存済みだった Pixel 8 shiba modem binary で、June 2026 Pixel bulletin の modem 修正を含む前後候補として扱った。

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01` / https://osv.dev/vulnerability/PUB-A-463414629` / https://storage.googleapis.com/android-osv/PUB-A-463414629.json` / https://cveawg.mitre.org/api/cve/CVE-2026-0127`

validated.md を表示
# CVE-2026-0127 Pixel Modem DoS 解析結果

## 結論

判定: **ng**

CVE-2026-0127 は Pixel / Pixel Modem の Moderate severity DoS。公開 OSV / CVE / NVD 情報では、`NrmmMsgCodec::DecodeUPUTransparentContext`(`cn_NrmmDecoder.cpp`)に out-of-bounds read があり、通信プロセッサのクラッシュによる remote denial of service につながる、と説明されている。CISA ADP の分類は `CWE-125 Out-of-bounds Read`、CVSS v3.1 は `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H`。

手元の Pixel 8 `shiba` modem firmware でも、NRMM / UPU 周辺の文字列、`cn_NrmmMsgCodec.cpp`、`UPU_PAYLOAD_LEN(_VALID)`、`UPU_MAC_AUSF`、`UPU_COUNTER`、`UPU_PAYLOAD_VALID`、`CNS_MM_SOR_UPU_SMS_IND`、`NRMM_NS_SOR_UPU_SMS_IND` などを確認できた。3GPP 仕様上の UPU transparent container は UE Parameters Update を運ぶ可変長コンテナで、AMF から UE へ DL NAS Transport で配送される。したがって脆弱性の大枠は、ネットワークから届く 5G NAS / NRMM の UPU transparent container を modem firmware が復号・解析する際、コンテナ長または内部 field 長の検証不足により buffer 末尾を越えて読む問題、と判断できる。

ただし、今回の作業では閉源の modem firmware に対する関数単位 patch diff までは到達できず、追加された bounds check の命令列、条件式、具体的に破綻する subfield を特定できなかった。この作業の基準では、ok はソースコードまたは脆弱性発生条件を完璧に説明できる場合のみなので、`ng` とした。

## 最初に確認した cve.md 情報

- CVE: `CVE-2026-0127`
- Android bug reference: `A-463414629`
- Component/Subcomponent: `Pixel / Pixel Modem`
- Type/Severity: `DoS / Moderate`
- Bulletin URL: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- Published/updated: `June 16, 2026`
- Security patch level: `2026-06-05 or later`

## 公開情報

保存先:

- `artifacts/public/PUB-A-463414629.json`
- `artifacts/public/PUB-A-463414629.pretty.json`
- `artifacts/public/CVE-2026-0127.cve.json`
- `artifacts/public/CVE-2026-0127.cve.pretty.json`
- `artifacts/public/pixel-2026-06-01.html`

確認したURL:

- Pixel Update Bulletin: `https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01`
- OSV: `https://osv.dev/vulnerability/PUB-A-463414629`
- OSV JSON: `https://storage.googleapis.com/android-osv/PUB-A-463414629.json`
- CVE Record API: `https://cveawg.mitre.org/api/cve/CVE-2026-0127`
- NVD: `https://nvd.nist.gov/vuln/detail/CVE-2026-0127`
- 3GPP / ETSI TS 33.501 UPU手順参考: `https://www.etsi.org/deliver/etsi_ts/133500_133599/133501/19.05.00_60/ts_133501v190500p.pdf`
- 3GPP / ETSI TS 29.509 UPU transparent container参考: `https://www.etsi.org/deliver/etsi_TS/129500_129599/129509/17.06.00_60/ts_129509v170600p.pdf`

Pixel bulletin の該当行は `CVE-2026-0127 / A-463414629* / DoS / Moderate / Pixel Modem`。`*` 付きなので Android bug は非公開で、bulletin FAQ の説明どおり修正は Pixel binary driver / firmware 側に含まれる類型と考えられる。

OSV / CVE の説明は以下の内容だった。

- 関数: `NrmmMsgCodec::DecodeUPUTransparentContext`
- ファイル名: `cn_NrmmDecoder.cpp`
- 問題: memory corruption による possible out-of-bounds read
- 影響: communication processor crash による remote DoS
- 権限: 追加権限不要
- ユーザー操作: 不要

## 解析したバイナリ

既存の `../binaries/pixel_shiba_modem_0135/` を使用した。CVE-2026-0135 の調査で保存済みだった Pixel 8 `shiba` modem binary で、June 2026 Pixel bulletin の modem 修正を含む前後候補として扱った。

- 修正前候補: `../binaries/pixel_shiba_modem_0135/modem_shiba_may_g5300i-251202-260127-B-14784800.bin`
  - SHA-256: `072eb34d8140a74f6d2508256ad4361175f388eafd7d5efcab8c8ea2b0891308`
- 修正後候補: `../binaries/pixel_shiba_modem_0135/modem_shiba_june_g5300i-260317-260505-B-15346003.bin`
  - SHA-256: `95dd7a59690f17ecfc43a8ccee381850c37787169b1442c1841074b9828b018a`

`file` ではどちらも `TOC sound file` と判定された。以前の modem 解析と同様に `modem.bin` は TOC を持つコンテナで、`MAIN` セクションが大規模に変化している。今回の作業では既存の抽出済み `modem.bin` を使い、追加の factory image ダウンロードは行っていない。

## 実施した patch diffing

OriginHQ の patch diffing pipeline と同じ流れで、advisory から非公開 bug ID と対象関数を確認し、前後 firmware を選び、バイナリ文字列とオフセット差分から対象コンポーネントを絞り込んだ。

主な付帯ファイル:

- `artifacts/analysis/modem_sha256.txt`
- `artifacts/analysis/modem_file.txt`
- `artifacts/analysis/old_modem_strings_offsets.txt`
- `artifacts/analysis/new_modem_strings_offsets.txt`
- `artifacts/analysis/old_nrmm_upu_strings.txt`
- `artifacts/analysis/new_nrmm_upu_strings.txt`
- `artifacts/analysis/focused_upu_offsets.txt`
- `artifacts/analysis/cn_nrmmmsgcodec_string_neighborhood.txt`
- `artifacts/analysis/upu_field_table_neighborhoods.txt`
- `artifacts/analysis/added_nrmm_upu_string_values.txt`
- `artifacts/analysis/removed_nrmm_upu_string_values.txt`
- `artifacts/artifacts_sha256.txt`

## バイナリで確認できたこと

`strings -a -t d` で前後 modem binary を調べると、NRMM 関連の C++ 型名とソースパスが残っていた。

- `N2cn2mm12NrmmMsgCodecE`
- `../../../SMPF/Protocol/CoreNetwork/MM/NRMM/cn_NrmmMsgCodec.cpp`
- `Registration accept`
- `DecodePayloadContainer`
- `CNS_MM_SOR_UPU_SMS_IND`
- `NRMM_NS_SOR_UPU_SMS_IND`

UPU / SOR 関連 field 名も複数残っていた。

- `UPU_PAYLOAD_LEN_VALID`
- `UPU_PAYLOAD_LEN`
- `UPU_PAYLOAD_VALID`
- `UPU_MAC_AUSF_VALID`
- `UPU_MAC_AUSF_LEN_VALID`
- `UPU_COUNTER_VALID`
- `UPU_RESULT_VALID`
- `UPU_MAC_UE_LEN_VALID`
- `UPU_COUNTER_UE_VALID`

これらは公開CVEの `DecodeUPUTransparentContext` と整合する。特に UPU transparent container は 3GPP TS 24.501 / TS 29.509 で定義される可変長のUE Parameters Update情報で、AUSF/UDM/AMF経由で UE に配送され、UE 側で MAC と counter を検証する。modem firmware 側では NRMM/NAS decode の一部として、payload length、MAC length、counter、payload body の存在/長さを順に読んでいく処理になっていると推測できる。

ただし `added_nrmm_upu_string_values.txt` / `removed_nrmm_upu_string_values.txt` は再配置や大規模更新の影響が強く、UPU専用の新規エラーログや明確な「length check added」文字列は見つからなかった。`UPU_*` field 名は修正前後の両方に存在し、文字列だけでは修正箇所を一意に切れない。

## 脆弱性と根本原因の推定

確度高く言えること:

- 攻撃面は 5G NAS / NRMM の UPU transparent container decode。
- 到達関数は `NrmmMsgCodec::DecodeUPUTransparentContext`。
- 入力はネットワークから届く UPU transparent container、またはそれを含む DL NAS Transport / Registration Accept 系の NRMM message。
- 根本原因カテゴリは、可変長 container の残り長、payload length、MAC/counter/payload subfield の整合性検証不足。
- 結果として decoder が受信 buffer 末尾を越えて読み、communication processor がクラッシュして remote DoS になる。

今回の推定される破綻パターン:

1. 攻撃者または不正基地局/ネットワーク側入力が、短すぎる UPU transparent container、または内部長 field と実際の残り長が矛盾する container を送る。
2. `DecodeUPUTransparentContext` が UPU header、counter、MAC、payload length、payload body などを順に読む。
3. どこかの `remaining >= needed` 相当の検証が不足し、`UPU_PAYLOAD_LEN` など入力由来の長さを信じて buffer 外を読む。
4. modem firmware 内で memory corruption / OOB read が起き、通信プロセッサがクラッシュする。

未確定な点:

- 具体的な subfield が `UPU_PAYLOAD_LEN` なのか、`UPU_MAC_AUSF_LEN` なのか、counter/MAC/payload の組み合わせなのかは断定できない。
- 修正後に追加された正確な条件式や early return は未特定。
- `cn_NrmmDecoder.cpp` と `cn_NrmmMsgCodec.cpp` の関係は公開CVEとバイナリ文字列から対応付けたが、ソースコードそのものは見つかっていない。

## 面白い点・調査メモ

- `A-463414629` は bulletin 上で `*` 付き。公開 commit はなく、Pixel binary firmware で修正された問題として扱う必要がある。
- CVE説明のファイル名は `cn_NrmmDecoder.cpp` だが、手元バイナリに見えた近傍ソースパスは `cn_NrmmMsgCodec.cpp`。クラス名は同じ `NrmmMsgCodec` なので、decoder 実装が別翻訳単位または統合ビルドで配置されている可能性がある。
- `UPU` は Universal Postal Union ではなく UE Parameters Update。検索時にノイズが多い。
- 3GPP上、UPU transparent container は AMF が UDM/AUSF由来の情報を UE に透過配送するための形式で、端末modemが外部ネットワーク由来の可変長binaryを直接解析する。長さ検証ミスが remote DoS になりやすい構造。
- 同じ June 2026 Pixel bulletin には Modem RCE/DoS が複数あり、同一 `modem.bin` 差分に複数修正が混在する。文字列差分だけで本CVE固有パッチを抜き出すのは難しい。

## ok にしなかった理由

この作業の基準では、ok とするにはソースコード、または脆弱性が起きる状況を完璧に説明できる必要がある。今回は公開情報で関数名と脆弱性種別はかなり狭く特定できたが、以下が不足している。

- `A-463414629` が非公開。
- Pixel Modem firmware は closed-source で、公開 commit/diff がない。
- `modem.bin` は大規模再ビルド差分で、複数CVE修正と通常更新が混在している。
- 関数単位の逆アセンブルdiff、xref、追加された bounds check の命令列を確認できていない。
- malformed UPU transparent container のうち、どの subfield / length 条件で OOB read するかを確定できていない。

## 追加で必要なもの

- `modem.bin` MAIN セクションを正しくロードできる Ghidra loader / Shannon modem向け解析環境。
- `NrmmMsgCodec::DecodeUPUTransparentContext` への xref と関数境界復元。
- May/June の関数単位 BinDiff / Diaphora 結果。
- `A-463414629` の crash log、PoC、または vendor bug の追加公開情報。
- 3GPP TS 24.501 clause 9.11.3.53A の正確な IE layout と、実装の読み取り順序の対応付け。
102 NG

CVE-2026-0144

102-ng-aoc-codec-frame-size-validation-dos

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentTelephony
TypeDoS
SeverityModerate
ReferencesA-495883315
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0144 is listed in the Pixel Update Bulletin as a Moderate severity DoS issue in Pixel / Telephony.

NG 判定の要点

判定: ng

理由: CVEの対象関数名、影響条件、May/June Pixel OTA間で増えた境界チェック文字列までは確認できたが、AocAudioCodec.cpp のソース本体または writeAocCommand の完全な関数差分を取得できなかった。したがって「ソースコード、もしくは脆弱性が起きる状況を完璧に説明できる場合のみok」という条件には届かない。

ただし、脆弱性の実体はかなり絞れている。CVE説明とファームウェア差分から、AoC audio codec command処理が、リモート由来の通話/codec設定またはcodec入力サイズを内部の期待値・バッファサイズと十分に照合せず、AoC側のメモリ安全性問題を起こしてPixel TelephonyのDoSにつながる問題だったと判断した。

未確定の理由 / 原因候補

記載なし。

どこから特定したか

公開情報: ・Pixel Update Bulletin June 2026:
- CVE-2026-0144 A-495883315 * DoS Moderate Telephony
- * 付きのAndroid bug IDなので、Googleの説明ではIssue自体は非公開。Bulletin FAQは、この種の修正がPixel用binary driversに含まれることが多いと説明している。
・OSV:
- PUB-A-495883315
- Details: In writeAocCommand of AocAudioCodec.cpp, there is a possible memory safety issue due to a missing bounds check. This coul…

URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01 / https://www.originhq.com/research/patch-diffing-pipeline

validated.md を表示
# CVE-2026-0144 検証メモ

## 結論

判定: **ng**

理由: CVEの対象関数名、影響条件、May/June Pixel OTA間で増えた境界チェック文字列までは確認できたが、`AocAudioCodec.cpp` のソース本体または `writeAocCommand` の完全な関数差分を取得できなかった。したがって「ソースコード、もしくは脆弱性が起きる状況を完璧に説明できる場合のみok」という条件には届かない。

ただし、脆弱性の実体はかなり絞れている。CVE説明とファームウェア差分から、AoC audio codec command処理が、リモート由来の通話/codec設定またはcodec入力サイズを内部の期待値・バッファサイズと十分に照合せず、AoC側のメモリ安全性問題を起こしてPixel TelephonyのDoSにつながる問題だったと判断した。

## 既存cve.md確認

- CVE: CVE-2026-0144
- 参照ID: A-495883315
- Component/Subcomponent: Pixel / Telephony
- Type/Severity: DoS / Moderate
- Bulletin URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- Security patch level: 2026-06-05 or later

## 公開情報

- Pixel Update Bulletin June 2026:
  - `CVE-2026-0144 A-495883315 * DoS Moderate Telephony`
  - `*` 付きのAndroid bug IDなので、Googleの説明ではIssue自体は非公開。Bulletin FAQは、この種の修正がPixel用binary driversに含まれることが多いと説明している。
- OSV:
  - `PUB-A-495883315`
  - Details: `In writeAocCommand of AocAudioCodec.cpp, there is a possible memory safety issue due to a missing bounds check. This could lead to remote denial of service with no additional execution privileges needed. User interaction is not needed for exploitation.`
  - Fixed: `Pixel-family specific:2026-06-05`
- NVD/CVE Record:
  - 同じ説明。CISA ADP側では CWE-120、CVSS v3.1 `AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H` が付いている。
- 参考にしたパッチdiff手法:
  - https://www.originhq.com/research/patch-diffing-pipeline

保存済み:

- `analysis/PUB-A-495883315.json`
- `analysis/PUB-A-495883315.storage.json`
- `analysis/osv_summary.txt`
- `analysis/origin-patch-diffing-pipeline.html`

## 使用したバイナリ

既存の展開済みPixel shiba vendorイメージを使用した。

- May / vulnerable候補:
  - `/Users/eric/workspace/android/2026-06/binaries/extracted_vendor/shiba-cp1a.260505.005/`
- June / fixed候補:
  - `/Users/eric/workspace/android/2026-06/binaries/extracted_vendor/shiba-cp2a.260605.012/`

対象フォルダへコピーした主なファイル:

- `blobs/aoc_may_cp1a.260505.005.bin`
- `blobs/aoc_june_cp2a.260605.012.bin`
- `blobs/android.hardware.audio.service-aidl.aoc_may_cp1a.260505.005`
- `blobs/android.hardware.audio.service-aidl.aoc_june_cp2a.260605.012`
- `blobs/vendor.google.whitechapel.audio.hal.utils.aoc_may.so`
- `blobs/vendor.google.whitechapel.audio.hal.utils.aoc_june.so`
- `blobs/libaoc_may.so`
- `blobs/libaoc_june.so`

SHA-256は `analysis/blob_sha256.txt` に保存した。AoC firmwareのhash:

- May `aoc.bin`: `1d2ea12539f05c8b74faa8a06e1ecb67d5989167acbf3384a0746203458a4571`
- June `aoc.bin`: `1fb7abc3600fbf6966e8b0359b545b4c7ca2fad5c7fb2f09893fc4e72cf4332c`

## 解析内容

### HAL側ライブラリ

`android.hardware.audio.service-aidl.aoc` は `vendor.google.whitechapel.audio.hal.utils.aoc.so` を利用している。`nm -D -C` で以下のAOC command関連シンボルを確認した。

- `vendor::google::whitechapel::audio::hal::utils::aoc::AocCommandExecutor::Execute(char*, int)`
- `AocTuningCommands::TuningFileDescriptors::Write(char const*, int)`
- `AocTuningCommands::TuningFileDescriptors::Read(...)`
- `AocTuningCommands::TuningFileDescriptors::SetParameterBulk(...)`

保存済み:

- `analysis/nmD_utils_aoc_may.txt`
- `analysis/nmD_utils_aoc_june.txt`
- `analysis/nmD_utils_aoc.diff`
- `analysis/AocCommandExecutor_Execute_may_vs_june.objdump.diff`
- `analysis/TuningFileDescriptors_Write_may_vs_june.objdump.diff`
- `analysis/TuningFileDescriptors_Execute_may_vs_june.objdump.diff`
- `analysis/TuningFileDescriptors_Read_may_vs_june.objdump.diff`

重要な観察:

- HAL側 `TuningFileDescriptors::Write` にはMay時点でも `request size > ring buffer size` のチェックが存在した。
- May/June差分はPLT配置、アドレスずれ、ログ文字列連結の揺れが中心で、CVE説明の「missing bounds check」を説明できる決定的な修正は見つからなかった。
- そのため、CVE本体はHALラッパではなくAoC firmware側にあると判断した。

### AoC firmware

`aoc.bin` のMay/June差分で、Juneにだけ存在するcodec/bounds check系文字列を確認した。

保存済み:

- `analysis/strings_aoc_bin_may.txt`
- `analysis/strings_aoc_bin_june.txt`
- `analysis/aoc_bin_interesting_unique_strings.txt`
- `analysis/aoc_bin_interesting_string_offsets.txt`
- `analysis/aoc_region_14369820_may_vs_june.diff`
- `analysis/aoc_region_14383471_may_vs_june.diff`
- `analysis/aoc_region_14383510_may_vs_june.diff`
- `analysis/aoc_region_14399391_may_vs_june.diff`

Juneにだけ存在した重要文字列:

- `in_size == octets_per_codec_frame_[stream_index]`
- `octetsPerCodecFrame is not match. (%u)(%u)`
- `samplingFrequency is not match. (%u)(%u)`
- `frameDuration is not match. (%u)(%u)`
- `Unsupported number of LC3 instances (%u) MAX:%d`
- `Bytes consumed (%d) > buffer size (%d)`
- `Valid buffer size %d larger than allocated %u`

オフセット:

- `in_size == octets_per_codec_frame_[stream_index]`: June `0xdb441c`
- `Bytes consumed (%d) > buffer size (%d)`: June `0xdb796f`
- `Valid buffer size %d larger than allocated %u`: June `0xdb7996`
- `octetsPerCodecFrame is not match. (%u)(%u)`: June `0xdbb79f`

`analysis/aoc_region_14369820_may_vs_june.diff` では、June側に `in_size == octets_per_codec_frame_[stream_index]` とその直前の `...not match to octets_per_codec_frame_[1](%u)` が追加されている。`analysis/aoc_region_14399391_may_vs_june.diff` では、LC3 codec設定の検証として `samplingFrequency`、`frameDuration`、`octetsPerCodecFrame` の不一致ログが追加されている。

## 推定される脆弱性

根本原因:

- `AocAudioCodec.cpp` の `writeAocCommand` が、AoCに渡すaudio codec commandまたはcodec frame入力について、外部/上位層から来るサイズと内部で期待するサイズを十分に検証していなかった。
- 特に、Bluetooth/telephony audio codecの `octetsPerCodecFrame`、`frameDuration`、`samplingFrequency`、LC3 instance数、実際の `in_size` が、streamごとの `octets_per_codec_frame_[stream_index]` や確保済みバッファサイズと一致するかを確認する境界チェックが不足していた可能性が高い。
- その結果、不正なcodec設定または期待より大きい/不一致のcodec frameが到達すると、AoC firmware内のwrite/parse/copy処理がバッファ境界外に進む、またはassert/abortを起こし、Telephony audio pathのDoSになる。

攻撃条件の推定:

- BulletinはPixel / Telephony、OSVはremote DoS、PR不要または追加権限不要、UI不要としている。
- CVSS enrichmentは `AV:N/AC:L/PR:L/UI:N/A:H` で、ネットワーク経由の通話/IMS/BT LE audio codec negotiationまたは音声フレーム処理から到達できる形と整合する。
- 端末側では `android.hardware.audio.service-aidl.aoc` がAoC audio serviceとして動き、vendor HALからAoC firmwareへcodec/tuning/stream commandを渡す。悪性または異常なcodecパラメータによりAoC側のcodec write commandが壊れると、音声/通話経路が停止しDoSになる。

修正内容の推定:

- codec設定の受理時に、LC3 instance数、sampling frequency、frame duration、octets per codec frameを既存stream状態と照合する。
- `writeAocCommand` またはその近傍で、`in_size == octets_per_codec_frame_[stream_index]` を保証する。
- parsing後に `Bytes consumed > buffer size` や `Valid buffer size > allocated` を検出し、バッファ境界外処理を拒否する。

## 面白い点・注意点

- Bulletin上のSubcomponentはTelephonyだが、実際の修正痕跡はAoC audio firmware内のBluetooth/LC3 codec設定検証に強く見える。Telephonyの通話音声経路がAoC audio codec処理を使うため、分類がTelephonyになった可能性がある。
- HAL側のAOC command wrapperにも境界チェック文字列があるが、May時点で既に `request size` とring buffer sizeのチェックがあるため、今回のCVEの根本原因とは見なしにくい。
- `AocAudioCodec.cpp` は公開AOSP/Pixelソース検索では見つからず、Pixel binary driver / AoC firmware側の非公開ソースと考えられる。
- `aoc.bin` の文字列領域差分だけでなく、該当文字列の周辺で多数のアドレス/文字列配置が変わっており、codec validation codeが追加または拡張されたことは確認できる。ただし命令レベルで `writeAocCommand` の制御フローを完全復元するには、Xtensa/AoC firmware向けの正確なロードアドレス、命令セット、シンボルが必要。

## 付帯ファイル

- `analysis/blob_file.txt`: file種別
- `analysis/blob_sha256.txt`: hash
- `analysis/nmD_*.txt`: dynamic symbol
- `analysis/strings_*.txt`: strings
- `analysis/*diff`: May/June差分
- `analysis/aoc_bin_interesting_unique_strings.txt`: Juneで増えた重要文字列
- `analysis/aoc_bin_interesting_string_offsets.txt`: 重要文字列オフセット
- `blobs/`: 解析対象バイナリコピー

## 未解決

- `AocAudioCodec.cpp` のソースコードと `writeAocCommand` の完全なパッチdiffは取得できなかった。
- AoC firmwareの関数シンボルがないため、追加された境界チェックがどの命令列に対応するかまでは未確定。
- したがって、脆弱性は「AoC codec command/frame size validation不足によるremote Telephony DoS」とかなり高い確度で特定したが、ok判定に必要な完全性には達していない。
103 OK

CVE-2026-0156

103-ok-rtpsession-ssrc-collision-ipaddr-null-deref-dos

cve.md の Android/Pixel 脆弱性情報

BulletinPixel Update Bulletin
Sourcehttps://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
Published/updatedJune 16, 2026
Security patch level2026-06-05 or later
ComponentPixel
SubcomponentTelephony
TypeDoS
SeverityModerate
ReferencesA-481274735
IncludedPixel/Google Devices Security Rewards candidate: Pixel component item, excluding kernel, Qualcomm, and obvious other-vendor Pixel rows.
Exclusion policy applied for this workspaceLinux/upstream kernel, general OSS/upstream-only issues, chipset/vendor sections, and other-vendor components were not created as target folders.
Short SummaryCVE-2026-0156 is listed in the Pixel Update Bulletin as a Moderate severity DoS issue in Pixel / Telephony.

特定した具体的な脆弱性

特定できた。CVE-2026-0156 は Pixel の Telephony/IMS media stack に含まれる libpixelimsmedia.so の RtpSession::checkSsrcCollisionOnRcv() における null pointer dereference によるリモート DoS だった。

根本原因は、既存 receiver entry の SSRC が受信 RTP/RTCP packet の SSRC と一致した場合に、旧実装が pobjRcvInfo->getIpAddr() の戻り値を検証せず、直後に pobjTmpDestAddr->getBuffer() を呼んでいたこと。RtpReceiverInfo に SSRC はあるが IP address buffer が未設定または破棄済みの状態で同じ SSRC の RTP/RTCP を受信すると、media process が null deref で落ち得る。

判定: ok。OSV が関数名と原因を公開しており、公開ソース相当の脆弱コードと Pixel May/June OTA の libpixelimsmedia.so 差分で、該当 null check の追加を確認できた。

原因

記載なし。

どこから特定したか

公開情報: ・OSV: https://osv.dev/vulnerability/PUB-A-481274735
・OSV JSON: artifacts/osv_PUB-A-481274735.json
・OSV detail: RtpSession.cpp の checkSsrcCollisionOnRcv で missing null check による memory safety issue。追加権限不要、user interaction 不要の remote DoS。

解析対象: 既存 OTA を使用した。

May/June バイナリ差分: objdump -T -C で RtpSession::checkSsrcCollisionOnRcv のサイズが増えている。

・May: address 0x175600, size 0x1c4
・June: address 0x180a40, size 0x1e4

保存物:

保存した主な成果物: ・payload_may_system_ext_summary.json
・payload_june_system_ext_summary.json
・extract_payload_partitions_may.log
・extract_payload_partitions_june.log
・artifacts/analysis/ota_and_img_sha256.txt
・artifacts/analysis/file_hash_comparison.tsv
・artifacts/analysis/file_types.txt
・artifacts/analysis/RtpSession_checkSsrcCollisionOnR…

validated.md を表示
# CVE-2026-0156 / A-481274735 検証メモ

## 結論

特定できた。CVE-2026-0156 は Pixel の Telephony/IMS media stack に含まれる `libpixelimsmedia.so` の `RtpSession::checkSsrcCollisionOnRcv()` における null pointer dereference によるリモート DoS だった。

根本原因は、既存 receiver entry の SSRC が受信 RTP/RTCP packet の SSRC と一致した場合に、旧実装が `pobjRcvInfo->getIpAddr()` の戻り値を検証せず、直後に `pobjTmpDestAddr->getBuffer()` を呼んでいたこと。`RtpReceiverInfo` に SSRC はあるが IP address buffer が未設定または破棄済みの状態で同じ SSRC の RTP/RTCP を受信すると、media process が null deref で落ち得る。

判定: `ok`。OSV が関数名と原因を公開しており、公開ソース相当の脆弱コードと Pixel May/June OTA の `libpixelimsmedia.so` 差分で、該当 null check の追加を確認できた。

## cve.md から確認した情報

- CVE: `CVE-2026-0156`
- 参照 ID: `A-481274735`
- Bulletin: Pixel Update Bulletin
- URL: https://source.android.com/docs/security/bulletin/pixel/2026/2026-06-01
- Component / subcomponent: `Pixel / Telephony`
- Type / severity: `DoS / Moderate`
- Fixed SPL: `2026-06-05`

Bulletin の該当行は `CVE-2026-0156 A-481274735 * DoS Moderate Telephony`。`*` 付きなので Android bug は非公開。

## 公開情報

- OSV: https://osv.dev/vulnerability/PUB-A-481274735
- OSV JSON: `artifacts/osv_PUB-A-481274735.json`
- OSV detail: `RtpSession.cpp` の `checkSsrcCollisionOnRcv` で missing null check による memory safety issue。追加権限不要、user interaction 不要の remote DoS。

## 解析対象

既存 OTA を使用した。

- May vulnerable: `../binaries/pixel_shiba_ota/shiba-ota-cp1a.260505.005.a1-7c6aa727.zip`
  - SHA-256: `71cbe004f1d76a981bbc65587465d5b36af22d85c7c7b18ee214c05488aee6fc`
- June fixed: `../binaries/pixel_shiba_ota/shiba-ota-cp2a.260605.012-b315a1a2.zip`
  - SHA-256: `b315a1a292e0fec4ddfa9a527f99fe0569bbfead09ff49f5fd3d156863b6baa9`
- 抽出 image:
  - `../binaries/pixel_shiba_telephony_cve0156/may/system_ext.img`
  - `../binaries/pixel_shiba_telephony_cve0156/june/system_ext.img`
- 抽出 library:
  - `artifacts/files_may/lib64__libpixelimsmedia.so`, BuildID `04d1927fb8d90a6a235602b626d2bd2c`
  - `artifacts/files_june/lib64__libpixelimsmedia.so`, BuildID `9805086f2f4b604be8076a9be5740ed6`

## 脆弱コード

公開 `packages/modules/ImsMedia` の `RtpSession.cpp` では、`checkSsrcCollisionOnRcv()` が既存 receiver list を走査し、同じ SSRC の entry を見つけると以下の順で処理する。

- `pobjRcvInfo->getIpAddr()` を `pobjTmpDestAddr` に代入。
- `pobjTmpDestAddr->getBuffer()` を即座に呼ぶ。
- その後で `pcDestAddr == nullptr || pcRcvDestAddr == nullptr` は検査するが、`pobjTmpDestAddr` 自体の null は検査しない。

保存した該当ソース:

- `artifacts/analysis/RtpSession_checkSsrcCollisionOnRcv_source_numbered.txt`
- `artifacts/analysis/RtpSession_processRcvdRtpPkt_callsite.txt`
- `artifacts/analysis/RtpSession_processRcvdRtcpPkt_callsite.txt`

重要箇所は `RtpSession.cpp:1349-1350`。

```cpp
RtpBuffer* pobjTmpDestAddr = pobjRcvInfo->getIpAddr();
RtpDt_UChar* pcDestAddr = pobjTmpDestAddr->getBuffer();
```

## May/June バイナリ差分

`objdump -T -C` で `RtpSession::checkSsrcCollisionOnRcv` のサイズが増えている。

- May: address `0x175600`, size `0x1c4`
- June: address `0x180a40`, size `0x1e4`

保存物:

- `artifacts/analysis/symbol_size_focus.tsv`
- `artifacts/analysis/checkSsrcCollisionOnRcv_may.objdump.txt`
- `artifacts/analysis/checkSsrcCollisionOnRcv_june.objdump.txt`
- `artifacts/analysis/strings_collision_diff.txt`
- `artifacts/analysis/inferred_patch_checkSsrcCollisionOnRcv.diff`

May 版は `getIpAddr()` 呼び出し直後に `RtpBuffer::getBuffer()` を呼ぶ。

- `0x175664`: `RtpReceiverInfo::getIpAddr()`
- `0x175668`: `RtpBuffer::getBuffer()`
- `getIpAddr()` の戻り値 `x0` に対する `cbz` がない。

June 版は `getIpAddr()` 後に null check が追加されている。

- `0x180b18`: `RtpReceiverInfo::getIpAddr()`
- `0x180b1c`: `cbz x0, 0x180b94`
- `0x180b20`: null でなければ `RtpBuffer::getBuffer()`
- `0x180b94` 以降: 新規ログを出して invalid params 経路に戻る。

June で追加された文字列:

- `[checkSsrcCollisionOnRcv] IP address is not available for SSRC: 0x%X`

これは `getIpAddr()==nullptr` を明示的に扱う修正で、OSV の missing null check と一致する。

## 脆弱性が起きる状況

攻撃面は RTP/RTCP 受信経路。`processRcvdRtpPkt()` と `processRtcpPkt()` はどちらも `checkSsrcCollisionOnRcv(pobjRtpAddr/pobjRtcpAddr, usPort, uiSsrc, eResult)` を呼ぶ。

成立条件は以下。

- IMS media session 等で Pixel が RTP または RTCP packet を受信する。
- 受信 packet の SSRC が `m_pobjRtpRcvrInfoList` 内の既存 `RtpReceiverInfo` の SSRC と一致する。
- その `RtpReceiverInfo` の `getIpAddr()` が `nullptr` を返す。
- 旧実装は `nullptr->getBuffer()` を実行し、プロセスがクラッシュする。

このため、リモートから到達する media packet により Telephony/IMS media service を落とせる DoS として扱われたと判断する。OSV の通り、追加権限やユーザー操作は不要。

## 面白かった点・調査メモ

- Bulletin の subcomponent は `Telephony` だが、実体は過去の `libpixelimsmedia` 系CVEと同じ `system_ext/lib64/libpixelimsmedia.so` 内の RTP stack だった。
- 公開AOSP相当の `packages/modules/ImsMedia` には脆弱な形の `RtpSession.cpp` が残っており、Pixel June blob 側で先に修正されているように見える。
- June では同じ `strings_collision_diff.txt` に `[decodeRtcpHeader] Truncated buffer: claims SSRC but buffer is only %d bytes` も追加されていた。これは別のRTCP hardeningと思われるが、CVE-2026-0156 のOSV関数名とは一致しないため主因にはしなかった。
- Telephony関連APK/JAR/SOをまとめて抽出し `file_hash_comparison.tsv` に残した。多くのAPK/JARはbuild差分でハッシュが変わるため、OSVの関数名がないと候補が広すぎる。

## 保存した主な成果物

- `payload_may_system_ext_summary.json`
- `payload_june_system_ext_summary.json`
- `extract_payload_partitions_may.log`
- `extract_payload_partitions_june.log`
- `artifacts/analysis/ota_and_img_sha256.txt`
- `artifacts/analysis/file_hash_comparison.tsv`
- `artifacts/analysis/file_types.txt`
- `artifacts/analysis/RtpSession_checkSsrcCollisionOnRcv_source_numbered.txt`
- `artifacts/analysis/checkSsrcCollisionOnRcv_may.objdump.txt`
- `artifacts/analysis/checkSsrcCollisionOnRcv_june.objdump.txt`
- `artifacts/analysis/strings_collision_diff.txt`
- `artifacts/analysis/inferred_patch_checkSsrcCollisionOnRcv.diff`
該当する項目がありません