{
 "month": "2026-10",
 "generated": "2026-10-14T01:30+00:00",
 "majors": {
  "14": {
   "counts": {
    "announced": 14,
    "certain": 13,
    "probable": 0,
    "not_published": 1,
    "not_covered": 0,
    "awaiting": 0
   },
   "advisories": [
    {
     "cve": "CVE-2026-55265",
     "osv_id": "ASB-A-517377150",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "DoS"
     ],
     "status": "announced-not-published",
     "detail": "platform/development,platform/frameworks/base",
     "coverage": {
      "n_ingested_tags": 30,
      "first_ingested_tag": "android-security-14.0.0_r1",
      "latest_ingested_tag": "android-security-14.0.0_r30",
      "window_base_tag": "android-14.0.0_r1",
      "window_start": "2023-10-04",
      "partial_tags": [],
      "projects": [
       {
        "project": "platform/development",
        "fetched_ok_in_tags": 30,
        "ingested_tags": 30,
        "latest_status": "ok"
       },
       {
        "project": "platform/frameworks/base",
        "fetched_ok_in_tags": 30,
        "ingested_tags": 30,
        "latest_status": "ok"
       }
      ]
     },
     "projects": [
      "platform/development",
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-58865",
     "osv_id": "ASB-A-513582756",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a bounds check on the well-known content-type index in PduParser.parseContentType and null checks on the parameter map and the parsed charset string in PduParser.parseContentTypeParams so a malformed MMS PDU no longer throws ArrayIndexOutOfBoundsException or NullPointerException out of PduParser.parse().",
      "confidence": "high",
      "backport_notes": [
       "The code change is self-contained and its hunks are identical on 14 through 17 (only the Android 17 base blob differs outside the hunks). It should apply cleanly to any tree where PduParser.java still has the unguarded `PduContentTypes.contentTypes[parseShortInteger(...)]` lookup and the two unguarded map.put sites. The new PduParserTest.java also contains two OOM tests that this diff does not fix. On a tree that lacks whatever handles those cases, drop testParse_malformedHugeHeaderLength_doesNotOOM and testPduParserUnderflowOOM or expect them to fail."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r30",
      "date": "2026-10-06",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r30",
      "date": "2026-10-06",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "53f75b4de6476512b83e3e4cd712d57fa256ab15",
       "tag": "android-security-14.0.0_r30",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-28667",
     "osv_id": "ASB-A-508389908",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a response-length check (length < p_i93->block_size) before three rw_i93_send_cmd_write_single_block calls in rw_t5t.cc, so a short tag response no longer leads to stale GKI buffer bytes being sent over RF in a WRITE_SINGLE_BLOCK command.",
      "confidence": "high",
      "backport_notes": [
       "This is a single, self-contained commit: three if (length < p_i93->block_size) guards in front of existing rw_i93_send_cmd_write_single_block calls. It uses only the local length variable and p_i93->block_size. On Android 16 and later the file is under packages/modules/Nfc/libnfc-nci instead of system/nfc."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/nfc",
       "sha": "f3a70c2a9415d2c8a160f1a599547b4982ed9568",
       "tag": "android-security-14.0.0_r29",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/system/nfc"
     ]
    },
    {
     "cve": "CVE-2026-45513",
     "osv_id": "ASB-A-508389591",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a length check in nfc_main_hal_data_cback (libnfc-nci nfc_main.cc). An incoming HAL data packet larger than the fixed NFC_NCI_POOL_ID GKI buffer capacity is now logged and dropped instead of being placed in a pool buffer that is too small.",
      "confidence": "high",
      "backport_notes": [
       "Single, self-contained commit. It depends only on GKI_get_pool_bufsize and on android_errorWriteLog (from log/log.h). On 14/15 the file is in platform/systemnfc; on 16/17 it is under libnfc-nci/ in platform/packages/modules/Nfc, and the patch applies to the same function in that file. NFC is a mainline module there (general platform knowledge)."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/nfc",
       "sha": "1dfa112088a9ac253249fdc86083ca3d93986df2",
       "tag": "android-security-14.0.0_r29",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/system/nfc"
     ]
    },
    {
     "cve": "CVE-2026-49878",
     "osv_id": "ASB-A-511544607",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "RCE"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Replaces two undersized os_zalloc(num_active_scs) allocations for the int arrays scs_resp[0] and scs_resp[1] in wpas_handle_robust_av_scs_recv_action with os_calloc(num_active_scs, sizeof(int)). This fixes the heap out-of-bounds write in the SCS Response handler.",
      "confidence": "high",
      "backport_notes": [
       "A single self-contained two-line change in wpa_supplicant/robust_av.c. Only the hunk line offset differs between branches (640/807/881/1072), so it should apply to any branch whose robust_av.c contains the (int *) os_zalloc(num_active_scs) pattern."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 6,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/external/wpa_supplicant_8",
       "sha": "5de2705a451f34218f00c3073533cb0c2823a0c0",
       "tag": "android-security-14.0.0_r29",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/external/wpa_supplicant_8"
     ]
    },
    {
     "cve": "CVE-2026-49885",
     "osv_id": "ASB-A-508389525",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a check in rw_t4t_set_ber_tlv() that p_t4t->max_update_size is larger than the ODO/DDO data header before computing data_length = max_update_size - data_header (in both realignment branches), and makes the caller rw_t4t_update_file() free the C-APDU GKI buffer when rw_t4t_set_ber_tlv() fails.",
      "confidence": "high",
      "backport_notes": [
       "Google applied the same hunks in a separate commit per major. Only the surrounding code differs (logging macro, line numbers, and the file path: libnfc-nci/src/nfc/tags/rw_t4t.cc in platform/packages/modules/Nfc on 16/17, src/nfc/tags/rw_t4t.cc in platform/system/nfc on 14/15).",
       "Apply both checks in rw_t4t_set_ber_tlv() together with the GKI_freebuf change in rw_t4t_update_file(). Adding the new false returns without the caller change would leak the C-APDU buffer."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/nfc",
       "sha": "90576eadff369f0a0eef2e77037859fe726dfc9c",
       "tag": "android-security-14.0.0_r29",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/system/nfc"
     ]
    },
    {
     "cve": "CVE-2026-49937",
     "osv_id": "ASB-A-514861024",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds bounds validation in libfmq's MessageQueueBase for kSynchronizedReadWrite queues. availableToReadBytes() now rejects a write/read pointer pair that claims more available bytes than the queue size, and beginRead() now rejects up front any read request larger than the queue's quantum count.",
      "confidence": "high",
      "backport_notes": [
       "Single-commit change confined to include/fmq/MessageQueueBase.h. Port both hunks (availableToReadBytes() and beginRead()) and keep the flavor == kSynchronizedReadWrite guard, which the commit message says is intentional for the unsync flavor. getQuantumCount() and mDesc->getSize() must exist in the target.",
       "MessageQueueBase is a class template defined in a header, so modules that instantiate it must be rebuilt for the fix to take effect."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 6,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/libfmq",
       "sha": "452c5e918cdeb5521464bee0464b6fe7866a1bf5",
       "tag": "android-security-14.0.0_r29",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/system/libfmq"
     ]
    },
    {
     "cve": "CVE-2026-55266",
     "osv_id": "ASB-A-509980995",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Rewrites the partition handling of the copied BSD qsort in libufdt's vendor sysdeps so that it recurses on the smaller partition and iterates on the larger one, bounding recursion depth to O(log n) instead of O(n) on adversarial inputs.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained commit. The diff is the same on 14/15 and on 16/17, with a two-line hunk offset on 16/17.",
       "Per index search, the qsort callers listed (bionic tests, gfxstream mesa u_qsort) are semantic matches. The material does not show that they use this vendor copy, so they are not evidence that it is reachable."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/libufdt",
       "sha": "bbc615c85bf160721f6d1034c26ab595c76cff8b",
       "tag": "android-security-14.0.0_r29",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/system/libufdt"
     ]
    },
    {
     "cve": "CVE-2026-55270",
     "osv_id": "ASB-A-517377154",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a `wrappedCallback == null` guard before `handleInCallMmiCommands(newDialString)` in `dialInternal` of both `GsmCdmaPhone` and `ImsPhone`, so that USSD requests (which carry a non-null ResultReceiver) are no longer interpreted as in-call MMI supplementary-service commands.",
      "confidence": "high",
      "backport_notes": [
       "The change adds one conjunct per file. On a tree where `dialInternal` has emergency-call feature-flag branches, add `wrappedCallback == null` to every path that calls `handleInCallMmiCommands` (as on 16) or to the enclosing condition (as on 17). Also check that the local `dialInternal` takes the `ResultReceiver wrappedCallback` parameter and that USSD requests pass a non-null receiver.",
       "The new tests rely on `replaceInstance` and the `mCT`/`mImsCT`/`mRingingCall`/`mGsmCdmaCall` mocks from `TelephonyTest`. Adjust the mock names if your local test base differs."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 6,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/opt/telephony",
       "sha": "a702397eed298a70bfd631241c8c6ab248a4835b",
       "tag": "android-security-14.0.0_r29",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/opt/telephony"
     ]
    },
    {
     "cve": "CVE-2026-58815",
     "osv_id": "ASB-A-514726373",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Changes the per-region loop bound in the camera metering-region mappers (DistortionMapper, RotateAndCropMapper, ZoomRatioMapper) from `j < entry.count` to `j + 5 <= entry.count`. A 5-int32 region tuple is now processed only when all five elements lie inside the metadata entry, which prevents heap out-of-bounds read and write when the region array length is not a multiple of 5.",
      "confidence": "high",
      "backport_notes": [
       "Single commit with six independent one-line loop-condition changes in three .cpp files. The hunk context lines are the same on 14 to 17, so the hunks apply with only line-offset differences.",
       "The commit message also names `correctMeteringRegions`, which this diff does not touch. When backporting, search the target tree for other `j < count; j += 5` loops over metering regions."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 7,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/av",
       "sha": "6654633902f82a2ca2191abbea06dfa274574570",
       "tag": "android-security-14.0.0_r29",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/av"
     ]
    },
    {
     "cve": "CVE-2026-58834",
     "osv_id": "ASB-A-515158597",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds an argument check in DevicePolicyManagerService.setPermissionGrantState that rejects any grantState other than GRANTED, DENIED or DEFAULT, and wraps the per-policy enforcePolicy calls in DevicePolicyEngine's policy re-apply loop in try/catch so that a bad persisted policy is logged with Slogf.wtf instead of crashing system_server.",
      "confidence": "high",
      "backport_notes": [
       "Single commit per release (it cites two upstream Cherrypick-From changes, Change-Id I090604a48f409e5109327217f642730258fb720f). The DevicePolicyEngine hunk context differs per release (shouldSkipEnforcementIfNotChanged() guard on 15+, userIds set iteration on 17), so apply the try/catch around whichever enforcePolicy calls exist in the re-apply loop. The DevicePolicyManagerService hunk and the test are textually identical across all four releases."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "057ff07691a6c6d8deea350c44ef10a012cb9204",
       "tag": "android-security-14.0.0_r29",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-58841",
     "osv_id": "ASB-A-515034370",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "VirtualAudioController.startListening now registers mAudioPlaybackDetector unconditionally instead of only when an IAudioConfigChangedCallback is supplied, so per the commit message the deferred silence-injection policy update recovers correctly when no config-changed callback is provided.",
      "confidence": "high",
      "backport_notes": [
       "Single commit that moves one line, with no dependencies. The hunk is identical on 14 through 17 apart from line offsets. Check that stopListening() in the target tree unregisters mAudioPlaybackDetector unconditionally, as in the shown code, so registration stays balanced."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "8ded15ca04993b1c24c8656eb9d96a079c196bd5",
       "tag": "android-security-14.0.0_r29",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-58854",
     "osv_id": "ASB-A-514727559",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds isRemote() (and, where missing, nullptr) validation before static_cast downcasts of caller-supplied ITunerFilter/ITunerDemux/ITunerLnb interface pointers in the mediatuner service, across both the AIDL and HIDL backends, rejecting remote binder proxies with Result::INVALID_ARGUMENT.",
      "confidence": "high",
      "backport_notes": [
       "Self-contained single commit; all hunks are additive guards. The only non-guard change is in services/tuner/hidl/TunerHidlDemux.cpp, which adds the Result.h include and `using ::aidl::android::hardware::tv::tuner::Result;`.",
       "When porting to a tree with customized tuner wrappers, apply the same isRemote() guard to every place a caller-supplied ITuner* interface is static_cast to a local Tuner*/TunerHidl* class, not just the eight methods listed."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 6,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/av",
       "sha": "f8520e699d1879281623b3b31469c7efa0f860cb",
       "tag": "android-security-14.0.0_r29",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/av"
     ]
    },
    {
     "cve": "CVE-2026-58856",
     "osv_id": "ASB-A-514734206",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a range check on the output slot index, a null check on the slot's GraphicBuffer, and a checked lookup in mBuffers in Camera3StreamSplitter::returnOutputBufferLocked. It also changes the outputSlots local from a copy to a reference.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained hunk in one .cpp file. Apply the Android 14/15 version to trees where the class is still Camera3StreamSplitter under device3/. Apply the 16/17 version where it has moved to device3/deprecated/DeprecatedCamera3StreamSplitter.cpp. SP_LOGE is already used in the file; check that PRIu64 is available.",
       "The copy-to-reference change for outputSlots is part of the fix (it makes the later outputSlots[slot] = nullptr take effect); keep it when resolving conflicts."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r29",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/av",
       "sha": "d74fdb8ae7d4ae9258e7b365713a686c32841915",
       "tag": "android-security-14.0.0_r29",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/av"
     ]
    }
   ],
   "tags": [
    "android-security-14.0.0_r30"
   ],
   "unannounced": [
    {
     "bug_ids": [
      "517376969"
     ],
     "commits": [
      {
       "project": "platform/frameworks/opt/telephony",
       "sha": "804a0e06d29190be1d62026d7fa691b27def6d43",
       "subject": "RESTRICT AUTOMERGE: Fix remote DoS in decodeWapPdu (b/517376969)",
       "tag": "android-security-14.0.0_r30",
       "merged": "2026-08-05",
       "markers": [
        "cve_fix",
        "restrict_automerge"
       ]
      }
     ],
     "tags": [
      "android-security-14.0.0_r30"
     ],
     "tag": "android-security-14.0.0_r30"
    }
   ],
   "coverage": {
    "n_ingested_tags": 30,
    "first_ingested_tag": "android-security-14.0.0_r1",
    "latest_ingested_tag": "android-security-14.0.0_r30",
    "window_base_tag": "android-14.0.0_r1",
    "window_start": "2023-10-04",
    "partial_tags": []
   },
   "platform_update_tags": {},
   "briefs": {
    "CVE-2026-58865": {
     "cve": "CVE-2026-58865",
     "summary": "Adds a bounds check on the well-known content-type index in PduParser.parseContentType and null checks on the parameter map and the parsed charset string in PduParser.parseContentTypeParams so a malformed MMS PDU no longer throws ArrayIndexOutOfBoundsException or NullPointerException out of PduParser.parse().",
     "component": "platform/frameworks/base, telephony/common MMS PDU parser (com.google.android.mms.pdu.PduParser)",
     "weakness": "Missing bounds check (array index taken from PDU input) and missing null checks, leading to uncaught exceptions",
     "root_cause": "In telephony/common/com/google/android/mms/pdu/PduParser.java, parseContentType indexed PduContentTypes.contentTypes directly with the value returned by parseShortInteger(pduDataStream). That value is read from the PDU (0-127 according to the added comment), but the table only has indices 0-82 (per the added comment and test). A short-integer content type of 83 or more therefore threw ArrayIndexOutOfBoundsException. In parseContentTypeParams, the short-integer branch of case P_TYPE/P_CT_MR_TYPE called map.put without checking map for null; per the added test, the ELEMENT_DESCRIPTOR path passes a null map. In the extension-charset branch of the charset parameter, charsetStr from parseWapString was passed to new String() and map.put was called without a null check on either. The added test shows an empty charset string value is expected to trigger this NPE, which implies parseWapString can return null, though its body is not shown. The tests reach all three paths from PduParser.parse() on malformed PDU bytes, and each one surfaced as an uncaught runtime exception.",
     "fix_analysis": [
      "PduParser.java:parseContentType: replaces the direct `PduContentTypes.contentTypes[parseShortInteger(pduDataStream)]` lookup with `int index = parseShortInteger(...)`. If `index < PduContentTypes.contentTypes.length` it uses the table entry, otherwise it falls back to `PduContentTypes.contentTypes[0]` (\"*/*\"). The check is an upper bound only; the added comment states parseShortInteger returns 0-127.",
      "PduParser.java:parseContentTypeParams, case PduPart.P_TYPE / P_CT_MR_TYPE, short-integer (well-known type) branch: wraps `map.put(PduPart.P_TYPE, type)` in `if (map != null)`. The sibling text-string branch already checked `(null != type) && (null != map)`, and this branch already ignored an out-of-range index.",
      "PduParser.java:parseContentTypeParams, charset parameter, Text-String (extension-charset) branch: wraps the whole try/catch (CharacterSets.getMibEnumValue(new String(charsetStr)) and both map.put calls) in `if (charsetStr != null && map != null)`, so a null charset string or a null map is silently skipped.",
      "tests/TelephonyCommonTests/src/com/google/android/mms/pdu/PduParserTest.java (new): adds testParse_invalidContentTypeIndex_doesNotThrowAIOOBE (Content-Type short-integer index 83), testParse_elementDescriptorWithParams_doesNotThrowNPE (ELEMENT_DESCRIPTOR 0xB2 with a P_TYPE parameter, null map) and testParse_emptyCharset_doesNotThrowNPE (P_CHARSET with an empty string). It also adds two OOM regression tests (testParse_malformedHugeHeaderLength_doesNotOOM, testPduParserUnderflowOOM) whose conditions this diff does not touch."
     ],
     "completeness": [
      "Covers: the direct table lookup in parseContentType; the null map in the short-integer P_TYPE branch of parseContentTypeParams; a null charsetStr or null map in the extension-charset branch of parseContentTypeParams.",
      "The new bounds check in parseContentType only tests `index < length`, not `index >= 0`. It relies on parseShortInteger returning 0-127, as the comment asserts (not shown in the material).",
      "The diff does not touch the Well-known-charset else branch of the charset parameter or the other parameter cases of parseContentTypeParams (e.g. start, name). The material does not show whether they dereference map without a null check.",
      "No code change in this commit addresses the two OOM tests added in PduParserTest.java (huge part header length, uintvar underflow). The material does not show whether other commits already present in these branches handle those conditions."
     ],
     "behavior_changes": [
      "A PDU whose Content-Type is encoded as a short integer with index >= PduContentTypes.contentTypes.length (83 or more) is now parsed with content type \"*/*\" (table entry 0) instead of aborting with an exception.",
      "A P_TYPE/P_CT_MR_TYPE well-known-type parameter seen while the parameter map is null (ELEMENT_DESCRIPTOR path) is now silently dropped instead of throwing NullPointerException.",
      "A text-string charset parameter is now silently ignored, instead of throwing NullPointerException, when parseWapString yields null or the map is null. When both are non-null, the existing behavior is unchanged, including mapping an unknown charset to CharacterSets.ANY_CHARSET."
     ],
     "preconditions": [
      "PduParser.parse() is invoked on malformed MMS PDU bytes (the tests construct `new PduParser(pduData, false)` and call parse()). The material does not show the production callers or where the bytes come from.",
      "AIOOBE path: a Content-Type header (0x84) whose value is a short integer with index 83 or above (e.g. 0xD3 in the test).",
      "NPE path 1: an ELEMENT_DESCRIPTOR header (0xB2) carrying a P_TYPE (0x83) parameter with a well-known short-integer value; per the test comment, that path passes a null map to parseContentTypeParams.",
      "NPE path 2: a Content-Type value with a P_CHARSET (0x81) parameter whose value is an empty text string (0x00)."
     ],
     "per_major": {
      "14": "Same fix: platform/frameworks/base 53f75b4de647 in android-security-14.0.0_r30, a cherry-pick of cbb0d81bf086 (Change-Id I4fab1579...). Identical hunks at the same line numbers (file index 6b3135945e53..775ef505ac2b) plus the new PduParserTest.java; 8/8 patched lines present.",
      "15": "Same fix: platform/frameworks/base 51268a5c0ff9 in android-security-15.0.0_r18. Diff and file indexes identical to Android 14; 8/8 patched lines present.",
      "16": "Same fix: platform/frameworks/base 60f9d9a0bcac in android-security-16.0.0_r9. Diff and file indexes identical to Android 14/15; 8/8 patched lines present.",
      "17": "Same fix: platform/frameworks/base 05fef2f15699 in android-security-17.0.0_r2. Identical hunks at the same line numbers, but the PduParser.java base blob differs (e805089306dc..d2f23026e5d8), so the file has differences outside the hunks; 8/8 patched lines present."
     },
     "backport_notes": [
      "The code change is self-contained and its hunks are identical on 14 through 17 (only the Android 17 base blob differs outside the hunks). It should apply cleanly to any tree where PduParser.java still has the unguarded `PduContentTypes.contentTypes[parseShortInteger(...)]` lookup and the two unguarded map.put sites. The new PduParserTest.java also contains two OOM tests that this diff does not fix. On a tree that lacks whatever handles those cases, drop testParse_malformedHugeHeaderLength_doesNotOOM and testPduParserUnderflowOOM or expect them to fail."
     ],
     "confidence": "high",
     "unknowns": [
      "Which process hosts PduParser.parse() for incoming MMS, and therefore what crashes (the material does not show callers or where the PDU bytes come from).",
      "Whether parseShortInteger can return a negative value; the new check has no lower bound and relies on the commented 0-127 range.",
      "Whether parseWapString returns null for an empty string (its body is not shown; only the test implies it).",
      "Whether the other parameter branches of parseContentTypeParams (Well-known-charset, start, name, etc.) dereference map without a null check.",
      "Which commit(s), if any, address the OOM conditions exercised by the two additional tests in the new PduParserTest.java.",
      "How the bulletin arrived at a Critical rating for a DoS type; the material gives only the rating."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-28667": {
     "cve": "CVE-2026-28667",
     "summary": "Adds a response-length check (length < p_i93->block_size) before three rw_i93_send_cmd_write_single_block calls in rw_t5t.cc, so a short tag response no longer leads to stale GKI buffer bytes being sent over RF in a WRITE_SINGLE_BLOCK command.",
     "component": "platform/system/nfc (Android 14/15) and platform/packages/modules/Nfc libnfc-nci (Android 16/17), NFC tag reader/writer, Type 5 Tag (ISO 15693) state machine in rw_t5t.cc",
     "weakness": "Missing bounds check on the received response length before the response buffer is reused as a fixed-size (block_size) write payload (information disclosure of stale buffer memory)",
     "root_cause": "In rw_t5t_sm_update_ndef and rw_t5t_sm_set_read_only, the code modifies block data in place through pointer p (for example *(p + xx) = ... and *(p + 1) |= I93_ICODE_CC_READ_ONLY) and then passes p to rw_i93_send_cmd_write_single_block. Per the commit message, this buffer is the response buffer, and nothing checked that the received length was at least block_size. If the response was shorter, stale GKI buffer slack was copied into the outgoing WRITE_SINGLE_BLOCK command and sent over RF. The material does not show the body of the send function; the block_size-sized copy is inferred from the commit message and the new guard. The commit message says this ports bounds checks from b/143109193, b/143155861 and b/143106535 to rw_t5t.cc.",
     "fix_analysis": [
      "rw_t5t.cc:rw_t5t_sm_update_ndef, first site (after writing the first part of the NDEF into the block holding the TLV start, block_number = (ndef_tlv_start_offset + 1) / block_size): before rw_i93_send_cmd_write_single_block(block_number, p), the fix checks length < p_i93->block_size. If the check is true, it logs android_errorWriteLog(0x534e4554, \"508389908\") and calls rw_i93_handle_error(NFC_STATUS_FAILED) instead of sending.",
      "rw_t5t.cc:rw_t5t_sm_update_ndef, second site (block_number = rw_offset / block_size, followed by advancing rw_offset to the start of the next block): the same guard, log and error handling are added before rw_i93_send_cmd_write_single_block(block_number, p).",
      "rw_t5t.cc:rw_t5t_sm_set_read_only: after I93_ICODE_CC_READ_ONLY is set in *(p + 1), the same guard is added before rw_i93_send_cmd_write_single_block(0, p) (the CC block write).",
      "Each guard is inserted as an if / else if in front of the existing send call, so the existing failure branch (rw_i93_handle_error on send failure) is unchanged. rw_i93_send_cmd_write_single_block itself is not modified."
     ],
     "completeness": [
      "The fix covers the three rw_i93_send_cmd_write_single_block call sites in rw_t5t.cc that send the in-place modified buffer p. The material does not show the whole file, so other similar sites cannot be ruled out.",
      "In the visible context, the RW_I93_SUBSTATE_WRITE_NDEF path sets p = p_i93->p_update_data + p_i93->rw_length (line 575). Its payload therefore comes from the caller-supplied update data, not from the response buffer, and the fix does not touch it.",
      "The check is a single comparison, length < block_size. The material does not show how length is derived from p_resp, so it cannot confirm that the comparison is exact.",
      "The fix rejects and fails: it does not zero or truncate the buffer. A short response aborts the operation."
     ],
     "behavior_changes": [
      "If a T5T tag response is shorter than block_size during an NDEF update or set-read-only operation, the operation now fails via rw_i93_handle_error(NFC_STATUS_FAILED) and no WRITE_SINGLE_BLOCK command is sent.",
      "A new log entry, android_errorWriteLog(0x534e4554, \"508389908\"), is emitted when this happens.",
      "Responses with length >= block_size follow the same path as before."
     ],
     "preconditions": [
      "NFC is enabled and the device is acting as reader/writer against a Type 5 Tag (ISO 15693 / I93).",
      "The device is running an NDEF update (rw_t5t_sm_update_ndef) or a set-read-only operation (rw_t5t_sm_set_read_only) on that tag.",
      "The tag response handled at these sites has a length shorter than p_i93->block_size."
     ],
     "per_major": {
      "14": "Same fix: platform/system/nfc f3a70c2a9415 in android-security-14.0.0_r29 adds three guards in src/nfc/tags/rw_t5t.cc. 8/8 patched lines present at android-security-14.0.0_r30.",
      "15": "Same fix: platform/system/nfc 620bfc1582b9 in android-security-15.0.0_r17, with identical hunks at different line offsets (571/749/831). 8/8 lines present at android-security-15.0.0_r18.",
      "16": "Same fix: platform/packages/modules/Nfc 144b34ba8906 in android-security-16.0.0_r8, file path libnfc-nci/src/nfc/tags/rw_t5t.cc, identical hunks. 8/8 lines present at android-security-16.0.0_r9.",
      "17": "Same fix: platform/packages/modules/Nfc 2ad8845ad77e in android-security-17.0.0_r1, same path and hunks as Android 16. 8/8 lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "This is a single, self-contained commit: three if (length < p_i93->block_size) guards in front of existing rw_i93_send_cmd_write_single_block calls. It uses only the local length variable and p_i93->block_size. On Android 16 and later the file is under packages/modules/Nfc/libnfc-nci instead of system/nfc."
     ],
     "confidence": "high",
     "unknowns": [
      "How length is computed from p_resp in these functions (for example, whether it excludes the response flags byte).",
      "The body of rw_i93_send_cmd_write_single_block and exactly how many bytes it copies from p.",
      "Whether the earlier bugs (b/143109193, b/143155861, b/143106535) fixed the same pattern in rw_i93.cc. The material only says the checks were ported from them.",
      "Which substate the second rw_t5t_sm_update_ndef hunk belongs to, and its exact purpose. The case label is outside the shown context.",
      "Whether rw_t5t.cc has other call sites that send response-buffer data without a length check."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-45513": {
     "cve": "CVE-2026-45513",
     "summary": "Adds a length check in nfc_main_hal_data_cback (libnfc-nci nfc_main.cc). An incoming HAL data packet larger than the fixed NFC_NCI_POOL_ID GKI buffer capacity is now logged and dropped instead of being placed in a pool buffer that is too small.",
     "component": "platform/system/nfc (Android 14/15) and platform/packages/modules/Nfc libnfc-nci (Android 16/17), NCI transport / HAL receive path (src/nfc/nfc/nfc_main.cc)",
     "weakness": "Missing bounds check leading to buffer overflow (fixed-size pool buffer vs. HAL-supplied data_len)",
     "root_cause": "In nfc_main_hal_data_cback, when the build takes the #else branch, the receive message buffer comes from GKI_getpoolbuf(NFC_NCI_POOL_ID), which returns a fixed-size buffer from that pool. The incoming data_len from the HAL was never compared against the pool buffer size minus sizeof(NFC_HDR) and NFC_RECEIVE_MSGS_OFFSET. According to the commit message, a packet longer than that remaining capacity could therefore overflow the pool buffer. The sibling #if branch allocates with GKI_getbuf(sizeof(NFC_HDR) + NFC_RECEIVE_MSGS_OFFSET + data_len), which sizes the buffer from data_len, and the fix does not change it.",
     "fix_analysis": [
      "src/nfc/nfc/nfc_main.cc:nfc_main_hal_data_cback (#else branch, before GKI_getpoolbuf): computes uint16_t max_len = GKI_get_pool_bufsize(NFC_NCI_POOL_ID) - sizeof(NFC_HDR) - NFC_RECEIVE_MSGS_OFFSET. If data_len > max_len, it logs both sizes with LOG(ERROR), calls android_errorWriteLog(0x534e4554, \"508389591\") and returns without allocating or queuing the message.",
      "Adds #include <log/log.h> to provide android_errorWriteLog.",
      "Note: the commit message names nfc_main_hal_read_cback, but the diff modifies nfc_main_hal_data_cback."
     ],
     "completeness": [
      "Covers the fixed-pool allocation path (#else branch) in nfc_main_hal_data_cback. In the shown code, this is the only place where a fixed-size buffer was used without a length check.",
      "The #if branch (GKI_getbuf sized from data_len) is left unchanged, because it sizes the allocation from data_len.",
      "The material does not show the code that copies p_data into p_msg after allocation. The diff therefore cannot confirm the exact overflow site, or whether other length assumptions exist downstream.",
      "The check assumes GKI_get_pool_bufsize(NFC_NCI_POOL_ID) is larger than sizeof(NFC_HDR) + NFC_RECEIVE_MSGS_OFFSET. The subtraction is stored in a uint16_t and would wrap if that were not true. The pool sizes are configuration constants and are not shown."
     ],
     "behavior_changes": [
      "HAL data packets whose length exceeds the NFC_NCI_POOL_ID buffer capacity are now dropped, so they are not delivered to the NFC task. Each drop writes an error log line.",
      "Each drop also writes a SafetyNet-style event log entry (tag 0x534e4554, id 508389591).",
      "Packets that fit are handled as before. The callback is void, so callers get no new return codes."
     ],
     "preconditions": [
      "libnfc-nci is built with the configuration that selects the #else branch (fixed GKI pool allocation via GKI_getpoolbuf) rather than the GKI_getbuf branch. The controlling macro is not shown in the material.",
      "The NFC HAL delivers a data packet to nfc_main_hal_data_cback with data_len greater than the pool buffer capacity minus the header overhead."
     ],
     "per_major": {
      "14": "same fix: platform/system/nfc 1dfa112088a9 in android-security-14.0.0_r29, src/nfc/nfc/nfc_main.cc. 7/7 lines present at android-security-14.0.0_r30. The added lines are identical to 15; the surrounding include context (base/logging.h, include order) and the hunk offsets differ.",
      "15": "same fix: platform/system/nfc 0a716527301d in android-security-15.0.0_r17, src/nfc/nfc/nfc_main.cc. 8/8 lines present at android-security-15.0.0_r18.",
      "16": "same fix, different project path: platform/packages/modules/Nfc 2db7814d87ba in android-security-16.0.0_r8, libnfc-nci/src/nfc/nfc/nfc_main.cc. 8/8 lines present at android-security-16.0.0_r9.",
      "17": "same fix, different project path: platform/packages/modules/Nfc 79b15334596b in android-security-17.0.0_r1, libnfc-nci/src/nfc/nfc/nfc_main.cc. 8/8 lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Single, self-contained commit. It depends only on GKI_get_pool_bufsize and on android_errorWriteLog (from log/log.h). On 14/15 the file is in platform/systemnfc; on 16/17 it is under libnfc-nci/ in platform/packages/modules/Nfc, and the patch applies to the same function in that file. NFC is a mainline module there (general platform knowledge)."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not include the code after allocation that copies data_len bytes into p_msg, which is the actual overflow site.",
      "The material does not show the name of the preprocessor macro that selects the #if (GKI_getbuf) or #else (GKI_getpoolbuf) branch, or which configuration Android builds use.",
      "The size of the NFC_NCI_POOL_ID buffers and the value of NFC_RECEIVE_MSGS_OFFSET are not shown.",
      "How nfc_main_hal_data_cback is registered and reached is not shown; the index search found no callers.",
      "The material does not show whether GKI_get_pool_bufsize already existed on all branches or was added separately. The patched lines are present in every branch's latest tag."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-49878": {
     "cve": "CVE-2026-49878",
     "summary": "Replaces two undersized os_zalloc(num_active_scs) allocations for the int arrays scs_resp[0] and scs_resp[1] in wpas_handle_robust_av_scs_recv_action with os_calloc(num_active_scs, sizeof(int)). This fixes the heap out-of-bounds write in the SCS Response handler.",
     "component": "platform/external/wpa_supplicant_8, wpa_supplicant Robust AV / SCS (Stream Classification Service) action frame handling (wpa_supplicant/robust_av.c)",
     "weakness": "Incorrect allocation size (byte count used where element count * sizeof(int) was needed), leading to a heap out-of-bounds write",
     "root_cause": "In wpa_supplicant/robust_av.c, wpas_handle_robust_av_scs_recv_action() processes a received SCS Response action frame. It first checks three things: the dialog token matches, the count field is valid (count != 0 and count * 3 <= remaining len), and count does not exceed num_active_scs = dl_list_len(&wpa_s->active_scs_ids). It then allocated two result arrays with scs_resp[0] = (int *) os_zalloc(num_active_scs) and scs_resp[1] = (int *) os_zalloc(num_active_scs). os_zalloc takes a byte size, so each buffer was only num_active_scs bytes. According to the commit message, the code uses these buffers as int arrays, which led to heap out-of-bounds writes. The writes happen in the per-response loop (for i < count). The exact write sites are not shown in the material.",
     "fix_analysis": [
      "wpa_supplicant/robust_av.c:wpas_handle_robust_av_scs_recv_action: scs_resp[0] = (int *) os_zalloc(num_active_scs) is replaced by scs_resp[0] = os_calloc(num_active_scs, sizeof(int)). This allocates num_active_scs zeroed int elements instead of num_active_scs bytes.",
      "wpa_supplicant/robust_av.c:wpas_handle_robust_av_scs_recv_action: the same change is made for scs_resp[1] = os_calloc(num_active_scs, sizeof(int)). The existing NULL checks, and the os_free(scs_resp[0]) when the second allocation fails, are unchanged.",
      "No validation logic changes. The existing frame checks (dialog token match, count != 0, count * 3 <= len, count <= num_active_scs) are unchanged, and they limit the loop to at most num_active_scs iterations."
     ],
     "completeness": [
      "Both undersized allocations shown (scs_resp[0] and scs_resp[1]) are corrected. The shown context (lines 614-673) has no other os_zalloc call.",
      "The fix relies on the existing check at line 637 (num_active_scs < count leads to a drop) to bound the loop count by num_active_scs. That check is untouched.",
      "Only part of the loop that writes into scs_resp is shown (up to line 673), so the exact write sites are not visible in the material.",
      "The fix only corrects the allocation size. It adds no new bounds checks, and the diff touches no other code in robust_av.c."
     ],
     "behavior_changes": [
      "scs_resp[0] and scs_resp[1] are now num_active_scs * sizeof(int) bytes instead of num_active_scs bytes. The diff does not change which frames are accepted or rejected, the logging, or the return paths.",
      "os_calloc in the hostap os abstraction checks nmemb * size for overflow and returns NULL on overflow, which would take the existing allocation-failure paths (general platform knowledge)."
     ],
     "preconditions": [
      "wpa_supplicant must receive a Robust AV SCS Response action frame that reaches wpas_handle_robust_av_scs_recv_action.",
      "The frame's dialog token must equal wpa_s->scs_dialog_token.",
      "num_active_scs = dl_list_len(&wpa_s->active_scs_ids) must be >= the frame's count field. count must be non-zero, and count * 3 must not exceed the remaining length."
     ],
     "per_major": {
      "14": "same fix: commit 5de2705a451f in android-security-14.0.0_r29, the same two-line change at robust_av.c hunk @@ -640. The code at android-security-14.0.0_r30 shows the os_calloc lines in place.",
      "15": "same fix: commit d14e657ca1ae in android-security-15.0.0_r17, the same change at hunk @@ -807 (only the line offset differs).",
      "16": "same fix: commit d131540379d6 in android-security-16.0.0_r8, the same change at hunk @@ -881.",
      "17": "same fix: commit ffd3987bbece in android-security-17.0.0_r1, the same change at hunk @@ -1072."
     },
     "backport_notes": [
      "A single self-contained two-line change in wpa_supplicant/robust_av.c. Only the hunk line offset differs between branches (640/807/881/1072), so it should apply to any branch whose robust_av.c contains the (int *) os_zalloc(num_active_scs) pattern."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact write sites into scs_resp[0]/scs_resp[1] inside the response loop, the values written, and how the arrays are used afterwards are not shown.",
      "Whether the SCS feature (populating active_scs_ids) is enabled or reachable by default on Android builds, and how scs_dialog_token gets set, is not shown.",
      "The content of the two internal Cherrypick-From commits is not shown.",
      "The material does not explain the resolver's '5/7 lines of the patched region present' figure, even though the os_calloc lines are visible at r30."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 6,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-49885": {
     "cve": "CVE-2026-49885",
     "summary": "Adds a check in rw_t4t_set_ber_tlv() that p_t4t->max_update_size is larger than the ODO/DDO data header before computing data_length = max_update_size - data_header (in both realignment branches), and makes the caller rw_t4t_update_file() free the C-APDU GKI buffer when rw_t4t_set_ber_tlv() fails.",
     "component": "platform/system/nfc (Android 14/15) and platform/packages/modules/Nfc libnfc-nci (Android 16/17), NFC Type 4 Tag reader/writer (rw_t4t.cc)",
     "weakness": "Integer underflow from a missing bounds check (max_update_size - data_header), plus a memory leak on the error path",
     "root_cause": "In src/nfc/tags/rw_t4t.cc rw_t4t_set_ber_tlv(), when the write has to be realigned to the tag's maximum update size (p_t4t->max_update_size), the code sets length = max_update_size and computes data_length = p_t4t->max_update_size - data_header, where data_header = RW_T4T_ODO_DDO_HEADER_MIN_LENGTH + length_size. Nothing checked that max_update_size is larger than data_header, so a max_update_size that is too small could make this subtraction underflow (the commit message calls this a potential underflow). The same pattern was in both the length == 0 branch and the length != 0 branch. Separately, rw_t4t_update_file() returned the result of rw_t4t_set_ber_tlv() directly, so a false return left the allocated p_c_apdu GKI buffer unfreed.",
     "fix_analysis": [
      "src/nfc/tags/rw_t4t.cc:rw_t4t_set_ber_tlv(): in the length == 0 path, inside the else branch where length is realigned to p_t4t->max_update_size, add `if (p_t4t->max_update_size <= data_header)` with LOG(ERROR) and return false, before data_length is computed. Because the comparison is <=, it also rejects the case where data_length would be zero.",
      "src/nfc/tags/rw_t4t.cc:rw_t4t_set_ber_tlv(): the same check is added in the length != 0 path, in the else branch where (length + data_header) > p_t4t->max_update_size, again before `data_length = p_t4t->max_update_size - data_header`.",
      "src/nfc/tags/rw_t4t.cc:rw_t4t_update_file(): in the MV 3.0 / NDEF size > 0x7FFF path, replace `return rw_t4t_set_ber_tlv(p_c_apdu, p, length);` with code that calls GKI_freebuf(p_c_apdu) and returns false when rw_t4t_set_ber_tlv() returns false, and otherwise returns true. As a result, the new error returns do not leak the C-APDU buffer."
     ],
     "completeness": [
      "Both `data_length = p_t4t->max_update_size - data_header` subtractions in rw_t4t_set_ber_tlv() are now guarded. No other `max_update_size - data_header` subtraction is visible in the shown context.",
      "The branches that do not realign (data_length = T4T_MAX_LENGTH_LC - data_header, and length += data_header) are unchanged. They do not subtract max_update_size.",
      "The leak fix covers only the visible caller, rw_t4t_update_file(). The material does not show whether rw_t4t_set_ber_tlv() has other callers (per index search, none were found, but that search is not conclusive).",
      "The fix checks max_update_size only where it is used. The code that sets max_update_size is not shown and is not changed by this commit."
     ],
     "behavior_changes": [
      "When the tag's max_update_size is less than or equal to the ODO/DDO header size and the realignment branch is taken, rw_t4t_set_ber_tlv() now logs \"max_update_size too small for ODO/DDO header\" and returns false instead of building the C-APDU. The NDEF update fails in that case.",
      "rw_t4t_update_file() now frees p_c_apdu with GKI_freebuf() when rw_t4t_set_ber_tlv() returns false, so these failures no longer leak a GKI buffer."
     ],
     "preconditions": [
      "An NDEF write (rw_t4t_update_file) to a Type 4 Tag on the path logged as MV 3.0 with an NDEF message size > 0x7FFF, where rw_t4t_set_ber_tlv() is called.",
      "The realignment branch is taken: T4T_MAX_LENGTH_LC > max_update_size when length == 0, or length + data_header > max_update_size otherwise. In addition, max_update_size <= data_header (RW_T4T_ODO_DDO_HEADER_MIN_LENGTH + length_size).",
      "The bulletin rates this High / EoP. The material does not say which privilege boundary is crossed."
     ],
     "per_major": {
      "14": "same fix: platform/system/nfc 90576eadff36 in android-security-14.0.0_r29, src/nfc/tags/rw_t4t.cc; 8/8 patched lines present at android-security-14.0.0_r30. The surrounding code uses DLOG_IF(INFO, nfc_debug_enabled) logging.",
      "15": "same fix: platform/system/nfc f01d5b0889f5 in android-security-15.0.0_r17, same file. Only the surrounding code differs (LOG(VERBOSE) instead of DLOG_IF, shifted line numbers). 8/8 lines present at android-security-15.0.0_r18.",
      "16": "same fix: platform/packages/modules/Nfc 9c0ae67d8733 in android-security-16.0.0_r8, in libnfc-nci/src/nfc/tags/rw_t4t.cc; 8/8 lines present at android-security-16.0.0_r9.",
      "17": "same fix: platform/packages/modules/Nfc 0dc8fad01628 in android-security-17.0.0_r1, in libnfc-nci/src/nfc/tags/rw_t4t.cc; 8/8 lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Google applied the same hunks in a separate commit per major. Only the surrounding code differs (logging macro, line numbers, and the file path: libnfc-nci/src/nfc/tags/rw_t4t.cc in platform/packages/modules/Nfc on 16/17, src/nfc/tags/rw_t4t.cc in platform/system/nfc on 14/15).",
      "Apply both checks in rw_t4t_set_ber_tlv() together with the GKI_freebuf change in rw_t4t_update_file(). Adding the new false returns without the caller change would leak the C-APDU buffer."
     ],
     "confidence": "high",
     "unknowns": [
      "The declared types of max_update_size, data_header and data_length, and how data_length is used after the subtraction, are not in the shown context. The exact memory-safety consequence of the underflow is therefore not shown by the material.",
      "Where p_t4t->max_update_size is set, and whether it is checked anywhere else, is not shown.",
      "Whether rw_t4t_set_ber_tlv() has callers other than rw_t4t_update_file().",
      "Whether rw_t4t_set_ber_tlv() had any false returns before this fix."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-49937": {
     "cve": "CVE-2026-49937",
     "summary": "Adds bounds validation in libfmq's MessageQueueBase for kSynchronizedReadWrite queues. availableToReadBytes() now rejects a write/read pointer pair that claims more available bytes than the queue size, and beginRead() now rejects up front any read request larger than the queue's quantum count.",
     "component": "platform/system/libfmq, MessageQueueBase (fast message queue read path, include/fmq/MessageQueueBase.h)",
     "weakness": "Missing bounds check on the read/write pointer difference and on the requested read count (bulletin type: ID)",
     "root_cause": "availableToReadBytes() loads mWritePtr and mReadPtr and rejected only the case writePtr < readPtr. If writePtr - readPtr exceeded the queue size (mDesc->getSize()), the function returned that oversized value unchanged. beginRead() also had no early check that nMessages fits in the queue (getQuantumCount()). The commit is a reapply of an earlier change. Per its message, the beginRead() check was fixed to apply only to kSynchronizedReadWrite, because the unsync flavor is expected to overflow when readers lag the writer. In the diff, both new checks are guarded by the flavor.",
     "fix_analysis": [
      "include/fmq/MessageQueueBase.h:availableToReadBytes(): computes queueSizeBytes = mDesc->getSize() and availableBytes = (writePtr >= readPtr) ? writePtr - readPtr : SIZE_MAX. It now returns 0 when writePtr < readPtr OR (flavor == kSynchronizedReadWrite && availableBytes > queueSizeBytes), and logs an error that includes writePtr, readPtr and the queue size. Otherwise it returns availableBytes.",
      "include/fmq/MessageQueueBase.h:beginRead(): adds a leading check, for kSynchronizedReadWrite only, that nMessages <= getQuantumCount(). If not, it logs an error, emits errorWriteLog(0x534e4554, \"514861024\") and returns false before the MemTransaction is initialized.",
      "On Android 15/16/17 the same logic is layered on the existing error-reporting variants: 15 sets *errorDetected = Error::POINTER_CORRUPTION, while 16 and 17 invoke mErrorHandler(Error::POINTER_CORRUPTION, ...). On 17 the beginRead() check omits the errorWriteLog call."
     ],
     "completeness": [
      "Covers the read side only: availableToReadBytes() and beginRead(). The diff makes no change to write-side functions, and the material does not show whether they need a similar guard.",
      "Both new checks are limited to flavor == kSynchronizedReadWrite. For the unsynchronized flavor, availableToReadBytes() still rejects only writePtr < readPtr, because the commit message says overflow is expected there.",
      "On Android 14, availableToReadBytes() signals corruption only by logging and returning 0 (the r30 code context shows no errorDetected/mErrorHandler path), so callers see it as no data available.",
      "The changed functions are template members defined in include/fmq/MessageQueueBase.h, so they take effect in binaries that instantiate them when those binaries are rebuilt against the patched header."
     ],
     "behavior_changes": [
      "Synchronized queues whose pointers claim more than the queue size in available bytes now report 0 available bytes and log 'The write or read pointer has become corrupted ...' with the pointer values and queue size.",
      "beginRead()/read() on a synchronized queue with nMessages > getQuantumCount() now fails immediately with false and logs an error, plus an errorWriteLog entry on 14, 15 and 16.",
      "On Android 14, the error log text in availableToReadBytes() now includes the write pointer, read pointer and queue size."
     ],
     "preconditions": [
      "A kSynchronizedReadWrite MessageQueue whose read/write pointer values (mReadPtr/mWritePtr) are inconsistent, followed by a read via read()/beginRead()/availableToReadBytes(). How the pointers become inconsistent is not shown in the material.",
      "For the beginRead() check: a caller requesting more messages than the queue's quantum count."
     ],
     "per_major": {
      "14": "Same fix: 452c5e918cde in android-security-14.0.0_r29, applied to the code variant where availableToReadBytes() only logs (no errorDetected/mErrorHandler). The r30 code context confirms the availableToReadBytes() change is present.",
      "15": "Adapted fix: 6d316edf3cc8 in android-security-15.0.0_r17. The same logic is merged into the variant that sets *errorDetected = Error::POINTER_CORRUPTION.",
      "16": "Adapted fix: 3aa82fe2d0a8 in android-security-16.0.0_r8. The same logic is merged into the mErrorHandler variant, including errorWriteLog in beginRead().",
      "17": "Adapted fix: f727482ff0c6 in android-security-17.0.0_r1. The same logic is applied to the mErrorHandler variant, but the beginRead() check omits the errorWriteLog(0x534e4554, ...) call."
     },
     "backport_notes": [
      "Single-commit change confined to include/fmq/MessageQueueBase.h. Port both hunks (availableToReadBytes() and beginRead()) and keep the flavor == kSynchronizedReadWrite guard, which the commit message says is intentional for the unsync flavor. getQuantumCount() and mDesc->getSize() must exist in the target.",
      "MessageQueueBase is a class template defined in a header, so modules that instantiate it must be rebuilt for the fix to take effect."
     ],
     "confidence": "high",
     "unknowns": [
      "The per-major resolver reports 6/8 lines of the patched region present in each latest security tag. The code context confirms the availableToReadBytes() hunk on 14.0.0_r30 but does not show the beginRead() hunk, so its presence in the latest tags is not directly verified here.",
      "Whether the write-side functions have an equivalent issue is not shown by the material.",
      "What the oversized available-byte value led to downstream in beginRead(), and the exact information-disclosure impact, are not shown in the diff.",
      "Why the original change was reverted is not stated in the material.",
      "The specific HAL or process involved (bugs 504768739 and 514861024), and how the pointers become corrupted, are not described in the material."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 6,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-55266": {
     "cve": "CVE-2026-55266",
     "summary": "Rewrites the partition handling of the copied BSD qsort in libufdt's vendor sysdeps so that it recurses on the smaller partition and iterates on the larger one, bounding recursion depth to O(log n) instead of O(n) on adversarial inputs.",
     "component": "platform/system/libufdt, sysdeps/libufdt_sysdeps_vendor.c (vendor sysdeps, qsort)",
     "weakness": "Uncontrolled recursion / stack exhaustion (unbounded recursion depth in qsort)",
     "root_cause": "The qsort implementation copied into sysdeps/libufdt_sysdeps_vendor.c always recursed on the left partition (`if ((r = pb - pa) > (int)es) qsort(a, r / es, es, cmp);`) and iterated via `goto loop` only on the right partition. The side chosen for recursion did not depend on partition size. An input whose pivot selection repeatedly left a large left partition therefore drove recursion depth proportional to n, so a large or adversarially ordered input could exhaust the stack (DoS per bulletin).",
     "fix_analysis": [
      "sysdeps/libufdt_sysdeps_vendor.c:qsort adds a new local `int l`. After the final vecswap calls it computes `l = pb - pa` (left partition byte size) and `r = pd - pc` (right partition byte size) explicitly, instead of reusing `r` for both.",
      "If `l < r`: recurse with `qsort(a, l / es, es, cmp)` on the left (only when `l > es`), then iterate on the right by setting `a = pn - r; n = r / es; goto loop` (only when `r > es`).",
      "Else: recurse with `qsort(pn - r, r / es, es, cmp)` on the right (only when `r > es`), then iterate on the left by setting `n = l / es; goto loop` (only when `l > es`). `a` is unchanged because the left partition starts at `a`.",
      "The recursive call is always made on the smaller of the two partitions, so each recursion level at least halves the problem and stack depth is bounded to O(log n). The stale comment `/* qsort(pn - r, r / es, es, cmp); */` is removed."
     ],
     "completeness": [
      "Covers the single recursion site in the vendor qsort. Both partitions now go through the size comparison, and the `> (int)es` guards are preserved on each branch.",
      "Sorting semantics are unchanged; only the order in which partitions are processed differs.",
      "Partition sizes `l`, `r` and `d` remain `int` values computed from pointer differences, as before the fix. The patch does not change these types or add any size validation.",
      "Only sysdeps/libufdt_sysdeps_vendor.c is touched; the material shows no change to any other sysdeps variant or caller."
     ],
     "behavior_changes": [
      "Maximum stack depth of the vendor qsort is bounded to O(log n) frames for any input ordering.",
      "No change to the sorted result, API, or return behavior. The order in which sub-partitions are processed changes (the right partition may now be sorted before the left)."
     ],
     "preconditions": [
      "libufdt built with the vendor sysdeps (sysdeps/libufdt_sysdeps_vendor.c), which defines its own qsort.",
      "A qsort call with n >= 7 elements (smaller inputs take the insertion-sort path and return) and an element ordering that repeatedly produces an unbalanced partition on the recursed side. The size needed depends on the available stack.",
      "Which libufdt code path invokes this qsort, and how its input is controlled, is not shown in the material."
     ],
     "per_major": {
      "14": "same fix: platform/system/libufdt bbc615c85bf1 in android-security-14.0.0_r29 (cherry-pick, Change-Id I260075b5280433ae59b61edef9b30cb6610bd02f). At android-security-14.0.0_r30 the new declaration `int d, l, r, swaptype, swap_cnt;` is visible, and the resolver reports 7/8 lines of the patched region present.",
      "15": "same fix: 109d68930129 in android-security-15.0.0_r17. Same diff, hunk offsets and file index (235d995..3b1e60a) as Android 14. 7/8 lines present at android-security-15.0.0_r18.",
      "16": "same fix: 8dfd47aab1f2 in android-security-16.0.0_r8. Same change with hunks two lines later (@@ -100 / @@ -161, file index fc5b186..57d334a). 7/8 lines present at android-security-16.0.0_r9.",
      "17": "same fix: 70c20864187d in android-security-17.0.0_r1. Identical to the Android 16 patch (same file index). 7/8 lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Single self-contained commit. The diff is the same on 14/15 and on 16/17, with a two-line hunk offset on 16/17.",
      "Per index search, the qsort callers listed (bionic tests, gfxstream mesa u_qsort) are semantic matches. The material does not show that they use this vendor copy, so they are not evidence that it is reachable."
     ],
     "confidence": "high",
     "unknowns": [
      "Which libufdt function calls this qsort and whether its input (e.g. device tree overlay data) is attacker controlled is not shown.",
      "Which build configurations actually compile sysdeps/libufdt_sysdeps_vendor.c (versus a libc-backed sysdeps) is not shown.",
      "Stack size of the affected environment and the input size required to trigger the overflow are not shown.",
      "Which line of the patched region the resolver counts as missing (7/8 lines present on every major) is not shown. The partition-handling block at the latest tags is not included in the code excerpt.",
      "Why the Android 16/17 hunks are offset by two lines is not shown."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-55270": {
     "cve": "CVE-2026-55270",
     "summary": "Adds a `wrappedCallback == null` guard before `handleInCallMmiCommands(newDialString)` in `dialInternal` of both `GsmCdmaPhone` and `ImsPhone`, so that USSD requests (which carry a non-null ResultReceiver) are no longer interpreted as in-call MMI supplementary-service commands.",
     "component": "platform/frameworks/opt/telephony, Phone dial / USSD handling (GsmCdmaPhone, imsphone/ImsPhone)",
     "weakness": "Missing request-context check: a USSD request string was passed to the in-call MMI (call control) handler, so a USSD request could perform call-state operations",
     "root_cause": "`dialInternal(String dialString, DialArgs dialArgs, ResultReceiver wrappedCallback)` serves both ordinary dialing (`ImsPhone.dial` passes `wrappedCallback = null`, per the code context) and USSD requests, which according to the commit message and tests carry a non-null ResultReceiver (the tests call `handleUssdRequest(\"2\", mockCallback)`). Before the fix, `dialInternal` called `handleInCallMmiCommands(newDialString)` with no condition: on every call in ImsPhone, and inside the `isPhoneTypeGsm()` branch in GsmCdmaPhone. It returned whenever the string was handled. A USSD request whose string matched an in-call MMI code (the tests use \"2\") therefore ran the matching in-call supplementary service instead of being treated as USSD. The tests check `acceptCall` on the call trackers, and the commit message also names hold, swap and conference. The bulletin rates this as a High severity EoP.",
     "fix_analysis": [
      "src/java/com/android/internal/telephony/GsmCdmaPhone.java:dialInternal (inside the `isPhoneTypeGsm()` branch): `if (handleInCallMmiCommands(newDialString))` becomes `if (wrappedCallback == null && handleInCallMmiCommands(newDialString))`. Because of short-circuit evaluation, `handleInCallMmiCommands` is never called when a ResultReceiver is present.",
      "src/java/com/android/internal/telephony/imsphone/ImsPhone.java:dialInternal: the same change. The code context at android-security-14.0.0_r30 (line 981) shows the guard in place. The string then reaches `ImsPhoneMmiCode.newFromDialString(networkPortion, this, wrappedCallback)` as before.",
      "tests/telephonytests/.../GsmCdmaPhoneTest.java: the new `testHandleUssdRequestWithInCallMmiCode` sets the call state to INCOMING, calls `mPhoneUT.handleUssdRequest(\"2\", mockCallback)`, asserts it returns true, and verifies with `verify(mCT, never()).acceptCall()`.",
      "tests/telephonytests/.../imsphone/ImsPhoneTest.java: the new `testHandleUssdRequestWithInCallMmiCode` expects `handleUssdRequest(\"2\", mockCallback)` to throw `CallStateException` with message `Phone.CS_FALLBACK`, and verifies that `mImsCT.acceptCall(anyInt())` is never called."
     ],
     "completeness": [
      "Covers the in-call MMI pre-check in `dialInternal` of both `GsmCdmaPhone` (GSM phone-type branch) and `ImsPhone`.",
      "The guard relies only on `wrappedCallback` being non-null to mark a USSD request. It is correct only if every USSD entry passes a non-null ResultReceiver and every ordinary dial passes null; the material shows `ImsPhone.dial` passing null. No separate check of where the request came from is added.",
      "`handleInCallMmiCommands` itself is unchanged, so ordinary dials still run in-call MMI codes as before.",
      "After the guard, USSD strings still go through regular MMI parsing (shown for ImsPhone via `ImsPhoneMmiCode.newFromDialString` with `wrappedCallback`). The material does not show how the GSM path handles a string such as \"2\" afterwards, beyond `handleUssdRequest` returning true."
     ],
     "behavior_changes": [
      "USSD requests whose string matches an in-call MMI code no longer trigger call-control actions (the tests check accept; the commit message names hold, swap and conference).",
      "On ImsPhone, per the new test, such a USSD request results in a `CallStateException` with message `Phone.CS_FALLBACK`.",
      "On GsmCdmaPhone, per the new test, `handleUssdRequest` returns true for such input and no `acceptCall` happens on the call tracker.",
      "Normal dialing (`wrappedCallback == null`) is unchanged."
     ],
     "preconditions": [
      "A USSD request must reach `handleUssdRequest`, and through it `dialInternal` with a non-null ResultReceiver, on a GSM-type `GsmCdmaPhone` or an `ImsPhone`. The caller chain and its permission checks are not shown in the material.",
      "The USSD string must match an in-call MMI code that `handleInCallMmiCommands` recognises (the tests use \"2\").",
      "A call must be in a state where that MMI code has an effect (the tests set a call to `State.INCOMING`, so `acceptCall` would otherwise be relevant)."
     ],
     "per_major": {
      "14": "same fix: commit a702397eed29 in android-security-14.0.0_r29. A one-line condition change in GsmCdmaPhone.dialInternal (GSM branch) and in ImsPhone.dialInternal, plus the two tests. The guard is confirmed present in ImsPhone at android-security-14.0.0_r30.",
      "15": "same fix: commit 92836c48ba6a in android-security-15.0.0_r17. The same one-line changes at shifted locations (hunks at GsmCdmaPhone line 1714 and ImsPhone line 1001) and the same tests.",
      "16": "adapted fix: commit ee04a37583c0 in android-security-16.0.0_r8. In both files the in-call MMI check has two branches, selected by `mFeatureFlags.skipMmiCodeCheckForEmergencyCall()`. `wrappedCallback == null` is added to both: the flagged branch becomes `!dialArgs.isEmergency && wrappedCallback == null && handleInCallMmiCommands(...)`, and the unflagged condition gets the same guard. Same tests.",
      "17": "adapted fix: commit 802f8f5c9920 in android-security-17.0.0_r1. The in-call MMI handling sits under an outer `if (!dialArgs.isEmergency)` block, with `mFeatureFlags.ignoreIncallMmiForEmergency()` logic inside. The outer condition becomes `!dialArgs.isEmergency && wrappedCallback == null`. Same tests."
     },
     "backport_notes": [
      "The change adds one conjunct per file. On a tree where `dialInternal` has emergency-call feature-flag branches, add `wrappedCallback == null` to every path that calls `handleInCallMmiCommands` (as on 16) or to the enclosing condition (as on 17). Also check that the local `dialInternal` takes the `ResultReceiver wrappedCallback` parameter and that USSD requests pass a non-null receiver.",
      "The new tests rely on `replaceInstance` and the `mCT`/`mImsCT`/`mRingingCall`/`mGsmCdmaCall` mocks from `TelephonyTest`. Adjust the mock names if your local test base differs."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show `handleUssdRequest`, the public entry point(s) that reach it, or the permission (if any) that gates them, so the attacker position implied by the EoP rating is not visible.",
      "The full GsmCdmaPhone.dialInternal (including any CDMA branch, and processing after the guard) is not shown.",
      "The full list of in-call MMI codes handled by `handleInCallMmiCommands`, beyond the \"2\" used in the tests, is not shown.",
      "The per-major note '6/8 lines of the patched region present' at the latest security tags is not explained, although the ImsPhone context shown at 14.0.0_r30 does contain the guard."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 6,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58815": {
     "cve": "CVE-2026-58815",
     "summary": "Changes the per-region loop bound in the camera metering-region mappers (DistortionMapper, RotateAndCropMapper, ZoomRatioMapper) from `j < entry.count` to `j + 5 <= entry.count`. A 5-int32 region tuple is now processed only when all five elements lie inside the metadata entry, which prevents heap out-of-bounds read and write when the region array length is not a multiple of 5.",
     "component": "platform/frameworks/av, services/camera/libcameraservice/device3 (cameraserver metadata mappers)",
     "weakness": "Missing bounds check leading to heap out-of-bounds read and write (loop stride larger than the remaining element count)",
     "root_cause": "The metering-region tags in kMeteringRegionsToCorrect (e.g. ANDROID_CONTROL_AE_REGIONS) are processed as 5-element int32 tuples, with the weight at offset 4. Six loops iterated with `for (j = 0; j < entry.count; j += 5)`, read `entry.data.i32[j + 4]` (the weight), and passed `entry.data.i32 + j` to an in-place coordinate transform. The loops are in DistortionMapper::correctCaptureRequest / correctCaptureResult, RotateAndCropMapper::updateCaptureRequest / updateCaptureResult and ZoomRatioMapper::separateZoomFromCropLocked / combineZoomAndCropLocked. The transforms are mapCorrectedToRaw, transformPoints plus swapRectToMinFirst, and the zoom region scaling. The loop condition only checked that the first element of the tuple was in range. When entry.count is not a multiple of 5 (the new tests use count 6), the last iteration starts at j = 5 with one element left. The weight read at index 9 and any coordinate access at indices 6..8 then go past the end of the metadata entry buffer. Per the commit message, this is triggered by a CaptureRequest containing such a metering region.",
     "fix_analysis": [
      "services/camera/libcameraservice/device3/DistortionMapper.cpp: in correctCaptureRequest and correctCaptureResult, the kMeteringRegionsToCorrect loop condition becomes `j + 5 <= e.count`. The weight read at e.data.i32[j + 4] and the in-place mapCorrectedToRaw(e.data.i32 + j, 2, ...) now happen only for complete 5-element tuples.",
      "services/camera/libcameraservice/device3/RotateAndCropMapper.cpp: in updateCaptureRequest and updateCaptureResult, the loop condition becomes `i + 5 <= entry.count`. This is checked before entry.data.i32[i + 4] is read and before transformPoints / swapRectToMinFirst operate on entry.data.i32 + i.",
      "services/camera/libcameraservice/device3/ZoomRatioMapper.cpp: in separateZoomFromCropLocked and combineZoomAndCropLocked, the loop condition becomes `j + 5 <= entry.count` before the weight read and the region scaling.",
      "Tests (MeteringRegionsBoundsTest) are added in tests/DistortionMapperTest.cpp, tests/RotateAndCropMapperTest.cpp and tests/ZoomRatioTest.cpp. Each test first writes a 10-element AE region array as poison, then overwrites the tag with a 6-element array {.., 50, 999} and runs the request mapper. It asserts that the count stays 6 and element [5] is still 999."
     ],
     "completeness": [
      "The six kMeteringRegionsToCorrect loops shown in the three mappers are all fixed, covering both the request and result directions.",
      "The fix does not check that entry.count is a multiple of 5 and does not return an error. A trailing partial tuple is silently left untransformed by the mappers.",
      "The kRectsToCorrect loop in DistortionMapper::correctCaptureRequest uses `e.count / 4` as the rect count, which already truncates to whole rects. This fix does not change it.",
      "The commit message names a fourth location, `correctMeteringRegions`, but no function by that name appears in the diff or the provided code context."
     ],
     "behavior_changes": [
      "Metering-region arrays whose length is not a multiple of 5 now have their trailing incomplete tuple skipped by the mappers instead of being processed with out-of-bounds accesses. No new error code is introduced, and the mapper return values are unchanged.",
      "For well-formed arrays (count a multiple of 5), behaviour is identical."
     ],
     "preconditions": [
      "A capture request or result containing one of the kMeteringRegionsToCorrect tags (e.g. ANDROID_CONTROL_AE_REGIONS) with an element count that is not a multiple of 5. The commit message names the CaptureRequest case.",
      "DistortionMapper path: mapperInfo->mValidMapping is true, and ANDROID_DISTORTION_CORRECTION_MODE is present and not ANDROID_DISTORTION_CORRECTION_MODE_OFF (DistortionMapper.cpp context).",
      "RotateAndCropMapper path: ANDROID_SCALER_ROTATE_AND_CROP is present and not ANDROID_SCALER_ROTATE_AND_CROP_NONE (RotateAndCropMapper.cpp context). The test uses ROTATE_AND_CROP_90.",
      "ZoomRatioMapper path: the test calls ZoomRatioMapper::updateCaptureRequest with ANDROID_SCALER_CROP_REGION set to a 2x crop so that the AE regions are rescaled. The call chain to the two *Locked functions is not shown.",
      "Per index search, Camera3OutputUtils.cpp sendCaptureResult (which takes a rotateAndCropAuto parameter) is a candidate caller on the result path. The call itself is not shown in the snippet."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/av 6654633902f8 in android-security-14.0.0_r29 (cherry-pick of cc78e7aa1be9). It has the six one-line condition changes plus the three tests. The resolver reports 7/8 lines of the patched region present at android-security-14.0.0_r30.",
      "15": "same fix: ff3f3a6b8194 in android-security-15.0.0_r17. Same hunks with small line offsets (DistortionMapper 145/184, RotateAndCropMapper 165/294, ZoomRatioMapper 352/390). 7/8 lines present at android-security-15.0.0_r18.",
      "16": "same fix: aff9120ec0b8 in android-security-16.0.0_r8. Same hunks (ZoomRatioMapper at 386/424). 7/8 lines present at android-security-16.0.0_r9.",
      "17": "same fix: 77f8ddbbd65b in android-security-17.0.0_r1, with the same blob indexes as the Android 16 diff. 7/8 lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Single commit with six independent one-line loop-condition changes in three .cpp files. The hunk context lines are the same on 14 to 17, so the hunks apply with only line-offset differences.",
      "The commit message also names `correctMeteringRegions`, which this diff does not touch. When backporting, search the target tree for other `j < count; j += 5` loops over metering regions."
     ],
     "confidence": "high",
     "unknowns": [
      "Where the `correctMeteringRegions` function named in the commit message is and what its status is. It is absent from the diff and the provided code context.",
      "Whether any length check on metering-region arrays exists upstream of the mappers (e.g. at request validation).",
      "Where the result-path metadata entries come from, and the exact call chain into ZoomRatioMapper's *Locked functions.",
      "What the resolver's '7/8 lines present' metric means relative to the six changed source lines."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 7,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58834": {
     "cve": "CVE-2026-58834",
     "summary": "Adds an argument check in DevicePolicyManagerService.setPermissionGrantState that rejects any grantState other than GRANTED, DENIED or DEFAULT, and wraps the per-policy enforcePolicy calls in DevicePolicyEngine's policy re-apply loop in try/catch so that a bad persisted policy is logged with Slogf.wtf instead of crashing system_server.",
     "component": "platform/frameworks/base, services/devicepolicy (DevicePolicyManagerService, DevicePolicyEngine)",
     "weakness": "Missing input validation of a persisted enum value (grantState), leading to an uncaught IllegalArgumentException during system_server boot (persistent DoS)",
     "root_cause": "DevicePolicyManagerService.setPermissionGrantState accepted an arbitrary int grantState from the calling admin without range-checking it. Per the commit message, the value was saved to disk, and on later system_server boots the policy re-application in DevicePolicyEngine called enforcePolicy(policyDefinition, policyValue, ...) for each global and local policy with no exception handling. The invalid stored value threw an uncaught IllegalArgumentException and crashed system_server during boot, repeatedly, until a factory reset.",
     "fix_analysis": [
      "services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java:setPermissionGrantState: immediately after Objects.requireNonNull(callback) and before getCallerIdentity / checkCanExecuteOrThrowUnsafe, adds Preconditions.checkArgument(grantState == PERMISSION_GRANT_STATE_GRANTED || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED || grantState == PERMISSION_GRANT_STATE_DEFAULT). Any other value now throws IllegalArgumentException to the caller before anything is stored. In the diff the check is unconditional at method entry; the commit message says it applies when the coexistence flag is enabled, but no flag condition appears in the added lines.",
      "services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java (re-apply loop over mGlobalPolicies and mLocalPolicies; the hunk header does not show the method name): the global-policy call enforcePolicy(policyDefinition, policyValue, UserHandle.USER_ALL) and the local-policy call enforcePolicy(policyDefinition, policyValue, userId) are each wrapped in try { ... } catch (Exception e) { Slogf.wtf(TAG, \"Failed to reapply policy \" + policy [+ \" for user \" + userId], e); }. A failure for one policy no longer aborts the loop or propagates out of it.",
      "services/tests/servicestests/.../DevicePolicyManagerTest.java: adds testSetPermissionGrantState_coexistence_invalidState_throwsException, which sets a device owner and asserts IllegalArgumentException for grantState 999."
     ],
     "completeness": [
      "Input validation covers only the setPermissionGrantState entry point. It is placed before the caller identity check, so it applies to every caller of this binder method regardless of admin type.",
      "The try/catch is applied only to the two enforcePolicy calls in the re-apply loop (global and local). It catches Exception generally, so it also absorbs exceptions from other policies whose enforcement throws at re-apply time, not only permission grant state.",
      "Other DevicePolicyEngine paths visible in the code context, for example transferPolicies calling setGlobalPolicy/setLocalPolicy, are not wrapped. Whether those methods call enforcePolicy is not shown in the material.",
      "The fix does not remove or repair an invalid value that was persisted before the patch. With the patch, an exception from enforcing that value in the re-apply loop is logged via wtf instead of escaping the loop.",
      "The material does not show the enforcement code that actually throws IllegalArgumentException for an out-of-range grant state."
     ],
     "behavior_changes": [
      "setPermissionGrantState now throws IllegalArgumentException for any grantState outside {GRANTED, DENIED, DEFAULT}, before permission and caller checks run.",
      "During policy re-application, an exception from enforcePolicy for a single policy is caught and logged via Slogf.wtf with the policy key (and the user id for local policies); the remaining policies are still re-applied."
     ],
     "preconditions": [
      "Caller must be an admin permitted to invoke DevicePolicyManagerService.setPermissionGrantState (the commit message cites a BYOD work-profile DPC; the test uses a device owner).",
      "Per the commit message, the issue involves the coexistence path that persists the value to disk and re-applies it at system_server start; the flag/gating logic itself is not shown in the material."
     ],
     "per_major": {
      "14": "same fix: commit 057ff07691a6 in android-security-14.0.0_r29; same three-file change. The DevicePolicyEngine hunks at ~1528/1539 have no shouldSkipEnforcementIfNotChanged() guard around the calls. 8/8 patched lines present at r30.",
      "15": "same fix: commit 49e1a4ba935f in android-security-15.0.0_r17; identical logic, with hunks at ~1799/1812 inside an existing if (!policyDefinition.shouldSkipEnforcementIfNotChanged()) block. 8/8 present at r18.",
      "16": "same fix: commit f4e7001b21fb in android-security-16.0.0_r8; identical to 15, with hunks at ~1818/1831. 8/8 present at r9.",
      "17": "same fix: commit c715c992cad0 in android-security-17.0.0_r1; identical logic, but the local-policy loop iterates a copied Set<Integer> userIds instead of indexing mLocalPolicies. 8/8 present at r2."
     },
     "backport_notes": [
      "Single commit per release (it cites two upstream Cherrypick-From changes, Change-Id I090604a48f409e5109327217f642730258fb720f). The DevicePolicyEngine hunk context differs per release (shouldSkipEnforcementIfNotChanged() guard on 15+, userIds set iteration on 17), so apply the try/catch around whichever enforcePolicy calls exist in the re-apply loop. The DevicePolicyManagerService hunk and the test are textually identical across all four releases."
     ],
     "confidence": "high",
     "unknowns": [
      "Name of the DevicePolicyEngine method containing the patched re-apply loop (the hunk header shows only the class).",
      "Where the IllegalArgumentException is thrown during enforcement of an invalid grant state (enforcement/persistence code not included).",
      "The exact coexistence flag gating referenced in the commit message; the added check itself is unconditional in the diff.",
      "Whether any other binder entry point can persist a permission-grant policy value without going through setPermissionGrantState.",
      "Whether setGlobalPolicy/setLocalPolicy (e.g. via transferPolicies) enforce policies in a way that could still throw unhandled.",
      "Whether the commit depends on other changes."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58841": {
     "cve": "CVE-2026-58841",
     "summary": "VirtualAudioController.startListening now registers mAudioPlaybackDetector unconditionally instead of only when an IAudioConfigChangedCallback is supplied, so per the commit message the deferred silence-injection policy update recovers correctly when no config-changed callback is provided.",
     "component": "platform/frameworks/base, services/companion (virtual device audio, VirtualAudioController)",
     "weakness": "Logic error: a required callback registration was gated on an unrelated optional parameter, causing a security policy (silence injection) update to be skipped",
     "root_cause": "In services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java, startListening() registered both mAudioPlaybackDetector and mAudioRecordingDetector inside `if (configChangedCallback != null)`. When a caller passed a null configChangedCallback, the controller was never registered with the playback detector and so did not receive playback callbacks. Per the commit message, this caused the deferred silence-injection policy update to be skipped and not recover. stopListening() unregisters both detectors unconditionally, so registration and unregistration of the playback detector were asymmetric.",
     "fix_analysis": [
      "services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java:startListening(): the call mAudioPlaybackDetector.register(/* callback= */ this) is moved out of the `if (configChangedCallback != null)` block. It now runs unconditionally, right after mRunningAppUids and mPlayingAppUids are cleared under mLock.",
      "The `if (configChangedCallback != null)` block is kept and now only guards mAudioRecordingDetector.register(/* callback= */ this). The commit message says the recording detector should be registered only when configChangedCallback is provided.",
      "Single-file change (1 insertion, 1 deletion); no other function is changed. stopListening() is unchanged and already unregisters both detectors unconditionally."
     ],
     "completeness": [
      "Covers the only registration site shown: startListening() in VirtualAudioController. The playback detector is now registered regardless of configChangedCallback.",
      "mAudioRecordingDetector.register remains conditional on configChangedCallback != null, as the commit message describes. The material does not show whether recording detection feeds any policy decision.",
      "The material does not show the playback callback handler or the policy update logic, so other possible skip conditions cannot be judged from the diff."
     ],
     "behavior_changes": [
      "Every startListening() call now registers VirtualAudioController as a callback with AudioPlaybackDetector, including when configChangedCallback is null, so it now receives playback callbacks in that case.",
      "No API, error code or timeout changes. stopListening() and the recording detector's registration behavior are unchanged."
     ],
     "preconditions": [
      "VirtualAudioController.startListening() must be called with a null IAudioConfigChangedCallback. The material does not show which callers do this.",
      "The controller must be listening for audio capture and injection on a virtual display (startListening() context). Further setup requirements are not shown."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/base 8ded15ca0499 in android-security-14.0.0_r29, the same one-line move (hunk starts at line 94). Patched region fully present at android-security-14.0.0_r30 (5/5 lines).",
      "15": "same fix: platform/frameworks/base a46c94ad2ccc in android-security-15.0.0_r17, identical diff (hunk starts at line 102). Patched region fully present at android-security-15.0.0_r18 (5/5 lines).",
      "16": "same fix: platform/frameworks/base 3184e06e737a in android-security-16.0.0_r8, identical diff (hunk starts at line 100). Patched region fully present at android-security-16.0.0_r9 (5/5 lines).",
      "17": "same fix: platform/frameworks/base 1412cbcc0c10 in android-security-17.0.0_r1, identical diff (hunk starts at line 102; the class header context line differs slightly). Patched region fully present at android-security-17.0.0_r2 (5/5 lines)."
     },
     "backport_notes": [
      "Single commit that moves one line, with no dependencies. The hunk is identical on 14 through 17 apart from line offsets. Check that stopListening() in the target tree unregisters mAudioPlaybackDetector unconditionally, as in the shown code, so registration stays balanced."
     ],
     "confidence": "high",
     "unknowns": [
      "The playback callback implementation and the deferred silence-injection update logic are not shown. The policy effect of the missed callbacks is known only from the commit message.",
      "The material does not show which callers pass a null IAudioConfigChangedCallback to startListening().",
      "The material does not show whether keeping mAudioRecordingDetector registration conditional has any policy consequence."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58854": {
     "cve": "CVE-2026-58854",
     "summary": "Adds isRemote() (and, where missing, nullptr) validation before static_cast downcasts of caller-supplied ITunerFilter/ITunerDemux/ITunerLnb interface pointers in the mediatuner service, across both the AIDL and HIDL backends, rejecting remote binder proxies with Result::INVALID_ARGUMENT.",
     "component": "platform/frameworks/av, services/tuner (mediatuner daemon, AIDL and HIDL tuner wrappers)",
     "weakness": "Type confusion (unchecked downcast of a binder interface pointer to a local implementation class; CWE-843), with missing null check on two paths",
     "root_cause": "Several mediatuner service methods accept an interface object from the binder caller (shared_ptr<ITunerFilter>, shared_ptr<ITunerDemux>, shared_ptr<ITunerLnb>) and static_cast it to the service-local implementation class (TunerFilter, TunerDemux, TunerLnb, or the TunerHidl* equivalents) to call getHalFilter() or getId(). When the caller passes a remote binder proxy or custom stub, the object is not of the local class, so the cast is invalid and, per the commit message, member reads go out-of-bounds relative to the proxy allocation. Before the fix, TunerDvr::attachFilter/detachFilter, TunerFilter::setDataSource, TunerFrontend::setLnb and their HIDL twins only checked for nullptr; TunerDemux::getAvSyncHwId and TunerDescrambler::setDemuxSource (and HIDL twins) had no check at all; TunerDescrambler::addPid/removePid only handled the nullptr-optional case.",
     "fix_analysis": [
      "Single commit (f8520e699d18 on android-security-14.0.0_r29) covering 10 files; each hunk inserts a guard that returns ::ndk::ScopedAStatus::fromServiceSpecificError(Result::INVALID_ARGUMENT) before the static_cast.",
      "services/tuner/TunerDemux.cpp:TunerDemux::getAvSyncHwId and services/tuner/hidl/TunerHidlDemux.cpp:TunerHidlDemux::getAvSyncHwId: new check `tunerFilter == nullptr || tunerFilter->isRemote()` (no check existed before). TunerHidlDemux.cpp also gains `#include <aidl/android/hardware/tv/tuner/Result.h>` and `using ::aidl::android::hardware::tv::tuner::Result;`.",
      "services/tuner/TunerDescrambler.cpp and services/tuner/hidl/TunerHidlDescrambler.cpp: setDemuxSource gains `in_tunerDemux == nullptr || in_tunerDemux->isRemote()`; addPid and removePid gain `in_optionalSourceFilter != nullptr && in_optionalSourceFilter->isRemote()` so that the optional-null case still passes through as a nullptr halFilter.",
      "services/tuner/TunerDvr.cpp and services/tuner/hidl/TunerHidlDvr.cpp: attachFilter and detachFilter extend the existing `in_filter == nullptr` test to `|| in_filter->isRemote()`.",
      "services/tuner/TunerFilter.cpp and services/tuner/hidl/TunerHidlFilter.cpp: setDataSource extends `filter == nullptr` to `|| filter->isRemote()` (under mLock, before the mShared check).",
      "services/tuner/TunerFrontend.cpp and services/tuner/hidl/TunerHidlFrontend.cpp: setLnb extends `lnb == nullptr` to `|| lnb->isRemote()`.",
      "Rationale: in NDK AIDL, an object implemented in-process reports isRemote() false while a binder object from another process is a proxy reporting isRemote() true (general platform knowledge); the fix uses this to reject proxies before the downcast."
     ],
     "completeness": [
      "Covers the static_cast downcasts of caller-supplied interfaces visible in the diff and context: getAvSyncHwId, setDemuxSource, addPid, removePid, attachFilter, detachFilter, setDataSource, setLnb, in both the AIDL (Tuner*) and HIDL (TunerHidl*) backends.",
      "Also closes a null dereference on TunerDemux::getAvSyncHwId / TunerHidlDemux::getAvSyncHwId and TunerDescrambler::setDemuxSource / TunerHidlDescrambler::setDemuxSource, which previously cast and called a member function without any nullptr check.",
      "The guard only distinguishes local vs remote; it does not verify that a local object is of the specific expected class. The context shows the service creating its local objects via SharedRefBase::make (TunerDemux::openFilter, openTimeFilter, openDvr), but does not show every creation site.",
      "Other methods on the same interfaces that take interface arguments are not shown in the material (e.g. ITunerDemux::setFrontendDataSource(ITunerFrontend) that DemuxClient.cpp calls per index search); the context only shows setFrontendDataSourceById(int), so whether a sibling downcast exists there cannot be judged from the material."
     ],
     "behavior_changes": [
      "Passing a remote ITunerFilter/ITunerDemux/ITunerLnb object to the listed methods now returns service-specific error Result::INVALID_ARGUMENT instead of proceeding.",
      "TunerDemux::getAvSyncHwId and TunerDescrambler::setDemuxSource (AIDL and HIDL) now return Result::INVALID_ARGUMENT for a null argument instead of dereferencing a null pointer.",
      "addPid/removePid keep accepting a null optional source filter; only non-null remote objects are newly rejected.",
      "Legitimate framework clients appear to pass back objects obtained from the service (per index search: Tuner.java -> JNI -> FilterClient, and DemuxClient using getAidlFrontend()), so no regression is expected for them; this is an inference, not tested in the material."
     ],
     "preconditions": [
      "Caller can reach the mediatuner service and obtain an ITunerDemux, ITunerDvr, ITunerFilter, ITunerFrontend or ITunerDescrambler object (commit message states unprivileged apps could reach these methods).",
      "Caller supplies its own binder object (remote proxy or custom stub) as the interface argument to one of the affected methods."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/av f8520e699d18 in android-security-14.0.0_r29, 10 files; 8/8 patched lines present at android-security-14.0.0_r30.",
      "15": "same fix: 7ccb7033d428 in android-security-15.0.0_r17, identical hunks (AIDL file line offsets differ by +2); 8/8 present at android-security-15.0.0_r18.",
      "16": "same fix: 183c2e3a4198 in android-security-16.0.0_r8, identical hunks; 8/8 present at android-security-16.0.0_r9.",
      "17": "same fix: 073ae498a43f in android-security-17.0.0_r1, identical hunks; 8/8 present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Self-contained single commit; all hunks are additive guards. The only non-guard change is in services/tuner/hidl/TunerHidlDemux.cpp, which adds the Result.h include and `using ::aidl::android::hardware::tv::tuner::Result;`.",
      "When porting to a tree with customized tuner wrappers, apply the same isRemote() guard to every place a caller-supplied ITuner* interface is static_cast to a local Tuner*/TunerHidl* class, not just the eight methods listed."
     ],
     "confidence": "high",
     "unknowns": [
      "Whether other interface-argument methods in services/tuner (for example ITunerDemux::setFrontendDataSource(ITunerFrontend) invoked by frameworks/base DemuxClient.cpp per index search) perform a similar downcast; their implementations are not in the material.",
      "Which specific member reads in the proxy allocation were reported in the bug; the commit message only states out-of-bounds reads relative to the proxy allocation.",
      "The exact binder access policy that lets unprivileged apps reach mediatuner is not shown; only asserted by the commit message.",
      "Under which device configurations (tuner HAL presence) mediatuner runs is not shown in the material."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 6,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58856": {
     "cve": "CVE-2026-58856",
     "summary": "Adds a range check on the output slot index, a null check on the slot's GraphicBuffer, and a checked lookup in mBuffers in Camera3StreamSplitter::returnOutputBufferLocked. It also changes the outputSlots local from a copy to a reference.",
     "component": "platform/frameworks/av, cameraserver (libcameraservice device3 Camera3StreamSplitter)",
     "weakness": "Missing bounds check (out-of-bounds read / type confusion) plus missing null and map-membership checks",
     "root_cause": "In services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp, returnOutputBufferLocked() takes an int slot and used it directly as an index into the per-output slot vector (*mOutputSlots[from]) with no range check. The caller shown in the context (lines 678-689) gets this slot from from->dequeueBuffer() on an output IGraphicBufferProducer. The returned sp<GraphicBuffer> was then dereferenced (buffer->getId()) without a null check. Its id was used with mBuffers[...] and the result was dereferenced right away, without checking that the buffer was tracked. Per the commit message the slot index is app-supplied, so an out-of-range value leads to an out-of-bounds read and type confusion in cameraserver. In addition, outputSlots was a by-value copy, so the later outputSlots[slot] = nullptr in the detach path changed only the copy and was never written back to mOutputSlots[from].",
     "fix_analysis": [
      "Camera3StreamSplitter.cpp:Camera3StreamSplitter::returnOutputBufferLocked: 'auto outputSlots = *mOutputSlots[from]' becomes 'auto& outputSlots = *mOutputSlots[from]'. The vector is now used in place, so later writes (outputSlots[slot] = nullptr after a successful detachBuffer) persist.",
      "Same function: a new check 'if (slot < 0 || static_cast<size_t>(slot) >= outputSlots.size())' logs via SP_LOGE and returns before indexing, which removes the out-of-bounds read.",
      "Same function: after 'buffer = outputSlots[slot]', a new 'if (buffer == nullptr)' check logs and returns before buffer->getId() is called.",
      "Same function: 'BufferTracker& tracker = *(mBuffers[buffer->getId()])' is replaced by mBuffers.find(buffer->getId()). If the id is not found, the function logs and returns; otherwise tracker is taken from it->second.",
      "Single commit; the diff changes no header or other file."
     ],
     "completeness": [
      "Covers the three hazards at the start of returnOutputBufferLocked: an out-of-range slot, a null buffer in a valid slot, and a buffer id missing from mBuffers.",
      "The code that follows in the same function (mDetachedBuffers lookup, from->detachBuffer(slot), outputSlots[slot] = nullptr) now runs on a validated slot and buffer, and on the real vector rather than a copy.",
      "Only returnOutputBufferLocked is changed. Other uses of mOutputSlots or mBuffers elsewhere in Camera3StreamSplitter.cpp are not shown in the material and are not touched by this diff.",
      "On Android 16 and 17 the fix is applied only to device3/deprecated/DeprecatedCamera3StreamSplitter.cpp. The material does not show whether a non-deprecated splitter exists there or whether it needs the same change."
     ],
     "behavior_changes": [
      "An out-of-range slot, a null buffer, or an untracked buffer id now causes an early return with an SP_LOGE message instead of a memory access. In those cases the fence merge, the detach and the rest of the processing for that buffer are skipped.",
      "Because outputSlots is now a reference, clearing a slot after a successful detachBuffer persists in mOutputSlots[from]. Before the fix the clear was lost on the copy.",
      "No API, return value or interface change; the function is still void."
     ],
     "preconditions": [
      "A Camera3StreamSplitter with an output surface (IGraphicBufferProducer 'from') whose mOutputSlots[from] entry is non-null. The existing early return for a removed output surface is kept.",
      "The caller shown in the context (lines 678-689) calls from->dequeueBuffer(&slot, ...) and then returnOutputBufferLocked(fence, from, surfaceId, slot). The slot value comes from the output producer, which the commit message says can be app-supplied."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/av d74fdb8ae7d4 (RESTRICT AUTOMERGE) in android-security-14.0.0_r29, services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp. At android-security-14.0.0_r30, 4/6 lines of the patched region match, and the code context shows the fixed code.",
      "15": "same fix: platform/frameworks/av de6bd248af67 (RESTRICT AUTOMERGE) in android-security-15.0.0_r17. Same file and identical hunk at a different line offset (704). At android-security-15.0.0_r18, 4/6 lines of the patched region match.",
      "16": "adapted fix: platform/frameworks/av 6e240fe4061a in android-security-16.0.0_r8, applied to services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp in DeprecatedCamera3StreamSplitter::returnOutputBufferLocked with identical logic. At android-security-16.0.0_r9, 5/6 lines of the patched region match.",
      "17": "adapted fix: platform/frameworks/av db4f7fd08e40 in android-security-17.0.0_r1, same deprecated file and class as Android 16. At android-security-17.0.0_r2, 5/6 lines of the patched region match."
     },
     "backport_notes": [
      "Single self-contained hunk in one .cpp file. Apply the Android 14/15 version to trees where the class is still Camera3StreamSplitter under device3/. Apply the 16/17 version where it has moved to device3/deprecated/DeprecatedCamera3StreamSplitter.cpp. SP_LOGE is already used in the file; check that PRIu64 is available.",
      "The copy-to-reference change for outputSlots is part of the fix (it makes the later outputSlots[slot] = nullptr take effect); keep it when resolving conflicts."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show the declared types of mOutputSlots and mBuffers (for example the map value types), only how they are used, so the exact behavior of mBuffers[] for an untracked id is not shown.",
      "The material does not show whether Android 16/17 contain a non-deprecated Camera3StreamSplitter alongside the deprecated one, or, if they do, whether it has the same pattern.",
      "The exact app-facing path by which an untrusted slot value reaches returnOutputBufferLocked is not shown beyond the commit message statement that the slot index is app-supplied.",
      "Whether returnOutputBufferLocked has callers other than the one shown in the context is not shown."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    }
   }
  },
  "15": {
   "counts": {
    "announced": 15,
    "certain": 14,
    "probable": 0,
    "not_published": 1,
    "not_covered": 0,
    "awaiting": 0
   },
   "advisories": [
    {
     "cve": "CVE-2026-55265",
     "osv_id": "ASB-A-517377150",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "DoS"
     ],
     "status": "announced-not-published",
     "detail": "platform/development,platform/frameworks/base",
     "coverage": {
      "n_ingested_tags": 18,
      "first_ingested_tag": "android-security-15.0.0_r1",
      "latest_ingested_tag": "android-security-15.0.0_r18",
      "window_base_tag": "android-15.0.0_r1",
      "window_start": "2024-09-03",
      "partial_tags": [],
      "projects": [
       {
        "project": "platform/development",
        "fetched_ok_in_tags": 18,
        "ingested_tags": 18,
        "latest_status": "ok"
       },
       {
        "project": "platform/frameworks/base",
        "fetched_ok_in_tags": 18,
        "ingested_tags": 18,
        "latest_status": "ok"
       }
      ]
     },
     "projects": [
      "platform/development",
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-58865",
     "osv_id": "ASB-A-513582756",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Hardens the MMS PDU parser (telephony/common/com/google/android/mms/pdu/PduParser.java). It bounds-checks the well-known content-type index in parseContentType and null-checks the parameter map and the parsed charset string in parseContentTypeParams, so malformed PDUs no longer throw ArrayIndexOutOfBoundsException or NullPointerException there.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained commit. The three PduParser.java hunks are identical on 14, 15, 16 and 17 (on 17 they apply to a different file blob). The new PduParserTest.java belongs to the TelephonyCommonTests module, and its two OOM tests may depend on changes outside this commit, so check that they pass on the target tree."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r18",
      "date": "2026-10-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r18",
      "date": "2026-10-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "51268a5c0ff999b0ed70d1b3feaf00d735de43ee",
       "tag": "android-security-15.0.0_r18",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-28667",
     "osv_id": "ASB-A-508389908",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a response-length check (length < p_i93->block_size) before three rw_i93_send_cmd_write_single_block() calls in rw_t5t.cc, so that a short tag response no longer leads to stale GKI buffer bytes being sent over RF in a WRITE_SINGLE_BLOCK command.",
      "confidence": "high",
      "backport_notes": [
       "This is a single self-contained commit. The only per-branch difference is the file location: src/nfc/tags/rw_t5t.cc in platform/system/nfc for 14/15, and libnfc-nci/src/nfc/tags/rw_t5t.cc in platform/packages/modules/Nfc for 16/17. Each hunk only uses the local `length` and `p_i93` variables already in scope."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 7,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/nfc",
       "sha": "620bfc1582b9f882335cb76e2f1e5d63c0b4523f",
       "tag": "android-security-15.0.0_r17",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/system/nfc"
     ]
    },
    {
     "cve": "CVE-2026-45513",
     "osv_id": "ASB-A-508389591",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a length check in nfc_main_hal_data_cback (src/nfc/nfc/nfc_main.cc). An incoming NFC HAL data packet whose data_len exceeds the capacity of a fixed-size NFC_NCI_POOL_ID GKI pool buffer is now logged and dropped instead of being copied into the pool buffer.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained hunk. On Android 16+ the libnfc-nci sources live in platform/packages/modules/Nfc under libnfc-nci/ (the NFC stack became a mainline module there (general platform knowledge)), while 14/15 use platform/system/nfc. Make sure GKI_get_pool_bufsize is available in the target's gki.h and that liblog is linked for android_errorWriteLog."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 2,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/nfc",
       "sha": "0a716527301ddcdb46c9daa3e20014820a255357",
       "tag": "android-security-15.0.0_r17",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/system/nfc"
     ]
    },
    {
     "cve": "CVE-2026-45516",
     "osv_id": "ASB-A-503542587",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds an unsigned-multiplication wraparound check on per_region_size * item_count in tt_var_load_item_variation_store (src/truetype/ttgxvar.c) before varData->deltaSet is allocated. When the product wraps, the function now returns Array_Too_Large.",
      "confidence": "high",
      "backport_notes": [
       "The patch is self-contained: one local variable plus one check placed just before FT_NEW_ARRAY( varData->deltaSet, per_region_size * item_count ) in tt_var_load_item_variation_store. On a differently structured base, put the same divide-back overflow check in front of whatever expression sizes deltaSet."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/external/freetype",
       "sha": "2e564343a4ce793418027295ee574413507608a2",
       "tag": "android-security-15.0.0_r17",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/external/freetype"
     ]
    },
    {
     "cve": "CVE-2026-49878",
     "osv_id": "ASB-A-511544607",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "RCE"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Replaces two undersized os_zalloc(num_active_scs) allocations with os_calloc(num_active_scs, sizeof(int)) for the int arrays scs_resp[0] and scs_resp[1] in wpas_handle_robust_av_scs_recv_action, so the buffers hold num_active_scs ints rather than num_active_scs bytes.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained commit. The diff content is identical across 14 through 17 and only the hunk line offset differs, so it should apply at an offset to any branch whose robust_av.c has the SCS Response handler with the os_zalloc(num_active_scs) calls. The bulletin also lists 16-qpr2 and 17-next as affected, but the material has no per-major facts for those branches."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/external/wpa_supplicant_8",
       "sha": "d14e657ca1aee27916bc757120d53dcf80131fce",
       "tag": "android-security-15.0.0_r17",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/external/wpa_supplicant_8"
     ]
    },
    {
     "cve": "CVE-2026-49885",
     "osv_id": "ASB-A-508389525",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a check in rw_t4t_set_ber_tlv() that p_t4t->max_update_size is strictly larger than the ODO/DDO data_header before computing data_length = max_update_size - data_header (both realignment branches), and makes the caller rw_t4t_update_file() free the C-APDU GKI buffer when rw_t4t_set_ber_tlv() returns false.",
      "confidence": "medium",
      "backport_notes": [
       "The change is self-contained in rw_t4t.cc: two 5-line guards in rw_t4t_set_ber_tlv() and the wrap around the call in rw_t4t_update_file(). On 16 and 17 the file is libnfc-nci/src/nfc/tags/rw_t4t.cc in packages/modules/Nfc; on 14 and 15 it is src/nfc/tags/rw_t4t.cc in system/nfc. The hunk offsets differ between branches.",
       "If a fork's rw_t4t_update_file() has other return paths after allocating p_c_apdu, check that they also free the buffer. The upstream fix only wraps the rw_t4t_set_ber_tlv() call."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 8,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/nfc",
       "sha": "f01d5b0889f5fa73baa257e82acbcd84badf00e0",
       "tag": "android-security-15.0.0_r17",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/system/nfc"
     ]
    },
    {
     "cve": "CVE-2026-49937",
     "osv_id": "ASB-A-514861024",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "libfmq's MessageQueueBase now rejects reads on kSynchronizedReadWrite queues when the shared read/write pointer distance exceeds the queue size (availableToReadBytes) or when the requested message count exceeds the queue capacity (beginRead), instead of returning a readable-byte count larger than the queue.",
      "confidence": "medium",
      "backport_notes": [
       "Single-header change. The per-branch differences are in how availableToReadBytes reports the error: logError only on 14, errorDetected/errorMessage out-params on 15, mErrorHandler on 16/17. Keep the flavor == kSynchronizedReadWrite condition on both checks. The commit message says the unsync flavor is expected to overflow when readers are slow.",
       "MessageQueueBase is header template code compiled into each user, so consumers must be rebuilt to pick up the checks (general platform knowledge)."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/libfmq",
       "sha": "6d316edf3cc840288f305b6f523e0e389fb19495",
       "tag": "android-security-15.0.0_r17",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/system/libfmq"
     ]
    },
    {
     "cve": "CVE-2026-55266",
     "osv_id": "ASB-A-509980995",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Rewrites the tail of the copied BSD qsort in libufdt's vendor sysdeps so it recurses only on the smaller partition and loops on the larger one, bounding recursion depth to O(log n) instead of O(n) on adversarial input.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained commit with no visible dependencies. The diff content is identical on all four majors; only line offsets differ between 14/15 and 16/17. Forks that still carry the original BSD tail (recurse left, goto right) can apply it directly."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/libufdt",
       "sha": "109d68930129f656822c7acb81f6324525289876",
       "tag": "android-security-15.0.0_r17",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/system/libufdt"
     ]
    },
    {
     "cve": "CVE-2026-55270",
     "osv_id": "ASB-A-517377154",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a `wrappedCallback == null` guard in `dialInternal` of both `GsmCdmaPhone` and `ImsPhone` so that USSD requests (which carry a non-null ResultReceiver) can no longer execute in-call MMI supplementary-service commands when the USSD string matches an in-call MMI code.",
      "confidence": "high",
      "backport_notes": [
       "Single-commit, one-line change per file; where the in-call MMI check is split across feature-flag branches (as in 16) or wrapped by an emergency condition (as in 17), the guard must be applied to every path that can call `handleInCallMmiCommands` from `dialInternal`.",
       "The new tests use `replaceInstance`, `mCT`, `mGsmCdmaCall`, `mRingingCall` and `mImsCT`; adjust if these fixtures differ on the target branch."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 8,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/opt/telephony",
       "sha": "92836c48ba6ac68d8610917eae58cd77fe8deccb",
       "tag": "android-security-15.0.0_r17",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/opt/telephony"
     ]
    },
    {
     "cve": "CVE-2026-58815",
     "osv_id": "ASB-A-514726373",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Changes the metering-region loop bound in the cameraserver DistortionMapper, RotateAndCropMapper and ZoomRatioMapper from `j < entry.count` to `j + 5 <= entry.count`, so a region entry whose element count is not a multiple of 5 no longer causes a heap out-of-bounds read and write past the end of the metadata entry.",
      "confidence": "high",
      "backport_notes": [
       "The fix is a single commit: six one-line loop-condition changes in DistortionMapper.cpp, RotateAndCropMapper.cpp and ZoomRatioMapper.cpp, plus three new tests. On 14 through 17 the same hunks appear with only line-offset differences. libcameraservice is part of the platform cameraserver, not a mainline module (general platform knowledge)."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/av",
       "sha": "ff3f3a6b819469a1fce96560310da9599595ca10",
       "tag": "android-security-15.0.0_r17",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/av"
     ]
    },
    {
     "cve": "CVE-2026-58834",
     "osv_id": "ASB-A-515158597",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds an argument check rejecting any grantState other than GRANTED/DENIED/DEFAULT in DevicePolicyManagerService.setPermissionGrantState, and wraps each enforcePolicy call in DevicePolicyEngine.reapplyAllPoliciesOnBootLocked in a try/catch so an invalid persisted policy no longer crashes system_server at boot.",
      "confidence": "high",
      "backport_notes": [
       "Single commit with two independent hunks plus a test. The service-side checkArgument hunk fits where setPermissionGrantState begins with Objects.requireNonNull(callback). The engine hunk must be fitted to the local shape of reapplyAllPoliciesOnBootLocked: Android 14 lacks the shouldSkipEnforcementIfNotChanged guard, and Android 17 iterates a copied user id set. Ensure Preconditions and Slogf are imported in the respective files."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 2,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "49e1a4ba935f726151e2b3954df23ff5ce29dfeb",
       "tag": "android-security-15.0.0_r17",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-58841",
     "osv_id": "ASB-A-515034370",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Moves the mAudioPlaybackDetector.register(this) call in VirtualAudioController.startListening out of the `if (configChangedCallback != null)` block so the playback detector is always registered, leaving only mAudioRecordingDetector registration conditional on the optional config-changed callback.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained hunk in VirtualAudioController.startListening with no dependencies. The change content is identical on 14 through 17; only line offsets differ. On a fork, verify the file still has the `if (configChangedCallback != null)` block wrapping both register calls and move only the playback register call above it; ensure stopListening still unregisters mAudioPlaybackDetector unconditionally."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 2,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "a46c94ad2ccceaddbd80710f6f3d742f77d20835",
       "tag": "android-security-15.0.0_r17",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-58854",
     "osv_id": "ASB-A-514727559",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds isRemote() checks, and nullptr checks where they were missing, before mediatuner downcasts caller-supplied ITunerFilter/ITunerDemux/ITunerLnb binder objects to its local implementation classes. Remote proxies are rejected with Result::INVALID_ARGUMENT in both the AIDL and HIDL tuner service paths.",
      "confidence": "high",
      "backport_notes": [
       "Single commit. services/tuner/hidl/TunerHidlDemux.cpp needs the added Result include and using-declaration. Check each of the 16 call sites individually, since forks may have restructured the wrappers.",
       "The material does not include a fork comparison, so no per-file fork verdict can be given."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 6,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/av",
       "sha": "7ccb7033d4281a5f6d5364d348f873de0846cfc4",
       "tag": "android-security-15.0.0_r17",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/av"
     ]
    },
    {
     "cve": "CVE-2026-58856",
     "osv_id": "ASB-A-514734206",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a range check on the slot index, a null check on the retrieved GraphicBuffer, and a lookup-before-use on mBuffers in Camera3StreamSplitter::returnOutputBufferLocked, and takes the per-output slot vector by reference instead of by copy.",
      "confidence": "high",
      "backport_notes": [
       "Each branch has a single commit with the same hunk: Camera3StreamSplitter.cpp on 14/15, and device3/deprecated/DeprecatedCamera3StreamSplitter.cpp on 16/17. SP_LOGE is already used in the file. The patch adds a PRIu64 use, so check that the format macro is available in customized forks.",
       "Port the `auto&` change together with the checks. With a by-value copy, the later `outputSlots[slot] = nullptr` is silently lost."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r17",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/av",
       "sha": "de6bd248af67f6406fe1200842e29a6a25d7acd5",
       "tag": "android-security-15.0.0_r17",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/av"
     ]
    }
   ],
   "tags": [
    "android-security-15.0.0_r18"
   ],
   "unannounced": [
    {
     "bug_ids": [
      "517376969"
     ],
     "commits": [
      {
       "project": "platform/frameworks/opt/telephony",
       "sha": "2ce2c3a8f95f0f58bbfdf63b9d2e348cb5864564",
       "subject": "RESTRICT AUTOMERGE: Fix remote DoS in decodeWapPdu (b/517376969)",
       "tag": "android-security-15.0.0_r18",
       "merged": "2026-08-05",
       "markers": [
        "cve_fix",
        "restrict_automerge"
       ]
      }
     ],
     "tags": [
      "android-security-15.0.0_r18"
     ],
     "tag": "android-security-15.0.0_r18"
    }
   ],
   "coverage": {
    "n_ingested_tags": 18,
    "first_ingested_tag": "android-security-15.0.0_r1",
    "latest_ingested_tag": "android-security-15.0.0_r18",
    "window_base_tag": "android-15.0.0_r1",
    "window_start": "2024-09-03",
    "partial_tags": []
   },
   "platform_update_tags": {},
   "briefs": {
    "CVE-2026-58865": {
     "cve": "CVE-2026-58865",
     "summary": "Hardens the MMS PDU parser (telephony/common/com/google/android/mms/pdu/PduParser.java). It bounds-checks the well-known content-type index in parseContentType and null-checks the parameter map and the parsed charset string in parseContentTypeParams, so malformed PDUs no longer throw ArrayIndexOutOfBoundsException or NullPointerException there.",
     "component": "platform/frameworks/base, telephony/common MMS PDU parser (com.google.android.mms.pdu.PduParser)",
     "weakness": "Missing bounds check on a table index decoded from untrusted input, plus missing null checks (unchecked ArrayIndexOutOfBoundsException / NullPointerException on untrusted input)",
     "root_cause": "PduParser trusted values decoded from the PDU byte stream. In parseContentType, the Short-integer branch indexed PduContentTypes.contentTypes directly with the result of parseShortInteger(pduDataStream). Per the fix comment that value is 0-127, but the table only covers indexes 0-82, so an index of 83 or more threw ArrayIndexOutOfBoundsException. In parseContentTypeParams, the P_TYPE/P_CT_MR_TYPE well-known-type branch called map.put without checking that map was non-null. The P_CHARSET Text-String (extension-charset) branch used the result of parseWapString in new String(charsetStr) without a null check, and also called map.put without checking map. The test comment states that the ELEMENT_DESCRIPTOR header path passes a null map.",
     "fix_analysis": [
      "telephony/common/com/google/android/mms/pdu/PduParser.java:parseContentType (hunk at ~line 1620): the Short-integer branch now stores parseShortInteger(pduDataStream) in a local index. It indexes PduContentTypes.contentTypes only when index < PduContentTypes.contentTypes.length; otherwise it falls back to PduContentTypes.contentTypes[0] (\"*/*\") instead of throwing.",
      "telephony/common/com/google/android/mms/pdu/PduParser.java:parseContentTypeParams, case PduPart.P_TYPE / PduPart.P_CT_MR_TYPE (hunk at ~line 1431): the existing index bounds check is kept, and map.put(PduPart.P_TYPE, type) is now wrapped in if (map != null). This matches the null check the Text-String branch at line 1443 already had.",
      "telephony/common/com/google/android/mms/pdu/PduParser.java:parseContentTypeParams, P_CHARSET Text-String (extension-charset) branch (hunk at ~line 1494): the try/catch that calls CharacterSets.getMibEnumValue(new String(charsetStr)) and map.put(PduPart.P_CHARSET, ...) is now guarded by if (charsetStr != null && map != null). A null charset string or a null map is silently skipped.",
      "tests/TelephonyCommonTests/src/com/google/android/mms/pdu/PduParserTest.java: new test class with testParse_invalidContentTypeIndex_doesNotThrowAIOOBE (content-type index 83), testParse_elementDescriptorWithParams_doesNotThrowNPE (ELEMENT_DESCRIPTOR with a P_TYPE parameter and a null map) and testParse_emptyCharset_doesNotThrowNPE (empty P_CHARSET string). It also adds two OOM regression tests (testParse_malformedHugeHeaderLength_doesNotOOM, testPduParserUnderflowOOM) that exercise code this diff does not change."
     ],
     "completeness": [
      "Covers the three crash sites named in the commit message: the unchecked table index in parseContentType, and the two null dereferences (map, charsetStr) in parseContentTypeParams for P_TYPE/P_CT_MR_TYPE and extension-charset P_CHARSET.",
      "The parseContentTypeParams P_TYPE well-known branch already had an index bounds check before this fix; only the null-map check was added there.",
      "The material does not show the Well-known-charset else branch of P_CHARSET or the other parameter cases of parseContentTypeParams (e.g. P_START and the remaining cases after line 1461). Whether they also dereference map without a null check cannot be judged from the code provided.",
      "Out-of-range content-type indexes in parseContentType are mapped to \"*/*\" rather than rejected, so the PDU keeps parsing instead of being treated as malformed.",
      "No PduParser.java change in this commit backs the two OOM-related tests added in PduParserTest. The material does not show whether the behavior they assert relies on earlier commits."
     ],
     "behavior_changes": [
      "parseContentType: a well-known content-type Short-integer index >= PduContentTypes.contentTypes.length now yields the default content type \"*/*\" (contentTypes[0]) instead of throwing ArrayIndexOutOfBoundsException.",
      "parseContentTypeParams: a P_TYPE/P_CT_MR_TYPE well-known type encountered while map is null is now ignored instead of throwing NullPointerException.",
      "parseContentTypeParams: an extension-charset P_CHARSET whose parsed string is null, or one encountered while map is null, is now ignored (no P_CHARSET entry, no log) instead of throwing NullPointerException."
     ],
     "preconditions": [
      "A malformed MMS PDU byte array reaches PduParser.parse() (constructed via PduParser(byte[], boolean), as in the tests).",
      "For the AIOOBE: a Content-Type header encoded as a Short-integer whose index is 83 or higher (the test uses 0xD3, index 83).",
      "For the NPEs: a Content-Type value with parameters where P_TYPE is parsed while the map argument is null (test comment: the ELEMENT_DESCRIPTOR header passes a null map), or a P_CHARSET parameter given as an empty text string.",
      "The material does not show which processes feed received MMS data into PduParser."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/base 53f75b4de647 in android-security-14.0.0_r30. The diff is byte-identical to Android 15 (same blob ids 6b3135945e53..775ef505ac2b); 8/8 patched lines present.",
      "15": "same fix: platform/frameworks/base 51268a5c0ff9 in android-security-15.0.0_r18 (cherry-pick of cbb0d81bf086, Change-Id I4fab1579d22c4a1dcf2d75d4f4aab0a352df1bd9); 8/8 patched lines present.",
      "16": "same fix: platform/frameworks/base 60f9d9a0bcac in android-security-16.0.0_r9. The diff is byte-identical to Android 15 (same blob ids); 8/8 patched lines present.",
      "17": "same fix: platform/frameworks/base 05fef2f15699 in android-security-17.0.0_r2. Identical hunks were applied to a different PduParser.java base (blob e805089306dc..d2f23026e5d8); 8/8 patched lines present."
     },
     "backport_notes": [
      "Single self-contained commit. The three PduParser.java hunks are identical on 14, 15, 16 and 17 (on 17 they apply to a different file blob). The new PduParserTest.java belongs to the TelephonyCommonTests module, and its two OOM tests may depend on changes outside this commit, so check that they pass on the target tree."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact production callers of PduParser (which process parses incoming MMS PDUs) are not shown in the material.",
      "Whether an uncaught AIOOBE/NPE from PduParser would crash the calling process depends on caller exception handling, which is not shown.",
      "What parseWapString returns for an empty string is not shown.",
      "Whether other parameter cases in parseContentTypeParams, or the Well-known-charset branch, also dereference a null map is not visible in the provided context.",
      "The material does not explain why the bulletin rates this DoS as Critical.",
      "Whether the OOM behaviors asserted by testParse_malformedHugeHeaderLength_doesNotOOM and testPduParserUnderflowOOM were fixed by earlier commits is not shown."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-28667": {
     "cve": "CVE-2026-28667",
     "summary": "Adds a response-length check (length < p_i93->block_size) before three rw_i93_send_cmd_write_single_block() calls in rw_t5t.cc, so that a short tag response no longer leads to stale GKI buffer bytes being sent over RF in a WRITE_SINGLE_BLOCK command.",
     "component": "platform/system/nfc (Android 14/15) and platform/packages/modules/Nfc libnfc-nci (Android 16/17), NFC Type 5 tag reader/writer state machine, rw_t5t.cc",
     "weakness": "Missing bounds check on the received response length, leading to information disclosure (stale GKI buffer slack beyond the valid response data sent over RF)",
     "root_cause": "In rw_t5t_sm_update_ndef() and rw_t5t_sm_set_read_only(), the code takes the response buffer (pointer p, length `length`), modifies it in place, and passes p to rw_i93_send_cmd_write_single_block() to build an outgoing WRITE_SINGLE_BLOCK command. Nothing checked that the response held at least block_size bytes. According to the commit message, stale GKI buffer slack could therefore be copied into the outgoing command. The commit says it ports missing bounds checks from b/143109193, b/143155861 and b/143106535 to rw_t5t.cc.",
     "fix_analysis": [
      "src/nfc/tags/rw_t5t.cc:rw_t5t_sm_update_ndef (first site, after block_number = (p_i93->ndef_tlv_start_offset + 1) / p_i93->block_size): before calling rw_i93_send_cmd_write_single_block(block_number, p), the fix checks `if (length < p_i93->block_size)`. If true, it logs android_errorWriteLog(0x534e4554, \"508389908\") and calls rw_i93_handle_error(NFC_STATUS_FAILED) instead of sending. Otherwise the original send and else-error logic is unchanged.",
      "src/nfc/tags/rw_t5t.cc:rw_t5t_sm_update_ndef (second site, after block_number = (p_i93->rw_offset / p_i93->block_size)): the same guard is added before rw_i93_send_cmd_write_single_block(block_number, p).",
      "src/nfc/tags/rw_t5t.cc:rw_t5t_sm_set_read_only (after `*(p + 1) |= I93_ICODE_CC_READ_ONLY`): the same guard is added before rw_i93_send_cmd_write_single_block(0, p).",
      "At all three sites the command is now sent only when length >= block_size."
     ],
     "completeness": [
      "The three rw_i93_send_cmd_write_single_block() call sites in rw_t5t.cc shown in the diff are all guarded. The diff touches no other file.",
      "The guard comes after the in-place changes to p (the TLV fill loop at lines 557-569 and the `*(p + 1) |=` CC update), so those writes still happen on a short response. Only the transmission is blocked. The existing check at line 558 (`xx > length`) did not catch a response of exactly block_size - 1 bytes, and it does not run when ndef_length == 0. The new check covers both cases.",
      "The material does not show whether `length` excludes the ISO 15693 flags byte, or how many bytes rw_i93_send_cmd_write_single_block copies. So it cannot be confirmed that the comparison lines up exactly with the copy.",
      "Any other command-building paths in rw_t5t.cc that copy from a response buffer are not shown and not modified."
     ],
     "behavior_changes": [
      "When a Type 5 tag returns a response shorter than block_size during an NDEF update or a set-read-only operation, the operation now fails via rw_i93_handle_error(NFC_STATUS_FAILED) instead of sending a WRITE_SINGLE_BLOCK command.",
      "In that case the fix also logs android_errorWriteLog(0x534e4554, \"508389908\")."
     ],
     "preconditions": [
      "The device is in NFC reader/writer mode with a Type 5 (T5T) tag and is running an NDEF write (rw_t5t_sm_update_ndef) or a set-read-only operation (rw_t5t_sm_set_read_only).",
      "The tag (or a device acting as one) returns a response payload shorter than p_i93->block_size.",
      "The bulletin classes this as information disclosure (ID) with High severity."
     ],
     "per_major": {
      "14": "same fix: platform/system/nfc f3a70c2a9415 in android-security-14.0.0_r29. The three-site guard in src/nfc/tags/rw_t5t.cc is identical, at different line offsets. 8/8 lines present at android-security-14.0.0_r30.",
      "15": "same fix: platform/system/nfc 620bfc1582b9 in android-security-15.0.0_r17 (cherry-pick, Change-Id I9aed2f8392a27bdc095a54b0f8005208305032b3). 8/8 lines present at android-security-15.0.0_r18.",
      "16": "same fix: platform/packages/modules/Nfc 144b34ba8906 in android-security-16.0.0_r8, file libnfc-nci/src/nfc/tags/rw_t5t.cc. 8/8 lines present at android-security-16.0.0_r9.",
      "17": "same fix: platform/packages/modules/Nfc 2ad8845ad77e in android-security-17.0.0_r1, file libnfc-nci/src/nfc/tags/rw_t5t.cc. 8/8 lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "This is a single self-contained commit. The only per-branch difference is the file location: src/nfc/tags/rw_t5t.cc in platform/system/nfc for 14/15, and libnfc-nci/src/nfc/tags/rw_t5t.cc in platform/packages/modules/Nfc for 16/17. Each hunk only uses the local `length` and `p_i93` variables already in scope."
     ],
     "confidence": "high",
     "unknowns": [
      "How `length` is derived from p_resp in these functions (for example, whether the flags byte is already stripped).",
      "How many bytes rw_i93_send_cmd_write_single_block copies from p.",
      "The sub_state of the second rw_t5t_sm_update_ndef hunk (around line 752), which is not in the provided context.",
      "Whether rw_t5t.cc has other response-to-command copy paths beyond the three patched sites.",
      "Where the earlier checks from b/143109193, b/143155861 and b/143106535 live."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 7,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-45513": {
     "cve": "CVE-2026-45513",
     "summary": "Adds a length check in nfc_main_hal_data_cback (src/nfc/nfc/nfc_main.cc). An incoming NFC HAL data packet whose data_len exceeds the capacity of a fixed-size NFC_NCI_POOL_ID GKI pool buffer is now logged and dropped instead of being copied into the pool buffer.",
     "component": "platform/system/nfc (Android 14/15) and platform/packages/modules/Nfc libnfc-nci (Android 16/17), NCI transport receive path (nfc_main.cc)",
     "weakness": "Missing bounds check leading to heap/pool buffer overflow (data copied into a fixed-size GKI pool buffer without checking the incoming length)",
     "root_cause": "In nfc_main_hal_data_cback, when the build uses the fixed-size pool path (the #else branch), the receive buffer comes from GKI_getpoolbuf(NFC_NCI_POOL_ID). Its size is fixed by the pool, not sized from data_len as in the GKI_getbuf branch. The HAL-supplied data_len was never compared against the pool buffer capacity (pool bufsize minus sizeof(NFC_HDR) and NFC_RECEIVE_MSGS_OFFSET), so an oversized HAL packet could be written past the end of the pool buffer. The commit message describes this as a potential buffer overflow on oversized HAL packets.",
     "fix_analysis": [
      "src/nfc/nfc/nfc_main.cc:nfc_main_hal_data_cback (#else branch, before GKI_getpoolbuf): computes uint16_t max_len = GKI_get_pool_bufsize(NFC_NCI_POOL_ID) - sizeof(NFC_HDR) - NFC_RECEIVE_MSGS_OFFSET. This is the payload capacity left in one NFC_NCI_POOL_ID buffer after the header and receive offset.",
      "If data_len > max_len, it emits LOG(ERROR) with the sizes, records a SafetyNet event via android_errorWriteLog(0x534e4554, \"508389591\") and returns early. No pool buffer is allocated and nothing is copied.",
      "Adds #include <log/log.h> for android_errorWriteLog. The commit message names the function nfc_main_hal_read_cback, but the function actually patched in the diff is nfc_main_hal_data_cback."
     ],
     "completeness": [
      "The check is only added to the #else branch that uses GKI_getpoolbuf(NFC_NCI_POOL_ID). The other branch, which calls GKI_getbuf(sizeof(NFC_HDR) + NFC_RECEIVE_MSGS_OFFSET + data_len), already sizes the allocation from data_len and is left unchanged.",
      "The check runs before allocation, so the copy that follows under `if (p_msg != nullptr)` (not shown in the material) is only reached with data_len <= max_len.",
      "max_len is computed in uint16_t. The fix assumes GKI_get_pool_bufsize(NFC_NCI_POOL_ID) is larger than sizeof(NFC_HDR) + NFC_RECEIVE_MSGS_OFFSET; otherwise the subtraction would wrap. The material does not show the pool size.",
      "No other HAL callback or receive path is modified by this commit (single file, 10 insertions)."
     ],
     "behavior_changes": [
      "HAL data packets longer than the NFC_NCI_POOL_ID buffer payload capacity are now dropped (not delivered to the NCI stack), with a LOG(ERROR) line.",
      "A SafetyNet/android_errorWriteLog event tagged 0x534e4554 with bug id 508389591 is written when a drop occurs.",
      "New dependency on <log/log.h> (liblog) in nfc_main.cc."
     ],
     "preconditions": [
      "The libnfc-nci build must use the fixed-size pool path (the #else branch calling GKI_getpoolbuf(NFC_NCI_POOL_ID)) rather than the GKI_getbuf branch. The macro that selects the branch is not shown in the material.",
      "A HAL data callback must deliver a packet with data_len larger than the pool buffer payload capacity to nfc_main_hal_data_cback. The data comes from the NFC HAL / NFC controller side.",
      "The bulletin rates it High severity EoP. The material gives no further trigger detail."
     ],
     "per_major": {
      "14": "same fix: platform/system/nfc 1dfa112088a9 in android-security-14.0.0_r29, identical check in src/nfc/nfc/nfc_main.cc. Only the include hunk context differs: <log/log.h> is placed after <base/logging.h>. 7/7 patched lines present at android-security-14.0.0_r30.",
      "15": "same fix: platform/system/nfc 0a716527301d in android-security-15.0.0_r17 (cherry-pick of internal cdcf610905cb). 8/8 patched lines present at android-security-15.0.0_r18.",
      "16": "same fix, different project/path: platform/packages/modules/Nfc 2db7814d87ba in android-security-16.0.0_r8, file libnfc-nci/src/nfc/nfc/nfc_main.cc. 8/8 lines present at android-security-16.0.0_r9.",
      "17": "same fix, different project/path: platform/packages/modules/Nfc 79b15334596b in android-security-17.0.0_r1, file libnfc-nci/src/nfc/nfc/nfc_main.cc. 8/8 lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Single self-contained hunk. On Android 16+ the libnfc-nci sources live in platform/packages/modules/Nfc under libnfc-nci/ (the NFC stack became a mainline module there (general platform knowledge)), while 14/15 use platform/system/nfc. Make sure GKI_get_pool_bufsize is available in the target's gki.h and that liblog is linked for android_errorWriteLog."
     ],
     "confidence": "high",
     "unknowns": [
      "The code after allocation (the memcpy of p_data into p_msg) and the name of the macro that selects the GKI_getbuf or GKI_getpoolbuf branch are not shown in the material.",
      "The actual NFC_NCI_POOL_ID buffer size and the NFC_RECEIVE_MSGS_OFFSET value are not shown, so whether the uint16_t max_len subtraction can wrap is not shown either.",
      "The bulletin does not describe how an attacker reaches the HAL data callback with an oversized packet."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 2,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-45516": {
     "cve": "CVE-2026-45516",
     "summary": "Adds an unsigned-multiplication wraparound check on per_region_size * item_count in tt_var_load_item_variation_store (src/truetype/ttgxvar.c) before varData->deltaSet is allocated. When the product wraps, the function now returns Array_Too_Large.",
     "component": "platform/external/freetype, TrueType GX/OpenType variation parsing (src/truetype/ttgxvar.c)",
     "weakness": "Integer overflow in an allocation size computation, so the allocation can be too small (bulletin type ID)",
     "root_cause": "In tt_var_load_item_variation_store, the size of each varData delta set array was computed as per_region_size * item_count in FT_UInt arithmetic with no overflow check. item_count, word_delta_count and region_idx_count are read from the font with FT_READ_USHORT. per_region_size is doubled when long_words is set. The product could wrap, and the wrapped value went straight to FT_NEW_ARRAY( varData->deltaSet, ... ), giving an allocation smaller than per_region_size * item_count.",
     "fix_analysis": [
      "src/truetype/ttgxvar.c:tt_var_load_item_variation_store: adds a new local FT_UInt delta_set_size and computes delta_set_size = per_region_size * item_count. If per_region_size is non-zero and delta_set_size / per_region_size != item_count (meaning the multiplication wrapped), the function emits an FT_TRACE2 message, sets error = FT_THROW( Array_Too_Large ) and jumps to Exit.",
      "The FT_NEW_ARRAY( varData->deltaSet, ... ) call that follows now uses the checked delta_set_size instead of computing the product inline. The FT_Stream_Read after it does not appear in the diff.",
      "The fix is a single commit, with the same hunk on Android 15, 16 and 17. No other function is touched."
     ],
     "completeness": [
      "The fix covers exactly one multiplication: per_region_size * item_count for varData->deltaSet in tt_var_load_item_variation_store. The guard skips the per_region_size == 0 case, where the product is 0 and cannot wrap.",
      "Other code in the same function shown in the context, such as FT_NEW_ARRAY( itemStore->varData, data_count ) and the varRegionList axisList parsing, is not changed by this commit. The material does not show whether any similar multiplications exist there.",
      "The fix only rejects the font. It does not change how deltaSet is used afterwards.",
      "No regression test is included (Test: locally built)."
     ],
     "behavior_changes": [
      "Fonts whose item variation store has a per_region_size * item_count that wraps FT_UInt now fail with Array_Too_Large. Before the fix, the wrapped size was passed to the allocation.",
      "New FT_TRACE2 diagnostic: 'tt_var_load_item_variation_store: bad delta set array size'."
     ],
     "preconditions": [
      "FreeType's TrueType driver parses a crafted TrueType/OpenType font that contains an item variation store, and the values reaching tt_var_load_item_variation_store make per_region_size * item_count wrap FT_UInt.",
      "Per index search, Android 15 code outside FreeType that calls into it includes frameworks/rs/rsFont.cpp (Font::init calls FT_New_Memory_Face / FT_New_Face) and an hwui unit test that uses android::FreeTypeFontMgr. The material does not show which entry points reach item variation store loading."
     ],
     "per_major": {
      "14": "Not affected per the bulletin (not listed). At android-security-14.0.0_r30 only 2/8 lines of the patched region are present, so the fix is not applied there. The material does not show whether the vulnerable multiplication exists in that FreeType version.",
      "15": "Same fix: commit 2e564343a4ce in android-security-15.0.0_r17, cherry-picked from internal change 68c9652af5e4 (Change-Id I44bdd6333551b1452f540a120fe29d5b9361823a). Hunks at lines 625/682. 7/8 lines present at android-security-15.0.0_r18.",
      "16": "Same fix: commit 285b264bf272 in android-security-16.0.0_r8. The diff and blob hashes (ad4f266b2..7fa8256d4) are identical to the Android 15 change. 7/8 lines present at android-security-16.0.0_r9.",
      "17": "Same fix: commit 333924d9d5ea in android-security-17.0.0_r1. The hunk content is identical but applies to a newer ttgxvar.c base (blob ef4ca0933..47076d945), with hunks at lines 628/697 instead of 625/682. 7/8 lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "The patch is self-contained: one local variable plus one check placed just before FT_NEW_ARRAY( varData->deltaSet, per_region_size * item_count ) in tt_var_load_item_variation_store. On a differently structured base, put the same divide-back overflow check in front of whatever expression sizes deltaSet."
     ],
     "confidence": "high",
     "unknowns": [
      "How per_region_size is computed from region_idx_count and word_delta_count (lines 655-682 are not shown), so the exact overflow bound is not visible.",
      "How deltaSet is used after the allocation, and which code would access memory out of bounds, is not shown.",
      "Which Android font-loading paths actually reach item variation store parsing with untrusted fonts.",
      "Whether the Android 14 FreeType version contains the same unchecked multiplication."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-49878": {
     "cve": "CVE-2026-49878",
     "summary": "Replaces two undersized os_zalloc(num_active_scs) allocations with os_calloc(num_active_scs, sizeof(int)) for the int arrays scs_resp[0] and scs_resp[1] in wpas_handle_robust_av_scs_recv_action, so the buffers hold num_active_scs ints rather than num_active_scs bytes.",
     "component": "platform/external/wpa_supplicant_8, wpa_supplicant Robust AV / SCS (Stream Classification Service) Response action frame handling (wpa_supplicant/robust_av.c)",
     "weakness": "Incorrect allocation size (byte count used where element count * sizeof(int) was needed) leading to heap out-of-bounds write",
     "root_cause": "In wpa_supplicant/robust_av.c, wpas_handle_robust_av_scs_recv_action processes a received SCS Response action frame. It first validates the dialog token, then the Count field (count != 0 and count * 3 <= len), then checks that num_active_scs = dl_list_len(&wpa_s->active_scs_ids) is not smaller than count. After that it allocated scs_resp[0] and scs_resp[1] with os_zalloc(num_active_scs). os_zalloc takes a byte size, but these buffers are used as int arrays (cast to int *), so each buffer was sizeof(int) times too small. Per the commit message, this led to heap out-of-bounds writes.",
     "fix_analysis": [
      "wpa_supplicant/robust_av.c:wpas_handle_robust_av_scs_recv_action: scs_resp[0] = (int *) os_zalloc(num_active_scs) is replaced by scs_resp[0] = os_calloc(num_active_scs, sizeof(int)), which allocates zeroed space for num_active_scs ints.",
      "wpa_supplicant/robust_av.c:wpas_handle_robust_av_scs_recv_action: the same change is applied to scs_resp[1]. The existing NULL checks and the os_free(scs_resp[0]) on second-allocation failure are unchanged.",
      "Single commit with a two-line change. No new validation of frame contents is added. The loop runs for i < count, and count <= num_active_scs is already checked, so only the allocation size was wrong."
     ],
     "completeness": [
      "The fix corrects the size of both scs_resp arrays, which are the only allocations changed. The existing checks (count * 3 <= len, num_active_scs >= count) are kept, so indexing up to num_active_scs ints is now within the allocation.",
      "The material does not show the rest of the function body (the code that fills scs_resp, after line 840). So the diff alone cannot confirm whether any other index into these arrays could exceed num_active_scs. The commit message attributes the OOB write solely to the allocation size.",
      "The provided context shows no other os_zalloc call sized by an element count, and no sibling path is shown as affected."
     ],
     "behavior_changes": [
      "None observable: the only change is a larger, correctly sized zeroed heap allocation per received SCS Response frame. Error handling and logging are unchanged."
     ],
     "preconditions": [
      "wpa_supplicant must receive a Robust AV SCS Response action frame handled by wpas_handle_robust_av_scs_recv_action.",
      "The frame's dialog token must equal wpa_s->scs_dialog_token.",
      "The Count field must be non-zero, count * 3 must not exceed the remaining frame length, and count must not exceed dl_list_len(&wpa_s->active_scs_ids).",
      "Per the commit message, the out-of-bounds writes come from treating the num_active_scs-byte buffers as int arrays."
     ],
     "per_major": {
      "14": "same fix: commit 5de2705a451f in android-security-14.0.0_r29, identical two-line diff at hunk offset @@ -640. At android-security-14.0.0_r30, 5 of the 7 lines of the patched region are present.",
      "15": "same fix: commit d14e657ca1ae in android-security-15.0.0_r17, identical diff at hunk offset @@ -807. The code context at android-security-15.0.0_r18 shows os_calloc(num_active_scs, sizeof(int)) for both buffers.",
      "16": "same fix: commit d131540379d6 in android-security-16.0.0_r8, identical diff at hunk offset @@ -881. At android-security-16.0.0_r9, 5 of the 7 lines of the patched region are present.",
      "17": "same fix: commit ffd3987bbece in android-security-17.0.0_r1, identical diff at hunk offset @@ -1072. At android-security-17.0.0_r2, 5 of the 7 lines of the patched region are present."
     },
     "backport_notes": [
      "Single self-contained commit. The diff content is identical across 14 through 17 and only the hunk line offset differs, so it should apply at an offset to any branch whose robust_av.c has the SCS Response handler with the os_zalloc(num_active_scs) calls. The bulletin also lists 16-qpr2 and 17-next as affected, but the material has no per-major facts for those branches."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not include the loop body that writes into scs_resp[0] / scs_resp[1] (after line 840), so the exact indices written and the exact overflow condition are not shown.",
      "How wpa_s->scs_dialog_token and active_scs_ids get populated (for example, by an earlier SCS Request) is not shown.",
      "Whether 16-qpr2, 17-next or vendor branches carry the fix is not shown.",
      "The upstream hostap status of this change is not shown in the material."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-49885": {
     "cve": "CVE-2026-49885",
     "summary": "Adds a check in rw_t4t_set_ber_tlv() that p_t4t->max_update_size is strictly larger than the ODO/DDO data_header before computing data_length = max_update_size - data_header (both realignment branches), and makes the caller rw_t4t_update_file() free the C-APDU GKI buffer when rw_t4t_set_ber_tlv() returns false.",
     "component": "platform/system/nfc (Android 14/15) and platform/packages/modules/Nfc libnfc-nci (Android 16/17), NFC Type 4 Tag reader/writer (rw_t4t.cc)",
     "weakness": "Missing bounds check leading to integer underflow in a length calculation (plus a GKI buffer leak on the error path)",
     "root_cause": "In rw_t4t_set_ber_tlv() (src/nfc/tags/rw_t4t.cc), when the requested write length exceeds p_t4t->max_update_size, the code realigns to max_update_size and computes data_length = p_t4t->max_update_size - data_header, where data_header = RW_T4T_ODO_DDO_HEADER_MIN_LENGTH + length_size. max_update_size was not checked against data_header, so per the commit message a value too small for the ODO/DDO header could underflow data_length. This subtraction appears in two branches (length == 0 and length != 0), and neither was guarded. Separately, the caller rw_t4t_update_file() returned the result of rw_t4t_set_ber_tlv() directly, so a false return left the allocated p_c_apdu GKI buffer unfreed.",
     "fix_analysis": [
      "src/nfc/tags/rw_t4t.cc:rw_t4t_set_ber_tlv(): in the length == 0 branch, after length = p_t4t->max_update_size, adds `if (p_t4t->max_update_size <= data_header)`, which logs an error and returns false before data_length = max_update_size - data_header.",
      "src/nfc/tags/rw_t4t.cc:rw_t4t_set_ber_tlv(): adds the same check in the length != 0 branch before its identical subtraction, so both realignment sites are guarded.",
      "src/nfc/tags/rw_t4t.cc:rw_t4t_update_file(): replaces `return rw_t4t_set_ber_tlv(p_c_apdu, p, length);` with a check that calls GKI_freebuf(p_c_apdu) and returns false on failure, and returns true otherwise. This covers the new error returns and any other false return from rw_t4t_set_ber_tlv().",
      "Single commit per branch. The changed lines are the same on all branches (same subject line; Change-Id I79c95f0817b4a693246e3d5327d399f117068c67 shown for the Android 15 commit)."
     ],
     "completeness": [
      "Both `max_update_size - data_header` subtraction sites in rw_t4t_set_ber_tlv() are guarded. The other two branches (data_length = T4T_MAX_LENGTH_LC - data_header, and length += data_header) do not subtract max_update_size and are unchanged.",
      "The check uses `<=`, so a max_update_size exactly equal to data_header (zero payload) is also rejected, not only the underflow case.",
      "The GKI_freebuf() in rw_t4t_update_file() applies to every false return from rw_t4t_set_ber_tlv(), not only the newly added ones.",
      "The check is local to the BER-TLV ODO/DDO write path. The material does not show whether other users of max_update_size need a similar guard."
     ],
     "behavior_changes": [
      "An NDEF write that goes through the ODO/DDO (BER-TLV) path, where max_update_size is less than or equal to the ODO/DDO header size, now fails with an ERROR log (\"max_update_size too small for ODO/DDO header\") and rw_t4t_update_file() returns false.",
      "On that failure path the C-APDU buffer is now released with GKI_freebuf()."
     ],
     "preconditions": [
      "Device is writing an NDEF message to a Type 4 tag. Per the context in rw_t4t_update_file(), the BER-TLV path is reached when Mapping Version 3.0 is detected and the NDEF message size exceeds 0x7FFF.",
      "p_t4t->max_update_size is smaller than the requested length and less than or equal to RW_T4T_ODO_DDO_HEADER_MIN_LENGTH + length_size.",
      "The bulletin rates this High / EoP. The material does not show how the underflowed data_length is used downstream."
     ],
     "per_major": {
      "14": "same fix: platform/system/nfc 90576eadff36 in android-security-14.0.0_r29, src/nfc/tags/rw_t4t.cc. The changed lines are identical (only the surrounding log macro differs, DLOG_IF vs LOG(VERBOSE)). 8/8 lines present at r30.",
      "15": "same fix: platform/system/nfc f01d5b0889f5 in android-security-15.0.0_r17, src/nfc/tags/rw_t4t.cc. 8/8 lines present at r18.",
      "16": "same fix, different path: platform/packages/modules/Nfc 9c0ae67d8733 in android-security-16.0.0_r8, libnfc-nci/src/nfc/tags/rw_t4t.cc. 8/8 lines present at r9.",
      "17": "same fix, different path: platform/packages/modules/Nfc 0dc8fad01628 in android-security-17.0.0_r1, libnfc-nci/src/nfc/tags/rw_t4t.cc. 8/8 lines present at r2."
     },
     "backport_notes": [
      "The change is self-contained in rw_t4t.cc: two 5-line guards in rw_t4t_set_ber_tlv() and the wrap around the call in rw_t4t_update_file(). On 16 and 17 the file is libnfc-nci/src/nfc/tags/rw_t4t.cc in packages/modules/Nfc; on 14 and 15 it is src/nfc/tags/rw_t4t.cc in system/nfc. The hunk offsets differ between branches.",
      "If a fork's rw_t4t_update_file() has other return paths after allocating p_c_apdu, check that they also free the buffer. The upstream fix only wraps the rw_t4t_set_ber_tlv() call."
     ],
     "confidence": "medium",
     "unknowns": [
      "How data_length is used after the subtraction and what type it has are not shown, so the concrete memory-safety consequence of the underflow is inferred only from the commit message.",
      "Where max_update_size (MLc) is set and whether it is validated when it is parsed from the tag.",
      "Whether rw_t4t_set_ber_tlv() had other false-returning paths before this change (the caller fix would cover them regardless).",
      "The two referenced bugs (498891727, 508389525) and which one corresponds to the leak and which to the underflow."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 8,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-49937": {
     "cve": "CVE-2026-49937",
     "summary": "libfmq's MessageQueueBase now rejects reads on kSynchronizedReadWrite queues when the shared read/write pointer distance exceeds the queue size (availableToReadBytes) or when the requested message count exceeds the queue capacity (beginRead), instead of returning a readable-byte count larger than the queue.",
     "component": "platform/system/libfmq, include/fmq/MessageQueueBase.h (Fast Message Queue read path)",
     "weakness": "Missing bounds check / improper validation of shared read-write pointers and read request size (bulletin type ID)",
     "root_cause": "availableToReadBytes() loaded mWritePtr and mReadPtr and only rejected the case writePtr < readPtr. Any larger difference was returned as-is as the number of readable bytes, even when it exceeded mDesc->getSize(), the size of the queue. beginRead() also had no check that nMessages fit within getQuantumCount(). For the kSynchronizedReadWrite flavor, where readable data should be bounded by the queue size, a corrupted pointer pair or an oversized request was therefore not rejected on the read path. The material does not show the downstream effect, but a read past the queue buffer is the likely consequence, consistent with the ID classification. The commit reapplies an earlier change (reverted by 11165074cdd9). Its message says the beginRead() check was fixed to apply only to kSynchronizedReadWrite, because the unsync flavor is expected to overflow when readers lag the writer.",
     "fix_analysis": [
      "include/fmq/MessageQueueBase.h:availableToReadBytes(): computes queueSizeBytes = mDesc->getSize() and availableBytes = (writePtr >= readPtr) ? writePtr - readPtr : SIZE_MAX. The corruption branch now triggers on writePtr < readPtr OR (flavor == kSynchronizedReadWrite && availableBytes > queueSizeBytes). On that branch it logs an error (the message now includes the queue size), reports Error::POINTER_CORRUPTION via errorDetected/errorMessage (Android 15 signature) and returns 0. Otherwise it returns availableBytes.",
      "include/fmq/MessageQueueBase.h:beginRead(): new early check before building the MemTransaction. If flavor == kSynchronizedReadWrite && nMessages > getQuantumCount(), it logs the error, emits hardware::details::errorWriteLog(0x534e4554, \"514861024\") and returns false. read() therefore fails for requests larger than the queue capacity, whatever the pointer values.",
      "Both new checks are gated on flavor == kSynchronizedReadWrite. Per the commit message, gating the beginRead() check this way is what changed compared with the reverted version, so the unsynchronized flavor keeps its expected overflow behavior."
     ],
     "completeness": [
      "Covers the read side (availableToReadBytes and beginRead) for kSynchronizedReadWrite queues. A pointer distance larger than the queue size and a request larger than the queue capacity are both rejected.",
      "The new size checks are intentionally not applied to the unsynchronized flavor. For that flavor, availableToReadBytes still returns any writePtr - readPtr value (only writePtr < readPtr is rejected), and beginRead relies on its existing overwrite-detection logic, which is not shown in the diff.",
      "This commit does not touch the write-side counterparts (availableToWriteBytes/beginWrite). The material does not show whether they have an equivalent bound, so this is unverified rather than a known gap.",
      "The security-branch cherry-pick changes only include/fmq/MessageQueueBase.h (1 file). The unit tests mentioned in the commit message are not part of this commit.",
      "The per-major facts report 6/8 lines of the patched region present at the latest tag of every major. The material does not explain the 2 missing lines, and the diffs shown contain the full check."
     ],
     "behavior_changes": [
      "Reads on synchronized queues now fail when writePtr - readPtr exceeds mDesc->getSize(): availableToReadBytes returns 0 and reports Error::POINTER_CORRUPTION. Previously the difference was returned as the readable byte count.",
      "beginRead()/read() on a synchronized queue now return false when nMessages > getQuantumCount(). This logs via logError and writes an errorWriteLog(0x534e4554, \"514861024\") entry (the errorWriteLog line is absent in the Android 17 variant).",
      "The pointer-corruption error message now also includes the queue size.",
      "No behavior change for unsynchronized-flavor queues."
     ],
     "preconditions": [
      "A MessageQueueBase instance of flavor kSynchronizedReadWrite whose read path (read()/beginRead()/availableToReadBytes()) is used.",
      "Either the read/write pointers hold values whose difference exceeds the queue size (for example, corrupted ones), or a caller requests more messages than the queue's quantum count.",
      "The material does not show which services or HALs expose such queues to a less-trusted peer."
     ],
     "per_major": {
      "14": "adapted fix (commit 452c5e918cde, android-security-14.0.0_r29): the same two checks. In availableToReadBytes, the inline logError string is replaced by an errorMsg variable passed to logError, and the corruption branch has no error-reporting hooks (no out-params or mErrorHandler in the diff).",
      "15": "same fix as analysed (commit 6d316edf3cc8, android-security-15.0.0_r17): checks added to the errorDetected/errorMessage variant of availableToReadBytes and to beginRead, including errorWriteLog.",
      "16": "adapted fix (commit 3aa82fe2d0a8, android-security-16.0.0_r8): identical checks. availableToReadBytes takes no parameters and reports via mErrorHandler(Error::POINTER_CORRUPTION, ...) instead of out-params.",
      "17": "adapted fix (commit f727482ff0c6, android-security-17.0.0_r1): the same checks on the mErrorHandler variant. The beginRead check omits the errorWriteLog(0x534e4554, \"514861024\") line and only logs via logError before returning false."
     },
     "backport_notes": [
      "Single-header change. The per-branch differences are in how availableToReadBytes reports the error: logError only on 14, errorDetected/errorMessage out-params on 15, mErrorHandler on 16/17. Keep the flavor == kSynchronizedReadWrite condition on both checks. The commit message says the unsync flavor is expected to overflow when readers are slow.",
      "MessageQueueBase is header template code compiled into each user, so consumers must be rebuilt to pick up the checks (general platform knowledge)."
     ],
     "confidence": "medium",
     "unknowns": [
      "Which FMQ users or HALs expose a synchronized queue to a less-trusted peer, and the concrete trigger scenario behind bugs 504768739 and 514861024.",
      "How beginRead used the unbounded availableToReadBytes value before the fix, and whether this led to memory access outside the queue buffer (the beginRead body is not shown).",
      "Why the original change was reverted beyond the commit message's note on the unsync flavor, whether the availableToReadBytes check differed in the reverted version, and the contents of the three upstream cherry-picked commits.",
      "Whether the write-side functions (availableToWriteBytes/beginWrite) already bound the pointer distance; they are not shown.",
      "Why the per-major facts show only 6/8 lines of the patched region at the latest security tags when the diffs shown contain the complete check."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-55266": {
     "cve": "CVE-2026-55266",
     "summary": "Rewrites the tail of the copied BSD qsort in libufdt's vendor sysdeps so it recurses only on the smaller partition and loops on the larger one, bounding recursion depth to O(log n) instead of O(n) on adversarial input.",
     "component": "platform/system/libufdt, sysdeps/libufdt_sysdeps_vendor.c (vendor qsort implementation)",
     "weakness": "Uncontrolled recursion / stack exhaustion (unbounded recursion depth in qsort)",
     "root_cause": "The qsort() in sysdeps/libufdt_sysdeps_vendor.c (a copied BSD quicksort) always recursed on the left partition (r = pb - pa) and iterated via goto loop on the right partition (r = pd - pc), whatever their relative sizes. When partitioning keeps producing a large left partition (unbalanced pivots on large or adversarial inputs), recursion depth grows linearly with n, so the call stack can be exhausted (stack overflow, crash). The 'iterate rather than recurse' comment only saved stack for the right side; the left side had no depth bound.",
     "fix_analysis": [
      "sysdeps/libufdt_sysdeps_vendor.c:qsort: a new int l holds the left partition byte size (pb - pa) and r holds the right partition byte size (pd - pc). Both are computed once after the vecswap calls instead of reusing r for both.",
      "sysdeps/libufdt_sysdeps_vendor.c:qsort: if l < r, recurse on the left (qsort(a, l / es, es, cmp) when l > es), then iterate on the right (a = pn - r; n = r / es; goto loop when r > es).",
      "sysdeps/libufdt_sysdeps_vendor.c:qsort: otherwise recurse on the right (qsort(pn - r, r / es, es, cmp) when r > es) and iterate on the left (n = l / es; goto loop when l > es). a is unchanged because the left partition starts at a.",
      "The recursive call always handles the partition that is no larger than half the current range, so recursion depth is bounded by log2(n) frames. The larger partition is always processed by goto loop, with no stack growth. The stale commented-out qsort(pn - r, ...) line is removed."
     ],
     "completeness": [
      "The fix covers the only recursion site in the vendor qsort and removes the unbounded case for both partition orientations. The partition and pivot-selection logic (med3, insertion sort for n < 7) is unchanged.",
      "Only the vendor sysdeps qsort is touched.",
      "Partition sizes are still held in int (l, r) and the comparisons against (int)es are unchanged, so the fix does not address any size handling beyond recursion depth."
     ],
     "behavior_changes": [
      "No change to sort results. The in-place algorithm is the same; only the order in which the two sub-partitions are processed changes (the smaller one is handled first, by recursion).",
      "Maximum stack usage of qsort is now logarithmic in the number of elements rather than potentially linear."
     ],
     "preconditions": [
      "libufdt must be built with the vendor sysdeps (sysdeps/libufdt_sysdeps_vendor.c) so that this local qsort is the one linked.",
      "A caller must sort an array that is large enough, and ordered adversely enough with respect to the med3 pivot selection, that repeated unbalanced partitions produce deep recursion. The in-tree libufdt callers of qsort are not shown in the material.",
      "Per index search, the only results were bionic's separate FreeBSD-derived qsort and its tests. That is a different implementation, and those tests are not callers of this function."
     ],
     "per_major": {
      "14": "same fix: commit bbc615c85bf1 in android-security-14.0.0_r29, identical diff (file index 235d995..3b1e60a, same hunk offsets as 15).",
      "15": "same fix: commit 109d68930129 in android-security-15.0.0_r17, identical diff (file index 235d995..3b1e60a).",
      "16": "same fix: commit 8dfd47aab1f2 in android-security-16.0.0_r8, identical content; hunks sit two lines lower (file index fc5b186..57d334a).",
      "17": "same fix: commit 70c20864187d in android-security-17.0.0_r1, identical content and offsets to 16 (file index fc5b186..57d334a)."
     },
     "backport_notes": [
      "Single self-contained commit with no visible dependencies. The diff content is identical on all four majors; only line offsets differ between 14/15 and 16/17. Forks that still carry the original BSD tail (recurse left, goto right) can apply it directly."
     ],
     "confidence": "high",
     "unknowns": [
      "Which libufdt code paths call this qsort, and what data (e.g. device tree node/property arrays) reaches it, is not shown in the material.",
      "Whether other sysdeps variants of libufdt use a different qsort is not shown.",
      "The per-major facts report 7/8 patched-region lines present at the latest security tags; the material does not show which line differs or why."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-55270": {
     "cve": "CVE-2026-55270",
     "summary": "Adds a `wrappedCallback == null` guard in `dialInternal` of both `GsmCdmaPhone` and `ImsPhone` so that USSD requests (which carry a non-null ResultReceiver) can no longer execute in-call MMI supplementary-service commands when the USSD string matches an in-call MMI code.",
     "component": "platform/frameworks/opt/telephony, GsmCdmaPhone / ImsPhone dial and USSD handling",
     "weakness": "Missing context check: USSD request path shared the dial path and did not exclude in-call MMI call-control commands (confused request type)",
     "root_cause": "Both `GsmCdmaPhone.dialInternal` (GSM branch) and `ImsPhone.dialInternal` call `handleInCallMmiCommands(newDialString)` first and return early if it handled the string. Per the commit message, USSD requests reach this path with a non-null wrappedCallback, while the normal `dial` path passes null (shown for ImsPhone.dial). Because the in-call MMI check did not distinguish the two, a USSD request string matching an in-call MMI code (for example \"2\" in the tests, with a call in INCOMING state) could be executed as a call-control action (the tests check `acceptCall` on the call tracker) instead of being treated as a USSD request.",
     "fix_analysis": [
      "src/java/com/android/internal/telephony/GsmCdmaPhone.java:dialInternal (GSM branch): `if (handleInCallMmiCommands(newDialString))` becomes `if (wrappedCallback == null && handleInCallMmiCommands(newDialString))`, so in-call MMI handling is only attempted when wrappedCallback is null. The short-circuit means `handleInCallMmiCommands` is not invoked at all for USSD requests.",
      "src/java/com/android/internal/telephony/imsphone/ImsPhone.java:dialInternal: same change. The regular `ImsPhone.dial` passes null for wrappedCallback, so normal dialing behaviour is unchanged.",
      "tests/telephonytests/.../GsmCdmaPhoneTest.java: new `testHandleUssdRequestWithInCallMmiCode` sets foreground/background/ringing calls to a mock in INCOMING state, calls `handleUssdRequest(\"2\", mockCallback)`, asserts it returns true and that `mCT.acceptCall()` is never invoked.",
      "tests/telephonytests/.../ImsPhoneTest.java: new `testHandleUssdRequestWithInCallMmiCode` sets the ringing call to INCOMING, calls `handleUssdRequest(\"2\", mockCallback)`, expects a `CallStateException` with message `Phone.CS_FALLBACK` and verifies `mImsCT.acceptCall(anyInt())` is never invoked."
     ],
     "completeness": [
      "Covers the in-call MMI pre-check in `dialInternal` of `GsmCdmaPhone` (GSM branch, the only hunk shown) and `ImsPhone`.",
      "The guard uses `wrappedCallback != null` as the sole indicator of a USSD request; any caller passing a non-null ResultReceiver bypasses in-call MMI handling, and any path passing null keeps the old behaviour. Other callers are not shown.",
      "In ImsPhone, after the guard the string falls through to `ImsPhoneMmiCode.newFromDialString` with the wrappedCallback. GsmCdmaPhone's subsequent handling is not shown; observable outcomes are only the test expectations (GsmCdmaPhone: handled == true; ImsPhone: CallStateException CS_FALLBACK).",
      "The body of `handleInCallMmiCommands` is not changed; the fix is a gate at the call site."
     ],
     "behavior_changes": [
      "USSD requests whose dial string matches an in-call MMI code no longer trigger in-call MMI call-control actions (commit message: hold, swap, conference; tests: accept).",
      "On ImsPhone with an incoming call, such a USSD request now results in a `CallStateException` with message `Phone.CS_FALLBACK` from `handleUssdRequest` (per the new test).",
      "Normal `dial` calls (wrappedCallback null) are unaffected."
     ],
     "preconditions": [
      "A USSD request reaches `handleUssdRequest` (with a non-null `ResultReceiver`) on a `GsmCdmaPhone` in GSM mode or on an `ImsPhone`.",
      "The stripped USSD string matches an in-call MMI code (tests use \"2\").",
      "The phone has call state on which the in-call MMI command acts (tests use calls in INCOMING state)."
     ],
     "per_major": {
      "14": "same fix: a702397eed29 in android-security-14.0.0_r29, identical one-line guards in GsmCdmaPhone.dialInternal and ImsPhone.dialInternal plus the same two tests; 6/8 lines of the patched region present at android-security-14.0.0_r30.",
      "15": "same fix: 92836c48ba6a in android-security-15.0.0_r17 (the analysed commit); code at android-security-15.0.0_r18 shows `wrappedCallback == null && handleInCallMmiCommands(newDialString)` in ImsPhone.dialInternal (6/8 lines of the patched region present).",
      "16": "adapted fix: ee04a37583c0 in android-security-16.0.0_r8. Both files have two branches under `mFeatureFlags.skipMmiCodeCheckForEmergencyCall()`; the `wrappedCallback == null` guard is added to both branches. Same tests. 6/8 lines of the patched region present at android-security-16.0.0_r9.",
      "17": "adapted fix: 802f8f5c9920 in android-security-17.0.0_r1. The in-call MMI handling is wrapped in `if (!dialArgs.isEmergency)` (with an inner `ignoreIncallMmiForEmergency` check); the fix changes the outer condition to `!dialArgs.isEmergency && wrappedCallback == null` in both files. Same tests. 6/8 lines of the patched region present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Single-commit, one-line change per file; where the in-call MMI check is split across feature-flag branches (as in 16) or wrapped by an emergency condition (as in 17), the guard must be applied to every path that can call `handleInCallMmiCommands` from `dialInternal`.",
      "The new tests use `replaceInstance`, `mCT`, `mGsmCdmaCall`, `mRingingCall` and `mImsCT`; adjust if these fixtures differ on the target branch."
     ],
     "confidence": "high",
     "unknowns": [
      "The body of `handleInCallMmiCommands` and the full set of in-call MMI actions reachable are not in the material.",
      "How the USSD string is processed after bypassing the in-call MMI check in GsmCdmaPhone is not shown beyond the test assertions.",
      "Whether the CDMA branch of GsmCdmaPhone.dialInternal has any in-call MMI handling is not shown.",
      "The external entry point (e.g. a TelephonyManager API), caller identity and permission checks for `handleUssdRequest` are not shown in the material."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 8,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58815": {
     "cve": "CVE-2026-58815",
     "summary": "Changes the metering-region loop bound in the cameraserver DistortionMapper, RotateAndCropMapper and ZoomRatioMapper from `j < entry.count` to `j + 5 <= entry.count`, so a region entry whose element count is not a multiple of 5 no longer causes a heap out-of-bounds read and write past the end of the metadata entry.",
     "component": "platform/frameworks/av, services/camera/libcameraservice (cameraserver, device3 metadata mappers)",
     "weakness": "Missing bounds check (heap out-of-bounds read/write, loop stride larger than remaining elements)",
     "root_cause": "The three camera metadata mappers iterate over metering region tags (kMeteringRegionsToCorrect, e.g. ANDROID_CONTROL_AE_REGIONS) and treat each region as 5 int32 values (4 coordinates plus a weight). The loops used `for (j = 0; j < entry.count; j += 5)`, then read `entry.data.i32[j + 4]` unconditionally and transformed the coordinates in place through `entry.data.i32 + j`. Shown examples: mapCorrectedToRaw with 2 points in DistortionMapper::correctCaptureRequest, and transformPoints with 2 points plus swapRectToMinFirst in RotateAndCropMapper::updateCaptureRequest. When entry.count is not a multiple of 5, the last iteration starts at an index with fewer than 5 elements left, so the weight read and the coordinate writes go past the end of the entry's buffer inside the CameraMetadata. The added tests show this with a 6-element entry written after a larger 10-element entry, and they check that element [5] is left untouched.",
     "fix_analysis": [
      "services/camera/libcameraservice/device3/DistortionMapper.cpp:DistortionMapper::correctCaptureRequest and DistortionMapper::correctCaptureResult: the loop condition is changed to `j + 5 <= e.count`, so a region is processed only when all 5 of its elements lie within the entry.",
      "services/camera/libcameraservice/device3/RotateAndCropMapper.cpp:RotateAndCropMapper::updateCaptureRequest and RotateAndCropMapper::updateCaptureResult: same change, `i + 5 <= entry.count`.",
      "services/camera/libcameraservice/device3/ZoomRatioMapper.cpp:ZoomRatioMapper::separateZoomFromCropLocked and ZoomRatioMapper::combineZoomAndCropLocked: same change, `j + 5 <= entry.count`.",
      "Tests added: DistortionMapperTest MeteringRegionsBoundsTest, RotationMapperTest MeteringRegionsBoundsTest and ZoomRatioTest MeteringRegionsBoundsTest. Each one first writes a 10-element AE_REGIONS entry as poison, then overwrites it with a 6-element entry ending in 999. It then runs the request mapper and asserts that the count stays 6 and that data.i32[5] is still 999.",
      "No validation or rejection is added. The trailing partial region is simply skipped, and the functions still return OK."
     ],
     "completeness": [
      "All six metering-region loops in the three mapper diffs are fixed, on both the request path (correctCaptureRequest, updateCaptureRequest, separateZoomFromCropLocked) and the result path (correctCaptureResult, updateCaptureResult, combineZoomAndCropLocked).",
      "The commit message also names a `correctMeteringRegions` function, but no such function appears in any of the four branch diffs provided.",
      "The sibling kRectsToCorrect loop in DistortionMapper::correctCaptureRequest uses `e.count / 4` as the rect count. That division truncates rather than over-reads, and the loop is not changed.",
      "The fix does not reject malformed entries. An entry whose count is not a multiple of 5 is accepted, and its trailing elements are left unprocessed."
     ],
     "behavior_changes": [
      "In metering region entries whose count is not a multiple of 5, the trailing partial region (fewer than 5 elements) is now left untransformed instead of being read and written out of bounds. No new error code is returned, and the mappers still return OK.",
      "Entries whose count is a multiple of 5 behave exactly as before."
     ],
     "preconditions": [
      "cameraserver processes a CaptureRequest, or a capture result, carrying one of the kMeteringRegionsToCorrect tags (e.g. ANDROID_CONTROL_AE_REGIONS) with an element count that is not a multiple of 5.",
      "The relevant mapper must be active. DistortionMapper needs a valid mapping (mapperInfo->mValidMapping) and ANDROID_DISTORTION_CORRECTION_MODE present and not OFF. RotateAndCropMapper::updateCaptureResult returns early unless ANDROID_SCALER_ROTATE_AND_CROP is present and not NONE; the matching check on the request path is not shown. The ZoomRatioMapper paths run from its updateCaptureRequest/updateCaptureResult, as the added tests exercise.",
      "The result-side paths are reached from the capture result pipeline. Per index search, sendCaptureResult in services/camera/libcameraservice/device3/Camera3OutputUtils.cpp was returned as a related caller, but the partial chunk does not show the mapper call itself.",
      "The bulletin rates this as a High severity EoP. The material does not say which caller context (app or HAL) the report used."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/av 6654633902f8 in android-security-14.0.0_r29. The six loop-condition changes and the tests are identical; only the hunk line offsets differ (DistortionMapper 143/182, RotateAndCropMapper 162/291, ZoomRatioMapper 349/387). The resolver reports 7/8 lines of the patched region present at android-security-14.0.0_r30.",
      "15": "same fix: platform/frameworks/av ff3f3a6b8194 in android-security-15.0.0_r17 (cherry-pick of cc78e7aa1be9, Change-Id I2edb88dbf20a1979ffb00e774cbb126fd9232cc1). The code at android-security-15.0.0_r18 shows the new conditions in place in DistortionMapper::correctCaptureRequest and RotateAndCropMapper::updateCaptureRequest. The resolver reports 7/8 lines present.",
      "16": "same fix: platform/frameworks/av aff9120ec0b8 in android-security-16.0.0_r8. The change is identical; the ZoomRatioMapper hunks are at lines 386/424. The resolver reports 7/8 lines present at android-security-16.0.0_r9.",
      "17": "same fix: platform/frameworks/av 77f8ddbbd65b in android-security-17.0.0_r1, identical to the Android 16 diff. The resolver reports 7/8 lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "The fix is a single commit: six one-line loop-condition changes in DistortionMapper.cpp, RotateAndCropMapper.cpp and ZoomRatioMapper.cpp, plus three new tests. On 14 through 17 the same hunks appear with only line-offset differences. libcameraservice is part of the platform cameraserver, not a mainline module (general platform knowledge)."
     ],
     "confidence": "high",
     "unknowns": [
      "Whether a function named correctMeteringRegions (mentioned in the commit message) exists on any branch and received the same change. It does not appear in the provided diffs.",
      "Why the resolver reports 7/8 rather than 8/8 lines of the patched region present in each latest security tag.",
      "The loop bodies of the result-path and ZoomRatioMapper loops, which the material does not show.",
      "Which caller path (an application-supplied CaptureRequest or a HAL-supplied result) the original report used."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58834": {
     "cve": "CVE-2026-58834",
     "summary": "Adds an argument check rejecting any grantState other than GRANTED/DENIED/DEFAULT in DevicePolicyManagerService.setPermissionGrantState, and wraps each enforcePolicy call in DevicePolicyEngine.reapplyAllPoliciesOnBootLocked in a try/catch so an invalid persisted policy no longer crashes system_server at boot.",
     "component": "platform/frameworks/base, DevicePolicyManagerService / DevicePolicyEngine (services/devicepolicy)",
     "weakness": "Missing input validation (unvalidated enum-like int argument persisted to disk) combined with an uncaught exception on the boot re-application path",
     "root_cause": "DevicePolicyManagerService.setPermissionGrantState accepted an arbitrary int grantState without checking it against the three defined constants. Per the commit message, the unvalidated value was saved to disk (tied to the coexistence/policy engine path). On subsequent boots DevicePolicyEngine.reapplyAllPoliciesOnBootLocked called enforcePolicy for each saved global and local policy with no exception handling, so the out-of-range value raised an uncaught IllegalArgumentException inside system_server during boot, producing a persistent boot loop.",
     "fix_analysis": [
      "services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java:setPermissionGrantState: adds Preconditions.checkArgument(grantState == PERMISSION_GRANT_STATE_GRANTED || grantState == PERMISSION_GRANT_STATE_DENIED || grantState == PERMISSION_GRANT_STATE_DEFAULT) immediately after the Objects.requireNonNull(callback) check and before getCallerIdentity/checkCanExecuteOrThrowUnsafe. An invalid value now throws IllegalArgumentException to the caller and is never persisted. The commit message says the check applies 'when the coexistence flag is enabled', but the diff places it unconditionally at method entry.",
      "services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java:reapplyAllPoliciesOnBootLocked: wraps enforcePolicy(policyDefinition, policyValue, UserHandle.USER_ALL) in the global-policy loop and enforcePolicy(policyDefinition, policyValue, userId) in the per-user local-policy loop in try { } catch (Exception e) { Slogf.wtf(TAG, ...) }. If re-applying one saved policy fails, the failure is logged and the loop continues with the remaining policies instead of propagating out of boot.",
      "services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java: adds testSetPermissionGrantState_coexistence_invalidState_throwsException, which sets a device owner and asserts IllegalArgumentException for grantState 999."
     ],
     "completeness": [
      "Entry validation covers only setPermissionGrantState. It is an exact whitelist of the three constants, so no other integer can be persisted through this API.",
      "The boot hardening covers only reapplyAllPoliciesOnBootLocked (both global and local loops). Other places that call enforcePolicy (for example at policy set time or on other lifecycle events) are not changed in this diff. Whether they need it is not shown.",
      "The fix does not sanitize or remove an invalid value already present on disk from a pre-fix device. Such a value stays stored. If its re-application still throws, the exception is caught and logged via Slogf.wtf at boot instead of crashing system_server.",
      "The catch is for Exception only; Errors are not caught. Slogf.wtf routes to Log.wtf, which in system_server by default reports rather than terminates, but can be made fatal via the WTF_IS_FATAL setting (general platform knowledge)."
     ],
     "behavior_changes": [
      "setPermissionGrantState now throws IllegalArgumentException for any grantState not equal to PERMISSION_GRANT_STATE_GRANTED, PERMISSION_GRANT_STATE_DENIED or PERMISSION_GRANT_STATE_DEFAULT, for all callers (the check precedes caller identity and admin checks).",
      "During boot, a failure to re-apply a single stored policy is logged with Slogf.wtf ('Failed to reapply policy ...') and skipped; remaining policies are still re-applied."
     ],
     "preconditions": [
      "Caller must be able to invoke setPermissionGrantState as an admin. The commit message states that a BYOD work-profile DPC is sufficient.",
      "Per the commit message, the issue is tied to the coexistence (DevicePolicyEngine) path. The crash occurs on a later system_server boot, when reapplyAllPoliciesOnBootLocked re-enforces saved policies."
     ],
     "per_major": {
      "14": "adapted fix: same Preconditions.checkArgument and same try/catch pattern, but reapplyAllPoliciesOnBootLocked in 14 has no shouldSkipEnforcementIfNotChanged guard, so the hunks differ in context. Commit 057ff07691a6 in android-security-14.0.0_r29; 8/8 lines present at r30.",
      "15": "this fix: commit 49e1a4ba935f in android-security-15.0.0_r17; 8/8 lines present at r18.",
      "16": "same fix: identical hunks at shifted line numbers. Commit f4e7001b21fb in android-security-16.0.0_r8; 8/8 lines present at r9.",
      "17": "adapted fix: same change, but the local-policy loop in 17 iterates a Set<Integer> userIds copy of mLocalPolicies.keySet(). Commit c715c992cad0 in android-security-17.0.0_r1; 8/8 lines present at r2."
     },
     "backport_notes": [
      "Single commit with two independent hunks plus a test. The service-side checkArgument hunk fits where setPermissionGrantState begins with Objects.requireNonNull(callback). The engine hunk must be fitted to the local shape of reapplyAllPoliciesOnBootLocked: Android 14 lacks the shouldSkipEnforcementIfNotChanged guard, and Android 17 iterates a copied user id set. Ensure Preconditions and Slogf are imported in the respective files."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact enforcement function inside DevicePolicyEngine/PolicyEnforcerCallbacks that threw IllegalArgumentException for the invalid value is not shown in the material.",
      "Whether the legacy (non-engine) permission grant path also persisted the invalid value is not shown; the commit message ties the issue to the coexistence flag.",
      "Whether other enforcePolicy call sites (outside reapplyAllPoliciesOnBootLocked) can be reached with an already-persisted invalid value is not shown.",
      "The full set of caller roles permitted to call setPermissionGrantState is not shown in the material.",
      "How the 16-qpr2 and 17-next branches listed as affected were patched is not shown."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 2,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58841": {
     "cve": "CVE-2026-58841",
     "summary": "Moves the mAudioPlaybackDetector.register(this) call in VirtualAudioController.startListening out of the `if (configChangedCallback != null)` block so the playback detector is always registered, leaving only mAudioRecordingDetector registration conditional on the optional config-changed callback.",
     "component": "platform/frameworks/base, services/companion (Virtual Device Manager, virtual audio: VirtualAudioController)",
     "weakness": "Logic error: a required callback registration (audio playback detector) was gated on an unrelated optional parameter, so the silence-injection policy update was skipped when that parameter was null (policy enforcement bypass by omission).",
     "root_cause": "In services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java, startListening(genericWindowPolicyController, routingCallback, configChangedCallback) registered both mAudioPlaybackDetector and mAudioRecordingDetector only inside `if (configChangedCallback != null)`. configChangedCallback is @Nullable. When a caller passed null, the controller never registered itself as the AudioPlaybackCallback, so it did not receive playback configuration changes. Per the commit message, the deferred silence-injection policy update then did not recover correctly (the silence-injection policy was skipped). stopListening unconditionally unregisters both detectors, so the asymmetry existed only on the registration side.",
     "fix_analysis": [
      "VirtualAudioController.java:startListening: `mAudioPlaybackDetector.register(/* callback= */ this)` is hoisted out of the `if (configChangedCallback != null)` block and executed unconditionally after the mRunningAppUids/mPlayingAppUids reset, so the controller always receives AudioPlaybackCallback events regardless of whether a config-changed callback was supplied.",
      "VirtualAudioController.java:startListening: `mAudioRecordingDetector.register(/* callback= */ this)` remains inside the `if (configChangedCallback != null)` block, so recording detection is still only enabled when the caller provides an IAudioConfigChangedCallback.",
      "Single-file, one-line move; no changes to stopListening, which already unregistered both detectors unconditionally."
     ],
     "completeness": [
      "Covers the only registration site shown: startListening now always registers the playback detector, which is what the commit message identifies as needed for the deferred silence-injection policy update.",
      "Recording detector registration stays conditional on configChangedCallback. The commit message describes this conditional registration explicitly, and the material gives no indication that it is a problem.",
      "The fix changes only startListening. It leaves the AudioPlaybackCallback handling code alone, and it does not change any caller that passes a null configChangedCallback. The material does not show whether such callers needed other changes.",
      "The commit message says the fix was tested with atest VirtualAudioControllerTest, but the test diff is not included in the material."
     ],
     "behavior_changes": [
      "VirtualAudioController now registers an AudioPlaybackCallback with AudioPlaybackDetector for every startListening call, including those with a null IAudioConfigChangedCallback. Playback-config change callbacks therefore fire for virtual devices that previously received none.",
      "No API, error code, or permission changes; stopListening behavior unchanged (it already unregistered both detectors)."
     ],
     "preconditions": [
      "A virtual device whose audio session reaches VirtualAudioController.startListening (virtual audio created via the Companion/Virtual Device Manager service), as shown by the class context.",
      "startListening invoked with configChangedCallback == null; with a non-null callback the pre-fix code already registered the playback detector."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/base 8ded15ca0499 in android-security-14.0.0_r29, identical one-line move (hunk at line 94); patched region present at android-security-14.0.0_r30.",
      "15": "same fix: platform/frameworks/base a46c94ad2ccc in android-security-15.0.0_r17, identical one-line move (hunk at line 102); patched region present at android-security-15.0.0_r18.",
      "16": "same fix: platform/frameworks/base 3184e06e737a in android-security-16.0.0_r8, identical one-line move (hunk at line 100); patched region present at android-security-16.0.0_r9.",
      "17": "same fix: platform/frameworks/base 1412cbcc0c10 in android-security-17.0.0_r1, identical one-line move (hunk at line 102; class declaration line in the hunk context differs slightly); patched region present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Single self-contained hunk in VirtualAudioController.startListening with no dependencies. The change content is identical on 14 through 17; only line offsets differ. On a fork, verify the file still has the `if (configChangedCallback != null)` block wrapping both register calls and move only the playback register call above it; ensure stopListening still unregisters mAudioPlaybackDetector unconditionally."
     ],
     "confidence": "high",
     "unknowns": [
      "Which caller(s) pass a null configChangedCallback to startListening and under what app-visible conditions; not shown in the material.",
      "The exact mechanism of the 'deferred silence injection policy update' and what the EoP consequence is in concrete terms; the commit message only names it.",
      "Contents of the VirtualAudioControllerTest changes referenced by the commit message.",
      "Role of the second bug id (521392631) listed in the commit."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 2,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58854": {
     "cve": "CVE-2026-58854",
     "summary": "Adds isRemote() checks, and nullptr checks where they were missing, before mediatuner downcasts caller-supplied ITunerFilter/ITunerDemux/ITunerLnb binder objects to its local implementation classes. Remote proxies are rejected with Result::INVALID_ARGUMENT in both the AIDL and HIDL tuner service paths.",
     "component": "platform/frameworks/av, services/tuner (mediatuner daemon, AIDL and HIDL HAL wrappers)",
     "weakness": "Type confusion from an unchecked static_cast of a binder interface pointer to a local implementation class (CWE-843), leading to out-of-bounds member reads",
     "root_cause": "Several mediatuner service methods take an AIDL interface argument (shared_ptr<ITunerFilter>, shared_ptr<ITunerDemux>, shared_ptr<ITunerLnb>) and immediately static_cast it to the service's own concrete class (TunerFilter, TunerDemux, TunerLnb, or TunerHidlFilter, TunerHidlDemux, TunerHidlLnb) to call getHalFilter() or getId(). Nothing checked that the object was actually a local instance. Per the commit message, a client could pass remote binder proxies or custom binder stubs. The static_cast then treated the proxy as the local class and read member fields (the HAL filter pointer, the id) out of bounds relative to the proxy allocation. Some sites (TunerDemux::getAvSyncHwId, TunerDescrambler::setDemuxSource and their HIDL equivalents) also had no nullptr check. addPid/removePid already handled nullptr through a ternary. The remaining sites only checked for nullptr.",
     "fix_analysis": [
      "services/tuner/TunerDemux.cpp:TunerDemux::getAvSyncHwId: a new guard `tunerFilter == nullptr || tunerFilter->isRemote()` returns service-specific error Result::INVALID_ARGUMENT before static_cast<TunerFilter*>(...)->getHalFilter().",
      "services/tuner/TunerDescrambler.cpp:TunerDescrambler::setDemuxSource: the same nullptr/isRemote guard before static_cast<TunerDemux*>(...)->getId(). TunerDescrambler::addPid and TunerDescrambler::removePid: guard `in_optionalSourceFilter != nullptr && in_optionalSourceFilter->isRemote()`. nullptr is still allowed because the filter is optional and is mapped to a nullptr HAL filter.",
      "services/tuner/TunerDvr.cpp:TunerDvr::attachFilter and TunerDvr::detachFilter: the existing `in_filter == nullptr` check is extended with `|| in_filter->isRemote()`. The later getHalFilter()==nullptr check is unchanged.",
      "services/tuner/TunerFilter.cpp:TunerFilter::setDataSource: the existing nullptr check is extended with `|| filter->isRemote()`. It runs under mLock, before the mShared check and the static_cast<TunerFilter*>.",
      "services/tuner/TunerFrontend.cpp:TunerFrontend::setLnb: the existing nullptr check is extended with `|| lnb->isRemote()` before static_cast<TunerLnb*>(lnb.get())->getId().",
      "services/tuner/hidl/TunerHidlDemux.cpp:TunerHidlDemux::getAvSyncHwId: the same nullptr/isRemote guard. This file also gains `#include <aidl/android/hardware/tv/tuner/Result.h>` and `using ::aidl::android::hardware::tv::tuner::Result;`.",
      "services/tuner/hidl/TunerHidlDescrambler.cpp:TunerHidlDescrambler::setDemuxSource, addPid, removePid; services/tuner/hidl/TunerHidlDvr.cpp:TunerHidlDvr::attachFilter, detachFilter; services/tuner/hidl/TunerHidlFilter.cpp:TunerHidlFilter::setDataSource; services/tuner/hidl/TunerHidlFrontend.cpp:TunerHidlFrontend::setLnb: guards identical to the AIDL files, placed before the static_cast to TunerHidlFilter/TunerHidlDemux/TunerHidlLnb.",
      "Per the commit message, the isRemote() checks reject remote proxy binders, so only binder objects local to the service process reach the static_cast."
     ],
     "completeness": [
      "All 16 static_cast sites changed in the commit (8 AIDL, 8 HIDL mirror) are guarded. The AIDL and HIDL backends are patched symmetrically in the same commit.",
      "The fix rejects remote binders. It does not replace static_cast with a type-safe lookup, so it assumes that any non-remote ITunerX object received is the service's own concrete class.",
      "The patch also adds nullptr rejection to getAvSyncHwId and setDemuxSource (AIDL and HIDL), which previously had none.",
      "The material does not show other mediatuner methods that take interface arguments but are not in the diff. One example is TunerDemux::setFrontendDataSource, which per index search is called from frameworks/base/media/jni/tuner/DemuxClient.cpp with an ITunerFrontend. Whether these methods contain a similar cast cannot be judged."
     ],
     "behavior_changes": [
      "Passing a remote binder object as the filter/demux/lnb argument to a patched method now fails with service-specific error Result::INVALID_ARGUMENT instead of being dereferenced.",
      "TunerDemux::getAvSyncHwId, TunerDescrambler::setDemuxSource and their HIDL counterparts now return INVALID_ARGUMENT for a null argument.",
      "Legitimate flows that pass objects obtained from mediatuner itself (as the frameworks/base Tuner JNI clients appear to do, per index search) are expected to be unaffected. The commit message says valid object flows were tested."
     ],
     "preconditions": [
      "The caller can reach the mediatuner binder interfaces ITunerDemux, ITunerDescrambler, ITunerDvr, ITunerFilter or ITunerFrontend. The commit message states unprivileged apps could do so.",
      "The caller obtains the target object (demux, descrambler, dvr, filter, frontend) from the service, then supplies a different binder object as the interface argument of one of the patched methods.",
      "The device runs the mediatuner daemon (AIDL or HIDL tuner HAL path). Per index search, the normal callers are the frameworks/base android.media.tv.tuner.Tuner Java API and its JNI clients (DemuxClient, DescramblerClient, FilterClient)."
     ],
     "per_major": {
      "14": "Same fix: platform/frameworks/av f8520e699d18 in android-security-14.0.0_r29. Same 10 files, same hunks, AIDL files at slightly different line offsets. 8/8 patched-region lines present at android-security-14.0.0_r30.",
      "15": "Same fix: platform/frameworks/av 7ccb7033d428 in android-security-15.0.0_r17 (Merged-In Id786837e7dda012109bedf46b95b5e133f898ae3; the commit message lists two Cherrypick-From entries). 8/8 lines present at android-security-15.0.0_r18.",
      "16": "Same fix: platform/frameworks/av 183c2e3a4198 in android-security-16.0.0_r8. The hunks match the 15 diff, though the TunerFilter.cpp blob indexes differ. 8/8 lines present at android-security-16.0.0_r9.",
      "17": "Same fix: platform/frameworks/av 073ae498a43f in android-security-17.0.0_r1. The hunks match the 15 diff, though the TunerFilter.cpp blob indexes differ. 8/8 lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Single commit. services/tuner/hidl/TunerHidlDemux.cpp needs the added Result include and using-declaration. Check each of the 16 call sites individually, since forks may have restructured the wrappers.",
      "The material does not include a fork comparison, so no per-file fork verdict can be given."
     ],
     "confidence": "high",
     "unknowns": [
      "Whether other mediatuner methods that take interface arguments (e.g. TunerDemux::setFrontendDataSource, TunerService-level methods) perform similar downcasts. Their implementations are not in the material.",
      "Whether any other local (non-remote) implementation of ITunerFilter/ITunerDemux/ITunerLnb exists in the mediatuner process. Such an object would still pass the isRemote() check.",
      "The access control on the mediatuner service (SELinux/permissions) is not shown beyond the commit message statement.",
      "How the two Cherrypick-From changes relate in scope is not shown."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 6,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58856": {
     "cve": "CVE-2026-58856",
     "summary": "Adds a range check on the slot index, a null check on the retrieved GraphicBuffer, and a lookup-before-use on mBuffers in Camera3StreamSplitter::returnOutputBufferLocked, and takes the per-output slot vector by reference instead of by copy.",
     "component": "platform/frameworks/av, cameraserver (libcameraservice device3 stream splitter)",
     "weakness": "Missing bounds check on an app-supplied index (out-of-bounds read / type confusion per the commit message), plus an unchecked null buffer and an unchecked operator[] lookup in mBuffers",
     "root_cause": "In services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp, returnOutputBufferLocked takes a slot index that the commit message calls app-supplied. The caller shown at lines 684-695 passes in the slot returned by from->dequeueBuffer() on an output IGraphicBufferProducer. The old code did `auto outputSlots = *mOutputSlots[from]; buffer = outputSlots[slot];` without checking that slot is in [0, outputSlots.size()), so an out-of-range slot read past the vector (OOB read / type confusion per the commit message). It then used `mBuffers[buffer->getId()]` without checking buffer for null and without checking that the id was tracked, and dereferenced the result. Also, outputSlots was a local copy of the vector, so the later `outputSlots[slot] = nullptr` after a successful detachBuffer changed the copy and not the stored slot table.",
     "fix_analysis": [
      "Camera3StreamSplitter.cpp:Camera3StreamSplitter::returnOutputBufferLocked: `auto outputSlots` becomes `auto& outputSlots`, so the function works on the real per-output slot vector (*mOutputSlots[from]) and the `outputSlots[slot] = nullptr` write in the detach path now persists.",
      "Same function: adds `if (slot < 0 || static_cast<size_t>(slot) >= outputSlots.size())`, which logs via SP_LOGE and returns before indexing. This rejects negative and too-large slots.",
      "Same function: after `buffer = outputSlots[slot]`, adds a null check that logs and returns, so buffer->getId() is never called on a null sp.",
      "Same function: replaces `mBuffers[buffer->getId()]` with `mBuffers.find(buffer->getId())`, logs and returns if the id is not tracked, and binds `tracker` to `*(it->second)`.",
      "The existing `mOutputSlots[from] == nullptr` early return above the patched region is unchanged."
     ],
     "completeness": [
      "Within returnOutputBufferLocked, the slot bounds, the null buffer and the tracker lookup are all checked before any dereference.",
      "The later `from->detachBuffer(slot)` and `outputSlots[slot] = nullptr` now run on a validated slot and on the real vector.",
      "Only Camera3StreamSplitter.cpp (14/15) or DeprecatedCamera3StreamSplitter.cpp (16/17) is touched. The material does not show whether other slot-indexed paths in the splitter perform equivalent checks.",
      "On 16/17 the fix lands only in the deprecated splitter. The material does not show the non-deprecated splitter code for those branches, so its state cannot be judged here."
     ],
     "behavior_changes": [
      "An out-of-range slot, a null buffer in the slot, or an untracked buffer id now causes an SP_LOGE message and an early return from returnOutputBufferLocked instead of continuing.",
      "Because outputSlots is now a reference, a successful detachBuffer now actually clears the slot entry in mOutputSlots[from]. Before the fix, the clear only hit a local copy.",
      "mBuffers is no longer accessed through operator[] for an id it may not track; find() is used instead."
     ],
     "preconditions": [
      "The splitter calls from->dequeueBuffer() on an output producer (caller at Camera3StreamSplitter.cpp lines 684-695) and passes the returned slot to returnOutputBufferLocked. Per the commit message, that slot index is app-supplied.",
      "The code runs in libcameraservice (cameraserver). The bulletin classifies the issue as EoP, High."
     ],
     "per_major": {
      "14": "Same fix: platform/frameworks/av d74fdb8ae7d4 (RESTRICT AUTOMERGE) in android-security-14.0.0_r29. Identical hunk in device3/Camera3StreamSplitter.cpp, at line 698 instead of 704. 4/6 lines of the patched region are found at android-security-14.0.0_r30.",
      "15": "Same fix: platform/frameworks/av de6bd248af67 (RESTRICT AUTOMERGE, cherry-pick of 349203358d1b) in android-security-15.0.0_r17, hunk at line 704 of device3/Camera3StreamSplitter.cpp. The fixed code is visible at android-security-15.0.0_r18 (the per-major check reports 4/6 lines of the patched region there).",
      "16": "Adapted fix: platform/frameworks/av 6e240fe4061a in android-security-16.0.0_r8. The same logic is applied to device3/deprecated/DeprecatedCamera3StreamSplitter.cpp, DeprecatedCamera3StreamSplitter::returnOutputBufferLocked (hunk at line 725). 5/6 lines of the patched region are found at r9.",
      "17": "Adapted fix: platform/frameworks/av db4f7fd08e40 in android-security-17.0.0_r1. Same hunk in device3/deprecated/DeprecatedCamera3StreamSplitter.cpp (line 735). 5/6 lines of the patched region are found at r2."
     },
     "backport_notes": [
      "Each branch has a single commit with the same hunk: Camera3StreamSplitter.cpp on 14/15, and device3/deprecated/DeprecatedCamera3StreamSplitter.cpp on 16/17. SP_LOGE is already used in the file. The patch adds a PRIu64 use, so check that the format macro is available in customized forks.",
      "Port the `auto&` change together with the checks. With a by-value copy, the later `outputSlots[slot] = nullptr` is silently lost."
     ],
     "confidence": "high",
     "unknowns": [
      "Whether the non-deprecated Camera3StreamSplitter on Android 16/17 has an equivalent slot-indexed path, and whether it was fixed separately.",
      "Whether other functions in the splitter that index mOutputSlots by a slot have comparable checks.",
      "Whether returnOutputBufferLocked has callers other than the dequeueBuffer path shown (the index search found none among its top results).",
      "The declared type of mBuffers and exactly what operator[] did for an untracked id.",
      "The session configuration needed to bring Camera3StreamSplitter into use."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    }
   }
  },
  "16": {
   "counts": {
    "announced": 21,
    "certain": 20,
    "probable": 0,
    "not_published": 1,
    "not_covered": 0,
    "awaiting": 0
   },
   "advisories": [
    {
     "cve": "CVE-2026-49933",
     "osv_id": "ASB-A-522372651",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Default-initializes MsftExtensionManager::impl::scanning_callbacks_ to nullptr and adds a null check in handle_le_monitor_device_event, so a MSFT LE monitor device vendor event received before the scanning callbacks are registered is dropped instead of invoking a virtual method through an indeterminate pointer.",
      "confidence": "high",
      "backport_notes": [
       "Single-file, self-contained change with no new dependencies. When applying it to a tree with a different impl member layout (as between 16 and 17), only the member-declaration hunk needs relocation. The Bluetooth stack ships as a mainline module, so updates can reach devices via module updates independent of the platform tag (general platform knowledge)."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 7,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "3d959c9229242fc0d327f940e53ff44da2664905",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2026-55265",
     "osv_id": "ASB-A-517377150",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "DoS"
     ],
     "status": "announced-not-published",
     "detail": "platform/development,platform/frameworks/base",
     "coverage": {
      "n_ingested_tags": 9,
      "first_ingested_tag": "android-security-16.0.0_r1",
      "latest_ingested_tag": "android-security-16.0.0_r9",
      "window_base_tag": "android-16.0.0_r2",
      "window_start": "2025-06-10",
      "partial_tags": [],
      "projects": [
       {
        "project": "platform/development",
        "fetched_ok_in_tags": 9,
        "ingested_tags": 9,
        "latest_status": "ok"
       },
       {
        "project": "platform/frameworks/base",
        "fetched_ok_in_tags": 9,
        "ingested_tags": 9,
        "latest_status": "ok"
       }
      ]
     },
     "projects": [
      "platform/development",
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-55269",
     "osv_id": "ASB-A-522372274",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Corrects an inverted size guard in SnoopLogger::FilterCapturedPacket. Short HCI ACL packets are now padded by EXTRA_BUF_SIZE before profile filtering writes the fixed \"PROHIBITED\" magic string into the packet buffer. The fix also clamps the output length to packet.size() + PACKET_TYPE_LENGTH.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained commit. The two code changes (guard flip and std::min clamp) apply to any tree where FilterCapturedPacket has the `packet.size() + EXTRA_BUF_SIZE > DEFAULT_PACKET_SIZE` guard. The test hunk may need adjusting, because the 16 test fixture calls snoop_logger->Start() explicitly and the 17 fixture does not."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 6,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "6effdf3d7c13342bbfe015b83914926a38024b78",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2026-55280",
     "osv_id": "ASB-A-522373576",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Zero-initializes the whole evt_data.activate structure in nfc_ncif_proc_activate() and clamps the NFCID1 and Kovio UID length fields in nfa_dm_notify_activation_status(). The goal is that a short or malformed RF_INTF_ACTIVATED_NTF from the NFCC can no longer feed uninitialized or oversized length values into a memcpy in the NFC process.",
      "confidence": "medium",
      "backport_notes": [
       "Single commit with changes in two files; apply both together. The nfa_dm_act.cc hunk needs <log/log.h> (android_errorWriteLog) and needs the constants NCI_NFCID1_MAX_LEN and NFC_KOVIO_MAX_LEN to exist in the target tree."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 10,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Nfc",
       "sha": "d6cb6aefb12713d2d470e680c01cd1688d75efa2",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Nfc"
     ]
    },
    {
     "cve": "CVE-2026-58835",
     "osv_id": "ASB-A-522371916",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "In system/btif/src/btif_storage.cc cfg2prop(), the BT_PROPERTY_UUIDS / BT_PROPERTY_UUIDS_LE path now limits btif_split_uuids_string() to the caller-supplied buffer capacity (prop->len / sizeof(Uuid)) instead of the hardcoded BT_MAX_NUM_UUIDS.",
      "confidence": "high",
      "backport_notes": [
       "The commit is described as a companion to ag/40421805, which is not in the material. The added zero-limit test exercises btif_split_uuids_string() behavior that this diff does not change, so find and backport the companion change together with this one and run atest net_test_btif.",
       "The one-line change applies cleanly as long as cfg2prop() in system/btif/src/btif_storage.cc contains the call btif_split_uuids_string(value, p_uuid, BT_MAX_NUM_UUIDS). Differences in the function's parameter names (remote_bd_addr vs addr) do not matter."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "91bef351ef64a6f5ce189c5d0493ba9434c436d5",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2026-58865",
     "osv_id": "ASB-A-513582756",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a bounds check on the well-known content-type index in PduParser.parseContentType and null checks on the parameter map and parsed charset string in PduParser.parseContentTypeParams so a malformed MMS PDU no longer throws ArrayIndexOutOfBoundsException or NullPointerException during parsing.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained commit; the PduParser.java hunks applied identically on 14 through 17, so the patch should apply cleanly to any tree with the same parseContentType / parseContentTypeParams structure. The new PduParserTest.java requires the tests/TelephonyCommonTests module to exist in the target tree; it can be dropped if that test target is absent."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 1,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r9",
      "date": "2026-10-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r9",
      "date": "2026-10-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "60f9d9a0bcac12ff87eec843d42693a18164f5e0",
       "tag": "android-security-16.0.0_r9",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-58880",
     "osv_id": "ASB-A-522373105",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Removes the num_ext_attr/ext_attrs parameters from the AVRCP controller playerapplicationsetting_cb HAL callback, so the callback no longer carries a pointer to ext_attrs data that handle_app_attr_val_txt_response frees. It also makes that free (cleanup_app_attr_val_txt_response) synchronous instead of posting it to the JNI thread.",
      "confidence": "medium",
      "backport_notes": [
       "Single commit, but it changes the HAL typedef in system/include/hardware/bt_rc.h. All implementations and call sites of playerapplicationsetting_cb (btif_rc.cc, the JNI file, the tests, and any vendor or fork implementations) must change together. On branches whose call sites use do_in_jni_thread rather than CTRL_HAL_CBACK, the Android 16 variant applies more directly."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 6,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r9",
      "date": "2026-10-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r9",
      "date": "2026-10-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "af2fe681d88de29a038f587036b6c222e64e06d1",
       "tag": "android-security-16.0.0_r9",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2026-28667",
     "osv_id": "ASB-A-508389908",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a response-length check (length < p_i93->block_size) before three rw_i93_send_cmd_write_single_block calls in rw_t5t.cc. A T5T tag response shorter than a block can no longer cause stale GKI buffer slack to be sent in an outgoing WRITE_SINGLE_BLOCK command.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained commit. The file is src/nfc/tags/rw_t5t.cc in platform/system/nfc for Android 14/15 and libnfc-nci/src/nfc/tags/rw_t5t.cc in platform/packages/modules/Nfc for 16/17. All three hunks use only `length` and `p_i93`, which are already in scope at each call site in every branch's diff."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Nfc",
       "sha": "144b34ba890627b56e5c2322097dd4cd30e8405c",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Nfc"
     ]
    },
    {
     "cve": "CVE-2026-45513",
     "osv_id": "ASB-A-508389591",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a length check in nfc_main_hal_data_cback so that an incoming NFC HAL packet larger than the fixed-size NFC_NCI_POOL_ID GKI buffer (minus NFC_HDR and NFC_RECEIVE_MSGS_OFFSET) is logged and dropped instead of being placed into the pool buffer.",
      "confidence": "high",
      "backport_notes": [
       "A single self-contained hunk plus one include. The path differs by release: platform/system/nfc src/nfc/nfc/nfc_main.cc on Android 14/15, and platform/packages/modules/Nfc libnfc-nci/src/nfc/nfc/nfc_main.cc on 16/17 (libnfc-nci moved into the Nfc mainline module in later releases, general platform knowledge).",
       "Requires GKI_get_pool_bufsize, NFC_NCI_POOL_ID, NFC_RECEIVE_MSGS_OFFSET and android_errorWriteLog (liblog). The material shows the same hunk applied on 14, 15, 16 and 17, with only the include context differing on 14."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Nfc",
       "sha": "2db7814d87baf726f01012eb32ffb79d5678fd88",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Nfc"
     ]
    },
    {
     "cve": "CVE-2026-45516",
     "osv_id": "ASB-A-503542587",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds an unsigned multiplication wrap-around check in tt_var_load_item_variation_store before the deltaSet array is allocated. A varData whose per_region_size * item_count wraps in FT_UInt is now rejected with Array_Too_Large instead of being allocated with the wrapped size.",
      "confidence": "high",
      "backport_notes": [
       "The fix is a single commit with one file and two hunks. It uses the existing per_region_size and item_count locals and the FT_THROW/FT_TRACE2 macros. Google applied the same content to 15, 16 and 17, and only the line offsets differ on 17."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/external/freetype",
       "sha": "285b264bf272f4ba115b3ae05a0e4895ca0f82ca",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/external/freetype"
     ]
    },
    {
     "cve": "CVE-2026-49878",
     "osv_id": "ASB-A-511544607",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "RCE"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Replaces two undersized os_zalloc(num_active_scs) allocations in wpas_handle_robust_av_scs_recv_action with os_calloc(num_active_scs, sizeof(int)), so the scs_resp[0]/scs_resp[1] int arrays are sized for num_active_scs integers instead of num_active_scs bytes.",
      "confidence": "high",
      "backport_notes": [
       "Single-commit, two-line change with no dependencies shown. Google applied the same change on 14/15/16/17, and only the hunk line offset differs (640 / 807 / 881 / 1072). Forks carrying the os_zalloc(num_active_scs) pattern in wpas_handle_robust_av_scs_recv_action should be able to apply the same edit."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/external/wpa_supplicant_8",
       "sha": "d131540379d631d7dcb09b0169e4462bc65abcca",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/external/wpa_supplicant_8"
     ]
    },
    {
     "cve": "CVE-2026-49880",
     "osv_id": "ASB-A-508390497",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds an allocated-size field (p_dataBuf_len) to the T4T NFCEE control block and checks rd_offset + p_data->len against it before the memcpy in nfa_t4tnfcee_store_rx_buf, plus length guards in nfa_t4tnfcee_check_sw and nfa_t4tnfcee_store_cc_info and NULL checks on the two nfa_mem_co_alloc results.",
      "confidence": "high",
      "backport_notes": [
       "Single commit touching two files. The struct change in nfa_nfcee_int.h (p_dataBuf_len) must go together with every allocation, free and init site in nfa_nfcee_act.cc, and <log/log.h> is needed for android_errorWriteLog."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 6,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Nfc",
       "sha": "4f214cca6dff82211c65ca43cc341d44d4e3bda3",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Nfc"
     ]
    },
    {
     "cve": "CVE-2026-49885",
     "osv_id": "ASB-A-508389525",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a guard in rw_t4t_set_ber_tlv() so that p_t4t->max_update_size must exceed the ODO/DDO data_header before data_length = max_update_size - data_header is computed, and makes rw_t4t_update_file() free the C-APDU GKI buffer when rw_t4t_set_ber_tlv() fails.",
      "confidence": "high",
      "backport_notes": [
       "On Android 14/15 the file lives in platform/system/nfc at src/nfc/tags/rw_t4t.cc; on 16/17 it is in platform/packages/modules/Nfc at libnfc-nci/src/nfc/tags/rw_t4t.cc. The added lines are identical across majors; context differs in path, line offsets, the \"%s - \" vs \"%s: \" log string format (14/15), and DLOG_IF instead of LOG(VERBOSE) (14).",
       "Keep the caller-side GKI_freebuf in rw_t4t_update_file() together with the new early returns, since rw_t4t_set_ber_tlv() does not free p_c_apdu itself."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Nfc",
       "sha": "9c0ae67d8733d048e6e97cca1b8c520fdcb66870",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Nfc"
     ]
    },
    {
     "cve": "CVE-2026-49937",
     "osv_id": "ASB-A-514861024",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds two bounds checks to the synchronized-flavor read path of libfmq MessageQueueBase. availableToReadBytes() now rejects a writePtr/readPtr distance larger than the queue size, and beginRead() now rejects a request for more messages than the queue holds.",
      "confidence": "high",
      "backport_notes": [
       "Single change to one header. The only branch-specific part is how availableToReadBytes() reports the error: logError only on 14, the errorDetected out-parameter on 15, mErrorHandler on 16/17. Keep the flavor == kSynchronizedReadWrite condition: the commit message says unsync queues are expected to overflow.",
       "The tests mentioned in the message (fmq_unit_tests) are not in the shown diff. Fetch them separately if you want them."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 6,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/libfmq",
       "sha": "3aa82fe2d0a829327ac132916c9a929edbbeb555",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/system/libfmq"
     ]
    },
    {
     "cve": "CVE-2026-55266",
     "osv_id": "ASB-A-509980995",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Rewrites the end of the copied qsort in libufdt's vendor sysdeps so that it recurses on the smaller partition and iterates on the larger one. This bounds recursion depth to O(log n) instead of potentially O(n).",
      "confidence": "high",
      "backport_notes": [
       "This is a single self-contained hunk in qsort() of sysdeps/libufdt_sysdeps_vendor.c with no dependencies. Google applied it on Android 14 through 17 with only line-offset differences. Trees carrying the original 'Iterate rather than recurse' block should be able to take it directly, but that is not verified for other trees.",
       "The index results shown (bionic qsort/qsort_r tests and fts.c) concern bionic's libc qsort, not this libufdt copy. They say nothing about whether the patched function can be reached."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/libufdt",
       "sha": "8dfd47aab1f20d4d08326932a4b80b36c2865a45",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/system/libufdt"
     ]
    },
    {
     "cve": "CVE-2026-55270",
     "osv_id": "ASB-A-517377154",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a `wrappedCallback == null` guard in `dialInternal` of both `GsmCdmaPhone` and `ImsPhone` so that USSD requests (which carry a non-null ResultReceiver) no longer execute in-call MMI supplementary-service commands when the dial string matches an in-call MMI code.",
      "confidence": "high",
      "backport_notes": [
       "Each branch received a single commit. The only adaptation across branches is the shape of the condition around `handleInCallMmiCommands`: unflagged on 14/15, two flag branches on 16, and an outer `!dialArgs.isEmergency` block on 17. In a customized tree, check that every `handleInCallMmiCommands` call reachable from `dialInternal` is guarded by `wrappedCallback == null`.",
       "The tests depend on TelephonyTest harness fields (`mCT`, `mGsmCdmaCall`, `mRingingCall`, `mImsCT`) and Mockito. If the harness differs, adapt the tests, but keep the code change."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/opt/telephony",
       "sha": "ee04a37583c0a965cbf77aef36d6868c38c93f9d",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/opt/telephony"
     ]
    },
    {
     "cve": "CVE-2026-58815",
     "osv_id": "ASB-A-514726373",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Changes the stride-5 metering-region loops in DistortionMapper, RotateAndCropMapper and ZoomRatioMapper from `j < entry.count` to `j + 5 <= entry.count`, so a region entry whose element count is not a multiple of 5 no longer leads to a heap out-of-bounds read and write past the end of the metadata entry.",
      "confidence": "high",
      "backport_notes": [
       "A single commit with six one-line loop-condition changes plus tests. The material shows no dependencies. The resolver reports 7/8 lines of the patched region present for every major, and the material does not explain the missing line, so check all six loops by hand."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 8,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/av",
       "sha": "aff9120ec0b8cb6194b3772793cf6153f757980f",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/av"
     ]
    },
    {
     "cve": "CVE-2026-58834",
     "osv_id": "ASB-A-515158597",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds an argument check on grantState in DevicePolicyManagerService.setPermissionGrantState so only GRANTED, DENIED or DEFAULT are accepted, and wraps the per-policy enforcePolicy calls in DevicePolicyEngine.reapplyAllPoliciesOnBootLocked in try/catch so a bad persisted policy logs a wtf instead of crashing system_server at boot.",
      "confidence": "high",
      "backport_notes": [
       "Single commit, no dependencies; both halves are independent and should be applied together (validation prevents new bad state, the try/catch recovers devices that already have it). When porting to trees with a different reapplyAllPoliciesOnBootLocked loop shape, wrap every enforcePolicy call in that method, as the 14 and 17 variants show.",
       "No diff adds import lines, which suggests Preconditions and Slogf are already imported in these files on all four branches; verify in a customised fork."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 2,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "f4e7001b21fb26b57d06c7e487de95fd6c63fe6e",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-58841",
     "osv_id": "ASB-A-515034370",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Moves mAudioPlaybackDetector.register(this) in VirtualAudioController.startListening out of the `if (configChangedCallback != null)` block so the playback detector is always registered, leaving only mAudioRecordingDetector registration conditional on a config-changed callback.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained one-line change with no dependencies. It applies to any branch where startListening has the `if (configChangedCallback != null)` block wrapping both register calls. On the target branch, check that stopListening unregisters mAudioPlaybackDetector unconditionally. It does in the Android 16 code shown; stopListening is not shown for the other branches."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 2,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "3184e06e737abef4dc41d6c3d7ac5af81631ceb1",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-58854",
     "osv_id": "ASB-A-514727559",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds an isRemote() check (and a null check where there was none) before every static_cast of a caller-supplied ITunerFilter/ITunerDemux/ITunerLnb binder to the local Tuner*/TunerHidl* implementation class in the mediatuner service. Remote proxies are now rejected with Result::INVALID_ARGUMENT.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained commit. The only change besides the checks is the added Result.h include and using-declaration in hidl/TunerHidlDemux.cpp, which Result::INVALID_ARGUMENT needs to resolve there. When applying to a tree with different line offsets (as on 14), check that every static_cast of an interface argument in services/tuner and services/tuner/hidl is preceded by an isRemote() check."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 2,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/av",
       "sha": "183c2e3a419845e2b19792626b9493c59b133072",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/av"
     ]
    },
    {
     "cve": "CVE-2026-58856",
     "osv_id": "ASB-A-514734206",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a range check on the output slot index, a null check on the slot's GraphicBuffer, and a tracked-buffer lookup (mBuffers.find instead of operator[]) in the camera stream splitter's returnOutputBufferLocked, and changes outputSlots from a copy to a reference so slot updates persist.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained hunk with no new dependencies; on Android 14/15 the class and file are Camera3StreamSplitter.cpp, on 16/17 it is deprecated/DeprecatedCamera3StreamSplitter.cpp. Verify presence by checking for the `auto& outputSlots` reference and the three early returns in returnOutputBufferLocked."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-16.0.0_r8",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/av",
       "sha": "6e240fe4061af5fae90974917dfd95efe2ab6a53",
       "tag": "android-security-16.0.0_r8",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/av"
     ]
    }
   ],
   "tags": [
    "android-security-16.0.0_r9"
   ],
   "unannounced": [
    {
     "bug_ids": [
      "517376969"
     ],
     "commits": [
      {
       "project": "platform/frameworks/opt/telephony",
       "sha": "71a0600c82464a945bd2ae8239c1c01ae18baf1b",
       "subject": "RESTRICT AUTOMERGE: Fix remote DoS in decodeWapPdu (b/517376969)",
       "tag": "android-security-16.0.0_r9",
       "merged": "2026-08-05",
       "markers": [
        "cve_fix",
        "restrict_automerge"
       ]
      }
     ],
     "tags": [
      "android-security-16.0.0_r9"
     ],
     "tag": "android-security-16.0.0_r9"
    }
   ],
   "coverage": {
    "n_ingested_tags": 9,
    "first_ingested_tag": "android-security-16.0.0_r1",
    "latest_ingested_tag": "android-security-16.0.0_r9",
    "window_base_tag": "android-16.0.0_r2",
    "window_start": "2025-06-10",
    "partial_tags": []
   },
   "platform_update_tags": {},
   "briefs": {
    "CVE-2026-49933": {
     "cve": "CVE-2026-49933",
     "summary": "Default-initializes MsftExtensionManager::impl::scanning_callbacks_ to nullptr and adds a null check in handle_le_monitor_device_event, so a MSFT LE monitor device vendor event received before the scanning callbacks are registered is dropped instead of invoking a virtual method through an indeterminate pointer.",
     "component": "platform/packages/modules/Bluetooth, system/gd/hci (GD HCI layer, MsftExtensionManager / Microsoft vendor extension)",
     "weakness": "Uninitialized pointer dereference (use of an uninitialized raw pointer member in an initialization race; CWE-824 class)",
     "root_cause": "In system/gd/hci/msft.cc the member `ScanningCallback* scanning_callbacks_` of `struct MsftExtensionManager::impl` was declared without an initializer, so it held an indeterminate value until it was set later. `handle_le_monitor_device_event` called `scanning_callbacks_->OnTrackAdvFoundLost(...)` with no null check whenever the event's monitor state was 0x00 or 0x01. Per the commit message, a controller that sends an MSFT_LE_MONITOR_DEVICE_EVENT during stack bring-up triggers a virtual call through the uninitialized pointer. The commit message says this could lead to control-flow hijack or denial of service in the privileged bluetooth process.",
     "fix_analysis": [
      "system/gd/hci/msft.cc, struct MsftExtensionManager::impl member list: `ScanningCallback* scanning_callbacks_;` becomes `ScanningCallback* scanning_callbacks_{nullptr};`, so the pointer has a defined null value until registration.",
      "system/gd/hci/msft.cc, MsftExtensionManager::impl::handle_le_monitor_device_event: after the existing `log::assert_that(view.IsValid(), ...)`, a new early return `if (scanning_callbacks_ == nullptr) { log::warn(\"scanning_callbacks_ is null, dropping Microsoft vendor event.\"); return; }` is added before any use of the pointer.",
      "Same function: the monitor-state check is inverted into an early return (`if (state != 0x00 && state != 0x01) { warn; return; }`). The AdvertisingFilterOnFoundOnLostInfo population and the `scanning_callbacks_->OnTrackAdvFoundLost(on_found_on_lost_info)` call move to straight-line code after both guards. The accepted states (0x00, 0x01) are unchanged. Because the null check comes first, an event with an invalid state that arrives while the pointer is null now logs the null warning instead of the invalid-state warning."
     ],
     "completeness": [
      "Covers the only dereference of scanning_callbacks_ visible in the diff (handle_le_monitor_device_event). Both the declaration and the use site are fixed.",
      "The fix is a null guard only. It does not change when or how scanning_callbacks_ is registered, and it does not gate event handling on bring-up having completed. The registration path is not shown in the material.",
      "Other impl members visible in the Android 16 diff context (msft_adv_monitor_add_cb_, msft_adv_monitor_remove_cb_, msft_adv_monitor_enable_cb_) are not touched. Their types and initialization state are not shown, so the material does not show whether they need similar treatment.",
      "handle_rssi_event is a stub that only logs and is unaffected."
     ],
     "behavior_changes": [
      "A MSFT_LE_MONITOR_DEVICE_EVENT that arrives while no ScanningCallback is registered is now dropped and the warning \"scanning_callbacks_ is null, dropping Microsoft vendor event.\" is logged. The event is not delivered.",
      "Accepted monitor states and the payload passed to OnTrackAdvFoundLost are unchanged. The invalid-state warning text is unchanged."
     ],
     "preconditions": [
      "The controller must report MSFT extension support (hal_->getMsftOpcode() != 0 in impl's initialization code, per the code context) so the manager proceeds past initialization.",
      "A vendor-specific HCI event must reach handle_msft_events with a payload whose prefix matches msft_.prefix and whose subevent dispatches to handle_le_monitor_device_event. Dispatch details beyond the prefix loop are not shown.",
      "The event must arrive before scanning_callbacks_ is set. The commit message describes this as a bring-up race triggered by a compromised Bluetooth controller.",
      "The code runs inside the privileged bluetooth process (per the commit message)."
     ],
     "per_major": {
      "14": "Not listed by the bulletin (not affected per the bulletin). At android-security-14.0.0_r30, 7/8 lines of the patched region are present. This ratio alone does not show whether the fix is present. The material includes no fix commit for 14.",
      "15": "Not listed by the bulletin (not affected per the bulletin). At android-security-15.0.0_r18, 8/8 lines of the patched region are present. This ratio alone does not show whether the fix is present. The material includes no fix commit for 15.",
      "16": "Same fix: commit 3d959c922924 in android-security-16.0.0_r8 (cherry-pick of d6505b430477, Change-Id I044a3cf62559a9e758c4d0f5d89525ae4574c57f). It modifies only system/gd/hci/msft.cc (+16/-9). At android-security-16.0.0_r9, 7/8 lines of the patched region are present, and the code context there shows the fixed function.",
      "17": "Same fix: commit 1af205db6af0 in android-security-17.0.0_r1 with an identical function body change. Only hunk offsets and the surrounding member list differ. On 17 the member declaration follows hal_, hci_layer_ and msft_ at about line 347. On 16 it follows the msft_adv_monitor_*_cb_ members at about line 318. At android-security-17.0.0_r2, 7/8 lines are present."
     },
     "backport_notes": [
      "Single-file, self-contained change with no new dependencies. When applying it to a tree with a different impl member layout (as between 16 and 17), only the member-declaration hunk needs relocation. The Bluetooth stack ships as a mainline module, so updates can reach devices via module updates independent of the platform tag (general platform knowledge)."
     ],
     "confidence": "high",
     "unknowns": [
      "Where and when scanning_callbacks_ is set (the registration function is not in the material), and whether the registration order relative to MsftExtensionManager start is adjusted elsewhere.",
      "Whether the 16-qpr2 branch listed as affected received this change (no commit for it is included).",
      "Types and initialization of the neighboring msft_adv_monitor_*_cb_ members, and whether a premature event can reach them.",
      "Whether Android 14/15 contain the vulnerable or the fixed code. The partial line-match ratios do not settle this, and the bulletin does not list them.",
      "Whether handle_msft_events can run before msft_.prefix is populated. The material shows the prefix loop but not where prefix is set or when the event handler is registered.",
      "Whether a regression test accompanies the change (the commit says only 'built and atest locally')."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 7,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-55269": {
     "cve": "CVE-2026-55269",
     "summary": "Corrects an inverted size guard in SnoopLogger::FilterCapturedPacket. Short HCI ACL packets are now padded by EXTRA_BUF_SIZE before profile filtering writes the fixed \"PROHIBITED\" magic string into the packet buffer. The fix also clamps the output length to packet.size() + PACKET_TYPE_LENGTH.",
     "component": "platform/packages/modules/Bluetooth, system/gd/hal SnoopLogger (btsnoop filtered logging)",
     "weakness": "Heap out-of-bounds write caused by an inverted bounds/resize condition (buffer not enlarged before a fixed-size overwrite)",
     "root_cause": "In system/gd/hal/snoop_logger.cc, SnoopLogger::FilterCapturedPacket is meant to grow the captured HciPacket by EXTRA_BUF_SIZE when the PBAP or MAP profile filter is enabled. That padding gives FilterProfiles (and SnoopLogger::PayloadStrip, per the commit message) room to write the fixed magic string \"PROHIBITED\" over the payload. The guard was written as `packet.size() + EXTRA_BUF_SIZE > DEFAULT_PACKET_SIZE`, the opposite of the intent: only large packets were resized, and small packets (for example an 8-byte ACL packet) kept their original size. Per the commit message, the magic-string write then went past the end of the heap-allocated buffer.",
     "fix_analysis": [
      "system/gd/hal/snoop_logger.cc:SnoopLogger::FilterCapturedPacket: the resize guard changes from `packet.size() + EXTRA_BUF_SIZE > DEFAULT_PACKET_SIZE` to `packet.size() + EXTRA_BUF_SIZE <= DEFAULT_PACKET_SIZE`. Packets that still fit within DEFAULT_PACKET_SIZE after padding are now resized by EXTRA_BUF_SIZE before FilterProfiles is called on packet.data(), which gives the magic-string overwrite enough backing storage.",
      "system/gd/hal/snoop_logger.cc:SnoopLogger::FilterCapturedPacket: a new final statement `length = std::min(length, static_cast<uint32_t>(packet.size() + PACKET_TYPE_LENGTH));` caps the output length at the packet buffer size plus the packet type byte, on every path that reaches the end of the function. The early-return paths (A2DP media, and FilterProfiles returning 0) skip the clamp and leave length at 0. The commit message does not mention the clamp, and the material does not show how the caller uses length.",
      "system/gd/hal/snoop_logger_test.cc: two 8-byte ACL test packets (incoming CID 0x0041, outgoing CID 0x0040) are appended to kTestData. profiles_filtered_pbap_magic_test, profiles_filtered_pbap_header_test and profiles_filtered_pbap_fullfilter_test now create the logger with 20 instead of 15 as the first NewSnoopLogger argument, most likely to make room for the extra packets."
     ],
     "completeness": [
      "Covers the only resize site in FilterCapturedPacket that feeds FilterProfiles. The inverted guard is corrected, and a length clamp is added at the end of the function; paths that return early with length 0 do not reach it.",
      "Packets for which `packet.size() + EXTRA_BUF_SIZE > DEFAULT_PACKET_SIZE` are still not resized, so the fix relies on such packets already being large enough for the magic string. The material does not show FilterProfiles or PayloadStrip gaining their own bounds checks, so safety depends on EXTRA_BUF_SIZE being at least the length of \"PROHIBITED\".",
      "The function still modifies the packet copy (the TODO b/335520123 in Capture about stopping this remains); the fix does not restructure that.",
      "The short-packet case is tested only through the PBAP filter tests; the diff adds no MAP-specific short-packet test."
     ],
     "behavior_changes": [
      "Small ACL packets processed under PBAP/MAP filtering are now grown by EXTRA_BUF_SIZE. Large packets near DEFAULT_PACKET_SIZE are no longer grown (the inverted guard used to grow only those).",
      "For filtered ACL packets that reach the end of FilterCapturedPacket, the output length is now capped at packet.size() + PACKET_TYPE_LENGTH.",
      "In the PBAP filter unit tests, the first NewSnoopLogger argument changes from 15 to 20."
     ],
     "preconditions": [
      "btsnoop_mode_ == kBtSnoopLogModeFiltered (filtered snoop logging enabled through Developer Options, per the commit message) and the packet type is ACL.",
      "The PBAP or MAP profile filter property (kBtSnoopLogFilterProfilePbapModeProperty / kBtSnoopLogFilterProfileMapModeProperty) is enabled; the commit message cites the \"magic\" filter mode.",
      "`length == ntohl(header.length_original)`, i.e. the headers filter has not already shortened the packet.",
      "An HCI ACL packet too short for the original buffer to hold the magic string. The commit message attributes the trigger to a malicious Bluetooth controller. SnoopLogger::Capture copies the packet into a mutable HciPacket and is listed as a caller of FilterCapturedPacket (per index search)."
     ],
     "per_major": {
      "14": "not affected per the bulletin. The per-major facts report 8/8 lines of the patched region present at android-security-14.0.0_r30; whether those lines are the pre-fix or post-fix code is not shown.",
      "15": "not affected per the bulletin. The per-major facts report 8/8 lines of the patched region present at android-security-15.0.0_r18; whether those lines are the pre-fix or post-fix code is not shown.",
      "16": "same fix: commit 6effdf3d7c13 in android-security-16.0.0_r8, cherry-picked from 0083751f4ce0 (Change-Id I3fae8e1b8af9f05970de542317bcdcc3d020bf9e). android-security-16.0.0_r9 has the corrected guard and the length clamp in place.",
      "17": "same fix: commit 62418c92b1bb in android-security-17.0.0_r1 with identical code changes. Only hunk line offsets and test fixture details differ (`auto snoop_logger`, and no Start() call in the tests)."
     },
     "backport_notes": [
      "Single self-contained commit. The two code changes (guard flip and std::min clamp) apply to any tree where FilterCapturedPacket has the `packet.size() + EXTRA_BUF_SIZE > DEFAULT_PACKET_SIZE` guard. The test hunk may need adjusting, because the 16 test fixture calls snoop_logger->Start() explicitly and the 17 fixture does not."
     ],
     "confidence": "high",
     "unknowns": [
      "The values of EXTRA_BUF_SIZE and DEFAULT_PACKET_SIZE are not shown, nor are the bodies of FilterProfiles and PayloadStrip. That EXTRA_BUF_SIZE is enough for the magic string is taken from the commit message.",
      "The material does not show how Capture uses the length output when it writes the snoop record.",
      "The per-major facts give 7/8 lines at the fixed 16 and 17 tags but 8/8 at the unlisted 14 and 15 tags. The material does not explain the difference or say whether the 14/15 code is pre-fix or post-fix.",
      "Whether the vulnerable guard exists in the 14 and 15 branches is not shown."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 6,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-55280": {
     "cve": "CVE-2026-55280",
     "summary": "Zero-initializes the whole evt_data.activate structure in nfc_ncif_proc_activate() and clamps the NFCID1 and Kovio UID length fields in nfa_dm_notify_activation_status(). The goal is that a short or malformed RF_INTF_ACTIVATED_NTF from the NFCC can no longer feed uninitialized or oversized length values into a memcpy in the NFC process.",
     "component": "platform/packages/modules/Nfc, libnfc-nci (NCI interface layer nfc_ncif.cc and NFA device manager nfa_dm_act.cc)",
     "weakness": "Use of uninitialized stack memory as a copy length, combined with a missing bounds check, leading to an out-of-bounds write",
     "root_cause": "In libnfc-nci/src/nfc/nfc/nfc_ncif.cc, nfc_ncif_proc_activate() declares a stack tNFC_DISCOVER evt_data but cleared only the intf_param sub-structure (memset(p_intf, 0, sizeof(tNFC_INTF_PARAMS))). The rf_tech_param union inside evt_data.activate stayed uninitialized. If the RF_INTF_ACTIVATED_NTF is too short (plen < 7, or plen < *p + 4), the function jumps to invalid_packet before nfc_ncif_decode_rf_params() fills rf_tech_param. Per the unit test ProcActivateInvalidPacketLength (per index search), the discovery callback is still called in that case with NFC_ACTIVATE_DEVT and NCI_STATUS_FAILED. Per the commit message, this uninitialized data is later used as a memcpy length and causes an out-of-bounds write in the NFC process. The fix also adds checks in nfa_dm_notify_activation_status() (libnfc-nci/src/nfa/dm/nfa_dm_act.cc), which reads the activation notification copied from nfa_dm_cb.p_activate_ntf (per index search). Before the fix, that function used the length fields nfcid1_len (POLL_A) and pk.uid_len (POLL_KOVIO) without bounds checks.",
     "fix_analysis": [
      "libnfc-nci/src/nfc/nfc/nfc_ncif.cc:nfc_ncif_proc_activate(): memset(p_intf, 0, sizeof(tNFC_INTF_PARAMS)) is replaced by memset(&evt_data.activate, 0, sizeof(evt_data.activate)), which runs before any length validation. On early-exit paths, every activate field that has not been parsed yet, including the rf_tech_param union, is now zero instead of indeterminate stack data.",
      "libnfc-nci/src/nfa/dm/nfa_dm_act.cc:nfa_dm_notify_activation_status(): in the NFC_DISCOVERY_TYPE_POLL_A else-branch, after nfcid_len = p_tech_params->param.pa.nfcid1_len, a new check clamps nfcid_len to NCI_NFCID1_MAX_LEN. It writes the clamped value back into p_tech_params->param.pa.nfcid1_len and logs android_errorWriteLog(0x534e4554, \"522373576\").",
      "libnfc-nci/src/nfa/dm/nfa_dm_act.cc:nfa_dm_notify_activation_status(): in the NFC_DISCOVERY_TYPE_POLL_KOVIO branch, the same pattern clamps nfcid_len = p_tech_params->param.pk.uid_len to NFC_KOVIO_MAX_LEN, writes it back into pk.uid_len, and logs the same SafetyNet event.",
      "libnfc-nci/src/nfa/dm/nfa_dm_act.cc: adds #include <log/log.h> for android_errorWriteLog."
     ],
     "completeness": [
      "The memset runs at function entry, so on every invalid_packet exit, the activate fields not yet parsed are zero. Fields already parsed keep their values: on the plen < *p + 4 path, rf_disc_id, intf type, protocol and mode are already set.",
      "The clamp in nfa_dm_notify_activation_status() does not depend on the memset. It bounds nfcid1_len and uid_len whatever the source of the value is.",
      "Only the POLL_A (nfcid1) and POLL_KOVIO (uid) length fields are clamped. The POLL_B and ISO15693 (pi93.uid) branches in the same function are not modified. The material does not show how their nfcid_len values are derived.",
      "The first (if) branch of the POLL_A case, which passes p_nfcid and nfcid_len to another call, is not modified. The material does not show where its length comes from.",
      "The fix adds no validation inside nfc_ncif_decode_rf_params(). The material does not show whether that function bounds the nfcid1_len and uid_len values it parses."
     ],
     "behavior_changes": [
      "On a short RF_INTF_ACTIVATED_NTF, the NFC_ACTIVATE_DEVT callback now receives zeros instead of indeterminate values in every activate field not yet parsed. On the plen < 7 path that includes rf_disc_id, protocol and rf_tech_param. The status is still NCI_STATUS_FAILED.",
      "An nfcid1_len above NCI_NFCID1_MAX_LEN, or a Kovio uid_len above NFC_KOVIO_MAX_LEN, is truncated to the maximum. The truncated length is written back into the tech parameters, and a SafetyNet log entry (tag 0x534e4554, id 522373576) is emitted.",
      "The diff adds no new error return. The clamped length replaces the original value."
     ],
     "preconditions": [
      "The NFCC (controller, or the NFC HAL path that feeds NCI packets to libnfc-nci) must deliver an RF_INTF_ACTIVATED_NTF that is either truncated (so nfc_ncif_proc_activate() exits through invalid_packet) or carries an out-of-range NFCID1 or Kovio UID length.",
      "nfa_dm_notify_activation_status() acts only when nfa_dm_cb.p_activate_ntf is set and status is NFA_STATUS_OK (per index search). nfa_dm_poll_disc_cback holds the activation notification on NFA_DM_RF_DISC_ACTIVATED_EVT (per index search).",
      "The affected code runs inside the NFC process that hosts libnfc-nci (per the commit message)."
     ],
     "per_major": {
      "14": "Not affected per the bulletin. platform/packages/modules/Nfc is not present at android-security-14.0.0_r30.",
      "15": "Not affected per the bulletin. platform/packages/modules/Nfc is not present at android-security-15.0.0_r18.",
      "16": "Same fix: commit d6cb6aefb127 in android-security-16.0.0_r8 (cherry-pick of f974b0fee85f, Change-Id Iedd07da2dd238a27550c8d8bdfa9ab8d4cd1050f). At android-security-16.0.0_r9, all 8/8 lines of the patched region are present.",
      "17": "Same fix: commit 897466771c24 in android-security-17.0.0_r1, with the same changes and only different line offsets (nfa_dm_act.cc hunks at 1712/1725 instead of 1707/1720, nfc_ncif.cc hunk at 964 instead of 993). At android-security-17.0.0_r2, all 8/8 lines are present."
     },
     "backport_notes": [
      "Single commit with changes in two files; apply both together. The nfa_dm_act.cc hunk needs <log/log.h> (android_errorWriteLog) and needs the constants NCI_NFCID1_MAX_LEN and NFC_KOVIO_MAX_LEN to exist in the target tree."
     ],
     "confidence": "medium",
     "unknowns": [
      "The exact memcpy that performs the out-of-bounds write and its destination are not shown in the material. They are known only from the commit message.",
      "Whether a failed activation (status NCI_STATUS_FAILED) still leads to the notification being stored in nfa_dm_cb.p_activate_ntf and consumed by nfa_dm_notify_activation_status() is not shown.",
      "Whether nfc_ncif_decode_rf_params() bounds nfcid1_len and uid_len when it parses a well-formed packet is not shown.",
      "How the POLL_B and ISO15693 branches derive nfcid_len is not visible in the provided context."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 10,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58835": {
     "cve": "CVE-2026-58835",
     "summary": "In system/btif/src/btif_storage.cc cfg2prop(), the BT_PROPERTY_UUIDS / BT_PROPERTY_UUIDS_LE path now limits btif_split_uuids_string() to the caller-supplied buffer capacity (prop->len / sizeof(Uuid)) instead of the hardcoded BT_MAX_NUM_UUIDS.",
     "component": "platform/packages/modules/Bluetooth, system/btif (btif_storage, bt_config property read-back)",
     "weakness": "Missing bounds check / out-of-bounds write (buffer overflow): the parse limit was not tied to the size of the destination buffer",
     "root_cause": "cfg2prop() in system/btif/src/btif_storage.cc reads the stored remote service UUID string (BTIF_STORAGE_KEY_REMOTE_SERVICE or BTIF_STORAGE_KEY_REMOTE_SERVICE_LE) into a 1280-byte local buffer. It then parses that string with btif_split_uuids_string(value, p_uuid, BT_MAX_NUM_UUIDS), where p_uuid is prop->val. BT_MAX_NUM_UUIDS is a constant and ignores prop->len, the real capacity of the caller's bt_property_t value buffer. Sibling cases in the same switch (e.g. BT_PROPERTY_CLASS_OF_DEVICE, BT_PROPERTY_REMOTE_VERSION_INFO) check prop->len against the type size before writing. This case had no link between the write limit and the buffer size, so a stored string with more UUIDs than fit in prop->val could be written past the end of the caller's buffer. The commit message also calls this a companion to ag/40421805, whose content is not in the material.",
     "fix_analysis": [
      "system/btif/src/btif_storage.cc:cfg2prop() (cases BT_PROPERTY_UUIDS / BT_PROPERTY_UUIDS_LE): the third argument to btif_split_uuids_string() changes from BT_MAX_NUM_UUIDS to prop->len / sizeof(Uuid). The parser now writes at most as many Uuid entries as fit in the caller-provided prop->val buffer. prop->len is then set to num_uuids * sizeof(Uuid), as before.",
      "system/btif/test/btif_storage_test.cc: adds TEST(BtifStorageTest, test_uuid_split_zero_limit). It calls btif_split_uuids_string() with a limit of 0 on a two-UUID string and asserts that it returns 0 and leaves the destination array untouched. This tests btif_split_uuids_string() itself, which this commit does not modify (that behavior may come from the companion change ag/40421805, which is not shown)."
     ],
     "completeness": [
      "Covers both BT_PROPERTY_UUIDS and BT_PROPERTY_UUIDS_LE, since they share one code block in cfg2prop().",
      "The fix depends on btif_split_uuids_string() honoring the max count, including a limit of 0. The new test asserts this, but btif_split_uuids_string() is not changed in this commit, so correctness may depend on the companion change ag/40421805 (contents unknown).",
      "prop->len is compared as an int in sibling cases. The new expression prop->len / sizeof(Uuid) converts it to size_t. This case adds no explicit check that prop->len is non-negative, unlike the explicit prop->len >= sizeof(...) checks in sibling cases. The material does not show whether a negative prop->len can reach this point.",
      "The commit only addresses the read-back path (cfg2prop). Other callers of btif_split_uuids_string() are not shown in the material and are not touched by this diff."
     ],
     "behavior_changes": [
      "When the stored UUID string holds more UUIDs than fit in the caller's buffer, the result is now silently truncated to prop->len / sizeof(Uuid) entries (prop->len reports the truncated size) instead of overflowing.",
      "If the caller passes a prop->len smaller than sizeof(Uuid), zero UUIDs are returned and prop->len becomes 0, while ret is still true.",
      "No new error codes or logging in the diff."
     ],
     "preconditions": [
      "cfg2prop() is reached for a bt_property_t of type BT_PROPERTY_UUIDS or BT_PROPERTY_UUIDS_LE, for a remote device whose bt_config entry BTIF_STORAGE_KEY_REMOTE_SERVICE / BTIF_STORAGE_KEY_REMOTE_SERVICE_LE exists.",
      "The stored UUID string must contain more UUIDs than prop->len / sizeof(Uuid) (bounded by the 1280-byte value buffer and BT_MAX_NUM_UUIDS), and the caller's prop->val buffer must be smaller than BT_MAX_NUM_UUIDS * sizeof(Uuid).",
      "The material does not show how the stored UUID string is populated or which callers pass a smaller buffer (cfg2prop is static, and the index search did not surface its callers)."
     ],
     "per_major": {
      "14": "Not listed by the bulletin (not affected per the bulletin). At android-security-14.0.0_r30, 4/6 lines of the patched region are present. The material does not show which lines are missing or whether the hardcoded-limit call exists on this branch.",
      "15": "Not listed by the bulletin (not affected per the bulletin). At android-security-15.0.0_r18, 4/6 lines of the patched region are present. Which lines are missing is not shown.",
      "16": "Same fix: commit 91bef351ef64 in android-security-16.0.0_r8 (cherry-pick of 95ecd904327158fc73ed6b156502f209fc3f8f6f, Change-Id Ib6041c55f705afd9e9a8b980d7af9ba23aae2f02). Patched code confirmed at android-security-16.0.0_r9 (btif_storage.cc lines 318-319).",
      "17": "Same fix: commit 5f719e21eef1 in android-security-17.0.0_r1. The btif_storage.cc change is identical apart from the hunk offset and the enclosing function's parameter name (addr instead of remote_bd_addr). The test addition is the same apart from a trailing blank line. Present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "The commit is described as a companion to ag/40421805, which is not in the material. The added zero-limit test exercises btif_split_uuids_string() behavior that this diff does not change, so find and backport the companion change together with this one and run atest net_test_btif.",
      "The one-line change applies cleanly as long as cfg2prop() in system/btif/src/btif_storage.cc contains the call btif_split_uuids_string(value, p_uuid, BT_MAX_NUM_UUIDS). Differences in the function's parameter names (remote_bd_addr vs addr) do not matter."
     ],
     "confidence": "high",
     "unknowns": [
      "Content of the companion change ag/40421805, and whether it modifies btif_split_uuids_string() (the new test suggests limit-0 handling depends on it).",
      "Which callers of cfg2prop() (via btif_storage) pass a prop->val buffer smaller than BT_MAX_NUM_UUIDS * sizeof(Uuid), and how the stored UUID string reaches bt_config.",
      "Whether the vulnerable call exists on the Android 14/15 branches even though the bulletin does not list them (the per-major facts only show partial region presence).",
      "Whether prop->len can be negative at this call site."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58865": {
     "cve": "CVE-2026-58865",
     "summary": "Adds a bounds check on the well-known content-type index in PduParser.parseContentType and null checks on the parameter map and parsed charset string in PduParser.parseContentTypeParams so a malformed MMS PDU no longer throws ArrayIndexOutOfBoundsException or NullPointerException during parsing.",
     "component": "platform/frameworks/base, telephony/common MMS PDU parser (com.google.android.mms.pdu.PduParser)",
     "weakness": "Missing bounds check on an attacker-controlled array index plus missing null checks (uncaught ArrayIndexOutOfBoundsException / NullPointerException leading to DoS)",
     "root_cause": "In telephony/common/com/google/android/mms/pdu/PduParser.java, parseContentType handled the Short-integer (well-known) encoding by indexing PduContentTypes.contentTypes directly with the value returned by parseShortInteger (0-127 per the added comment). The table has fewer entries (the comment states 0-82), so an out-of-range index threw ArrayIndexOutOfBoundsException. In parseContentTypeParams, the P_TYPE/P_CT_MR_TYPE Short-integer branch and the P_CHARSET Text-String (extension-charset) branch called map.put without checking that map is non-null (the added test notes that ELEMENT_DESCRIPTOR parsing passes a null map). The charset branch also called new String(charsetStr) without checking charsetStr, the value returned by parseWapString, for null (the fix adds that guard, and the matching test uses an empty charset string). The result was a NullPointerException. These uncaught exceptions occur while parsing externally supplied PDU bytes.",
     "fix_analysis": [
      "PduParser.java:parseContentType (hunk at ~line 1620): the Short-integer path now stores parseShortInteger(pduDataStream) in a local index and only indexes PduContentTypes.contentTypes when index < PduContentTypes.contentTypes.length; otherwise it falls back to PduContentTypes.contentTypes[0] (\"*/*\") instead of throwing.",
      "PduParser.java:parseContentTypeParams, case PduPart.P_TYPE / P_CT_MR_TYPE (~line 1431): inside the existing index bounds check, map.put(PduPart.P_TYPE, type) is now wrapped in if (map != null), matching the null guard already present in the Text-String (extension-media) branch.",
      "PduParser.java:parseContentTypeParams, P_CHARSET Text-String branch (~line 1494): the try/catch that calls CharacterSets.getMibEnumValue(new String(charsetStr)) and map.put(PduPart.P_CHARSET, ...) is now wrapped in if (charsetStr != null && map != null); the UnsupportedEncodingException fallback to CharacterSets.ANY_CHARSET is unchanged inside the guard.",
      "tests/TelephonyCommonTests/src/com/google/android/mms/pdu/PduParserTest.java (new): adds tests for an out-of-range content-type index (0xD3, index 83), an ELEMENT_DESCRIPTOR with a P_TYPE parameter (null map), an empty charset string, plus two OOM tests (huge part header length and uintvar underflow) that exercise code not changed by this diff."
     ],
     "completeness": [
      "Covers the only unguarded table lookup in parseContentType's Short-integer path, and two null dereferences in parseContentTypeParams (P_TYPE Short-integer map.put, and P_CHARSET extension-charset charsetStr/map).",
      "The P_TYPE Text-String branch already checked (null != type) && (null != map) and is unchanged.",
      "The Well-known-charset branch of P_CHARSET and the other parameter cases in parseContentTypeParams (e.g. the start parameter case following P_TYPE) are not shown in the material, so whether they guard map against null cannot be judged from the diff.",
      "The new test file includes testParse_malformedHugeHeaderLength_doesNotOOM and testPduParserUnderflowOOM, but this diff makes no change to length/uintvar handling; whether those conditions are addressed by other commits is not shown."
     ],
     "behavior_changes": [
      "A well-known content-type index outside the PduContentTypes.contentTypes table in parseContentType now resolves to \"*/*\" (index 0) instead of throwing ArrayIndexOutOfBoundsException.",
      "A P_TYPE/P_CT_MR_TYPE Short-integer parameter encountered while map is null is now silently ignored.",
      "An extension-charset parameter whose parsed string is null, or encountered while map is null, is now silently skipped (no P_CHARSET entry set, no exception)."
     ],
     "preconditions": [
      "Malformed MMS PDU bytes reach PduParser.parse() (the tests construct a PduParser(byte[], boolean) over a Send-Req PDU and call parse()).",
      "For the AIOOBE: a Content-Type encoded as a Short-integer whose value is >= PduContentTypes.contentTypes.length (the test uses 0xD3, index 83).",
      "For the NPEs: a content-type parameter list parsed with a null map (test comment: ELEMENT_DESCRIPTOR passes null map) containing a Short-integer P_TYPE parameter, or a P_CHARSET parameter encoded as a Text-String for which parseWapString yields null (the test uses an empty string).",
      "PduParser in telephony/common is the MMS PDU decoder used by messaging/MMS components that receive PDUs from the network (general platform knowledge)."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/base 53f75b4de647 in android-security-14.0.0_r30, identical hunks to the Android 16 commit (only the file mode, 100755, differs); 8/8 patched lines present.",
      "15": "same fix: platform/frameworks/base 51268a5c0ff9 in android-security-15.0.0_r18, identical hunks; 8/8 patched lines present.",
      "16": "same fix: platform/frameworks/base 60f9d9a0bcac in android-security-16.0.0_r9 (cherry-pick of cbb0d81bf086, Change-Id I4fab1579d22c4a1dcf2d75d4f4aab0a352df1bd9); 8/8 patched lines present.",
      "17": "same fix: platform/frameworks/base 05fef2f15699 in android-security-17.0.0_r2, identical hunks against a slightly different base blob (e805089306dc); 8/8 patched lines present."
     },
     "backport_notes": [
      "Single self-contained commit; the PduParser.java hunks applied identically on 14 through 17, so the patch should apply cleanly to any tree with the same parseContentType / parseContentTypeParams structure. The new PduParserTest.java requires the tests/TelephonyCommonTests module to exist in the target tree; it can be dropped if that test target is absent."
     ],
     "confidence": "high",
     "unknowns": [
      "Which process crashes (which component invokes PduParser on received PDUs) is not shown in the material.",
      "Whether the OOM conditions exercised by the two added OOM tests are fixed by separate commits.",
      "Whether other parameter cases in parseContentTypeParams not shown in the diff also dereference a possibly-null map.",
      "Under which inputs parseWapString returns null (its implementation is not shown)."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 1,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58880": {
     "cve": "CVE-2026-58880",
     "summary": "Removes the num_ext_attr/ext_attrs parameters from the AVRCP controller playerapplicationsetting_cb HAL callback, so the callback no longer carries a pointer to ext_attrs data that handle_app_attr_val_txt_response frees. It also makes that free (cleanup_app_attr_val_txt_response) synchronous instead of posting it to the JNI thread.",
     "component": "platform/packages/modules/Bluetooth, system/btif AVRCP controller (btif_rc.cc, bt_rc.h HAL interface, com_android_bluetooth_avrcp_controller.cpp JNI)",
     "weakness": "Use-after-free (pointer to freed ext_attrs data passed to an asynchronous callback)",
     "root_cause": "In system/btif/src/btif_rc.cc, the final branch of handle_app_attr_val_txt_response (reached after all extended attribute value texts were received) bound bt_rc_ctrl_callbacks->playerapplicationsetting_cb with the raw pointers p_app_settings->attrs and p_app_settings->ext_attrs. On Android 16 it posted the callback to the JNI thread with do_in_jni_thread; on Android 17 it dispatched it through the CTRL_HAL_CBACK macro. It also arranged for cleanup_app_attr_val_txt_response(p_app_settings) to free memory held inside the ext_attrs structure. Per the commit message, the callback runs asynchronously on the JNI thread while the calling thread frees the ext_attrs memory, so the callback can see a dangling ext_attrs pointer. The JNI implementation btavrcp_playerapplicationsetting_callback never used num_ext_attr/ext_attrs: both are commented out, next to a \"TODO ext attrs\" note.",
     "fix_analysis": [
      "system/include/hardware/bt_rc.h: the btrc_ctrl_playerapplicationsetting_callback typedef drops the uint8_t num_ext_attr and btrc_player_app_ext_attr_t* ext_attrs parameters. The HAL callback now takes only (bd_addr, num_attr, app_attrs).",
      "system/btif/src/btif_rc.cc: all four call sites are updated. handle_app_val_response, handle_app_attr_txt_response and the first branch of handle_app_attr_val_txt_response used to pass (0, nullptr) and now pass only (rc_addr, num_attrs, attrs). The final branch of handle_app_attr_val_txt_response used to pass p_app_settings->num_ext_attrs and p_app_settings->ext_attrs and now passes only attrs, so the callback no longer receives an ext_attrs pointer.",
      "system/btif/src/btif_rc.cc:handle_app_attr_val_txt_response: the deferred do_in_jni_thread(base::BindOnce(cleanup_app_attr_val_txt_response, p_app_settings)) is replaced by a direct synchronous call to cleanup_app_attr_val_txt_response(p_app_settings). As before, p_app_settings->num_attrs = 0 follows.",
      "android/app/jni/com_android_bluetooth_avrcp_controller.cpp:btavrcp_playerapplicationsetting_callback: the signature is reduced to (bd_addr, num_attr, app_attrs) to match the new typedef. The body is unchanged and only flattens app_attrs.",
      "system/btif/test/btif_rc_test.cc: callback lambdas are updated to the new signature. The btif_transfer_context test stub now copies parameters (through p_copy_cback when provided) and calls p_cback directly. On Android 17, more per-test lambdas are updated, and one assertion in btif_rc_transaction_timer_timeout_passthru flips from ASSERT_TRUE to ASSERT_FALSE on transaction_set.transaction[1].in_use."
     ],
     "completeness": [
      "Covers every caller of playerapplicationsetting_cb in btif_rc.cc (four sites), because the HAL typedef change forces all of them to change. The JNI callback is also updated. The compiler now rejects any call site that still passes ext_attrs.",
      "The callback still receives a raw pointer to p_app_settings->attrs (part of p_dev->rc_app_settings). The material shows neither the definition of btif_rc_player_app_settings_t nor what cleanup_app_attr_val_txt_response frees. So the diff cannot confirm that attrs stays valid while the JNI task is pending, now that cleanup runs synchronously. The fix assumes attrs remains valid and that only ext_attrs memory was freed.",
      "The extended attribute data is now dropped at the HAL boundary. No replacement path delivers ext_attrs to Java (the JNI side never consumed it)."
     ],
     "behavior_changes": [
      "HAL/JNI interface change: btrc_ctrl_playerapplicationsetting_callback takes three parameters instead of five. Any out-of-tree implementation of this callback must be updated or it will fail to compile.",
      "cleanup_app_attr_val_txt_response now runs synchronously on the thread handling the AVRCP response instead of being queued on the JNI thread.",
      "Test-only: the btif_transfer_context stub now calls p_cback directly. On Android 17, one assertion in btif_rc_transaction_timer_timeout_passthru was flipped from ASSERT_TRUE to ASSERT_FALSE."
     ],
     "preconditions": [
      "The device acts as an AVRCP controller (bt_rc_ctrl_callbacks registered) and is connected to a remote AVRCP target.",
      "The remote target reports extended player application setting attributes, so num_ext_attrs > 0 and the flow reaches the final branch of handle_app_attr_val_txt_response.",
      "The JNI callback runs asynchronously relative to the thread processing the response (do_in_jni_thread on Android 16, per the code and the commit message)."
     ],
     "per_major": {
      "14": "Not listed by the bulletin (not affected per the bulletin). The resolver finds 4/8 lines of the patched region at android-security-14.0.0_r30. No fix commit is linked for this branch.",
      "15": "Not listed by the bulletin (not affected per the bulletin). The resolver finds 6/8 lines of the patched region at android-security-15.0.0_r18. No fix commit is linked for this branch.",
      "16": "Same fix: af2fe681d88d in android-security-16.0.0_r9, a cherry-pick of 3e7ec1e85fec (Change-Id Ib2f73a3bed18eeb835404073d3fc2ae1ef746aa1). Call sites use do_in_jni_thread(base::BindOnce(...)).",
      "17": "Adapted fix: df3b47977847 in android-security-17.0.0_r2. Same subject and same logic, but call sites use the CTRL_HAL_CBACK macro, btif_transfer_context returns BtStatus, more test lambdas are updated, and one test assertion is flipped."
     },
     "backport_notes": [
      "Single commit, but it changes the HAL typedef in system/include/hardware/bt_rc.h. All implementations and call sites of playerapplicationsetting_cb (btif_rc.cc, the JNI file, the tests, and any vendor or fork implementations) must change together. On branches whose call sites use do_in_jni_thread rather than CTRL_HAL_CBACK, the Android 16 variant applies more directly."
     ],
     "confidence": "medium",
     "unknowns": [
      "The definition of btif_rc_player_app_settings_t and the body of cleanup_app_attr_val_txt_response are not shown, so exactly which allocations are freed (ext_attrs text strings or the array) is not visible.",
      "Before the fix on Android 16, both the callback and the cleanup were posted to the JNI thread, callback first. Why that ordering still led to a use-after-free is explained only by the commit message, not by code in the material.",
      "Whether CTRL_HAL_CBACK (Android 17) dispatches synchronously or asynchronously is not shown.",
      "Whether p_app_settings->attrs can be modified by later responses before the posted JNI task runs is not shown.",
      "Whether Android 14/15 contain the pre-fix pattern in a reachable form. The bulletin does not list them."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 6,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-28667": {
     "cve": "CVE-2026-28667",
     "summary": "Adds a response-length check (length < p_i93->block_size) before three rw_i93_send_cmd_write_single_block calls in rw_t5t.cc. A T5T tag response shorter than a block can no longer cause stale GKI buffer slack to be sent in an outgoing WRITE_SINGLE_BLOCK command.",
     "component": "platform/packages/modules/Nfc (Android 16/17) and platform/system/nfc (Android 14/15), libnfc-nci NFC Type 5 tag (ISO 15693) reader/writer state machine, rw_t5t.cc",
     "weakness": "Missing bounds (length) check: stale buffer contents past the received data copied into an RF command (information disclosure)",
     "root_cause": "rw_t5t_sm_update_ndef and rw_t5t_sm_set_read_only prepare a block in the buffer p and pass it to rw_i93_send_cmd_write_single_block. Nothing checked that the response length (length) was at least p_i93->block_size before the send. The existing check in the update_ndef fill loop (xx > length, logged as 122320256) only guards the in-place writes, not the later send. Per the commit message, this let stale GKI buffer slack be copied into outgoing WRITE_SINGLE_BLOCK commands sent over RF.",
     "fix_analysis": [
      "libnfc-nci/src/nfc/tags/rw_t5t.cc:rw_t5t_sm_update_ndef (the substate before RW_I93_SUBSTATE_WRITE_NDEF, where block_number = (ndef_tlv_start_offset + 1) / block_size): adds `if (length < p_i93->block_size)` before rw_i93_send_cmd_write_single_block(block_number, p). When true, it logs android_errorWriteLog(0x534e4554, \"508389908\") and calls rw_i93_handle_error(NFC_STATUS_FAILED). The send and the rw_offset/sub_state updates move into the else-if branch.",
      "libnfc-nci/src/nfc/tags/rw_t5t.cc:rw_t5t_sm_update_ndef (a later substate around line 752, where block_number = rw_offset / block_size; the substate is not shown in the context): adds the same length < block_size guard before rw_i93_send_cmd_write_single_block(block_number, p).",
      "libnfc-nci/src/nfc/tags/rw_t5t.cc:rw_t5t_sm_set_read_only: after *(p + 1) |= I93_ICODE_CC_READ_ONLY, adds the same guard before rw_i93_send_cmd_write_single_block(0, p). The transition to RW_I93_SUBSTATE_WAIT_UPDATE_CC now happens only in the else-if branch.",
      "The commit message says these checks are ports of the bounds checks from b/143109193, b/143155861 and b/143106535 that were missing in rw_t5t.cc."
     ],
     "completeness": [
      "Covers all three rw_i93_send_cmd_write_single_block call sites in the rw_t5t.cc diff (two in rw_t5t_sm_update_ndef, one in rw_t5t_sm_set_read_only), each with the same length-vs-block_size check.",
      "The check comes right before the send. In rw_t5t_sm_set_read_only, the in-place write *(p + 1) |= I93_ICODE_CC_READ_ONLY still happens before the length check. The material shows no issue with that write.",
      "Only rw_t5t.cc is changed. The material does not show whether other callers of rw_i93_send_cmd_write_single_block in the same library already have equivalent checks."
     ],
     "behavior_changes": [
      "During an NDEF update or set-read-only, a T5T tag response shorter than p_i93->block_size now aborts the operation via rw_i93_handle_error(NFC_STATUS_FAILED). No WRITE_SINGLE_BLOCK command is sent.",
      "An android_errorWriteLog(0x534e4554, \"508389908\") entry is written when the condition is hit.",
      "No change for tags whose responses are at least block_size long."
     ],
     "preconditions": [
      "The device is in NFC reader/writer mode with a Type 5 (ISO 15693) tag, and an NDEF write (rw_t5t_sm_update_ndef) or set-read-only (rw_t5t_sm_set_read_only) operation is in progress.",
      "The tag returns a response whose length is smaller than p_i93->block_size.",
      "The attack surface is the RF interface. The material indicates no app-side privilege."
     ],
     "per_major": {
      "14": "same fix, applied to platform/system/nfc src/nfc/tags/rw_t5t.cc as commit f3a70c2a9415 (android-security-14.0.0_r29). Same three hunks at different line offsets (550/728/810). 8/8 patched lines present at android-security-14.0.0_r30.",
      "15": "same fix, applied to platform/system/nfc src/nfc/tags/rw_t5t.cc as commit 620bfc1582b9 (android-security-15.0.0_r17). Identical hunks. 8/8 patched lines present at android-security-15.0.0_r18.",
      "16": "same fix, applied to platform/packages/modules/Nfc libnfc-nci/src/nfc/tags/rw_t5t.cc as commit 144b34ba8906 (android-security-16.0.0_r8), cherry-picked from 5fdacfff0f15. 8/8 patched lines present at android-security-16.0.0_r9.",
      "17": "same fix, applied to platform/packages/modules/Nfc libnfc-nci/src/nfc/tags/rw_t5t.cc as commit 2ad8845ad77e (android-security-17.0.0_r1). Identical hunks. 8/8 patched lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Single self-contained commit. The file is src/nfc/tags/rw_t5t.cc in platform/system/nfc for Android 14/15 and libnfc-nci/src/nfc/tags/rw_t5t.cc in platform/packages/modules/Nfc for 16/17. All three hunks use only `length` and `p_i93`, which are already in scope at each call site in every branch's diff."
     ],
     "confidence": "high",
     "unknowns": [
      "How `length` and `p` are derived from p_resp in these functions is not shown. Only the existing xx > length check uses `length` in the visible context.",
      "How many bytes rw_i93_send_cmd_write_single_block copies from p is not shown in the material.",
      "The substate containing the second rw_t5t_sm_update_ndef hunk is not shown in the context.",
      "Whether other rw_i93_send_cmd_write_single_block callers (e.g. in rw_i93.cc) already have the checks from b/143109193, b/143155861 and b/143106535 is not shown.",
      "What the disclosed stale GKI buffer slack contains is not described beyond the commit message."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-45513": {
     "cve": "CVE-2026-45513",
     "summary": "Adds a length check in nfc_main_hal_data_cback so that an incoming NFC HAL packet larger than the fixed-size NFC_NCI_POOL_ID GKI buffer (minus NFC_HDR and NFC_RECEIVE_MSGS_OFFSET) is logged and dropped instead of being placed into the pool buffer.",
     "component": "platform/packages/modules/Nfc (Android 16/17) and platform/system/nfc (Android 14/15), libnfc-nci NCI transport layer (nfc_main.cc)",
     "weakness": "Missing bounds check (potential buffer overflow of a fixed-size GKI pool buffer)",
     "root_cause": "In nfc_main_hal_data_cback (libnfc-nci/src/nfc/nfc/nfc_main.cc), the non-dynamic allocation path (the #else branch) gets a fixed-size buffer with GKI_getpoolbuf(NFC_NCI_POOL_ID) whatever the HAL-supplied data_len is. The sibling path uses GKI_getbuf(sizeof(NFC_HDR) + NFC_RECEIVE_MSGS_OFFSET + data_len) and is sized exactly. The pool path never checked that data_len fits in GKI_get_pool_bufsize(NFC_NCI_POOL_ID) minus the header and receive offset. Per the commit message, an oversized HAL packet could therefore overflow the pool buffer. The copy itself comes after the hunk and is not shown.",
     "fix_analysis": [
      "libnfc-nci/src/nfc/nfc/nfc_main.cc:nfc_main_hal_data_cback: before GKI_getpoolbuf(NFC_NCI_POOL_ID), compute uint16_t max_len = GKI_get_pool_bufsize(NFC_NCI_POOL_ID) - sizeof(NFC_HDR) - NFC_RECEIVE_MSGS_OFFSET.",
      "If data_len > max_len, log an error via LOG(ERROR) << StringPrintf(...) with the actual and maximum sizes, emit android_errorWriteLog(0x534e4554, \"508389591\"), and return without allocating. The packet is not passed to the stack.",
      "Adds #include <log/log.h> to make android_errorWriteLog available.",
      "The GKI_getbuf path (the #if branch) is unchanged because it already allocates sizeof(NFC_HDR) + NFC_RECEIVE_MSGS_OFFSET + data_len.",
      "Note: the commit message names nfc_main_hal_read_cback, but the diff modifies nfc_main_hal_data_cback."
     ],
     "completeness": [
      "Covers only the fixed-pool allocation branch of nfc_main_hal_data_cback. This is the only place in the diff where a fixed-size buffer receives HAL-sized data.",
      "The limit is computed from GKI_get_pool_bufsize(NFC_NCI_POOL_ID), so it follows the configured pool size instead of a hardcoded value.",
      "The dynamically sized GKI_getbuf branch is unchanged and does not need the check, because its allocation already includes data_len.",
      "max_len is a uint16_t derived by subtraction. The material does not show the pool size; if the pool buffer were smaller than sizeof(NFC_HDR) + NFC_RECEIVE_MSGS_OFFSET, the subtraction would wrap. Nothing in the material suggests such a configuration exists.",
      "The compile-time macro that selects between the two branches is not shown, so the material cannot confirm whether a given build uses the vulnerable branch."
     ],
     "behavior_changes": [
      "HAL packets whose data_len exceeds the NCI pool capacity are now dropped instead of queued, so the stack no longer sees them.",
      "New LOG(ERROR) message 'dropping oversized HAL packet (N bytes > M capacity)' and a new android_errorWriteLog event tagged 0x534e4554 / 508389591 when the condition is hit.",
      "New dependency on <log/log.h> in nfc_main.cc."
     ],
     "preconditions": [
      "The build must use the GKI_getpoolbuf(NFC_NCI_POOL_ID) branch of nfc_main_hal_data_cback (the #else branch of the allocation #if). The selecting macro is not shown in the material.",
      "A packet whose data_len is larger than the pool buffer capacity minus sizeof(NFC_HDR) and NFC_RECEIVE_MSGS_OFFSET must reach the NFC stack through the NFC HAL data callback.",
      "The bulletin rates this EoP, High. The material does not show where the oversized packet comes from (HAL process, NFCC, or peer device)."
     ],
     "per_major": {
      "14": "Same fix, applied to platform/system/nfc (commit 1dfa112088a9, android-security-14.0.0_r29) in src/nfc/nfc/nfc_main.cc. Only the context differs: the include block has <base/logging.h>, and <log/log.h> is inserted after it. Resolver reports 7/7 patched-region lines present at android-security-14.0.0_r30.",
      "15": "Same fix, applied to platform/system/nfc (commit 0a716527301d, android-security-15.0.0_r17) in src/nfc/nfc/nfc_main.cc, with identical hunk content. 8/8 lines present at android-security-15.0.0_r18.",
      "16": "Fix commit 2db7814d87ba in platform/packages/modules/Nfc (android-security-16.0.0_r8) in libnfc-nci/src/nfc/nfc/nfc_main.cc, cherry-picked from internal changes f58169d22b82 and 90a7b2235d84. 8/8 lines present at android-security-16.0.0_r9.",
      "17": "Same fix, commit 79b15334596b in platform/packages/modules/Nfc (android-security-17.0.0_r1), with identical hunk content. 8/8 lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "A single self-contained hunk plus one include. The path differs by release: platform/system/nfc src/nfc/nfc/nfc_main.cc on Android 14/15, and platform/packages/modules/Nfc libnfc-nci/src/nfc/nfc/nfc_main.cc on 16/17 (libnfc-nci moved into the Nfc mainline module in later releases, general platform knowledge).",
      "Requires GKI_get_pool_bufsize, NFC_NCI_POOL_ID, NFC_RECEIVE_MSGS_OFFSET and android_errorWriteLog (liblog). The material shows the same hunk applied on 14, 15, 16 and 17, with only the include context differing on 14."
     ],
     "confidence": "high",
     "unknowns": [
      "The preprocessor condition that selects GKI_getbuf versus GKI_getpoolbuf in nfc_main_hal_data_cback, and therefore which device builds use the vulnerable branch.",
      "The code after the hunk that copies p_data into p_msg (the actual overflowing write) is not shown.",
      "The configured size of the NFC_NCI_POOL_ID pool and the value of NFC_RECEIVE_MSGS_OFFSET.",
      "Whether the packet length can be controlled by a party outside the HAL or NFCC.",
      "Whether the second internal cherry-pick (90a7b2235d84) contained anything beyond this hunk. The AOSP commit contains only the single-file change."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-45516": {
     "cve": "CVE-2026-45516",
     "summary": "Adds an unsigned multiplication wrap-around check in tt_var_load_item_variation_store before the deltaSet array is allocated. A varData whose per_region_size * item_count wraps in FT_UInt is now rejected with Array_Too_Large instead of being allocated with the wrapped size.",
     "component": "platform/external/freetype, TrueType GX/OpenType variation support (src/truetype/ttgxvar.c)",
     "weakness": "Integer overflow in an allocation size computation (missing overflow check before FT_NEW_ARRAY)",
     "root_cause": "In tt_var_load_item_variation_store, each varData entry reads item_count, word_delta_count and region_idx_count from the font with FT_READ_USHORT. per_region_size is computed (and doubled when long_words is set), and then varData->deltaSet was allocated with FT_NEW_ARRAY( varData->deltaSet, per_region_size * item_count ). The product of these FT_UInt values was not checked for unsigned wrap-around, so a wrapped value could be passed as the element count. The bulletin classifies the issue as information disclosure (ID).",
     "fix_analysis": [
      "src/truetype/ttgxvar.c:tt_var_load_item_variation_store: adds a new local, FT_UInt delta_set_size, and computes delta_set_size = per_region_size * item_count before the allocation.",
      "Same function: if per_region_size is non-zero and delta_set_size / per_region_size != item_count, the code emits the FT_TRACE2 message 'bad delta set array size', sets error = FT_THROW( Array_Too_Large ) and jumps to Exit. No allocation or stream read happens for that varData.",
      "Same function: FT_NEW_ARRAY now uses delta_set_size, so the allocation size and the checked value are the same quantity."
     ],
     "completeness": [
      "The fix guards one computation: the deltaSet element count in the per-varData loop of tt_var_load_item_variation_store. The division-based check is a correct wrap-around test for unsigned operands. When per_region_size is 0, the product is 0.",
      "The diff does not touch any other size computation in ttgxvar.c, for example the earlier varData array allocation with data_count. The material does not show whether those computations have independent bounds.",
      "The FT_Stream_Read into varData->deltaSet that follows is only partly shown. The material does not show whether the read and later consumers use a size consistent with delta_set_size."
     ],
     "behavior_changes": [
      "A varData whose per_region_size * item_count wraps in FT_UInt now makes the item variation store fail to load with Array_Too_Large. Before the fix, the wrapped size was allocated.",
      "A new FT_TRACE2 diagnostic, 'tt_var_load_item_variation_store: bad delta set array size', is emitted when tracing is enabled.",
      "Fonts whose product does not wrap behave as before."
     ],
     "preconditions": [
      "FreeType must parse a crafted TrueType/OpenType font with an item variation store that reaches tt_var_load_item_variation_store.",
      "The varData values must pass the earlier consistency checks (word_delta_count <= region_idx_count, region_idx_count <= itemStore->regionCount).",
      "Platform reachability (per index search): frameworks/rs/rsFont.cpp Font::init loads faces with FT_New_Memory_Face / FT_New_Face. Other FreeType consumers may exist."
     ],
     "per_major": {
      "14": "Not listed by the bulletin as affected. At android-security-14.0.0_r30, 2/8 lines of the patched region are present. The material does not explain why.",
      "15": "Same fix: platform/external/freetype 2e564343a4ce in android-security-15.0.0_r17. The diff is identical to Android 16 (same hunk offsets and blob ids). 7/8 patched lines are present at android-security-15.0.0_r18.",
      "16": "Same fix: platform/external/freetype 285b264bf272 in android-security-16.0.0_r8, cherry-picked from internal change 9a879fc426c80c832ca5e1bc02704648e78c29b7. 7/8 patched lines are present at android-security-16.0.0_r9.",
      "17": "Same fix: platform/external/freetype 333924d9d5ea in android-security-17.0.0_r1. The content is identical but sits at different line offsets (hunks at 628/697 instead of 625/682). 7/8 patched lines are present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "The fix is a single commit with one file and two hunks. It uses the existing per_region_size and item_count locals and the FT_THROW/FT_TRACE2 macros. Google applied the same content to 15, 16 and 17, and only the line offsets differ on 17."
     ],
     "confidence": "high",
     "unknowns": [
      "How per_region_size is derived from word_delta_count and region_idx_count is not shown (only the '*= 2' for long_words).",
      "The size argument of the following FT_Stream_Read and how later code iterates varData->deltaSet are not shown, so the exact consequence of the undersized allocation is not visible.",
      "Why Android 14 is not listed as affected is not explained; only the line-presence count (2/8) is given."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-49878": {
     "cve": "CVE-2026-49878",
     "summary": "Replaces two undersized os_zalloc(num_active_scs) allocations in wpas_handle_robust_av_scs_recv_action with os_calloc(num_active_scs, sizeof(int)), so the scs_resp[0]/scs_resp[1] int arrays are sized for num_active_scs integers instead of num_active_scs bytes.",
     "component": "platform/external/wpa_supplicant_8, wpa_supplicant Robust AV / SCS (Stream Classification Service) Response action frame handling (wpa_supplicant/robust_av.c)",
     "weakness": "Incorrect buffer size calculation leading to heap out-of-bounds write (allocation sized in bytes rather than elements)",
     "root_cause": "In wpa_supplicant/robust_av.c:wpas_handle_robust_av_scs_recv_action, the function parses the dialog token and the count field of a received SCS Response frame and checks count against num_active_scs = dl_list_len(&wpa_s->active_scs_ids). It then allocated scs_resp[0] and scs_resp[1] with os_zalloc(num_active_scs). That allocates num_active_scs bytes, but both buffers are used as int arrays (per the commit message and the (int *) cast), so storing int elements writes past the end of each heap buffer. The count field comes from the received frame, so the number of iterations of the following loop is set by the peer and bounded only by num_active_scs.",
     "fix_analysis": [
      "wpa_supplicant/robust_av.c:wpas_handle_robust_av_scs_recv_action: scs_resp[0] = (int *) os_zalloc(num_active_scs) is replaced by scs_resp[0] = os_calloc(num_active_scs, sizeof(int)), so the buffer holds num_active_scs integers.",
      "wpa_supplicant/robust_av.c:wpas_handle_robust_av_scs_recv_action: the same change is applied to scs_resp[1]. The existing NULL checks and the os_free(scs_resp[0]) when the second allocation fails are unchanged.",
      "The surrounding validation (dialog token match, count != 0, count * 3 <= len, num_active_scs >= count) is unchanged. The fix only corrects the allocation size to num_active_scs ints, and count is already checked to be at most num_active_scs."
     ],
     "completeness": [
      "Both int-array allocations in this function (scs_resp[0] and scs_resp[1]) are corrected. The material shows no other allocation in the function.",
      "The fix does not change any parsing or bounds logic. If the writes into scs_resp are indexed by loop position below count, the existing num_active_scs >= count check keeps them inside the correctly sized arrays.",
      "The code that writes into scs_resp[0]/scs_resp[1] (after the loop starts at line 897) is not in the provided context, so the exact indexing cannot be checked from the material. The commit message states the buffers are used as int arrays."
     ],
     "behavior_changes": [
      "The allocation size of the two scs_resp arrays grows from num_active_scs bytes to num_active_scs * sizeof(int) bytes. Frame acceptance, error paths and logging do not change. os_calloc also returns zeroed memory, so initialization matches the previous os_zalloc (general platform knowledge)."
     ],
     "preconditions": [
      "wpa_supplicant must have at least one active SCS descriptor (wpa_s->active_scs_ids non-empty, i.e. num_active_scs >= 1).",
      "An SCS Response action frame is received whose dialog token equals wpa_s->scs_dialog_token and whose count field is non-zero, with count * 3 <= remaining length and count <= num_active_scs.",
      "The material does not show whether a given device's wpa_supplicant build compiles in the Robust AV / SCS code path (build configuration)."
     ],
     "per_major": {
      "14": "same fix: identical two-line os_zalloc to os_calloc change in wpa_supplicant/robust_av.c (commit 5de2705a451f, android-security-14.0.0_r29; hunk at line ~640).",
      "15": "same fix: identical change (commit d14e657ca1ae, android-security-15.0.0_r17; hunk at line ~807).",
      "16": "same fix: identical change (commit d131540379d6, android-security-16.0.0_r8; hunk at line ~881). Code at android-security-16.0.0_r9 shows os_calloc in place.",
      "17": "same fix: identical change (commit ffd3987bbece, android-security-17.0.0_r1; hunk at line ~1072)."
     },
     "backport_notes": [
      "Single-commit, two-line change with no dependencies shown. Google applied the same change on 14/15/16/17, and only the hunk line offset differs (640 / 807 / 881 / 1072). Forks carrying the os_zalloc(num_active_scs) pattern in wpas_handle_robust_av_scs_recv_action should be able to apply the same edit."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact write sites into scs_resp[0]/scs_resp[1] (loop body after line 897) are not in the provided context.",
      "Whether the SCS/Robust AV handler is compiled in and reachable in default Android wpa_supplicant build configurations is not shown.",
      "How entries are added to wpa_s->active_scs_ids (e.g. by a prior SCS Request) is not shown.",
      "The upstream hostap origin of the fix is not shown (the cherry-pick links point to internal review)."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-49880": {
     "cve": "CVE-2026-49880",
     "summary": "Adds an allocated-size field (p_dataBuf_len) to the T4T NFCEE control block and checks rd_offset + p_data->len against it before the memcpy in nfa_t4tnfcee_store_rx_buf, plus length guards in nfa_t4tnfcee_check_sw and nfa_t4tnfcee_store_cc_info and NULL checks on the two nfa_mem_co_alloc results.",
     "component": "platform/packages/modules/Nfc, libnfc-nci NFA T4T NFCEE (ndefnfcee/t4t/nfa_nfcee_act.cc)",
     "weakness": "Missing bounds check leading to heap out-of-bounds write (plus integer/pointer underflow and unchecked allocation in adjacent code)",
     "root_cause": "nfa_t4tnfcee_store_rx_buf copied p_data->len bytes of received T4T NFCEE data into nfa_t4tnfcee_cb.p_dataBuf at nfa_t4tnfcee_cb.rd_offset and then advanced rd_offset, with no knowledge of the buffer's allocated size. The buffer is allocated earlier with a fixed size: lenDataToBeRead in nfa_t4tnfcee_handle_file_operations, or p_data->len in nfa_t4tnfcee_store_cc_info. Incoming data whose cumulative length exceeds that allocation therefore overflows the heap buffer. The control block had no field recording the allocation size, so no check was possible. Adjacent issues: nfa_t4tnfcee_check_sw computed p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE) without checking that len is at least T4T_RSP_STATUS_WORDS_SIZE, so short responses underflow the pointer. The else branch of nfa_t4tnfcee_store_cc_info used p_data->len without checking that it covers 0x07 plus the status bytes (a uint16 underflow per the commit message). Neither nfa_mem_co_alloc result was checked for NULL.",
     "fix_analysis": [
      "libnfc-nci/src/nfa/include/nfa_nfcee_int.h:tNFA_T4TNFCEE_CB: adds uint32_t p_dataBuf_len, which records the allocated size of p_dataBuf.",
      "nfa_nfcee_act.cc:nfa_t4tnfcee_handle_file_operations: after nfa_mem_co_alloc(lenDataToBeRead), a NULL result now sets p_dataBuf_len = 0 and status = NFC_STATUS_FAILED, calls nfa_t4tnfcee_notify_rx_evt() and breaks. Otherwise it records p_dataBuf_len = lenDataToBeRead before calling RW_T4tNfceeReadFile.",
      "nfa_nfcee_act.cc:nfa_t4tnfcee_store_cc_info (allocating branch): sets p_dataBuf_len = p_data->len and does the memcpy only if the allocation succeeded; otherwise sets p_dataBuf_len = 0.",
      "nfa_nfcee_act.cc:nfa_t4tnfcee_store_cc_info (else branch): rejects p_data->len < (0x07 + T4TNFCEE_SIZEOF_STATUS_BYTES) with an error log and an early return, before ccInfo is computed with jumpToFirstTLV.",
      "nfa_nfcee_act.cc:nfa_t4tnfcee_store_rx_buf: does the memcpy and rd_offset += p_data->len only if ((uint32_t)rd_offset + p_data->len) <= p_dataBuf_len, with the sum and the comparison done as unsigned 32-bit. Otherwise it logs, sets nfa_t4tnfcee_cb.status = NFA_STATUS_FAILED and emits android_errorWriteLog(0x534e4554, \"508390497\").",
      "nfa_nfcee_act.cc:nfa_t4tnfcee_check_sw: if p_r_apdu->len < T4T_RSP_STATUS_WORDS_SIZE, sets p_rwData->raw_frame.status = NFC_STATUS_FAILED, logs and returns before the pointer arithmetic.",
      "nfa_nfcee_act.cc:nfa_t4tnfcee_free_rx_buf and nfa_t4tnfcee_initialize_data: reset p_dataBuf_len to 0 so the size field stays consistent with the buffer lifecycle. <log/log.h> is included for android_errorWriteLog."
     ],
     "completeness": [
      "Covers the write site in nfa_t4tnfcee_store_rx_buf. Both allocation sites of p_dataBuf in the diff (nfa_t4tnfcee_handle_file_operations and nfa_t4tnfcee_store_cc_info) now record p_dataBuf_len, and both reset paths (free_rx_buf, initialize_data) clear it.",
      "In the overflow case, store_rx_buf sets status to NFA_STATUS_FAILED but does not return a value or change rw_state. The material does not show how the caller reacts to that status.",
      "rd_offset is still uint16_t. The check ensures the sum fits within p_dataBuf_len (uint32_t), but if p_dataBuf_len could exceed 0xFFFF, the stored rd_offset could still be truncated. The material does not show the type or range of lenDataToBeRead, so this cannot be judged.",
      "The allocating branch of nfa_t4tnfcee_store_cc_info still allocates and copies p_data->len bytes without a minimum-length check. Only the else branch gained the 0x07 + status-bytes check. The material does not show whether a short input on that branch is harmful.",
      "If allocation fails in store_cc_info, p_dataBuf_len is 0, so any later non-empty store into p_dataBuf would fail the bounds check. No explicit error notification is added on that path."
     ],
     "behavior_changes": [
      "Received data that would exceed p_dataBuf_len is dropped. The drop is logged, sets nfa_t4tnfcee_cb.status = NFA_STATUS_FAILED and emits an android_errorWriteLog event (0x534e4554, \"508390497\").",
      "Responses shorter than T4T_RSP_STATUS_WORDS_SIZE now make nfa_t4tnfcee_check_sw set raw_frame.status = NFC_STATUS_FAILED instead of parsing status words.",
      "In the else branch of nfa_t4tnfcee_store_cc_info, data shorter than 0x07 + T4TNFCEE_SIZEOF_STATUS_BYTES is ignored with an error log.",
      "An allocation failure during a file read in nfa_t4tnfcee_handle_file_operations now reports NFC_STATUS_FAILED through nfa_t4tnfcee_notify_rx_evt, instead of starting the read with a NULL p_dataBuf."
     ],
     "preconditions": [
      "T4T NFCEE (NDEF NFCEE emulation) must be in use with a read in progress. After RW_T4tNfceeReadFile, rw_state is set to WAIT_READ_FILE. The dispatch of received data to nfa_t4tnfcee_store_cc_info / nfa_t4tnfcee_store_rx_buf is likely tied to the read states, but this is not shown.",
      "The cumulative received length (p_data->len) must exceed the size allocated for p_dataBuf. Per the commit message, the data comes from reading the T4T NFCEE.",
      "The exact trigger path, and which party controls the data, are not shown beyond the commit message."
     ],
     "per_major": {
      "14": "not affected per bulletin; packages/modules/Nfc not present in android-security-14.0.0_r30 security tags",
      "15": "not affected per bulletin; packages/modules/Nfc not present in android-security-15.0.0_r18 security tags",
      "16": "same fix: commit 4f214cca6dff cherry-picked into android-security-16.0.0_r8 (Merged-In I6c39b1f2...), patched region fully present at android-security-16.0.0_r9",
      "17": "same fix: commit ebcfc2564b95 in android-security-17.0.0_r1 with an identical diff, patched region fully present at android-security-17.0.0_r2"
     },
     "backport_notes": [
      "Single commit touching two files. The struct change in nfa_nfcee_int.h (p_dataBuf_len) must go together with every allocation, free and init site in nfa_nfcee_act.cc, and <log/log.h> is needed for android_errorWriteLog."
     ],
     "confidence": "high",
     "unknowns": [
      "The type and maximum value of lenDataToBeRead, and how the caller of nfa_t4tnfcee_store_rx_buf handles nfa_t4tnfcee_cb.status = NFA_STATUS_FAILED, are not shown.",
      "The diff context does not include the exact uint16 underflow expression in nfa_t4tnfcee_store_cc_info that the new length check protects, nor the condition that selects between its two branches.",
      "The material does not show which party (remote tag or reader, NFCEE firmware, local app) can influence the chunk lengths.",
      "Which rw_state values route received data to store_cc_info and store_rx_buf is not shown."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 6,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-49885": {
     "cve": "CVE-2026-49885",
     "summary": "Adds a guard in rw_t4t_set_ber_tlv() so that p_t4t->max_update_size must exceed the ODO/DDO data_header before data_length = max_update_size - data_header is computed, and makes rw_t4t_update_file() free the C-APDU GKI buffer when rw_t4t_set_ber_tlv() fails.",
     "component": "platform/packages/modules/Nfc (libnfc-nci), Type 4 Tag reader/writer (libnfc-nci/src/nfc/tags/rw_t4t.cc)",
     "weakness": "Missing bounds check leading to unsigned integer underflow in a length calculation (plus a GKI buffer leak on the new error path)",
     "root_cause": "In rw_t4t_set_ber_tlv(), when the data does not fit in p_t4t->max_update_size, the code realigns length to max_update_size and computes data_length = p_t4t->max_update_size - data_header, where data_header = RW_T4T_ODO_DDO_HEADER_MIN_LENGTH + length_size. There was no check that max_update_size is larger than data_header, so per the commit message the subtraction could underflow when max_update_size is too small for the ODO/DDO header. This subtraction exists in two sibling branches (the length == 0 path and the explicit-length path). Separately, rw_t4t_update_file() returned the result of rw_t4t_set_ber_tlv() directly, so a false return would leave the already allocated p_c_apdu GKI buffer unfreed.",
     "fix_analysis": [
      "libnfc-nci/src/nfc/tags/rw_t4t.cc:rw_t4t_set_ber_tlv(): in the length == 0 branch, after length = p_t4t->max_update_size, add `if (p_t4t->max_update_size <= data_header)` -> LOG(ERROR) and return false, before data_length = max_update_size - data_header.",
      "libnfc-nci/src/nfc/tags/rw_t4t.cc:rw_t4t_set_ber_tlv(): the identical check is added in the else branch (length + data_header larger than max_update_size) before the same subtraction.",
      "libnfc-nci/src/nfc/tags/rw_t4t.cc:rw_t4t_update_file(): the MV 3.0 path (NDEF size > 0x7FFF) replaces `return rw_t4t_set_ber_tlv(p_c_apdu, p, length);` with a check that calls GKI_freebuf(p_c_apdu) and returns false on failure, otherwise returns true. The new early returns in rw_t4t_set_ber_tlv() do not free the buffer themselves; the caller does.",
      "Single commit, one file; no new helpers or headers."
     ],
     "completeness": [
      "Both subtraction sites `max_update_size - data_header` in rw_t4t_set_ber_tlv() are guarded; the other two branches (T4T_MAX_LENGTH_LC - data_header and length += data_header) do not subtract max_update_size and are left unchanged.",
      "The check uses <= so a max_update_size equal to data_header (zero payload) is also rejected.",
      "The caller-side GKI_freebuf covers any false return from rw_t4t_set_ber_tlv() reached from rw_t4t_update_file(), not only the two new ones; the material shows no other caller of rw_t4t_set_ber_tlv() (per index search, which may be incomplete).",
      "The fix does not validate max_update_size at the point where it is populated; it is only rejected at use in this function. Other uses of max_update_size in rw_t4t.cc are not shown in the material."
     ],
     "behavior_changes": [
      "A T4T NDEF write on the MV 3.0, size > 0x7FFF path now fails with an ERROR log 'max_update_size too small for ODO/DDO header' instead of computing data_length by a subtraction that can underflow when max_update_size cannot hold the ODO/DDO header.",
      "rw_t4t_update_file() now frees p_c_apdu on rw_t4t_set_ber_tlv() failure (no leak), and returns false to its caller."
     ],
     "preconditions": [
      "A Type 4 Tag write operation reaching rw_t4t_update_file() on the Mapping Version 3.0 path where the NDEF message size exceeds 0x7FFF, so that rw_t4t_set_ber_tlv() is used.",
      "p_t4t->max_update_size is smaller than T4T_MAX_LENGTH_LC (length == 0 branch) or than length + data_header (other branch), and not larger than data_header (RW_T4T_ODO_DDO_HEADER_MIN_LENGTH + length_size). How max_update_size is populated is not shown in the material.",
      "The bulletin rates this EoP, High."
     ],
     "per_major": {
      "14": "same fix, applied to platform/system/nfc (src/nfc/tags/rw_t4t.cc) as 90576eadff36 in android-security-14.0.0_r29; only context differs (DLOG_IF(INFO, nfc_debug_enabled) and \"%s - \" log strings, different line offsets). 8/8 patched lines present at android-security-14.0.0_r30.",
      "15": "same fix, applied to platform/system/nfc (src/nfc/tags/rw_t4t.cc) as f01d5b0889f5 in android-security-15.0.0_r17; added lines identical, context differs only in the \"%s - \" log string format and line offsets. 8/8 patched lines present at android-security-15.0.0_r18.",
      "16": "fix commit 9c0ae67d8733 in platform/packages/modules/Nfc (libnfc-nci/src/nfc/tags/rw_t4t.cc) in android-security-16.0.0_r8, cherry-picked from 91208e26395b. 8/8 patched lines present at android-security-16.0.0_r9.",
      "17": "same fix, 0dc8fad01628 in platform/packages/modules/Nfc in android-security-17.0.0_r1; identical hunks with different offsets. 8/8 patched lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "On Android 14/15 the file lives in platform/system/nfc at src/nfc/tags/rw_t4t.cc; on 16/17 it is in platform/packages/modules/Nfc at libnfc-nci/src/nfc/tags/rw_t4t.cc. The added lines are identical across majors; context differs in path, line offsets, the \"%s - \" vs \"%s: \" log string format (14/15), and DLOG_IF instead of LOG(VERBOSE) (14).",
      "Keep the caller-side GKI_freebuf in rw_t4t_update_file() together with the new early returns, since rw_t4t_set_ber_tlv() does not free p_c_apdu itself."
     ],
     "confidence": "high",
     "unknowns": [
      "Where p_t4t->max_update_size is populated and whether it is validated at parse time (not in the material).",
      "The declared type of data_length and how it is consumed after the subtraction (the APDU construction after the guarded code is only partially shown), so the exact consequence of the underflow beyond the commit message's description is not confirmed by the material.",
      "Whether rw_t4t_set_ber_tlv() had pre-existing false returns that also leaked p_c_apdu before this change.",
      "How the T4T write path is triggered in practice (hardware/tag requirements) is not described in the material."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-49937": {
     "cve": "CVE-2026-49937",
     "summary": "Adds two bounds checks to the synchronized-flavor read path of libfmq MessageQueueBase. availableToReadBytes() now rejects a writePtr/readPtr distance larger than the queue size, and beginRead() now rejects a request for more messages than the queue holds.",
     "component": "platform/system/libfmq, MessageQueueBase (include/fmq/MessageQueueBase.h), fast message queue read path",
     "weakness": "Missing bounds check on the shared read/write pointer distance and on the requested read count. The bulletin type is information disclosure (ID). An out-of-bounds read is the likely consequence but the material does not show it.",
     "root_cause": "availableToReadBytes() loads mReadPtr and mWritePtr. Before the fix, its only sanity check was writePtr < readPtr. A pointer pair where writePtr - readPtr was larger than the queue size (mDesc->getSize()) passed the check and was returned as the available byte count. beginRead() also had no comparison of nMessages against the queue capacity (getQuantumCount()). For the kSynchronizedReadWrite flavor, where the fix treats a distance larger than the queue as corruption, such values could reach the read path unchecked. What they lead to downstream in beginRead() is not shown in the material.",
     "fix_analysis": [
      "include/fmq/MessageQueueBase.h:availableToReadBytes(): computes queueSizeBytes = mDesc->getSize() and availableBytes = writePtr - readPtr (SIZE_MAX if writePtr < readPtr). The corruption branch now fires when writePtr < readPtr OR (flavor == kSynchronizedReadWrite && availableBytes > queueSizeBytes). In that branch it logs an error that now also includes the queue size, calls mErrorHandler with Error::POINTER_CORRUPTION if one is set, and returns 0. Otherwise it returns availableBytes.",
      "include/fmq/MessageQueueBase.h:beginRead(): adds an early check before *result = MemTransaction(). If flavor == kSynchronizedReadWrite && nMessages > getQuantumCount(), it logs an error, calls hardware::details::errorWriteLog(0x534e4554, \"514861024\") and returns false. read() then short-circuits before copyFromSized() and commitRead().",
      "The commit reapplies a reverted change (11165074cdd9). Per its message, the beginRead() check was changed to apply only to kSynchronizedReadWrite because the unsync flavor is expected to overflow when readers are slow. The commit lists three Cherrypick-From references. The message mentions tests (atest fmq_unit_tests), but they are not part of the shown diff."
     ],
     "completeness": [
      "Both new checks only apply when flavor == kSynchronizedReadWrite. For the unsynchronized flavor, availableToReadBytes() still returns writePtr - readPtr without comparing it to the queue size, and beginRead() gets no new nMessages check. The commit message says unsync overflow is expected.",
      "Only the read side changes (availableToReadBytes, beginRead). The write side is untouched: commitWrite appears in the context and simply increments mWritePtr, and beginWrite/availableToWriteBytes are not in the diff. The material does not show whether the write side has an equivalent check.",
      "The existing writePtr < readPtr check is kept. The fix adds to it rather than replacing it.",
      "The beginRead() check compares against getQuantumCount() (the queue capacity), not the shared pointers, so it catches oversized caller requests whatever the pointer state."
     ],
     "behavior_changes": [
      "Synchronized queues: when writePtr - readPtr exceeds the queue size, availableToReadBytes() now returns 0 and reports Error::POINTER_CORRUPTION (via mErrorHandler on 16/17). Before the fix it returned the oversized count.",
      "Synchronized queues: beginRead(), and therefore read(), now returns false when nMessages > getQuantumCount().",
      "The pointer-corruption error message now includes the queue size.",
      "A new errorWriteLog(0x534e4554, \"514861024\") entry is written when the beginRead() check trips. It is in the 14/15/16 commits and missing from the 17 commit.",
      "No change for the unsynchronized flavor."
     ],
     "preconditions": [
      "The queue must use the kSynchronizedReadWrite flavor for the new checks to apply.",
      "The reading process must reach availableToReadBytes() or beginRead(), e.g. through MessageQueueBase::read(), which calls beginRead(), then copyFromSized() and commitRead() (shown in the context).",
      "Either the read/write pointers show a writePtr - readPtr distance larger than the queue, or a caller requests more messages than the queue holds.",
      "The material does not show any specific callers outside libfmq."
     ],
     "per_major": {
      "14": "adapted fix (452c5e918cde, android-security-14.0.0_r29): same two checks. The availableToReadBytes() error path in this branch has no mErrorHandler/errorDetected handling in the shown diff, so the fix builds the errorMsg string and passes it to logError only. Includes the errorWriteLog line.",
      "15": "adapted fix (6d316edf3cc8, android-security-15.0.0_r17): same two checks. availableToReadBytes() has an errorDetected out-parameter, which it sets to Error::POINTER_CORRUPTION. A few lines of that error path are not shown. Includes the errorWriteLog line.",
      "16": "same fix (3aa82fe2d0a8, android-security-16.0.0_r8): the diff analysed here, with mErrorHandler and errorWriteLog.",
      "17": "adapted fix (f727482ff0c6, android-security-17.0.0_r1): identical availableToReadBytes() change. The beginRead() check is present but has no errorWriteLog line, only logError and return false."
     },
     "backport_notes": [
      "Single change to one header. The only branch-specific part is how availableToReadBytes() reports the error: logError only on 14, the errorDetected out-parameter on 15, mErrorHandler on 16/17. Keep the flavor == kSynchronizedReadWrite condition: the commit message says unsync queues are expected to overflow.",
      "The tests mentioned in the message (fmq_unit_tests) are not in the shown diff. Fetch them separately if you want them."
     ],
     "confidence": "high",
     "unknowns": [
      "Which HAL or service queue was the reported trigger. Bugs 504768739 and 514861024 are not described.",
      "What an oversized available count or nMessages leads to inside beginRead()/copyFromSized(), since that code is not shown.",
      "Whether the write-side functions (beginWrite/availableToWriteBytes) have a comparable check. They are not in the diff or context.",
      "Why the Android 17 commit leaves out the errorWriteLog line.",
      "Why the original change was reverted, beyond the commit message's note about unsync overflow.",
      "What the test changes mentioned in the commit message contain.",
      "Per-major facts report only 6 of 8 lines of the patched region present at each latest security tag. The material does not say which lines differ."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 6,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-55266": {
     "cve": "CVE-2026-55266",
     "summary": "Rewrites the end of the copied qsort in libufdt's vendor sysdeps so that it recurses on the smaller partition and iterates on the larger one. This bounds recursion depth to O(log n) instead of potentially O(n).",
     "component": "platform/system/libufdt, sysdeps/libufdt_sysdeps_vendor.c (the qsort implementation copied into the vendor sysdeps)",
     "weakness": "Uncontrolled recursion (stack exhaustion) caused by unbounded recursion depth in quicksort",
     "root_cause": "In sysdeps/libufdt_sysdeps_vendor.c, qsort() always recursed on the left partition (r = pb - pa) and iterated with goto loop on the right partition (r = pd - pc), whatever their relative sizes. If the left partition is repeatedly the larger one, recursion depth grows with the number of elements. A large or adversarial input can then exhaust the stack (stack overflow, DoS). The existing comment \"Iterate rather than recurse to save stack space\" applied only to the right side.",
     "fix_analysis": [
      "sysdeps/libufdt_sysdeps_vendor.c:qsort: adds a local `int l` and, after the vecswap steps, computes both partition byte sizes: l = pb - pa (left of the pivot) and r = pd - pc (right of the pivot).",
      "sysdeps/libufdt_sysdeps_vendor.c:qsort: if l < r, it calls qsort(a, l / es, es, cmp) recursively on the left part (only when l > es). It then iterates on the right part by setting a = pn - r and n = r / es and jumping to loop (only when r > es).",
      "sysdeps/libufdt_sysdeps_vendor.c:qsort: otherwise (l >= r), it calls qsort(pn - r, r / es, es, cmp) recursively on the right part (when r > es). It then iterates on the left part by setting n = l / es and jumping to loop. a stays unchanged because the left part starts at a.",
      "Recursion now always runs on the partition that is no larger than half the current range, so recursion depth stays at about log2(n) frames. The loop handles the larger partition without using a new stack frame. The commented-out line `/* qsort(pn - r, r / es, es, cmp); */` is removed."
     ],
     "completeness": [
      "The fix covers the single recursion site in qsort() in sysdeps/libufdt_sysdeps_vendor.c. After the change every recursive call runs on the smaller partition, so depth is O(log n) for any input.",
      "The size thresholds (> es), partitioning logic, med3 pivot selection, insertion sort for n < 7 and swap helpers are unchanged. The fix limits stack depth only; it does not change worst-case running time.",
      "Partition sizes are still held in `int` variables (l, r) computed from pointer differences; the fix does not change these types. The commit touches no other file."
     ],
     "behavior_changes": [
      "Sub-partitions are processed in a different order: the smaller one by recursion, the larger one by iteration. Sorted output should be the same. Stack usage is bounded by O(log n) frames. No API or error-code changes."
     ],
     "preconditions": [
      "The patched qsort in sysdeps/libufdt_sysdeps_vendor.c must be compiled in and called. The material does not show which build configurations or libufdt callers do this, or with what data.",
      "The input must be large enough, or ordered against the med3 pivot choice, that the left partition is repeatedly the larger one, so recursion depth approaches the element count and exceeds the available stack."
     ],
     "per_major": {
      "14": "Same fix: platform/system/libufdt bbc615c85bf1 in android-security-14.0.0_r29. Hunk content is identical; only the line offsets differ (98/159 vs 100/161). At android-security-14.0.0_r30, 7 of 8 lines of the patched region are present.",
      "15": "Same fix: platform/system/libufdt 109d68930129 in android-security-15.0.0_r17. Hunk content is identical, with the same offsets as Android 14. At android-security-15.0.0_r18, 7 of 8 lines of the patched region are present.",
      "16": "Same fix: platform/system/libufdt 8dfd47aab1f2 in android-security-16.0.0_r8 (the analysed commit). At android-security-16.0.0_r9, 7 of 8 lines of the patched region are present.",
      "17": "Same fix: platform/system/libufdt 70c20864187d in android-security-17.0.0_r1. The diff is identical to Android 16 (same blob indexes). At android-security-17.0.0_r2, 7 of 8 lines of the patched region are present."
     },
     "backport_notes": [
      "This is a single self-contained hunk in qsort() of sysdeps/libufdt_sysdeps_vendor.c with no dependencies. Google applied it on Android 14 through 17 with only line-offset differences. Trees carrying the original 'Iterate rather than recurse' block should be able to take it directly, but that is not verified for other trees.",
      "The index results shown (bionic qsort/qsort_r tests and fts.c) concern bionic's libc qsort, not this libufdt copy. They say nothing about whether the patched function can be reached."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show which libufdt code paths call this vendor qsort, or whether the sorted data can be influenced by an attacker (for example, from device tree blobs).",
      "The material does not show which Android builds or configurations compile libufdt_sysdeps_vendor.c instead of a libc-backed sysdeps.",
      "The specific trigger input and the stack size of the affected environment are not shown."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-55270": {
     "cve": "CVE-2026-55270",
     "summary": "Adds a `wrappedCallback == null` guard in `dialInternal` of both `GsmCdmaPhone` and `ImsPhone` so that USSD requests (which carry a non-null ResultReceiver) no longer execute in-call MMI supplementary-service commands when the dial string matches an in-call MMI code.",
     "component": "platform/frameworks/opt/telephony, GsmCdmaPhone / ImsPhone dial and USSD handling",
     "weakness": "Missing context check (USSD request path reused the dial path without excluding in-call MMI command handling)",
     "root_cause": "`dialInternal(String dialString, DialArgs dialArgs, ResultReceiver wrappedCallback)` in `GsmCdmaPhone.java` and `ImsPhone.java` is used both by the normal `dial()` path (which passes a null wrappedCallback, as shown for ImsPhone) and by USSD requests (non-null wrappedCallback, per the commit message). Before the fix, `dialInternal` called `handleInCallMmiCommands(newDialString)` first, gated only by `!dialArgs.isEmergency` when the `skipMmiCodeCheckForEmergencyCall` flag is on. As a result, a USSD string that matched an in-call MMI code (the tests use \"2\" with an incoming call, which would reach `acceptCall`) was handled as an in-call supplementary-service command (such as hold, swap, conference, or accept) against the current calls instead of as a USSD request.",
     "fix_analysis": [
      "GsmCdmaPhone.java:dialInternal: in the `isPhoneTypeGsm()` branch, both the flag-on condition (`!dialArgs.isEmergency && ...`) and the flag-off condition now require `wrappedCallback == null` before `handleInCallMmiCommands(newDialString)` is evaluated. Because of short-circuit evaluation, the in-call MMI handler is not invoked for USSD requests.",
      "ImsPhone.java:dialInternal: the same change is made to both the `skipMmiCodeCheckForEmergencyCall` flag-on and flag-off branches. The guard sits before the CDMA early return (`mCT.dial`).",
      "GsmCdmaPhoneTest.java:testHandleUssdRequestWithInCallMmiCode: with calls in the INCOMING state, `handleUssdRequest(\"2\", callback)` must return true and `mCT.acceptCall()` must never be called.",
      "ImsPhoneTest.java:testHandleUssdRequestWithInCallMmiCode: with the ringing call INCOMING, `handleUssdRequest(\"2\", callback)` must throw CallStateException with message `Phone.CS_FALLBACK` and `mImsCT.acceptCall(anyInt())` must never be called."
     ],
     "completeness": [
      "On Android 16, the fix guards every `handleInCallMmiCommands` call site visible in the diff: both feature-flag branches in GsmCdmaPhone.dialInternal (GSM branch) and in ImsPhone.dialInternal.",
      "The guard relies on the convention that a non-null `wrappedCallback` identifies a USSD request. The normal `dial()` path passes null and keeps the previous in-call MMI behavior.",
      "The fix only removes the in-call MMI shortcut for USSD requests. It does not add validation of the USSD string itself."
     ],
     "behavior_changes": [
      "A USSD request whose string matches an in-call MMI code no longer acts on existing calls through `handleInCallMmiCommands`. It continues into the rest of `dialInternal`. On ImsPhone, the new test shows this can surface as a CallStateException with message CS_FALLBACK.",
      "Ordinary dial strings (wrappedCallback null) still have in-call MMI codes handled as before."
     ],
     "preconditions": [
      "A USSD request reaches `handleUssdRequest` on a GsmCdmaPhone (GSM type) or an ImsPhone, so that `dialInternal` is entered with a non-null `wrappedCallback`.",
      "The USSD string, after `PhoneNumberUtils.stripSeparators`, matches an in-call MMI code recognized by `handleInCallMmiCommands` (the tests use \"2\").",
      "A call state in which the in-call MMI command has an effect (the tests use an INCOMING call).",
      "On Android 16, if `skipMmiCodeCheckForEmergencyCall` is enabled, `dialArgs.isEmergency` must be false."
     ],
     "per_major": {
      "14": "adapted fix (android-security-14.0.0_r29, commit a702397eed29): the `wrappedCallback == null &&` guard is added to the single unflagged `handleInCallMmiCommands` check in GsmCdmaPhone.dialInternal (GSM branch) and in ImsPhone.dialInternal, and the same tests are added. 6/8 lines of the patched region are present at 14.0.0_r30.",
      "15": "adapted fix (android-security-15.0.0_r17, commit 92836c48ba6a): same shape as the 14 variant, a single unflagged check in each file. 6/8 lines of the patched region are present at 15.0.0_r18.",
      "16": "this fix (android-security-16.0.0_r8, commit ee04a37583c0): the guard is added to both the `skipMmiCodeCheckForEmergencyCall` flag-on and flag-off branches in each file. The 16.0.0_r9 code context shows the ImsPhone change in place; per-major facts report 6/8 lines of the patched region present.",
      "17": "adapted fix (android-security-17.0.0_r1, commit 802f8f5c9920): the condition is the outer `if (!dialArgs.isEmergency)` block (containing the `ignoreIncallMmiForEmergency` check), changed to `!dialArgs.isEmergency && wrappedCallback == null` in both files. 6/8 lines of the patched region are present at 17.0.0_r2."
     },
     "backport_notes": [
      "Each branch received a single commit. The only adaptation across branches is the shape of the condition around `handleInCallMmiCommands`: unflagged on 14/15, two flag branches on 16, and an outer `!dialArgs.isEmergency` block on 17. In a customized tree, check that every `handleInCallMmiCommands` call reachable from `dialInternal` is guarded by `wrappedCallback == null`.",
      "The tests depend on TelephonyTest harness fields (`mCT`, `mGsmCdmaCall`, `mRingingCall`, `mImsCT`) and Mockito. If the harness differs, adapt the tests, but keep the code change."
     ],
     "confidence": "high",
     "unknowns": [
      "The caller chain and permission requirements for `handleUssdRequest` (which API or process can issue a USSD request) are not in the material.",
      "The full definition of `handleInCallMmiCommands` and the exact set of in-call MMI codes it accepts are not shown.",
      "Whether the CDMA branch of GsmCdmaPhone.dialInternal contains any in-call MMI handling is not shown in the material.",
      "Why the per-major facts report only 6/8 lines of the patched region present at the latest tags is not explained."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58815": {
     "cve": "CVE-2026-58815",
     "summary": "Changes the stride-5 metering-region loops in DistortionMapper, RotateAndCropMapper and ZoomRatioMapper from `j < entry.count` to `j + 5 <= entry.count`, so a region entry whose element count is not a multiple of 5 no longer leads to a heap out-of-bounds read and write past the end of the metadata entry.",
     "component": "platform/frameworks/av, cameraserver libcameraservice device3 metadata mappers (DistortionMapper, RotateAndCropMapper, ZoomRatioMapper)",
     "weakness": "Missing bounds check (heap out-of-bounds read and write from a loop condition that does not account for the stride)",
     "root_cause": "Each mapper loops over the tags in kMeteringRegionsToCorrect and treats the int32 entry as consecutive 5-element tuples, with the weight at offset 4. The condition `j < entry.count; j += 5` only checked that the tuple's start index was inside the entry. Inside the loop the code reads entry.data.i32[j + 4] and, if the weight is non-zero, modifies the region in place: mapCorrectedToRaw(e.data.i32 + j, 2, ...) in DistortionMapper::correctCaptureRequest, and transformPoints/swapRectToMinFirst on entry.data.i32 + i in RotateAndCropMapper::updateCaptureRequest. When entry.count is not a multiple of 5 (for example 6, as in the new tests), the last iteration starts at index 5. It reads index 9 and can write indices 5..8, all past the 6-element entry. Per the commit message, the trigger is a CaptureRequest containing such a metering region.",
     "fix_analysis": [
      "services/camera/libcameraservice/device3/DistortionMapper.cpp:DistortionMapper::correctCaptureRequest: the loop over kMeteringRegionsToCorrect now uses `j + 5 <= e.count`, so a full 5-tuple must fit before e.data.i32[j + 4] is read and mapCorrectedToRaw(e.data.i32 + j, 2, ...) writes the coordinates.",
      "services/camera/libcameraservice/device3/DistortionMapper.cpp:DistortionMapper::correctCaptureResult: the result-side loop gets the same condition change.",
      "services/camera/libcameraservice/device3/RotateAndCropMapper.cpp:RotateAndCropMapper::updateCaptureRequest: the loop now uses `i + 5 <= entry.count` before reading entry.data.i32[i + 4] and calling transformPoints / swapRectToMinFirst on entry.data.i32 + i.",
      "services/camera/libcameraservice/device3/RotateAndCropMapper.cpp:RotateAndCropMapper::updateCaptureResult: the result-side loop gets the same condition change.",
      "services/camera/libcameraservice/device3/ZoomRatioMapper.cpp:ZoomRatioMapper::separateZoomFromCropLocked: the loop now uses `j + 5 <= entry.count` before reading the weight.",
      "services/camera/libcameraservice/device3/ZoomRatioMapper.cpp:ZoomRatioMapper::combineZoomAndCropLocked: the unscale loop gets the same condition change.",
      "New tests: DistortionMapperTest MeteringRegionsBoundsTest, RotationMapperTest MeteringRegionsBoundsTest and ZoomRatioTest MeteringRegionsBoundsTest. Each one first writes a 10-element AE_REGIONS entry as poison, then replaces it with a 6-element entry and runs the request-side mapper. It then asserts that the count is still 6 and that element [5] is still 999."
     ],
     "completeness": [
      "All six stride-5 metering-region loops in the three mapper files (the request and result side of each) are changed the same way. The diff is the same in all four majors apart from line offsets.",
      "The kRectsToCorrect loop in DistortionMapper::correctCaptureRequest (line 157 of the r9 context) passes e.count / 4 as the rect count, so integer division already excludes a trailing partial rect. It is not changed.",
      "The fix skips a trailing partial tuple instead of rejecting the request, and no error is returned. The material does not show whether earlier metadata validation rejects such entries.",
      "The commit message also names correctMeteringRegions, but no function with that name appears in the diff.",
      "Other point/rect consumers in these mappers (for example kResultPointsToCorrectNoClamp and face landmarks) are not in the diff, and the material does not show how they handle bounds."
     ],
     "behavior_changes": [
      "When a metering-region entry from kMeteringRegionsToCorrect has an element count that is not a multiple of 5, the distortion, rotate-and-crop and zoom-ratio mappers now leave the trailing partial tuple alone instead of accessing memory past the entry. Entries whose counts are multiples of 5 are processed as before. No new error codes are added."
     ],
     "preconditions": [
      "Per the commit message, a CaptureRequest contains a metering-region tag from kMeteringRegionsToCorrect whose int32 element count is not a multiple of 5. Result-side loops were also changed.",
      "DistortionMapper request path: mapperInfo->mValidMapping is true and ANDROID_DISTORTION_CORRECTION_MODE is present and not OFF (per the correctCaptureRequest context).",
      "RotateAndCropMapper: ANDROID_SCALER_ROTATE_AND_CROP is present and not NONE (shown for updateCaptureResult in the context; the request test uses ROTATE_AND_CROP_90).",
      "ZoomRatioMapper: the new test sets a 2x crop region so that updateCaptureRequest modifies the AE regions.",
      "Per index search, Camera3OutputUtils.cpp sendCaptureResult (rotateAndCropAuto/useZoomRatio parameters) is related to the result path. The snippet does not show the actual mapper call."
     ],
     "per_major": {
      "14": "Same fix: platform/frameworks/av 6654633902f8 in android-security-14.0.0_r29. It has the same six loop-condition changes and the same three tests. Hunk offsets differ (RotateAndCropMapper 162/291, ZoomRatioMapper 349/387, ZoomRatioTest 467). At r30, 7/8 lines of the patched region are present.",
      "15": "Same fix: platform/frameworks/av ff3f3a6b8194 in android-security-15.0.0_r17, with the same changes. Hunk offsets differ (DistortionMapper 145/184, RotateAndCropMapper 165/294, ZoomRatioMapper 352/390, ZoomRatioTest 467). At r18, 7/8 lines of the patched region are present.",
      "16": "Same fix: platform/frameworks/av aff9120ec0b8 in android-security-16.0.0_r8, a cherry-pick of cc78e7aa1be9. The r9 context shows the patched loops in DistortionMapper and RotateAndCropMapper. At r9, 7/8 lines of the patched region are present.",
      "17": "Same fix: platform/frameworks/av 77f8ddbbd65b in android-security-17.0.0_r1. Its hunks and blob indexes are identical to the Android 16 commit. At r2, 7/8 lines of the patched region are present."
     },
     "backport_notes": [
      "A single commit with six one-line loop-condition changes plus tests. The material shows no dependencies. The resolver reports 7/8 lines of the patched region present for every major, and the material does not explain the missing line, so check all six loops by hand."
     ],
     "confidence": "high",
     "unknowns": [
      "Whether metadata validation before the mappers rejects region entries whose count is not divisible by 5.",
      "What kMeteringRegionsToCorrect contains, and whether the three files share one definition.",
      "What the commit message's 'correctMeteringRegions' refers to, since no function with that name is in the diff.",
      "Why the resolver reports 7/8 rather than 8/8 lines of the patched region present in every latest tag.",
      "What the loop bodies of correctCaptureResult, updateCaptureResult and the ZoomRatioMapper loops contain."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 8,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58834": {
     "cve": "CVE-2026-58834",
     "summary": "Adds an argument check on grantState in DevicePolicyManagerService.setPermissionGrantState so only GRANTED, DENIED or DEFAULT are accepted, and wraps the per-policy enforcePolicy calls in DevicePolicyEngine.reapplyAllPoliciesOnBootLocked in try/catch so a bad persisted policy logs a wtf instead of crashing system_server at boot.",
     "component": "platform/frameworks/base, DevicePolicyManagerService / DevicePolicyEngine (device policy, services/devicepolicy)",
     "weakness": "Missing input validation (unchecked enum-like int argument) persisted to disk, plus unhandled exception during boot-time policy re-application",
     "root_cause": "DevicePolicyManagerService.setPermissionGrantState accepted any int for grantState without checking it against the three defined PERMISSION_GRANT_STATE_* values. Per the commit message, on the coexistence (policy engine) path the raw value was stored in the device policy engine's on-disk state. On every subsequent boot, DevicePolicyEngine.reapplyAllPoliciesOnBootLocked iterated the saved global and local policies and called enforcePolicy() with no exception handling, so the invalid value raised an uncaught IllegalArgumentException inside system_server, which crashed and re-crashed on each boot (persistent boot loop recoverable only by factory reset, per the commit message).",
     "fix_analysis": [
      "services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java:setPermissionGrantState: immediately after Objects.requireNonNull(callback) and before getCallerIdentity/checkCanExecuteOrThrowUnsafe, adds Preconditions.checkArgument(grantState == PERMISSION_GRANT_STATE_GRANTED || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED || grantState == PERMISSION_GRANT_STATE_DEFAULT). An out-of-range value now throws IllegalArgumentException to the caller before anything is stored. Note: the commit message says the check applies 'when the coexistence flag is enabled', but in the diff the check is unconditional and runs for every caller of this method.",
      "services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java:reapplyAllPoliciesOnBootLocked: both enforcePolicy() calls (the global-policy loop with UserHandle.USER_ALL and the per-user local-policy loop) are wrapped in try { ... } catch (Exception e) { Slogf.wtf(TAG, \"Failed to reapply policy \" + policy [+ \" for user \" + userId], e); }. Any exception from re-applying one saved policy is logged and the loop continues with the next policy, so system_server no longer dies at boot because of a single bad persisted entry.",
      "services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java: adds testSetPermissionGrantState_coexistence_invalidState_throwsException, which sets a device owner and asserts that dpm.setPermissionGrantState(admin1, pkg, READ_CALENDAR, 999) throws IllegalArgumentException."
     ],
     "completeness": [
      "Input validation covers only setPermissionGrantState; it is the only entry point changed. It rejects every value other than the three defined constants, so the invalid state can no longer be persisted through this API.",
      "The boot-time catch is generic (catch Exception) around both enforcePolicy call sites in reapplyAllPoliciesOnBootLocked, so it also neutralises boot crashes from any other malformed persisted policy, not just permission grant state. It does not remove or repair the bad entry: an already-persisted invalid value remains on disk and will be logged via Slogf.wtf on each boot. DevicePoliciesReaderWriter.readFromFileLocked / load() are not changed, so no sanitisation happens at load time.",
      "Slogf.wtf is used in the catch; whether wtf is fatal depends on the build's Log.wtf configuration (by default it logs and reports without killing the process on production builds) (general platform knowledge)."
     ],
     "behavior_changes": [
      "setPermissionGrantState now throws IllegalArgumentException for any grantState other than PERMISSION_GRANT_STATE_GRANTED, _DENIED or _DEFAULT, for all callers, and the check runs before the caller identity and admin permission checks.",
      "At boot, a policy that fails to re-apply in reapplyAllPoliciesOnBootLocked is logged with Slogf.wtf ('Failed to reapply policy ...') and skipped instead of propagating an exception out of system_server startup; remaining policies are still applied."
     ],
     "preconditions": [
      "Caller must be an admin permitted to call DevicePolicyManagerService.setPermissionGrantState (the commit message cites a BYOD work-profile DPC; the test uses a device owner).",
      "Per the commit message, the persisted invalid state path requires the coexistence (device policy engine) storage path to be in use for permission grant state.",
      "The boot-loop symptom requires a system_server restart/reboot after the invalid value has been persisted."
     ],
     "per_major": {
      "14": "adapted fix: same checkArgument and test; the DevicePolicyEngine try/catch is applied to loops that lack the shouldSkipEnforcementIfNotChanged() condition (different context, same two enforcePolicy sites). Commit 057ff07691a6 in android-security-14.0.0_r29; 8/8 patched lines present at r30.",
      "15": "same fix: commit 49e1a4ba935f in android-security-15.0.0_r17, identical hunks to Android 16; 8/8 patched lines present at r18.",
      "16": "same fix: commit f4e7001b21fb in android-security-16.0.0_r8; 8/8 patched lines present at r9.",
      "17": "same hunks with slightly different context: identical checkArgument and try/catch; before the local-policy loop the context creates Set<Integer> userIds = new HashSet<>(mLocalPolicies.keySet()). Commit c715c992cad0 in android-security-17.0.0_r1; 8/8 patched lines present at r2."
     },
     "backport_notes": [
      "Single commit, no dependencies; both halves are independent and should be applied together (validation prevents new bad state, the try/catch recovers devices that already have it). When porting to trees with a different reapplyAllPoliciesOnBootLocked loop shape, wrap every enforcePolicy call in that method, as the 14 and 17 variants show.",
      "No diff adds import lines, which suggests Preconditions and Slogf are already imported in these files on all four branches; verify in a customised fork."
     ],
     "confidence": "high",
     "unknowns": [
      "Which enforcement callback inside enforcePolicy threw the IllegalArgumentException on the stored value is not shown in the material.",
      "Whether the coexistence flag/policy-engine path is enabled on all affected builds, and whether the non-coexistence (legacy) path tolerated the invalid value, is not shown.",
      "Whether a device that already persisted an invalid value gets the entry cleaned up by any other change is not shown; this commit only logs and skips it.",
      "Whether enforcePolicy has other call sites outside reapplyAllPoliciesOnBootLocked that could hit persisted invalid data without exception handling is not shown."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 2,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58841": {
     "cve": "CVE-2026-58841",
     "summary": "Moves mAudioPlaybackDetector.register(this) in VirtualAudioController.startListening out of the `if (configChangedCallback != null)` block so the playback detector is always registered, leaving only mAudioRecordingDetector registration conditional on a config-changed callback.",
     "component": "platform/frameworks/base, services/companion (VirtualDeviceManager virtual audio, VirtualAudioController)",
     "weakness": "Logic error: a security-relevant callback registration was gated on an unrelated optional parameter, so the silence-injection policy update could be skipped (missing enforcement step)",
     "root_cause": "In VirtualAudioController.startListening, both mAudioPlaybackDetector.register(this) and mAudioRecordingDetector.register(this) were inside `if (configChangedCallback != null)`. When a caller started listening with a routing callback but a null configChangedCallback, the playback detector was never registered, so the controller did not receive audio playback callbacks. Per the commit message, without this registration the deferred silence-injection policy update did not recover correctly.",
     "fix_analysis": [
      "services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java:startListening: the call mAudioPlaybackDetector.register(/* callback= */ this) is moved before and outside the `if (configChangedCallback != null)` check, so it runs unconditionally on every startListening call.",
      "Same function: mAudioRecordingDetector.register(/* callback= */ this) stays inside the conditional, so the recording detector is still registered only when a config-changed callback is supplied.",
      "stopListening is unchanged. In the Android 16 code it already unregisters both detectors unconditionally, so the new unconditional registration is also torn down."
     ],
     "completeness": [
      "Covers the only registration site shown: startListening now always registers the playback detector regardless of configChangedCallback.",
      "The recording detector remains conditional. The commit message presents this as intended, so recording-based callbacks are still not delivered when configChangedCallback is null.",
      "The fix does not change how the playback callback handles state or the deferred update runnable (mUpdateAudioRoutingRunnable). It only makes sure the callback source is registered. The material does not show the callback implementation, so the code provided does not show whether other paths depend on it.",
      "Single-line fix in one file. The shown diff includes no test changes, although the commit message references VirtualAudioControllerTest."
     ],
     "behavior_changes": [
      "VirtualAudioController now registers an AudioPlaybackCallback with AudioPlaybackDetector on every startListening call, including when configChangedCallback is null. Playback callbacks are therefore delivered in that mode, and the silence-injection policy update can run.",
      "No new error codes, permissions, or API surface changes."
     ],
     "preconditions": [
      "VirtualAudioController.startListening must be called with a non-null routingCallback and a null configChangedCallback (virtual device audio set up for routing without a config-changed callback).",
      "Requires a virtual device with virtual audio created through the companion VirtualDeviceManager service. The material does not show the exact caller of startListening."
     ],
     "per_major": {
      "14": "same fix: commit 8ded15ca0499 in android-security-14.0.0_r29, identical one-line move (hunk at line 94); 5/5 patched lines present at r30.",
      "15": "same fix: commit a46c94ad2ccc in android-security-15.0.0_r17, identical one-line move (hunk at line 102); 5/5 patched lines present at r18.",
      "16": "same fix: commit 3184e06e737a in android-security-16.0.0_r8, cherry-pick of internal change I2af61fc32fb2d19e68037fdb8a10a23dc4b37071; 5/5 patched lines present at r9.",
      "17": "same fix: commit 1412cbcc0c10 in android-security-17.0.0_r1, identical one-line move (the class declaration line differs only in context); 5/5 patched lines present at r2."
     },
     "backport_notes": [
      "Single self-contained one-line change with no dependencies. It applies to any branch where startListening has the `if (configChangedCallback != null)` block wrapping both register calls. On the target branch, check that stopListening unregisters mAudioPlaybackDetector unconditionally. It does in the Android 16 code shown; stopListening is not shown for the other branches."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show the callers of startListening or which of them pass a null configChangedCallback.",
      "The material does not include the implementation of the playback callback or of the deferred silence-injection policy update (what is injected and when).",
      "The material does not describe the two bug IDs (515034370, 521392631) or how they relate to the EoP rating beyond the commit message.",
      "The material does not show stopListening on Android 14, 15 and 17."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 2,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58854": {
     "cve": "CVE-2026-58854",
     "summary": "Adds an isRemote() check (and a null check where there was none) before every static_cast of a caller-supplied ITunerFilter/ITunerDemux/ITunerLnb binder to the local Tuner*/TunerHidl* implementation class in the mediatuner service. Remote proxies are now rejected with Result::INVALID_ARGUMENT.",
     "component": "platform/frameworks/av, services/tuner (mediatuner daemon, AIDL and HIDL backends)",
     "weakness": "Type confusion (unchecked downcast of a binder interface pointer to a local implementation class; CWE-843 style)",
     "root_cause": "Several mediatuner binder methods take an AIDL interface argument (shared_ptr<ITunerFilter>, ITunerDemux, ITunerLnb) and immediately static_cast it to the service's own implementation class (TunerFilter, TunerDemux, TunerLnb, or the TunerHidlFilter/TunerHidlDemux/TunerHidlLnb equivalents) to call getHalFilter() or getId(). Nothing checked that the object really was a local instance of that class. A caller could pass a remote binder proxy or its own custom binder stub. The cast pointer then refers to a proxy object, and reading the implementation class's member fields through it reads out of bounds relative to the proxy allocation (per the commit message). Some sites already rejected nullptr but not proxies: TunerDvr::attachFilter/detachFilter, TunerFilter::setDataSource, TunerFrontend::setLnb and their HIDL counterparts. TunerDemux::getAvSyncHwId and TunerDescrambler::setDemuxSource (and their HIDL counterparts) had no check at all.",
     "fix_analysis": [
      "Single commit (183c2e3a4198 in android-security-16.0.0_r8), cherry-picked from two internal changes, touching 10 files. Every site that downcasts a caller-supplied interface now rejects objects for which isRemote() is true. It returns ScopedAStatus::fromServiceSpecificError(Result::INVALID_ARGUMENT) before the static_cast runs.",
      "services/tuner/TunerDemux.cpp:TunerDemux::getAvSyncHwId and services/tuner/hidl/TunerHidlDemux.cpp:TunerHidlDemux::getAvSyncHwId: new check `tunerFilter == nullptr || tunerFilter->isRemote()` (previously no validation). TunerHidlDemux.cpp also gains `#include <aidl/android/hardware/tv/tuner/Result.h>` and `using ::aidl::android::hardware::tv::tuner::Result;` so that Result::INVALID_ARGUMENT resolves there.",
      "services/tuner/TunerDescrambler.cpp and services/tuner/hidl/TunerHidlDescrambler.cpp: setDemuxSource gains `in_tunerDemux == nullptr || in_tunerDemux->isRemote()` (previously no validation). addPid and removePid gain `in_optionalSourceFilter != nullptr && in_optionalSourceFilter->isRemote()`: the optional filter may still be null, but a proxy is rejected before the existing ternary static_cast.",
      "services/tuner/TunerDvr.cpp and services/tuner/hidl/TunerHidlDvr.cpp: attachFilter and detachFilter extend the existing `in_filter == nullptr` check to `in_filter == nullptr || in_filter->isRemote()`.",
      "services/tuner/TunerFilter.cpp:TunerFilter::setDataSource and services/tuner/hidl/TunerHidlFilter.cpp:TunerHidlFilter::setDataSource: the existing null check is extended with `|| filter->isRemote()`. It runs under mLock, before the mShared check.",
      "services/tuner/TunerFrontend.cpp:TunerFrontend::setLnb and services/tuner/hidl/TunerHidlFrontend.cpp:TunerHidlFrontend::setLnb: the existing null check is extended with `|| lnb->isRemote()`, before the static_cast to TunerLnb/TunerHidlLnb and the getId() call."
     ],
     "completeness": [
      "The fix covers every static_cast-to-local-class site visible in the diff and context, in both the AIDL backend (TunerDemux, TunerDescrambler, TunerDvr, TunerFilter, TunerFrontend) and the HIDL backend (TunerHidlDemux, TunerHidlDescrambler, TunerHidlDvr, TunerHidlFilter, TunerHidlFrontend). That is five classes and 16 call sites in total.",
      "The check relies on isRemote(), so any object that is not a local binder in the mediatuner process is rejected. It does not verify that a local object is the specific expected subclass. The context shows the service creating these objects itself via SharedRefBase::make (openFilter, openDvr, openTimeFilter). It does not show whether any other local implementations exist.",
      "The material does not show TunerDemux::setFrontendDataSource(ITunerFrontend); only the int-taking setFrontendDataSourceById at TunerDemux.cpp line 68 is in context. Whether any other interface-taking method in services/tuner does a similar downcast cannot be judged from the material."
     ],
     "behavior_changes": [
      "Passing a remote or foreign binder as the filter, demux or lnb argument to the listed methods now returns service-specific error Result::INVALID_ARGUMENT instead of going ahead with the unsafe cast.",
      "TunerDemux::getAvSyncHwId, TunerHidlDemux::getAvSyncHwId, TunerDescrambler::setDemuxSource and TunerHidlDescrambler::setDemuxSource now also return INVALID_ARGUMENT for a null argument. Previously they would dereference it.",
      "addPid/removePid still accept a null optional source filter; only a non-null remote one is rejected.",
      "Legitimate flows, where the client passes back a TunerFilter/TunerDemux/TunerLnb object it got from the same mediatuner service, are expected to be unaffected because isRemote() is false for those local objects. The commit reports testing with valid object flows."
     ],
     "preconditions": [
      "Caller can reach the mediatuner service and invoke ITunerDvr::attachFilter/detachFilter, ITunerDemux::getAvSyncHwId, ITunerFilter::setDataSource, ITunerDescrambler::setDemuxSource/addPid/removePid, or ITunerFrontend::setLnb. The commit message states that unprivileged apps could do so.",
      "Caller supplies an ITunerFilter/ITunerDemux/ITunerLnb argument that is not a local object of the service (a remote proxy or a caller-implemented stub).",
      "Device runs the mediatuner daemon (TV tuner stack). Per index search, the normal path is android.media.tv.tuner.Tuner (frameworks/base) -> android_media_tv_Tuner.cpp -> DemuxClient/FilterClient -> ITunerDemux and the other interfaces."
     ],
     "per_major": {
      "14": "same fix: f8520e699d18 in android-security-14.0.0_r29. The added lines match 16, but the base blob hashes differ for TunerDemux.cpp, TunerDescrambler.cpp, TunerDvr.cpp, TunerFilter.cpp, TunerFrontend.cpp and TunerHidlFilter.cpp, and the hunk offsets differ for the five AIDL-backend files. 8/8 patched-region lines present at android-security-14.0.0_r30.",
      "15": "same fix: 7ccb7033d428 in android-security-15.0.0_r17, identical content (only the TunerFilter.cpp base blob differs from 16). 8/8 present at android-security-15.0.0_r18.",
      "16": "same fix: 183c2e3a4198 in android-security-16.0.0_r8. 8/8 present at android-security-16.0.0_r9.",
      "17": "same fix: 073ae498a43f in android-security-17.0.0_r1, identical to the 16 commit. 8/8 present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Single self-contained commit. The only change besides the checks is the added Result.h include and using-declaration in hidl/TunerHidlDemux.cpp, which Result::INVALID_ARGUMENT needs to resolve there. When applying to a tree with different line offsets (as on 14), check that every static_cast of an interface argument in services/tuner and services/tuner/hidl is preceded by an isRemote() check."
     ],
     "confidence": "high",
     "unknowns": [
      "Whether any other interface-taking method in services/tuner performs a similar unchecked downcast. One example is TunerDemux::setFrontendDataSource(ITunerFrontend), which DemuxClient::setFrontendDataSource calls per index search; its body is not in the material.",
      "Whether any local implementation of these interfaces other than the service's own Tuner*/TunerHidl* classes exists in the daemon.",
      "The exact two internal changes named in the Cherrypick-From lines, and how the work was split between them."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 2,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58856": {
     "cve": "CVE-2026-58856",
     "summary": "Adds a range check on the output slot index, a null check on the slot's GraphicBuffer, and a tracked-buffer lookup (mBuffers.find instead of operator[]) in the camera stream splitter's returnOutputBufferLocked, and changes outputSlots from a copy to a reference so slot updates persist.",
     "component": "platform/frameworks/av, cameraserver (services/camera/libcameraservice/device3, Camera3StreamSplitter / DeprecatedCamera3StreamSplitter)",
     "weakness": "Missing bounds check (out-of-bounds read of the outputSlots vector by an unchecked slot index), plus unchecked null buffer dereference and unchecked mBuffers lookup",
     "root_cause": "In returnOutputBufferLocked(fence, from, surfaceId, slot), the slot value (obtained in the calling overload via from->dequeueBuffer(&slot, ...) and described by the commit message as app-supplied) was used directly as an index into the outputSlots vector (*mOutputSlots[from]) with no check that 0 <= slot < outputSlots.size(). The commit message states this could lead to an out-of-bounds read and type confusion. The resulting buffer was then dereferenced without a null check, and the tracker was obtained via mBuffers[buffer->getId()] without verifying the id was tracked. Separately, outputSlots was declared as a copy (auto outputSlots = ...), so the later outputSlots[slot] = nullptr after detachBuffer modified the copy and was not persisted.",
     "fix_analysis": [
      "services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp : DeprecatedCamera3StreamSplitter::returnOutputBufferLocked (4-arg overload): `auto outputSlots = *mOutputSlots[from];` becomes `auto& outputSlots = *mOutputSlots[from];` so the function operates on, and writes back to, the actual per-output slot vector.",
      "Same function: adds `if (slot < 0 || static_cast<size_t>(slot) >= outputSlots.size())` with SP_LOGE and early return before `buffer = outputSlots[slot]`, removing the out-of-bounds index.",
      "Same function: after reading the slot, adds `if (buffer == nullptr)` with SP_LOGE and early return, so an empty slot is no longer dereferenced via buffer->getId().",
      "Same function: replaces `BufferTracker& tracker = *(mBuffers[buffer->getId()]);` with `mBuffers.find(buffer->getId())`, an end() check with SP_LOGE and early return, and `BufferTracker& tracker = *(it->second);`, so an untracked buffer id is rejected before use.",
      "Android 14 (d74fdb8ae7d4) and Android 15 (de6bd248af67): identical hunk applied to services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp : Camera3StreamSplitter::returnOutputBufferLocked, marked RESTRICT AUTOMERGE."
     ],
     "completeness": [
      "The fix validates the slot index, the slot contents, and the tracker lookup only within returnOutputBufferLocked; all three failure cases now log and return without further processing (the fence is not merged and the buffer is not released back to the input in those cases).",
      "Changing outputSlots to a reference also fixes the latent bug that `outputSlots[slot] = nullptr` in the detach path (line 758 in the r9 context) previously wrote to a local copy.",
      "The calling overload (lines 705-716) still passes the dequeued slot to handleOutputDequeueStatusLocked(res, slot) before the check; the material does not show what that function does with slot.",
      "Other functions in the splitter that index outputSlots or mBuffers are not shown in the material, so coverage beyond this function cannot be judged from the code provided."
     ],
     "behavior_changes": [
      "New SP_LOGE error logs and early return for: out-of-range slot, null buffer in slot, buffer id not present in mBuffers.",
      "mBuffers is no longer accessed via operator[] on an unchecked id in this function.",
      "Slot updates made in this function (e.g. clearing the slot after a successful detachBuffer) now persist in the real per-output slot vector instead of a local copy."
     ],
     "preconditions": [
      "A camera stream routed through the stream splitter (Camera3StreamSplitter on 14/15, DeprecatedCamera3StreamSplitter on 16/17), with the output surface still registered (mOutputSlots[from] != nullptr).",
      "The 4-arg returnOutputBufferLocked is reached from its sibling overload in the same file, which calls from->dequeueBuffer(&slot, ...) on the output IGraphicBufferProducer and forwards the returned slot; the commit message describes the slot index as app-supplied.",
      "No index-search callers were found outside this file (per index search); the only visible caller is the overload at line 715 of the same file."
     ],
     "per_major": {
      "14": "adapted fix: same hunk applied to services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp (Camera3StreamSplitter::returnOutputBufferLocked), commit d74fdb8ae7d4, RESTRICT AUTOMERGE, in android-security-14.0.0_r29; 4/6 lines of the patched region matched at r30.",
      "15": "adapted fix: same hunk applied to services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp (Camera3StreamSplitter::returnOutputBufferLocked), commit de6bd248af67, RESTRICT AUTOMERGE, in android-security-15.0.0_r17; 4/6 lines of the patched region matched at r18.",
      "16": "same fix: commit 6e240fe4061a in services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp, cherry-picked (Change-Id I12684395411ff45393e724345f1cbbb870167101), in android-security-16.0.0_r8; the r9 code excerpt shows the patched hunk (per-major facts report 5/6 lines matched).",
      "17": "same fix: commit db4f7fd08e40 in services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp, in android-security-17.0.0_r1; 5/6 lines of the patched region matched at r2."
     },
     "backport_notes": [
      "Single self-contained hunk with no new dependencies; on Android 14/15 the class and file are Camera3StreamSplitter.cpp, on 16/17 it is deprecated/DeprecatedCamera3StreamSplitter.cpp. Verify presence by checking for the `auto& outputSlots` reference and the three early returns in returnOutputBufferLocked."
     ],
     "confidence": "high",
     "unknowns": [
      "What handleOutputDequeueStatusLocked does with the unvalidated slot before the fixed function is reached.",
      "How the slot value becomes app-controlled (the commit only says app-supplied).",
      "The container type of mBuffers and the exact consequence of the old operator[] access on an untracked id.",
      "Why only 4/6 (14, 15) and 5/6 (16, 17) lines of the patched region match at the latest tags.",
      "Whether a non-deprecated splitter implementation exists alongside DeprecatedCamera3StreamSplitter on 16/17 with an equivalent path.",
      "The exact trigger details and the concrete consequence observed in the bug (the commit message only states out-of-bounds read and type confusion)."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    }
   }
  },
  "17": {
   "counts": {
    "announced": 25,
    "certain": 24,
    "probable": 0,
    "not_published": 1,
    "not_covered": 0,
    "awaiting": 0
   },
   "advisories": [
    {
     "cve": "CVE-2026-49933",
     "osv_id": "ASB-A-522372651",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Default-initializes the raw ScanningCallback* member scanning_callbacks_ to nullptr in MsftExtensionManager::impl and adds a null check in handle_le_monitor_device_event so a MSFT_LE_MONITOR_DEVICE_EVENT received before scanning callbacks are registered is dropped with a warning instead of calling OnTrackAdvFoundLost through an uninitialized pointer.",
      "confidence": "high",
      "backport_notes": [
       "Single-commit change to one file, system/gd/hci/msft.cc. The two hunks (the null guard in handle_le_monitor_device_event and the {nullptr} member initializer) do not depend on the surrounding member list or the constructor signature, which differ between 16 and 17, so the same hunk content applies with only line-offset adjustment. Bluetooth is a mainline module, so the fix can also ship via module update (general platform knowledge)."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "1af205db6af0c9d22342d5aacd95c5d09c40bf90",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2026-55265",
     "osv_id": "ASB-A-517377150",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "DoS"
     ],
     "status": "announced-not-published",
     "detail": "platform/development,platform/frameworks/base",
     "coverage": {
      "n_ingested_tags": 2,
      "first_ingested_tag": "android-security-17.0.0_r1",
      "latest_ingested_tag": "android-security-17.0.0_r2",
      "window_base_tag": "android-17.0.0_r1",
      "window_start": "2026-06-16",
      "partial_tags": [],
      "projects": [
       {
        "project": "platform/development",
        "fetched_ok_in_tags": 2,
        "ingested_tags": 2,
        "latest_status": "ok"
       },
       {
        "project": "platform/frameworks/base",
        "fetched_ok_in_tags": 2,
        "ingested_tags": 2,
        "latest_status": "ok"
       }
      ]
     },
     "projects": [
      "platform/development",
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-55269",
     "osv_id": "ASB-A-522372274",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Inverts the resize guard in SnoopLogger::FilterCapturedPacket so short ACL packets receive EXTRA_BUF_SIZE padding before the PBAP/MAP profile filter writes its magic string, and clamps the reported length to the packet size.",
      "confidence": "high",
      "backport_notes": [
       "The production change is two lines in SnoopLogger::FilterCapturedPacket: flip `>` to `<=` and append the std::min clamp. The test file context differs between 16 and 17 (auto* vs auto, snoop_logger->Start() present or not), so the test hunks may need manual adjustment."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 6,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "62418c92b1bbe91fe063b4bf3da050c080a50dac",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2026-55280",
     "osv_id": "ASB-A-522373576",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Zero-initializes the whole evt_data.activate structure in nfc_ncif_proc_activate() and clamps nfcid1_len / uid_len to NCI_NFCID1_MAX_LEN / NFC_KOVIO_MAX_LEN in nfa_dm_notify_activation_status(), so that a malformed RF_INTF_ACTIVATED_NTF cannot drive an oversized memcpy in the NFC process.",
      "confidence": "high",
      "backport_notes": [
       "Single commit touching two files. It needs <log/log.h> for android_errorWriteLog and the existing NCI_NFCID1_MAX_LEN / NFC_KOVIO_MAX_LEN constants. The 16 and 17 commits have identical hunks that differ only in line offsets. Nfc is a mainline module in these releases, so fixes may also ship through module updates (general platform knowledge)."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 6,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Nfc",
       "sha": "897466771c24e408deda87ab69fb1f631d9182f0",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Nfc"
     ]
    },
    {
     "cve": "CVE-2026-58835",
     "osv_id": "ASB-A-522371916",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "In system/btif/src/btif_storage.cc cfg2prop(), the BT_PROPERTY_UUIDS / BT_PROPERTY_UUIDS_LE path now passes the caller's buffer capacity (prop->len / sizeof(Uuid)) to btif_split_uuids_string instead of the hardcoded BT_MAX_NUM_UUIDS, so parsed UUIDs can no longer be written past the end of prop->val.",
      "confidence": "high",
      "backport_notes": [
       "The source change replaces one argument at the btif_split_uuids_string call in cfg2prop, and the patch is the same whether the parameter is named addr or remote_bd_addr. The commit says it is a companion to ag/40421805 and 'can be backported'. That companion change is not in the material and its content is unknown, so check whether it is also needed, for example for the zero-limit behaviour the new test checks."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "5f719e21eef19233b25852f9610d010fa7fa274d",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2026-58865",
     "osv_id": "ASB-A-513582756",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a bounds check on the well-known content type index in PduParser.parseContentType and null checks for the parameter map and the parsed charset string in PduParser.parseContentTypeParams so a malformed MMS PDU no longer throws ArrayIndexOutOfBoundsException or NullPointerException during parsing.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained commit; the three PduParser.java hunks apply identically on 14 through 17 (only the pre-image blob differs between 17 and the older branches).",
       "The new PduParserTest.java also contains two OOM tests that do not correspond to code in this commit; if a fork lacks related changes those two tests may fail independently of this fix, so verify them separately."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r2",
      "date": "2026-10-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r2",
      "date": "2026-10-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "05fef2f15699db8e2fef050748ba8b76ef6dec3b",
       "tag": "android-security-17.0.0_r2",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-58880",
     "osv_id": "ASB-A-522373105",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "Critical",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Removes the num_ext_attr/ext_attrs parameters from the AVRCP controller playerapplicationsetting_cb HAL callback so that the asynchronously executed JNI callback no longer receives pointers into ext_attrs memory freed by cleanup_app_attr_val_txt_response, and makes cleanup_app_attr_val_txt_response run synchronously on the caller.",
      "confidence": "high",
      "backport_notes": [
       "Branches differ in how the callback is dispatched (CTRL_HAL_CBACK on 17 vs do_in_jni_thread(base::BindOnce(...)) on 16), so adapt the argument-list edit in handle_app_val_response, handle_app_attr_txt_response and handle_app_attr_val_txt_response to the target branch's dispatch form and keep the synchronous cleanup_app_attr_val_txt_response call.",
       "The bt_rc.h typedef change is a HAL-level signature change; all implementers of btrc_ctrl_callbacks_t (JNI, btif_rc_test.cc, any vendor forks) must be updated together or the build breaks."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r2",
      "date": "2026-10-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r2",
      "date": "2026-10-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "df3b47977847249dd05d30320cfc7e23359c22b7",
       "tag": "android-security-17.0.0_r2",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2026-28667",
     "osv_id": "ASB-A-508389908",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a response-length check (length < p_i93->block_size) before three rw_i93_send_cmd_write_single_block calls in rw_t5t.cc, so that a short tag response no longer causes stale GKI buffer bytes beyond the received data to be sent back to the tag in a WRITE_SINGLE_BLOCK command.",
      "confidence": "high",
      "backport_notes": [
       "A single self-contained commit. Only the file path differs between trees: src/nfc/tags/rw_t5t.cc in platform/system/nfc (14/15) versus libnfc-nci/src/nfc/tags/rw_t5t.cc in platform/packages/modules/Nfc (16/17, where libnfc-nci is part of the NFC mainline module (general platform knowledge)). Apply it by matching the three rw_i93_send_cmd_write_single_block calls. The variables length and p_i93 are already in scope at each site."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Nfc",
       "sha": "2ad8845ad77ea509c99df902f115580c4118cc35",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Nfc"
     ]
    },
    {
     "cve": "CVE-2026-45513",
     "osv_id": "ASB-A-508389591",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a length check in nfc_main_hal_data_cback (libnfc-nci nfc_main.cc) that drops incoming HAL packets whose data_len exceeds the usable capacity of a fixed-size NFC_NCI_POOL_ID GKI pool buffer, before any buffer is allocated.",
      "confidence": "high",
      "backport_notes": [
       "This is a single self-contained hunk. The only path difference is system/nfc/src/nfc/nfc/nfc_main.cc (Android 14/15) versus packages/modules/Nfc/libnfc-nci/src/nfc/nfc/nfc_main.cc (Android 16/17). The target tree must provide GKI_get_pool_bufsize and <log/log.h> / android_errorWriteLog.",
       "The commit message names nfc_main_hal_read_cback, but the function actually patched is nfc_main_hal_data_cback. Apply the check inside the #else (GKI_getpoolbuf) branch only."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Nfc",
       "sha": "79b15334596b744ef28642bb32cbff3f7486ab8c",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Nfc"
     ]
    },
    {
     "cve": "CVE-2026-45516",
     "osv_id": "ASB-A-503542587",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds an unsigned-multiplication overflow check on the deltaSet array size (per_region_size * item_count) in tt_var_load_item_variation_store in external/freetype. Overflowing sizes now fail with Array_Too_Large instead of allocating a wrapped-around (too small) buffer.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained hunk in tt_var_load_item_variation_store with no dependencies shown. Google applied it to 15, 16 and 17 with only line-offset differences."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/external/freetype",
       "sha": "333924d9d5ea53e0c428c958740d1c970ad44000",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/external/freetype"
     ]
    },
    {
     "cve": "CVE-2026-45524",
     "osv_id": "ASB-A-514740359",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "WifiPermissionsUtil#isSystem now returns false for Private Compute Core UIDs (when SdkLevel.isAtLeastC()), so PCC callers are no longer treated as system apps for Wi-Fi permission decisions.",
      "confidence": "high",
      "backport_notes": [
       "The fix uses Process.isPrivateComputeCoreUid behind an SdkLevel.isAtLeastC() gate. The bulletin lists older branches as not affected, so no backport is indicated. Wifi is a mainline module, so the module build must compile against an SDK that exposes Process.isPrivateComputeCoreUid (general platform knowledge)."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Wifi",
       "sha": "78ed5791579271dd99f60d35700c4a6c8d966ed4",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Wifi"
     ]
    },
    {
     "cve": "CVE-2026-49878",
     "osv_id": "ASB-A-511544607",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "RCE"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Replaces two undersized os_zalloc(num_active_scs) allocations for the int arrays scs_resp[0] and scs_resp[1] in wpas_handle_robust_av_scs_recv_action with os_calloc(num_active_scs, sizeof(int)), so the buffers are sized in int elements rather than bytes.",
      "confidence": "high",
      "backport_notes": [
       "Self-contained two-line change with no shown dependencies. The same diff was applied on 14 through 17; only the hunk offset differs."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/external/wpa_supplicant_8",
       "sha": "ffd3987bbecefc8cd6946014e576263e45b777d9",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/external/wpa_supplicant_8"
     ]
    },
    {
     "cve": "CVE-2026-49880",
     "osv_id": "ASB-A-508390497",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a p_dataBuf_len field to the T4T NFCEE control block, records the allocated size at each allocation, and checks rd_offset + p_data->len against it before the memcpy in nfa_t4tnfcee_store_rx_buf. It also adds length underflow checks in nfa_t4tnfcee_check_sw and nfa_t4tnfcee_store_cc_info and NULL checks on the nfa_mem_co_alloc results.",
      "confidence": "high",
      "backport_notes": [
       "This is a single commit touching two files. The header change (new p_dataBuf_len in tNFA_T4TNFCEE_CB) must go in together with the .cc change. All allocation and reset sites of p_dataBuf in the target tree must also be updated, otherwise the check in nfa_t4tnfcee_store_rx_buf compares against a stale or zero length. The android_errorWriteLog call requires <log/log.h> (liblog)."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 2,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Nfc",
       "sha": "ebcfc2564b95916fdcbc99582c947ba2e9586ea6",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Nfc"
     ]
    },
    {
     "cve": "CVE-2026-49885",
     "osv_id": "ASB-A-508389525",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds an underflow guard in rw_t4t_set_ber_tlv() so data_length is only computed when p_t4t->max_update_size exceeds the ODO/DDO data_header, and makes rw_t4t_update_file() free the C-APDU GKI buffer when rw_t4t_set_ber_tlv() fails.",
      "confidence": "high",
      "backport_notes": [
       "Single-commit fix. The file sits in platform/system/nfc on Android 14/15 and in platform/packages/modules/Nfc/libnfc-nci on Android 16/17, so between branches only the path and hunk offsets change. The context on 14 uses different logging macros (DLOG_IF), but the added lines use LOG(ERROR) << StringPrintf, which is how they appear in the 14 backport too."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Nfc",
       "sha": "0dc8fad0162803ab42eb098e7f6a16e86313ceb2",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Nfc"
     ]
    },
    {
     "cve": "CVE-2026-49937",
     "osv_id": "ASB-A-514861024",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "libfmq's MessageQueueBase now treats a read/write pointer distance larger than the queue size as pointer corruption (synchronized flavor only) and rejects beginRead() requests for more messages than getQuantumCount() (synchronized flavor only).",
      "confidence": "medium",
      "backport_notes": [
       "Single header-only change. The only differences between branches are how availableToReadBytes() reports errors (mErrorHandler on 16/17, errorDetected out-param on 15, log only on 14) and the optional errorWriteLog line in beginRead() on 14 to 16. Keep the flavor == kSynchronizedReadWrite gate: the commit message says the unsync flavor is expected to overflow, and this commit reapplies a change that had been reverted (11165074cdd9)."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 6,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/libfmq",
       "sha": "f727482ff0c6a26b4c64c5106c62c176415b2d81",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/system/libfmq"
     ]
    },
    {
     "cve": "CVE-2026-55266",
     "osv_id": "ASB-A-509980995",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Rewrites the partition handling in the qsort copy in libufdt's vendor sysdeps so it recurses on the smaller partition and iterates on the larger one, bounding recursion depth to O(log n).",
      "confidence": "high",
      "backport_notes": [
       "The fix is one self-contained hunk in qsort() of sysdeps/libufdt_sysdeps_vendor.c, with no other dependencies shown. Google shipped identical hunk content on 14 through 17, differing only by a 2-line offset on 14 and 15."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/libufdt",
       "sha": "70c20864187df19f3e7d358ca8436f77d61a3f39",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/system/libufdt"
     ]
    },
    {
     "cve": "CVE-2026-55270",
     "osv_id": "ASB-A-517377154",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a `wrappedCallback == null` guard in GsmCdmaPhone.dialInternal and ImsPhone.dialInternal so that USSD requests (which carry a non-null ResultReceiver) can no longer trigger in-call MMI supplementary-service actions (for example accept, hold, swap, conference) when the USSD string matches an in-call MMI code.",
      "confidence": "high",
      "backport_notes": [
       "Single commit with no dependency. The only adaptation is matching the local shape of the in-call MMI block (whether it has isPhoneTypeGsm(), skipMmiCodeCheckForEmergencyCall or ignoreIncallMmiForEmergency branches). Every branch that calls handleInCallMmiCommands in the ResultReceiver overload of dialInternal must get the `wrappedCallback == null` guard, in both GsmCdmaPhone and ImsPhone.",
       "The added tests rely on TelephonyTest fixtures (mCT, mGsmCdmaCall, mRingingCall, mImsCT, replaceInstance). On heavily customised trees, check that these mocks exist before carrying the tests over."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/opt/telephony",
       "sha": "802f8f5c99207035e1d2d523bbef2969ae134b4c",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/opt/telephony"
     ]
    },
    {
     "cve": "CVE-2026-55279",
     "osv_id": "ASB-A-514747079",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "ImageManager::MapAllImages in libfiemap now logs an error and returns false when the metadata directory does not exist, instead of silently returning true, so first-stage init no longer treats a non-existent or invalid DSU slot as a successfully mapped, running DSU.",
      "confidence": "high",
      "backport_notes": [
       "Trivial 2-line change in ImageManager::MapAllImages; if porting to a tree where libfiemap lives in a different project path, apply the same change to the MetadataExists early-return and verify that no local caller depends on the old success-on-missing-metadata behavior."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 1,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/fs/fs_mgr",
       "sha": "666f09f0529cadadd4994923faadb3c9f1542eb0",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/system/fs/fs_mgr"
     ]
    },
    {
     "cve": "CVE-2026-55286",
     "osv_id": "ASB-A-522376740",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds an early length check in stpropnci_process() (ST NFC HAL, libstpropnci) that drops and logs any NCI message whose payloadlen exceeds MAX_NCI_MESSAGE_LEN.",
      "confidence": "medium",
      "backport_notes": [
       "Single commit adding 6 lines. It uses MAX_NCI_MESSAGE_LEN and LOG_E, which already exist in the library. Relevant only to trees that carry hardware/st/nfc/libstpropnci (absent from the 14, 15 and 16 security tags)."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 7,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/hardware/st/nfc",
       "sha": "bbb2d21c4d503006f8bb70e5863dfa03d78f2ef8",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/hardware/st/nfc"
     ]
    },
    {
     "cve": "CVE-2026-58815",
     "osv_id": "ASB-A-514726373",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Changes the stride-5 metering-region loops in DistortionMapper, RotateAndCropMapper and ZoomRatioMapper from `j < entry.count` to `j + 5 <= entry.count` so that a metering-region entry whose element count is not a multiple of 5 no longer causes a heap out-of-bounds read and write past the end of the metadata entry.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained commit: six one-token loop-condition changes in three mapper files; on older or vendor-modified trees, check every `+= 5` loop over kMeteringRegionsToCorrect in these files uses the `+ 5 <=` form (the commit message also mentions a `correctMeteringRegions` site not present in this diff).",
       "The resolver reports 7/8 patched-region lines present in every latest security tag (14 r30, 15 r18, 16 r9, 17 r2); the 17 r2 code context shows the fixed conditions in DistortionMapper and RotateAndCropMapper, so this may be a matching artifact, but verify all six loop conditions directly when confirming a build."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 7,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/av",
       "sha": "77f8ddbbd65b2ff0dbe212e6f182e6a554869bf3",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/av"
     ]
    },
    {
     "cve": "CVE-2026-58834",
     "osv_id": "ASB-A-515158597",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds an argument check in DevicePolicyManagerService.setPermissionGrantState so only GRANTED, DENIED or DEFAULT grant states are accepted. It also wraps the boot-time policy re-application calls in DevicePolicyEngine.reapplyAllPoliciesOnBootLocked in try/catch, so a bad persisted policy no longer crashes system_server.",
      "confidence": "high",
      "backport_notes": [
       "The two parts are independent and small. The checkArgument goes right after Objects.requireNonNull(callback) in setPermissionGrantState. The try/catch wraps the two enforcePolicy calls in reapplyAllPoliciesOnBootLocked, whatever the loop shape on the branch. None of the shown diffs adds an import, so confirm that Preconditions and Slogf are available in both files on your branch."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "c715c992cad0393eb17fa145dbd4c0c39c138287",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-58841",
     "osv_id": "ASB-A-515034370",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Makes VirtualAudioController.startListening register the AudioPlaybackDetector unconditionally instead of only when an IAudioConfigChangedCallback is supplied, so the deferred silence-injection policy update recovers correctly (per the commit message).",
      "confidence": "high",
      "backport_notes": [
       "Self-contained one-line move in startListening(). It applies cleanly to any branch where both register() calls sit inside the configChangedCallback null check. On the target branch, check that stopListening() unregisters mAudioPlaybackDetector unconditionally so register and unregister stay balanced."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "1412cbcc0c10ef846dcaed030cbecbca3c20bae7",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2026-58854",
     "osv_id": "ASB-A-514727559",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds isRemote() checks, plus nullptr checks where none existed, before the mediatuner service static_casts caller-supplied ITunerFilter/ITunerDemux/ITunerLnb binder objects to its local TunerXxx/TunerHidlXxx implementation classes. Remote proxies are now rejected with Result::INVALID_ARGUMENT.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained commit with the same hunk content on 14 through 17. When porting to a customised tree, make sure every site that static_casts a client-supplied ITunerFilter/ITunerDemux/ITunerLnb gets the guard. Also make sure TunerHidlDemux.cpp gains the Result.h include and using-declaration; this is the only file where the commit adds them."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/av",
       "sha": "073ae498a43f00b1bff40c5cbb46ba3693161988",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/av"
     ]
    },
    {
     "cve": "CVE-2026-58856",
     "osv_id": "ASB-A-514734206",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a range check on the slot index, a null check on the slot's GraphicBuffer, and a check that the buffer is tracked in mBuffers before use, all inside DeprecatedCamera3StreamSplitter::returnOutputBufferLocked. It also makes outputSlots a reference instead of a copy, so changes to the slots persist.",
      "confidence": "high",
      "backport_notes": [
       "A single hunk in a single file. On 14 and 15, which do not have the deprecated/ file, Google applied the same hunk to device3/Camera3StreamSplitter.cpp."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/av",
       "sha": "db4f7fd08e40617b9fda0ff9c0addb7ddb847186",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/frameworks/av"
     ]
    },
    {
     "cve": "CVE-2026-58859",
     "osv_id": "ASB-A-517377722",
     "source": "osv",
     "announced": "2026-10-01",
     "severity": "High",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Changes catch (Exception) to catch (Throwable) in Ts43PhoneNumberRetriever.fetchPhoneNumber and adds a new catch (Throwable) in the Ts43PhoneNumberController fetch method, so a StackOverflowError from JSON parsing of a server response no longer escapes and crashes the process.",
      "confidence": "high",
      "backport_notes": [
       "A single self-contained commit: one changed catch clause in the retriever, one new catch block in the controller, plus tests. It only applies to trees that contain Ts43PhoneNumberRetriever/Ts43PhoneNumberController in packages/modules/Telephony. These files are absent in the 14, 15 and 16 security tags."
      ],
      "meta": {
       "generated": "2026-10-06",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-17.0.0_r1",
      "date": "2026-09-08",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Telephony",
       "sha": "e04c40c70a0827d88a59920c2284aa01ccecdaaa",
       "tag": "android-security-17.0.0_r1",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 23,
     "projects": [
      "platform/packages/modules/Telephony"
     ]
    }
   ],
   "tags": [
    "android-security-17.0.0_r2"
   ],
   "unannounced": [
    {
     "bug_ids": [
      "517376969"
     ],
     "commits": [
      {
       "project": "platform/frameworks/opt/telephony",
       "sha": "735d9672603fa206c4b43cb668c1aa273db70b97",
       "subject": "RESTRICT AUTOMERGE: Fix remote DoS in decodeWapPdu (b/517376969)",
       "tag": "android-security-17.0.0_r2",
       "merged": "2026-08-05",
       "markers": [
        "cve_fix",
        "restrict_automerge"
       ]
      }
     ],
     "tags": [
      "android-security-17.0.0_r2"
     ],
     "tag": "android-security-17.0.0_r2"
    }
   ],
   "coverage": {
    "n_ingested_tags": 2,
    "first_ingested_tag": "android-security-17.0.0_r1",
    "latest_ingested_tag": "android-security-17.0.0_r2",
    "window_base_tag": "android-17.0.0_r1",
    "window_start": "2026-06-16",
    "partial_tags": []
   },
   "platform_update_tags": {},
   "briefs": {
    "CVE-2026-49933": {
     "cve": "CVE-2026-49933",
     "summary": "Default-initializes the raw ScanningCallback* member scanning_callbacks_ to nullptr in MsftExtensionManager::impl and adds a null check in handle_le_monitor_device_event so a MSFT_LE_MONITOR_DEVICE_EVENT received before scanning callbacks are registered is dropped with a warning instead of calling OnTrackAdvFoundLost through an uninitialized pointer.",
     "component": "platform/packages/modules/Bluetooth, GD HCI layer, Microsoft (MSFT) vendor extension manager (system/gd/hci/msft.cc)",
     "weakness": "Uninitialized pointer dereference (uninitialized member used before assignment), reachable via an initialization-order race with controller-originated events",
     "root_cause": "In system/gd/hci/msft.cc, struct MsftExtensionManager::impl declared the member `ScanningCallback* scanning_callbacks_;` without an initializer, and handle_le_monitor_device_event called the virtual method `scanning_callbacks_->OnTrackAdvFoundLost(...)` for any event whose monitor state was 0x00 or 0x01 with no check that the pointer had been set. The handler processes MSFT LE monitor device events from the controller. The dispatch from handle_msft_events (which checks the MSFT prefix) is likely but not shown in the material. If such an event arrives during stack bring-up before the scanning callbacks are registered, the virtual call is made through an indeterminate pointer value. Per the commit message, a premature MSFT_LE_MONITOR_DEVICE_EVENT from a compromised controller triggers this.",
     "fix_analysis": [
      "system/gd/hci/msft.cc, struct MsftExtensionManager::impl member list: `ScanningCallback* scanning_callbacks_;` becomes `ScanningCallback* scanning_callbacks_{nullptr};`, so the member has a defined null value from construction until it is assigned.",
      "system/gd/hci/msft.cc, MsftExtensionManager::impl::handle_le_monitor_device_event: immediately after the view.IsValid() assert, a new early return `if (scanning_callbacks_ == nullptr) { log::warn(...); return; }` drops the event before any field extraction or callback invocation.",
      "Same function: the monitor state check is restructured from an if/else (state == 0x00 || == 0x01 then dispatch, else warn) into an early-return guard (`if (state != 0x00 && state != 0x01) { warn; return; }`), followed by the unconditional build of AdvertisingFilterOnFoundOnLostInfo and the call to scanning_callbacks_->OnTrackAdvFoundLost. This is a refactor that accepts the same states; the only behavioral change is the added null guard."
     ],
     "completeness": [
      "The fix covers the one dereference site shown in the diff, handle_le_monitor_device_event, and makes scanning_callbacks_ deterministically null until it is set. The diff does not show how the other members are initialized.",
      "The null check and the pointer assignment are separate operations. The diff does not show where scanning_callbacks_ is assigned or whether it can be reset to null later, so the guard is a defensive check for the bring-up window rather than a synchronization change. The handler threading model is not visible in the material, so the diff alone does not establish any ordering guarantees.",
      "Other members of MsftExtensionManager::impl visible in the Android 16 context (msft_adv_monitor_add_cb_, msft_adv_monitor_remove_cb_, msft_adv_monitor_enable_cb_) are not touched. The material does not show whether they can be called before registration, so nothing can be concluded about them.",
      "handle_rssi_event is a stub that only logs and is not affected."
     ],
     "behavior_changes": [
      "A MSFT LE monitor device event arriving while scanning_callbacks_ is null is now dropped and the warning \"scanning_callbacks_ is null, dropping Microsoft vendor event.\" is logged, instead of being dispatched.",
      "The null check now runs before the monitor state validation, so an event with an invalid monitor state received while callbacks are unset logs the null warning rather than the invalid-state warning.",
      "No change for events received after callbacks are registered: the same states are accepted (0x00, 0x01) and OnTrackAdvFoundLost is dispatched as before."
     ],
     "preconditions": [
      "The controller must support the MSFT extension: hal_->getMsftOpcode() returns a non-zero opcode and the MSFT supported-features read completes, so that the vendor prefix is derived and handle_msft_events accepts vendor-specific events.",
      "The controller must deliver a vendor-specific HCI event whose payload matches the MSFT prefix and carries an LE monitor device event, before the Bluetooth stack has registered the scanning callbacks on MsftExtensionManager. The commit message attributes this to a compromised Bluetooth controller.",
      "The code runs inside the privileged bluetooth process; per the material, no app-level interaction is involved."
     ],
     "per_major": {
      "14": "Not listed as affected by the bulletin. At android-security-14.0.0_r30 the per-major scan reports 7/8 lines of the patched region present, the same ratio as the resolved 16 and 17 tags, but the material identifies no fix commit for 14.",
      "15": "Not listed as affected by the bulletin. At android-security-15.0.0_r18 the per-major scan reports 8/8 lines of the patched region present; the material identifies no fix commit for 15.",
      "16": "Same fix with different context: commit 3d959c922924 in android-security-16.0.0_r8 applies the identical hunk to handle_le_monitor_device_event and the identical member initializer. Only the surrounding lines differ: the member list has msft_adv_monitor_*_cb_ callbacks before scanning_callbacks_, and the constructor is the argument-less MsftExtensionManager::MsftExtensionManager(). Line offsets differ (@@ -83 / -308 vs -74 / -337).",
      "17": "Same fix: commit 1af205db6af0 in android-security-17.0.0_r1, cherry-picked from d6505b430477 (Change-Id I044a3cf62559a9e758c4d0f5d89525ae4574c57f). The fixed code is present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Single-commit change to one file, system/gd/hci/msft.cc. The two hunks (the null guard in handle_le_monitor_device_event and the {nullptr} member initializer) do not depend on the surrounding member list or the constructor signature, which differ between 16 and 17, so the same hunk content applies with only line-offset adjustment. Bluetooth is a mainline module, so the fix can also ship via module update (general platform knowledge)."
     ],
     "confidence": "high",
     "unknowns": [
      "Where and when scanning_callbacks_ is assigned (the setter is not in the diff or the shown context), and whether it can be cleared again after registration.",
      "The threading model of the handler (whether handle_msft_events and the callback registration run on the same os::Handler), so the material cannot show whether the null check alone is race-free.",
      "The exact dispatch path from handle_msft_events to handle_le_monitor_device_event, which the shown context does not include.",
      "Why Android 14 and 15 are not listed as affected although the per-major scan finds the patched region present in their latest security tags, and whether a fix commit landed there.",
      "Whether the bulletin's Critical rating reflects the control-flow hijack potential mentioned in the commit message or only the DoS type listed."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-55269": {
     "cve": "CVE-2026-55269",
     "summary": "Inverts the resize guard in SnoopLogger::FilterCapturedPacket so short ACL packets receive EXTRA_BUF_SIZE padding before the PBAP/MAP profile filter writes its magic string, and clamps the reported length to the packet size.",
     "component": "platform/packages/modules/Bluetooth, system/gd/hal SnoopLogger (btsnoop filtered logging)",
     "weakness": "Inverted bounds/capacity check leading to heap out-of-bounds write (buffer not enlarged before fixed-size string write)",
     "root_cause": "In system/gd/hal/snoop_logger.cc, SnoopLogger::FilterCapturedPacket handles the case where the PBAP or MAP filter profile property is enabled and the headers filter did not shorten the packet (length == ntohl(header.length_original)). There the code is supposed to grow the packet buffer by EXTRA_BUF_SIZE so that the profile filter has room even when the payload is shorter than the magic string. Per the commit message, FilterProfiles reaches PayloadStrip, which writes the fixed string 'PROHIBITED'. The guard was written as `packet.size() + EXTRA_BUF_SIZE > DEFAULT_PACKET_SIZE`, the opposite of the intent: small packets, the ones that need padding, skipped the resize, and only large packets were resized. A short ACL packet from the controller (the test adds 8-byte packets) therefore reached the magic-string overwrite with a heap buffer too small to hold it. The result was a heap out-of-bounds write.",
     "fix_analysis": [
      "system/gd/hal/snoop_logger.cc : SnoopLogger::FilterCapturedPacket: the guard changes from `packet.size() + EXTRA_BUF_SIZE > DEFAULT_PACKET_SIZE` to `packet.size() + EXTRA_BUF_SIZE <= DEFAULT_PACKET_SIZE`. Packets whose size plus padding fits in DEFAULT_PACKET_SIZE are now resized by EXTRA_BUF_SIZE before FilterProfiles(...) is called, which gives the 'PROHIBITED' overwrite enough backing storage.",
      "system/gd/hal/snoop_logger.cc : SnoopLogger::FilterCapturedPacket: a new final statement `length = std::min(length, static_cast<uint32_t>(packet.size() + PACKET_TYPE_LENGTH));` clamps the output length (passed by reference) to the packet buffer plus the packet-type byte. It runs on every path that reaches the end of the function. The early returns (non-filtered mode or non-ACL, A2DP media, FilterProfiles returning 0) bypass it.",
      "system/gd/hal/snoop_logger_test.cc: kTestData gains two 8-byte short ACL packets (incoming CID 0x0041, outgoing CID 0x0040). In profiles_filtered_pbap_magic_test, profiles_filtered_pbap_header_test and profiles_filtered_pbap_fullfilter_test, the first NewSnoopLogger argument changes from 15 to 20."
     ],
     "completeness": [
      "Covers the PBAP/MAP profile-filter path in FilterCapturedPacket: short packets are now padded before FilterProfiles runs. The returned length is clamped to the buffer size on every path that reaches the end of the function.",
      "Packets with packet.size() + EXTRA_BUF_SIZE > DEFAULT_PACKET_SIZE are no longer resized, and the commit adds no separate check for them. The material does not show the constant values or the magic string length, so it does not show whether such packets always have enough room.",
      "The padding is only applied when length == ntohl(header.length_original). If the headers filter already shortened length, FilterProfiles is not called, so that path does not reach this write.",
      "FilterProfiles and PayloadStrip are not modified: the fix relies only on the caller providing enough capacity. The material does not show whether those functions do their own bounds checks.",
      "The other parsers called on packet.data() in the same function (IsA2dpMediaPacket, CalculateAclPacketLength, ShouldFilterLog) are untouched. The material does not show their internals, so how they handle short packets is unknown."
     ],
     "behavior_changes": [
      "In filtered snoop mode with the PBAP or MAP filter enabled, ACL packets small enough to fit (size + EXTRA_BUF_SIZE <= DEFAULT_PACKET_SIZE) are now grown by EXTRA_BUF_SIZE before profile filtering. Large packets are no longer grown. Before the fix it was the reverse.",
      "On paths that reach the end of FilterCapturedPacket, the length passed back is now capped at packet.size() + PACKET_TYPE_LENGTH.",
      "No API, error code or user-visible change beyond the logged packet contents/length in filtered mode."
     ],
     "preconditions": [
      "btsnoop_mode_ == kBtSnoopLogModeFiltered (snoop log filtering enabled via Developer Options, per the commit message).",
      "The PBAP or MAP filter profile property (kBtSnoopLogFilterProfilePbapModeProperty / kBtSnoopLogFilterProfileMapModeProperty) is enabled, so FilterProfiles runs. The commit message names the 'magic' mode.",
      "Packet type is ACL and the headers filter did not alter length (length == ntohl(header.length_original)).",
      "A very short HCI ACL packet arrives from the Bluetooth controller, e.g. 8 bytes as in the added test data. Per index search, SnoopLogger::Capture copies the incoming packet into a mutable copy, and its comment refers to FilterCapture modifying packets. The call to FilterCapturedPacket is not shown in the excerpt."
     ],
     "per_major": {
      "14": "Not affected per the bulletin (not listed). The resolver reports 8/8 lines of the patched region present at android-security-14.0.0_r30, but the material shows no fix commit for this branch.",
      "15": "Not affected per the bulletin (not listed). The resolver reports 8/8 lines of the patched region present at android-security-15.0.0_r18, but the material shows no fix commit for this branch.",
      "16": "Same fix: commit 6effdf3d7c13 in android-security-16.0.0_r8. The snoop_logger.cc change is identical (guard inversion plus length clamp) at different line offsets. The test diff differs only in surrounding context (auto* and snoop_logger->Start()). Resolver: 7/8 lines of the patched region present at android-security-16.0.0_r9.",
      "17": "Same fix: commit 62418c92b1bb in android-security-17.0.0_r1 (cherry-pick of 0083751f4ce0). The code at android-security-17.0.0_r2 shows the `<=` guard and the std::min clamp in place. Resolver: 7/8 lines of the patched region present."
     },
     "backport_notes": [
      "The production change is two lines in SnoopLogger::FilterCapturedPacket: flip `>` to `<=` and append the std::min clamp. The test file context differs between 16 and 17 (auto* vs auto, snoop_logger->Start() present or not), so the test hunks may need manual adjustment."
     ],
     "confidence": "high",
     "unknowns": [
      "The bodies of FilterProfiles and PayloadStrip are not shown, nor are the values of EXTRA_BUF_SIZE and DEFAULT_PACKET_SIZE or the exact magic string write.",
      "Whether packets that are no longer padded (size + EXTRA_BUF_SIZE > DEFAULT_PACKET_SIZE) always have room for the magic string.",
      "Whether Android 14 and 15 contain the inverted guard or the fix. The bulletin lists them as not affected, and the resolver data is not conclusive.",
      "Which system properties or Developer Options map to kBtSnoopLogFilterProfilePbapModeProperty and kBtSnoopLogFilterProfileMapModeProperty.",
      "What the first NewSnoopLogger argument in the tests means."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 6,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-55280": {
     "cve": "CVE-2026-55280",
     "summary": "Zero-initializes the whole evt_data.activate structure in nfc_ncif_proc_activate() and clamps nfcid1_len / uid_len to NCI_NFCID1_MAX_LEN / NFC_KOVIO_MAX_LEN in nfa_dm_notify_activation_status(), so that a malformed RF_INTF_ACTIVATED_NTF cannot drive an oversized memcpy in the NFC process.",
     "component": "platform/packages/modules/Nfc, libnfc-nci (NCI interface layer nfc_ncif.cc and NFA device manager nfa_dm_act.cc)",
     "weakness": "Use of uninitialized stack memory as a copy length (missing initialization), together with a missing bounds check on a length field used by memcpy (out-of-bounds write)",
     "root_cause": "In libnfc-nci/src/nfc/nfc/nfc_ncif.cc nfc_ncif_proc_activate(), the local tNFC_DISCOVER evt_data lives on the stack, and only evt_data.activate.intf_param (p_intf) was zeroed with memset. The length checks `if (plen < 7)` and `if (plen < *p + 4)` jump to invalid_packet before nfc_ncif_decode_rf_params() fills evt_data.activate.rf_tech_param. The callback still fires on that path: the ProcActivateInvalidPacketLength test expects it with NFC_ACTIVATE_DEVT and status NCI_STATUS_FAILED (per index search). As a result, the rf_tech_param union (including param.pa.nfcid1_len and param.pk.uid_len) held uninitialized stack data. Further downstream, nfa_dm_notify_activation_status() in nfa_dm_act.cc copies the stored activation notification and reads nfcid_len directly from p_tech_params->param.pa.nfcid1_len (POLL_A) or param.pk.uid_len (POLL_KOVIO) with no bound. Per the commit message, that value is used as a memcpy length, which produces an out-of-bounds write in the NFC process.",
     "fix_analysis": [
      "libnfc-nci/src/nfc/nfc/nfc_ncif.cc:nfc_ncif_proc_activate(): replaces `memset(p_intf, 0, sizeof(tNFC_INTF_PARAMS))` with `memset(&evt_data.activate, 0, sizeof(evt_data.activate))`. The entire activate member, including rf_tech_param and its param union, is now zeroed before either length check can bail out to invalid_packet. A short packet therefore reaches the callback with zeroed tech parameters instead of leftover stack data.",
      "libnfc-nci/src/nfa/dm/nfa_dm_act.cc:nfa_dm_notify_activation_status(): in the NFC_DISCOVERY_TYPE_POLL_A branch, right after `nfcid_len = p_tech_params->param.pa.nfcid1_len;`, adds `if (nfcid_len > NCI_NFCID1_MAX_LEN)`. When it triggers, it logs android_errorWriteLog(0x534e4554, \"522373576\"), clamps nfcid_len to NCI_NFCID1_MAX_LEN and writes the clamped value back into p_tech_params->param.pa.nfcid1_len.",
      "libnfc-nci/src/nfa/dm/nfa_dm_act.cc:nfa_dm_notify_activation_status(): adds the same clamp in the NFC_DISCOVERY_TYPE_POLL_KOVIO branch. It bounds nfcid_len = param.pk.uid_len to NFC_KOVIO_MAX_LEN and writes the result back to p_tech_params->param.pk.uid_len.",
      "libnfc-nci/src/nfa/dm/nfa_dm_act.cc: adds `#include <log/log.h>` for android_errorWriteLog."
     ],
     "completeness": [
      "The memset covers the full evt_data.activate member, and the invalid_packet paths set evt_data.status explicitly. The material does not show whether the rest of the tNFC_DISCOVER union beyond activate matters to consumers.",
      "Length clamping is added only to the POLL_A (nfcid1_len) and POLL_KOVIO (uid_len) branches of nfa_dm_notify_activation_status(). The POLL_B and ISO15693 (pi93.uid) branches visible in the diff context are not changed. The material does not show whether those branches use fixed-size lengths or lengths taken from the union.",
      "The fix clamps at the consumer in nfa_dm. It adds no validation in nfc_ncif_decode_rf_params(), where the values are parsed, so any other consumers of rf_tech_param.param.pa.nfcid1_len or param.pk.uid_len still receive the raw values. The material does not show whether such consumers exist.",
      "The clamp bounds oversized lengths whatever their source (uninitialized data or an out-of-range value supplied by the NFCC). That is broader than the uninitialized-stack trigger described in the commit message."
     ],
     "behavior_changes": [
      "On a truncated RF_INTF_ACTIVATED_NTF, the discovery callback now receives a zeroed activate structure with status NCI_STATUS_FAILED, instead of one where only intf_param is zeroed. On the plen < 7 path every field is zero. On the second length check, rf_disc_id, intf_param.type, protocol and rf_tech_param.mode have already been read from the packet.",
      "If nfcid1_len exceeds NCI_NFCID1_MAX_LEN, or a Kovio uid_len exceeds NFC_KOVIO_MAX_LEN, the length is truncated to the maximum, the value stored in the copied notification is overwritten, and an android_errorWriteLog(0x534e4554, \"522373576\") entry is emitted. No new error is returned to the caller."
     ],
     "preconditions": [
      "The NFC process must receive an RF_INTF_ACTIVATED_NTF from the NFCC that is too short for the length checks in nfc_ncif_proc_activate() (plen < 7, or plen < rf-param-length + 4), so that parsing stops before nfc_ncif_decode_rf_params().",
      "An activation notification must be stored in nfa_dm_cb.p_activate_ntf. nfa_dm_notify_activation_status() returns early if p_activate_ntf is null, and it runs the copy path only when status == NFA_STATUS_OK (per the function body shown in the index).",
      "nfa_dm_poll_disc_cback holds the activation notification on NFA_DM_RF_DISC_ACTIVATED_EVT until a sub-module is ready (per index search). The full path by which a failed-parse notification reaches nfa_dm_notify_activation_status() is not shown.",
      "The notification's mode must be NFC_DISCOVERY_TYPE_POLL_A or NFC_DISCOVERY_TYPE_POLL_KOVIO for the new clamps to apply."
     ],
     "per_major": {
      "14": "Not affected per the bulletin. platform/packages/modules/Nfc is not present in the android-security-14.0.0_r30 tags. The material does not cover where libnfc-nci lived before it became part of this module.",
      "15": "Not affected per the bulletin. platform/packages/modules/Nfc is not present in the android-security-15.0.0_r18 tags.",
      "16": "Same fix: commit d6cb6aefb127 in android-security-16.0.0_r8. The hunks are identical (same memset replacement, same two clamps, same include) at slightly different line offsets (nfa_dm_act.cc ~1708/1726, nfc_ncif.cc ~993). All 8/8 lines of the patched region are present at android-security-16.0.0_r9.",
      "17": "Same fix: commit 897466771c24 in android-security-17.0.0_r1 (cherry-pick of f974b0fee85f, Change-Id Iedd07da2dd238a27550c8d8bdfa9ab8d4cd1050f). All 8/8 lines of the patched region are present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Single commit touching two files. It needs <log/log.h> for android_errorWriteLog and the existing NCI_NFCID1_MAX_LEN / NFC_KOVIO_MAX_LEN constants. The 16 and 17 commits have identical hunks that differ only in line offsets. Nfc is a mainline module in these releases, so fixes may also ship through module updates (general platform knowledge)."
     ],
     "confidence": "high",
     "unknowns": [
      "The memcpy in the callback path that consumes nfcid_len is only described in the commit message. The material does not show the lines in nfa_dm_notify_activation_status() where p_nfcid / nfcid_len are copied, or the size of the destination buffer.",
      "Whether nfc_ncif_decode_rf_params() itself bounds nfcid1_len / uid_len when parsing a well-formed packet, and whether other consumers of rf_tech_param read these lengths.",
      "Whether the POLL_B, ISO15693 and any other branches (for example POLL_F, which is not visible) use fixed lengths or lengths taken from the packet.",
      "Whether the NFA-layer handler for NFC_ACTIVATE_DEVT checks evt_data.status before storing the notification, i.e. the exact path by which a failed-parse notification reaches nfa_dm_notify_activation_status().",
      "Whether the rest of the tNFC_DISCOVER union beyond the activate member is read on the failure path."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 6,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58835": {
     "cve": "CVE-2026-58835",
     "summary": "In system/btif/src/btif_storage.cc cfg2prop(), the BT_PROPERTY_UUIDS / BT_PROPERTY_UUIDS_LE path now passes the caller's buffer capacity (prop->len / sizeof(Uuid)) to btif_split_uuids_string instead of the hardcoded BT_MAX_NUM_UUIDS, so parsed UUIDs can no longer be written past the end of prop->val.",
     "component": "platform/packages/modules/Bluetooth, system/btif (btif_storage, bt_config property loading)",
     "weakness": "Missing bounds check leading to out-of-bounds write (buffer overflow) when parsing stored UUID strings into a caller-provided buffer",
     "root_cause": "cfg2prop() reads the stored remote service UUID string (key BTIF_STORAGE_KEY_REMOTE_SERVICE or BTIF_STORAGE_KEY_REMOTE_SERVICE_LE) into a 1280-byte local buffer. It then calls btif_split_uuids_string(value, p_uuid, BT_MAX_NUM_UUIDS), where p_uuid is prop->val reinterpreted as Uuid*. The limit passed was the fixed constant BT_MAX_NUM_UUIDS, not the capacity of the caller's buffer described by prop->len. If the stored string contained more UUIDs than fit in prop->val, btif_split_uuids_string could write past the end of the buffer. Sibling cases in the same switch (e.g. BT_PROPERTY_CLASS_OF_DEVICE, BT_PROPERTY_REMOTE_VERSION_INFO) check prop->len before writing; the UUID cases did not.",
     "fix_analysis": [
      "system/btif/src/btif_storage.cc:cfg2prop (cases BT_PROPERTY_UUIDS and BT_PROPERTY_UUIDS_LE): the third argument to btif_split_uuids_string changes from BT_MAX_NUM_UUIDS to prop->len / sizeof(Uuid), so the parser stops after as many UUIDs as fit in the caller-provided buffer. prop->len is then set to num_uuids * sizeof(Uuid), as before.",
      "system/btif/test/btif_storage_test.cc: adds TEST(BtifStorageTest, test_uuid_split_zero_limit). It checks that btif_split_uuids_string with a limit of 0 returns 0 and does not modify the output array. The test exercises btif_split_uuids_string (the test includes btif/include/btif_util.h), not cfg2prop directly.",
      "The commit message calls this a companion to ag/40421805. That change is not in the material, so it is not visible whether it modifies btif_split_uuids_string."
     ],
     "completeness": [
      "Covers the single call site in cfg2prop(), which serves both BT_PROPERTY_UUIDS and BT_PROPERTY_UUIDS_LE (they share one case body).",
      "The fix relies on prop->len accurately describing the capacity of prop->val. It adds no separate check of prop->val and no check for a non-positive prop->len. Sibling cases compare prop->len to static_cast<int>(sizeof(...)), which suggests prop->len is an int. If so, a negative value converted to size_t in prop->len / sizeof(Uuid) would give a very large limit. The material does not show whether callers can supply such a value.",
      "Correct behaviour with a limit of 0 (returning 0 without writing) depends on btif_split_uuids_string. The new unit test checks this, but the function is not modified in this commit, and the companion change ag/40421805 is not in the material."
     ],
     "behavior_changes": [
      "When the stored UUID string contains more UUIDs than fit in the caller's prop->val buffer, the result is now cut down to the buffer capacity instead of overflowing it. prop->len becomes num_uuids * sizeof(Uuid) for the parsed subset. Callers that pass a buffer smaller than BT_MAX_NUM_UUIDS Uuids will receive fewer UUIDs than before.",
      "If a caller passes a prop->len smaller than sizeof(Uuid), the limit is 0, so (per the new test of btif_split_uuids_string) zero UUIDs are parsed, prop->len becomes 0 and ret is still true."
     ],
     "preconditions": [
      "cfg2prop() must be called for a remote device with prop->type BT_PROPERTY_UUIDS or BT_PROPERTY_UUIDS_LE and a prop->val buffer whose capacity is smaller than BT_MAX_NUM_UUIDS * sizeof(Uuid).",
      "The bt_config entry for that device under BTIF_STORAGE_KEY_REMOTE_SERVICE or BTIF_STORAGE_KEY_REMOTE_SERVICE_LE must contain more space-separated UUIDs than fit in the caller's buffer (the local string buffer is 1280 bytes).",
      "The material does not show how the stored UUID string is populated or which callers of cfg2prop pass undersized buffers (per index search, no callers were returned)."
     ],
     "per_major": {
      "14": "Not affected per the bulletin (not listed). At android-security-14.0.0_r30, 4/6 lines of the patched region are present. The material does not show which lines are missing or whether the old BT_MAX_NUM_UUIDS call exists in that branch.",
      "15": "Not affected per the bulletin (not listed). At android-security-15.0.0_r18, 4/6 lines of the patched region are present. The material does not show which lines are missing or whether the old BT_MAX_NUM_UUIDS call exists in that branch.",
      "16": "Same fix: commit 91bef351ef64 in android-security-16.0.0_r8. The code change is identical; the only context difference is that the function parameter is named remote_bd_addr instead of addr. It adds the same unit test. 5/6 lines of the patched region are present at android-security-16.0.0_r9.",
      "17": "Same fix: commit 5f719e21eef1 in android-security-17.0.0_r1 (cherry-pick of f6f30f9f5c32, Change-Id Ib6041c55f705afd9e9a8b980d7af9ba23aae2f02). The new call is present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "The source change replaces one argument at the btif_split_uuids_string call in cfg2prop, and the patch is the same whether the parameter is named addr or remote_bd_addr. The commit says it is a companion to ag/40421805 and 'can be backported'. That companion change is not in the material and its content is unknown, so check whether it is also needed, for example for the zero-limit behaviour the new test checks."
     ],
     "confidence": "high",
     "unknowns": [
      "Content of the companion change ag/40421805, and whether btif_split_uuids_string already handles a limit of 0 safely without it.",
      "Value of BT_MAX_NUM_UUIDS, and which callers of cfg2prop / btif_storage pass a buffer smaller than BT_MAX_NUM_UUIDS Uuids.",
      "How the stored UUID string in bt_config is populated and its maximum length relative to the 1280-byte local buffer.",
      "Whether the Android 14 and 15 branches contain the old BT_MAX_NUM_UUIDS call (the bulletin lists them as not affected)."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58865": {
     "cve": "CVE-2026-58865",
     "summary": "Adds a bounds check on the well-known content type index in PduParser.parseContentType and null checks for the parameter map and the parsed charset string in PduParser.parseContentTypeParams so a malformed MMS PDU no longer throws ArrayIndexOutOfBoundsException or NullPointerException during parsing.",
     "component": "platform/frameworks/base, telephony/common MMS PDU parser (com.google.android.mms.pdu.PduParser)",
     "weakness": "Missing bounds check (array index from PDU input) and missing null checks on parser state / parsed values, leading to uncaught runtime exceptions (DoS)",
     "root_cause": "In PduParser.java three sites trusted values parsed from the PDU without validation. (1) parseContentType indexed PduContentTypes.contentTypes directly with the value returned by parseShortInteger(pduDataStream); per the fix comments parseShortInteger returns 0-127 while the table covers 0-82, so an out-of-range short integer raised ArrayIndexOutOfBoundsException. (2) In parseContentTypeParams, case P_TYPE / P_CT_MR_TYPE, the short-integer branch called map.put(PduPart.P_TYPE, type) without checking map for null, although the method can be invoked with a null map (the new test notes that the ELEMENT_DESCRIPTOR path passes a null map); the sibling text-string branch at line 1443 already checked both type and map for null. (3) In parseContentTypeParams, case P_CHARSET, the extension-charset branch called new String(charsetStr) and map.put(PduPart.P_CHARSET, ...) without checking that parseWapString returned non-null or that map was non-null, raising NullPointerException on an empty charset string (per the new test) or a null map.",
     "fix_analysis": [
      "telephony/common/com/google/android/mms/pdu/PduParser.java:parseContentType (hunk at ~line 1624): the short-integer result is first stored in a local index; if index < PduContentTypes.contentTypes.length the table entry is used, otherwise contentType falls back to PduContentTypes.contentTypes[0] (\"*/*\") instead of throwing.",
      "telephony/common/com/google/android/mms/pdu/PduParser.java:parseContentTypeParams, case P_TYPE / P_CT_MR_TYPE (hunk at ~line 1431): map.put(PduPart.P_TYPE, type) is now wrapped in if (map != null), matching the existing null guard in the text-string branch.",
      "telephony/common/com/google/android/mms/pdu/PduParser.java:parseContentTypeParams, case P_CHARSET extension-charset branch (hunk at ~line 1496): the whole try/catch that builds new String(charsetStr) and stores P_CHARSET is now wrapped in if (charsetStr != null && map != null); when either is null the parameter is silently skipped.",
      "tests/TelephonyCommonTests/src/com/google/android/mms/pdu/PduParserTest.java (new file): adds regression tests testParse_invalidContentTypeIndex_doesNotThrowAIOOBE (content type index 83), testParse_elementDescriptorWithParams_doesNotThrowNPE (null map via ELEMENT_DESCRIPTOR), testParse_emptyCharset_doesNotThrowNPE (empty P_CHARSET string), plus two OOM tests (testParse_malformedHugeHeaderLength_doesNotOOM, testPduParserUnderflowOOM)."
     ],
     "completeness": [
      "Covers the three sites named in the commit message: the unchecked contentTypes index in parseContentType, the null map in the P_TYPE short-integer branch, and null charsetStr / null map in the P_CHARSET extension-charset branch.",
      "The bounds check only tests index < contentTypes.length (no lower bound); per the fix comment parseShortInteger returns 0-127 so a negative index is not expected, but this is not verified in the shown material.",
      "The well-known-charset (else) branch of the P_CHARSET case and the other parameter cases of parseContentTypeParams are not in the diff or the shown context, so whether they also perform map.put without a null check cannot be judged from the material.",
      "The new test file contains two OOM regression tests (huge part header length, uintvar underflow) that correspond to no code change in this commit; whether those conditions are handled elsewhere is unknown from the material."
     ],
     "behavior_changes": [
      "An out-of-range well-known content type index in parseContentType now resolves to contentTypes[0] (\"*/*\") instead of aborting the parse with ArrayIndexOutOfBoundsException.",
      "When parseContentTypeParams is invoked with a null map, well-known P_TYPE values are silently dropped instead of throwing NullPointerException.",
      "An extension charset string for which parseWapString returns null is silently ignored and no P_CHARSET entry is stored, instead of a NullPointerException.",
      "No new error codes or logging; the exceptional cases are handled by fall-through or fallback values."
     ],
     "preconditions": [
      "A malformed MMS PDU byte array reaches PduParser.parse() (constructed via new PduParser(byte[], boolean) as in the tests).",
      "For the AIOOBE: a Content-Type header encoded as a short integer whose value is >= PduContentTypes.contentTypes.length (the test uses 0xD3, index 83).",
      "For the P_TYPE NPE: a content type with a P_TYPE parameter parsed on a path that passes a null map (the test uses an ELEMENT_DESCRIPTOR header, 0xB2).",
      "For the charset NPE: a Content-Type with parameters whose P_CHARSET value is an empty text string (0x00) or parsed with a null map.",
      "The bulletin rates this Critical DoS; the material does not state which process parses the PDU in practice or who supplies it."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/base 53f75b4de647 in android-security-14.0.0_r30, identical diff (same three hunks and same new test file); 8/8 patched lines present.",
      "15": "same fix: platform/frameworks/base 51268a5c0ff9 in android-security-15.0.0_r18, identical diff; 8/8 patched lines present.",
      "16": "same fix: platform/frameworks/base 60f9d9a0bcac in android-security-16.0.0_r9, identical diff; 8/8 patched lines present.",
      "17": "same fix: platform/frameworks/base 05fef2f15699 in android-security-17.0.0_r2 (cherry-pick of cbb0d81bf086, Change-Id I4fab1579d22c4a1dcf2d75d4f4aab0a352df1bd9); 8/8 patched lines present."
     },
     "backport_notes": [
      "Single self-contained commit; the three PduParser.java hunks apply identically on 14 through 17 (only the pre-image blob differs between 17 and the older branches).",
      "The new PduParserTest.java also contains two OOM tests that do not correspond to code in this commit; if a fork lacks related changes those two tests may fail independently of this fix, so verify them separately."
     ],
     "confidence": "high",
     "unknowns": [
      "Which process or app parses the PDU in the affected configuration, how the PDU is delivered and who controls it (the bulletin and diff do not say), and therefore the exact blast radius of the uncaught exception.",
      "Which components build or bundle the telephony/common PduParser source.",
      "Whether the OOM conditions exercised by testParse_malformedHugeHeaderLength_doesNotOOM and testPduParserUnderflowOOM are addressed by separate commits under the same bug.",
      "Whether the remaining parameter cases in parseContentTypeParams (not shown in the material) guard map against null."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58880": {
     "cve": "CVE-2026-58880",
     "summary": "Removes the num_ext_attr/ext_attrs parameters from the AVRCP controller playerapplicationsetting_cb HAL callback so that the asynchronously executed JNI callback no longer receives pointers into ext_attrs memory freed by cleanup_app_attr_val_txt_response, and makes cleanup_app_attr_val_txt_response run synchronously on the caller.",
     "component": "platform/packages/modules/Bluetooth, system/btif AVRCP controller (btif_rc.cc), bt_rc.h HAL interface, AVRCP controller JNI",
     "weakness": "Use-after-free (asynchronous callback holds pointer to memory freed via cleanup_app_attr_val_txt_response)",
     "root_cause": "In system/btif/src/btif_rc.cc handle_app_attr_val_txt_response, after the attribute/value text responses were collected, the stack dispatched bt_rc_ctrl_callbacks->playerapplicationsetting_cb (CTRL_HAL_CBACK on 17, do_in_jni_thread(base::BindOnce(...)) on 16) with p_app_settings->num_ext_attrs and p_app_settings->ext_attrs, then posted cleanup_app_attr_val_txt_response(p_app_settings) via do_in_jni_thread and set num_attrs = 0 on the calling thread. Per the commit message, the callback executes asynchronously on the JNI thread while memory within ext_attrs is freed via cleanup_app_attr_val_txt_response, creating a use-after-free. The JNI implementation btavrcp_playerapplicationsetting_callback never used ext_attrs (commented out with a TODO), so the parameter carried a potentially dangling pointer for no purpose.",
     "fix_analysis": [
      "system/include/hardware/bt_rc.h: btrc_ctrl_playerapplicationsetting_callback typedef loses the uint8_t num_ext_attr and btrc_player_app_ext_attr_t* ext_attrs parameters; the callback now only takes bd_addr, num_attr and app_attrs.",
      "android/app/jni/com_android_bluetooth_avrcp_controller.cpp: btavrcp_playerapplicationsetting_callback signature updated to match; its body already ignored ext_attrs so no logic changes.",
      "system/btif/src/btif_rc.cc: the three call sites that passed `0, nullptr` (handle_app_val_response, handle_app_attr_txt_response, first branch of handle_app_attr_val_txt_response) and the one that passed p_app_settings->num_ext_attrs / p_app_settings->ext_attrs (final branch of handle_app_attr_val_txt_response) now pass only num_attrs and attrs.",
      "system/btif/src/btif_rc.cc handle_app_attr_val_txt_response: `do_in_jni_thread(base::BindOnce(cleanup_app_attr_val_txt_response, p_app_settings))` is replaced by a direct synchronous call `cleanup_app_attr_val_txt_response(p_app_settings)`; this is consistent with the callback no longer referencing ext_attrs.",
      "system/btif/test/btif_rc_test.cc: callback lambdas updated to the new 3-argument signature; the btif_transfer_context stub now copies parameters and invokes p_cback; btif_rc_transaction_timer_timeout_passthru now uses ASSERT_FALSE on transaction[1].in_use."
     ],
     "completeness": [
      "All four playerapplicationsetting_cb dispatch sites shown in btif_rc.cc are updated, and the HAL typedef change forces every implementer (JNI and tests) to drop the parameter, so no caller can still receive ext_attrs.",
      "The callback still receives p_app_settings->attrs (a pointer into p_dev->rc_app_settings) asynchronously while the posting thread sets p_app_settings->num_attrs = 0; the fix does not copy attrs for the async callback. The material does not show the storage lifetime of rc_app_settings, so whether this matters cannot be determined from the diff.",
      "Ext attribute data is now freed synchronously and is not delivered to the application at all (it was not used before either), so the fix removes rather than secures the ext_attrs delivery path."
     ],
     "behavior_changes": [
      "HAL interface change: btrc_ctrl_playerapplicationsetting_callback has 3 parameters instead of 5; any out-of-tree implementer of btrc_ctrl_callbacks_t must be updated.",
      "cleanup_app_attr_val_txt_response now runs synchronously on the calling thread instead of being posted to the JNI thread.",
      "No change in data delivered to Java: extended attributes were already ignored by the JNI layer.",
      "Unit test stub btif_transfer_context now executes callbacks, and the passthrough timeout test expectation changed to ASSERT_FALSE on in_use."
     ],
     "preconditions": [
      "AVRCP controller role with a connected remote AVRCP target, since the code lives in the bt_rc_ctrl_callbacks handling in btif_rc.cc.",
      "Remote target responds to player application setting attribute/value text requests such that handle_app_attr_val_txt_response reaches its final branch with ext_attrs populated, the only site that passed real ext_attrs to the callback.",
      "Bulletin rates this Critical EoP; the material does not detail the attacker position beyond the remote-device-driven response path."
     ],
     "per_major": {
      "14": "not affected per the bulletin (not listed); patched region partially present (4/8 lines) at android-security-14.0.0_r30; reason not shown in the material.",
      "15": "not affected per the bulletin (not listed); patched region partially present (6/8 lines) at android-security-15.0.0_r18; reason not shown in the material.",
      "16": "adapted fix: commit af2fe681d88d in android-security-16.0.0_r9 makes the same interface and cleanup changes, but call sites use do_in_jni_thread(base::BindOnce(bt_rc_ctrl_callbacks->playerapplicationsetting_cb, ...)) instead of CTRL_HAL_CBACK, the test stub uses bt_status_t/BT_STATUS_SUCCESS and std::copy_n, and the ASSERT_FALSE test change does not appear in the shown diff.",
      "17": "same fix: commit df3b47977847 in android-security-17.0.0_r2 (cherry pick of 3e7ec1e85fec), call sites use the CTRL_HAL_CBACK macro."
     },
     "backport_notes": [
      "Branches differ in how the callback is dispatched (CTRL_HAL_CBACK on 17 vs do_in_jni_thread(base::BindOnce(...)) on 16), so adapt the argument-list edit in handle_app_val_response, handle_app_attr_txt_response and handle_app_attr_val_txt_response to the target branch's dispatch form and keep the synchronous cleanup_app_attr_val_txt_response call.",
      "The bt_rc.h typedef change is a HAL-level signature change; all implementers of btrc_ctrl_callbacks_t (JNI, btif_rc_test.cc, any vendor forks) must be updated together or the build breaks."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact implementation of CTRL_HAL_CBACK on Android 17 (how it posts to the JNI thread) is not shown.",
      "What cleanup_app_attr_val_txt_response frees exactly and the storage/lifetime of p_dev->rc_app_settings.attrs are not shown.",
      "The precise ordering between the posted callback and the previously posted cleanup that produced the UAF is described only in the commit message.",
      "Why the passthrough timeout test assertion changed is not explained in the material.",
      "Why Android 14 and 15 are considered not affected despite containing part of the patched region is not shown."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-28667": {
     "cve": "CVE-2026-28667",
     "summary": "Adds a response-length check (length < p_i93->block_size) before three rw_i93_send_cmd_write_single_block calls in rw_t5t.cc, so that a short tag response no longer causes stale GKI buffer bytes beyond the received data to be sent back to the tag in a WRITE_SINGLE_BLOCK command.",
     "component": "platform/packages/modules/Nfc (Android 16/17) and platform/system/nfc (Android 14/15), libnfc-nci Type 5 tag (ISO 15693 / T5T) reader-writer state machine, rw_t5t.cc",
     "weakness": "Missing bounds check on the received response length before the response buffer is reused as a block_size-length command payload (disclosure of stale buffer memory over RF)",
     "root_cause": "In rw_t5t_sm_update_ndef and rw_t5t_sm_set_read_only, a pointer p into the received response buffer is passed to rw_i93_send_cmd_write_single_block(block_number, p) as the payload of an outgoing WRITE_SINGLE_BLOCK command. In the first update_ndef site the buffer is first modified in place, and in set_read_only *(p + 1) gets I93_ICODE_CC_READ_ONLY. The code never checked that the response actually held at least block_size bytes (the variable length). Per the commit message, a response shorter than block_size led to stale GKI buffer slack being copied into the outgoing command and sent over RF. The existing check in the preceding loop (xx > length, bug 122320256) only guards the in-place writes when ndef_length > 0. It does not guard the outgoing copy. The commit message says it ports bounds checks from b/143109193, b/143155861 and b/143106535 that were missing in rw_t5t.cc.",
     "fix_analysis": [
      "libnfc-nci/src/nfc/tags/rw_t5t.cc:rw_t5t_sm_update_ndef (first hunk, after block_number is computed from ndef_tlv_start_offset): a new 'if (length < p_i93->block_size)' runs before rw_i93_send_cmd_write_single_block(block_number, p). It logs android_errorWriteLog(0x534e4554, \"508389908\") and calls rw_i93_handle_error(NFC_STATUS_FAILED). The write is only sent from the else-if branch.",
      "libnfc-nci/src/nfc/tags/rw_t5t.cc:rw_t5t_sm_update_ndef (second hunk, block_number = rw_offset / block_size, the path that moves rw_offset to the start of the next block): the same length < block_size guard is added before rw_i93_send_cmd_write_single_block(block_number, p).",
      "libnfc-nci/src/nfc/tags/rw_t5t.cc:rw_t5t_sm_set_read_only (after I93_ICODE_CC_READ_ONLY is set in *(p + 1)): the same guard is added before rw_i93_send_cmd_write_single_block(0, p), so the CC block is only written back when the response held a full block.",
      "All three sites are in one commit, with no helper or header changes."
     ],
     "completeness": [
      "The fix guards three call sites of rw_i93_send_cmd_write_single_block in rw_t5t.cc that pass a pointer into the received response buffer. Each now requires length >= block_size. The material does not show the whole file, so other call sites cannot be ruled out.",
      "The check compares length to block_size only. rw_i93_send_cmd_write_single_block itself is unchanged, so this commit does not protect any other caller that passes a short buffer (none appears in the material).",
      "The pre-existing in-loop check (xx > length, bug 122320256) stays. The new check is additional and runs whether or not ndef_length > 0.",
      "The commit message says it ports checks from b/143109193, b/143155861 and b/143106535. Where those earlier fixes were applied is not shown in this material."
     ],
     "behavior_changes": [
      "During NDEF update or set-read-only, a T5T tag response shorter than the configured block_size now makes the operation fail through rw_i93_handle_error(NFC_STATUS_FAILED). Before the fix, a WRITE_SINGLE_BLOCK command was sent anyway.",
      "A new android_errorWriteLog(0x534e4554, \"508389908\") event is logged when the check trips.",
      "Nothing changes for tags whose responses contain at least block_size bytes."
     ],
     "preconditions": [
      "The device is reading or writing a Type 5 (ISO 15693) tag, and the libnfc-nci T5T state machine is in rw_t5t_sm_update_ndef or rw_t5t_sm_set_read_only at a point where the received response buffer is reused as a write payload.",
      "The tag returns a response shorter than p_i93->block_size.",
      "The data is disclosed over RF, i.e. within NFC range (commit title)."
     ],
     "per_major": {
      "14": "Same fix, applied to platform/system/nfc src/nfc/tags/rw_t5t.cc (commit f3a70c2a9415, android-security-14.0.0_r29). The three hunks are identical, at slightly different line offsets (550, 728, 810). 8/8 patched lines present at r30.",
      "15": "Same fix, applied to platform/system/nfc src/nfc/tags/rw_t5t.cc (commit 620bfc1582b9, android-security-15.0.0_r17), with hunks at the same offsets as 16/17. 8/8 lines present at r18.",
      "16": "Same fix, applied to platform/packages/modules/Nfc libnfc-nci/src/nfc/tags/rw_t5t.cc (commit 144b34ba8906, android-security-16.0.0_r8). 8/8 lines present at r9.",
      "17": "Same fix, platform/packages/modules/Nfc commit 2ad8845ad77e in android-security-17.0.0_r1 (cherry-pick of 5fdacfff0f15). 8/8 lines present at r2."
     },
     "backport_notes": [
      "A single self-contained commit. Only the file path differs between trees: src/nfc/tags/rw_t5t.cc in platform/system/nfc (14/15) versus libnfc-nci/src/nfc/tags/rw_t5t.cc in platform/packages/modules/Nfc (16/17, where libnfc-nci is part of the NFC mainline module (general platform knowledge)). Apply it by matching the three rw_i93_send_cmd_write_single_block calls. The variables length and p_i93 are already in scope at each site."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show the sub_state case labels for the first two hunks in rw_t5t_sm_update_ndef, how 'length' is derived from p_resp, or which command produced the response.",
      "The body of rw_i93_send_cmd_write_single_block (that it copies block_size bytes from p) is not in the material. This comes from the commit message.",
      "Where the earlier referenced fixes (b/143109193, b/143155861, b/143106535) were applied, and whether they fully cover analogous paths, is not shown.",
      "Whether rw_t5t.cc has other call sites that pass short buffers is not shown."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-45513": {
     "cve": "CVE-2026-45513",
     "summary": "Adds a length check in nfc_main_hal_data_cback (libnfc-nci nfc_main.cc) that drops incoming HAL packets whose data_len exceeds the usable capacity of a fixed-size NFC_NCI_POOL_ID GKI pool buffer, before any buffer is allocated.",
     "component": "platform/packages/modules/Nfc (Android 16/17) and platform/system/nfc (Android 14/15), libnfc-nci NCI transport layer (nfc_main.cc)",
     "weakness": "Missing bounds check leading to a pool buffer overflow (data length from the HAL is not validated against the fixed-size GKI pool buffer)",
     "root_cause": "In nfc_main_hal_data_cback, when the build takes the #else branch, the NCI packet received from the NFC HAL goes into a fixed-size buffer obtained with GKI_getpoolbuf(NFC_NCI_POOL_ID). The HAL-supplied data_len was never compared against the pool buffer size minus sizeof(NFC_HDR) and NFC_RECEIVE_MSGS_OFFSET. Per the commit message, an oversized HAL packet could therefore overflow the buffer. The sibling #if branch allocates with GKI_getbuf(sizeof(NFC_HDR) + NFC_RECEIVE_MSGS_OFFSET + data_len), which is sized to the data, and it is not changed.",
     "fix_analysis": [
      "libnfc-nci/src/nfc/nfc/nfc_main.cc:nfc_main_hal_data_cback (the commit message calls it nfc_main_hal_read_cback, but the diff is in nfc_main_hal_data_cback): in the #else (fixed pool) branch, before GKI_getpoolbuf(NFC_NCI_POOL_ID), the fix computes max_len = GKI_get_pool_bufsize(NFC_NCI_POOL_ID) - sizeof(NFC_HDR) - NFC_RECEIVE_MSGS_OFFSET.",
      "If data_len > max_len, the function logs an ERROR with both sizes, emits android_errorWriteLog(0x534e4554, \"508389591\") (a SafetyNet event log), and returns without allocating a buffer, so the packet is dropped.",
      "Adds #include <log/log.h> for android_errorWriteLog. Because the check runs before allocation, no pool buffer is leaked on the drop path."
     ],
     "completeness": [
      "Covers only the #else branch of nfc_main_hal_data_cback, which uses a fixed-size NFC_NCI_POOL_ID buffer. The GKI_getbuf branch is sized from data_len and is left as is.",
      "The check runs before allocation in this branch. The copy code that follows (inside 'if (p_msg != nullptr)') is not shown in the material. It is unchanged by the diff and is skipped by the early return.",
      "max_len is computed as uint16_t from GKI_get_pool_bufsize minus the header offsets. The material does not show the pool size, so the diff alone cannot tell whether the subtraction can underflow for an unusually small pool configuration.",
      "The commit changes one file with 10 inserted lines. No other HAL callback or pool-buffer consumer is modified."
     ],
     "behavior_changes": [
      "HAL packets larger than the pool buffer capacity are now dropped by this function (it returns early) and an ERROR log line states the sizes.",
      "A SafetyNet event log (tag 0x534e4554, bug id 508389591) is emitted when an oversized packet is dropped.",
      "nfc_main.cc now includes <log/log.h> and calls android_errorWriteLog."
     ],
     "preconditions": [
      "An NCI packet is delivered from the NFC HAL to the libnfc-nci stack through nfc_main_hal_data_cback, with data_len larger than the fixed pool buffer capacity.",
      "The build takes the #else branch (fixed-size GKI pool allocation via GKI_getpoolbuf) in nfc_main_hal_data_cback. The controlling #if condition is not shown in the material."
     ],
     "per_major": {
      "14": "Same fix: platform/system/nfc 1dfa112088a9 in android-security-14.0.0_r29, file src/nfc/nfc/nfc_main.cc. The hunk is identical; the includes block differs slightly (<base/logging.h> is present). 7/7 lines present at r30.",
      "15": "Same fix: platform/system/nfc 0a716527301d in android-security-15.0.0_r17, file src/nfc/nfc/nfc_main.cc. Identical hunk. 8/8 lines present at r18.",
      "16": "Same fix: platform/packages/modules/Nfc 2db7814d87ba in android-security-16.0.0_r8, file libnfc-nci/src/nfc/nfc/nfc_main.cc. Identical hunk. 8/8 lines present at r9.",
      "17": "Same fix: platform/packages/modules/Nfc 79b15334596b in android-security-17.0.0_r1, file libnfc-nci/src/nfc/nfc/nfc_main.cc. 8/8 lines present at r2."
     },
     "backport_notes": [
      "This is a single self-contained hunk. The only path difference is system/nfc/src/nfc/nfc/nfc_main.cc (Android 14/15) versus packages/modules/Nfc/libnfc-nci/src/nfc/nfc/nfc_main.cc (Android 16/17). The target tree must provide GKI_get_pool_bufsize and <log/log.h> / android_errorWriteLog.",
      "The commit message names nfc_main_hal_read_cback, but the function actually patched is nfc_main_hal_data_cback. Apply the check inside the #else (GKI_getpoolbuf) branch only."
     ],
     "confidence": "high",
     "unknowns": [
      "The preprocessor condition that selects GKI_getbuf versus GKI_getpoolbuf in nfc_main_hal_data_cback, and which branch production builds use.",
      "The exact copy code after allocation, and the configured size of NFC_NCI_POOL_ID buffers (neither is shown in the material).",
      "When and from where nfc_main_hal_data_cback is invoked (the index search found no other callers).",
      "Whether liblog is already linked in each target build.",
      "Whether the two Cherrypick-From sources contain anything beyond this single hunk (only this diff is provided)."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-45516": {
     "cve": "CVE-2026-45516",
     "summary": "Adds an unsigned-multiplication overflow check on the deltaSet array size (per_region_size * item_count) in tt_var_load_item_variation_store in external/freetype. Overflowing sizes now fail with Array_Too_Large instead of allocating a wrapped-around (too small) buffer.",
     "component": "platform/external/freetype, TrueType GX/OpenType variation loader (src/truetype/ttgxvar.c)",
     "weakness": "Integer overflow in allocation size computation leading to an undersized heap buffer (missing bounds check)",
     "root_cause": "In src/truetype/ttgxvar.c, tt_var_load_item_variation_store reads item_count, word_delta_count and region_idx_count with FT_READ_USHORT from the font's item variation store. It computes per_region_size (doubled when the long_words flag is set) and then allocated varData->deltaSet with FT_NEW_ARRAY( varData->deltaSet, per_region_size * item_count ). Both operands are FT_UInt and nothing checked the product for wrap-around, so a crafted font could make the 32-bit product wrap and produce an allocation smaller than the per_region_size by item_count size the code intended. The material does not show which later access of deltaSet would then go out of bounds (bulletin type: ID, information disclosure).",
     "fix_analysis": [
      "src/truetype/ttgxvar.c:tt_var_load_item_variation_store: a new local FT_UInt delta_set_size is declared next to per_region_size.",
      "Once per_region_size is final (including the long_words doubling), the code computes delta_set_size = per_region_size * item_count. If per_region_size is non-zero and delta_set_size / per_region_size != item_count (the unsigned multiplication wrapped), the function logs via FT_TRACE2, sets error = FT_THROW( Array_Too_Large ) and jumps to Exit.",
      "FT_NEW_ARRAY( varData->deltaSet, ... ) now uses delta_set_size instead of computing the product inline. Nothing else changes (single commit, 14 insertions, 1 deletion)."
     ],
     "completeness": [
      "The fix covers only the deltaSet allocation size in tt_var_load_item_variation_store. The division round-trip test is an exact overflow check for a two-operand unsigned product, and a per_region_size of zero cannot overflow.",
      "The diff does not show the length argument of the FT_Stream_Read into varData->deltaSet that follows the allocation. The material does not show whether that length was already the same product or is bounded some other way.",
      "Other size computations in the same function (for example the region list and varData arrays allocated earlier) are outside the diff. The material does not show whether they have equivalent checks."
     ],
     "behavior_changes": [
      "Fonts whose item variation store makes per_region_size * item_count wrap in 32 bits now fail to load with FT_Err_Array_Too_Large. Before the fix the allocation went ahead with the wrapped size.",
      "New FT_TRACE2 diagnostic message \"tt_var_load_item_variation_store: bad delta set array size\"."
     ],
     "preconditions": [
      "A TrueType/OpenType font with an item variation store (parsed by tt_var_load_item_variation_store) whose item_count, region_idx_count/word_delta_count and long_words flag make the deltaSet size product wrap.",
      "FreeType must open the font on the device. Per index search, Font::init in frameworks/rs/rsFont.cpp calls FT_New_Memory_Face / FT_New_Face on caller-supplied font data, and frameworks/minikin uses FreeType in its test font factory (FreeTypeMinikinFontForTest)."
     ],
     "per_major": {
      "14": "Not affected per the bulletin, and the material gives no Android 14 fix commit. At android-security-14.0.0_r30, 2/8 lines of the patched region are present. That count alone does not show whether the pre-fix code exists there.",
      "15": "Same fix: commit 2e564343a4ce in android-security-15.0.0_r17 (identical hunk, line offsets 625/682 instead of 628/697). 7/8 lines of the patched region present at r18.",
      "16": "Same fix: commit 285b264bf272 in android-security-16.0.0_r8 (identical hunk to Android 15). 7/8 lines present at r9.",
      "17": "Same fix: commit 333924d9d5ea in android-security-17.0.0_r1 (cherry-pick of e6bcebe7f6e0, Change-Id I71441187859a413c0094637f7e9cfead76616a95). 7/8 lines present at r2."
     },
     "backport_notes": [
      "Single self-contained hunk in tt_var_load_item_variation_store with no dependencies shown. Google applied it to 15, 16 and 17 with only line-offset differences."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show the exact out-of-bounds consequence (which later access of deltaSet goes out of bounds). The diff only makes the undersized allocation evident.",
      "The third argument of the FT_Stream_Read after the allocation is not shown, so it is unknown whether the wrap also affected the read length.",
      "The material does not show how per_region_size is computed from word_delta_count and region_idx_count.",
      "The material does not explain why the bulletin does not list Android 14, or whether the vulnerable code is present there (only 2/8 lines of the patched region are present)."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-45524": {
     "cve": "CVE-2026-45524",
     "summary": "WifiPermissionsUtil#isSystem now returns false for Private Compute Core UIDs (when SdkLevel.isAtLeastC()), so PCC callers are no longer treated as system apps for Wi-Fi permission decisions.",
     "component": "platform/packages/modules/Wifi, WifiPermissionsUtil (Wi-Fi service permission checks)",
     "weakness": "Improper privilege/identity classification (missing exclusion check): a restricted UID class was granted system-app status, bulletin type ID (information disclosure)",
     "root_cause": "WifiPermissionsUtil.isSystem(packageName, uid) decided system-app status only by looking up ApplicationInfo for the package/uid and testing APP_INFO_FLAGS_SYSTEM_APP. The only UID-class exclusion was for SDK sandbox UIDs (Process.isSdkSandboxUid on T+). Private Compute Core UIDs were not excluded, so a PCC caller whose package resolved to a system-flagged ApplicationInfo was treated as a system app for Wi-Fi permissions, which the commit message says should not happen.",
     "fix_analysis": [
      "service/java/com/android/server/wifi/util/WifiPermissionsUtil.java:isSystem: after the existing isSdkSandboxUid exclusion and before the PackageManager lookup, adds `if (SdkLevel.isAtLeastC() && Process.isPrivateComputeCoreUid(uid))`, which logs a warning and returns false. Like the sandbox check, it runs inside the Binder.clearCallingIdentity/restoreCallingIdentity block.",
      "service/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java: adds testIsSystem covering the sandbox UID (T+), the PCC UID (C+), a system app flag, a non-system app, and NameNotFoundException. Process is mocked statically for the UID-class cases and PackageManager is mocked for the ApplicationInfo cases."
     ],
     "completeness": [
      "Covers only the isSystem helper. The PCC exclusion comes before the ApplicationInfo lookup, so it applies whatever flags the package has.",
      "The exclusion is gated on SdkLevel.isAtLeastC(). On devices where this returns false, the check is skipped and behavior is unchanged.",
      "The commit message says the behavior is tied to the enablePccFrameworkSupport flag, but the diff shows no flag read. The only gate in the code is SdkLevel.isAtLeastC().",
      "Other permission helpers in WifiPermissionsUtil are not shown in the material and this commit does not touch them. The material does not show whether any of them classify PCC UIDs on their own."
     ],
     "behavior_changes": [
      "On builds where SdkLevel.isAtLeastC() is true, isSystem returns false for any UID for which Process.isPrivateComputeCoreUid(uid) is true, even if the resolved ApplicationInfo has a system-app flag.",
      "A new Log.w line 'isSystem: isPrivateComputeCoreUid, returning false' is emitted when the exclusion triggers.",
      "Any Wi-Fi service path that relied on isSystem to grant system-only treatment now denies it to PCC callers."
     ],
     "preconditions": [
      "A binder call into the Wi-Fi service from a Private Compute Core UID reaches a code path that consults WifiPermissionsUtil.isSystem. The callers are not shown in the material, and per index search nothing outside the Wifi component was found.",
      "SdkLevel.isAtLeastC() is true on the device; otherwise the new check is bypassed.",
      "The PCC package resolves via getApplicationInfoAsUser to an ApplicationInfo carrying a system-app flag."
     ],
     "per_major": {
      "14": "not affected per the bulletin; at android-security-14.0.0_r30, 4/6 lines of the patched region are present (the material does not show which lines are missing); no fix applied",
      "15": "not affected per the bulletin; at android-security-15.0.0_r18, 4/6 lines of the patched region are present (which lines are missing is not shown); no fix applied",
      "16": "not affected per the bulletin; at android-security-16.0.0_r9, 4/6 lines of the patched region are present (which lines are missing is not shown); no fix applied",
      "17": "same fix: commit 78ed57915792 (cherry-pick of fc70c981d930) in android-security-17.0.0_r1; all 6/6 patched lines present at android-security-17.0.0_r2"
     },
     "backport_notes": [
      "The fix uses Process.isPrivateComputeCoreUid behind an SdkLevel.isAtLeastC() gate. The bulletin lists older branches as not affected, so no backport is indicated. Wifi is a mainline module, so the module build must compile against an SDK that exposes Process.isPrivateComputeCoreUid (general platform knowledge)."
     ],
     "confidence": "high",
     "unknowns": [
      "Which Wi-Fi service entry points call isSystem, and what data or capability a PCC caller obtained through system-app status (the bulletin only states type ID, High).",
      "How the enablePccFrameworkSupport flag mentioned in the commit message relates to the code; the diff shows only the SdkLevel.isAtLeastC() gate.",
      "Which Android release SdkLevel C corresponds to; the material does not state it.",
      "Which lines of the patched region are missing on 14, 15 and 16.",
      "Whether the original commit fc70c981d930 differs from the cherry-pick."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-49878": {
     "cve": "CVE-2026-49878",
     "summary": "Replaces two undersized os_zalloc(num_active_scs) allocations for the int arrays scs_resp[0] and scs_resp[1] in wpas_handle_robust_av_scs_recv_action with os_calloc(num_active_scs, sizeof(int)), so the buffers are sized in int elements rather than bytes.",
     "component": "platform/external/wpa_supplicant_8, wpa_supplicant Robust AV / SCS (Stream Classification Service) action frame handling",
     "weakness": "Incorrect allocation size (heap out-of-bounds write)",
     "root_cause": "In wpa_supplicant/robust_av.c, wpas_handle_robust_av_scs_recv_action allocated scs_resp[0] and scs_resp[1] with os_zalloc(num_active_scs), which is num_active_scs bytes, but both buffers are used as int arrays. The allocations were sizeof(int) times too small. According to the commit message, this led to heap out-of-bounds writes.",
     "fix_analysis": [
      "wpa_supplicant/robust_av.c:wpas_handle_robust_av_scs_recv_action: scs_resp[0] = (int *) os_zalloc(num_active_scs) becomes scs_resp[0] = os_calloc(num_active_scs, sizeof(int)), which allocates num_active_scs zero-initialized int elements.",
      "wpa_supplicant/robust_av.c:wpas_handle_robust_av_scs_recv_action: the same change is made for scs_resp[1]. These parts are unchanged: the NULL checks, the os_free(scs_resp[0]) when the second allocation fails, and the earlier validation (dialog token match, count != 0, count * 3 <= len, num_active_scs >= count).",
      "Single commit, two-line change. No new bounds checks are added."
     ],
     "completeness": [
      "The fix corrects both allocations in the function. No other allocation in the shown region uses the byte-count pattern.",
      "The code that stores into scs_resp comes after line 1105 and is not shown, so the material does not let us verify that its indexing stays within num_active_scs elements.",
      "No other functions in robust_av.c are touched. The material does not show any sibling handler with the same pattern."
     ],
     "behavior_changes": [
      "scs_resp[0] and scs_resp[1] are now larger allocations (num_active_scs * sizeof(int) bytes). No protocol, logging or return-value change."
     ],
     "preconditions": [
      "wpa_supplicant must receive a Robust AV SCS Response action frame that reaches wpas_handle_robust_av_scs_recv_action.",
      "The frame's dialog token must equal wpa_s->scs_dialog_token, and the frame must pass count > 0, count * 3 <= remaining length, and dl_list_len(&wpa_s->active_scs_ids) >= count."
     ],
     "per_major": {
      "14": "same fix: commit 5de2705a451f in android-security-14.0.0_r29, the same two-line change at a different offset (@@ -640). At android-security-14.0.0_r30, 5/7 lines of the patched region are reported present.",
      "15": "same fix: commit d14e657ca1ae in android-security-15.0.0_r17, the same two-line change at @@ -807. At android-security-15.0.0_r18, 5/7 lines of the patched region are reported present.",
      "16": "same fix: commit d131540379d6 in android-security-16.0.0_r8, the same two-line change at @@ -881. At android-security-16.0.0_r9, 5/7 lines of the patched region are reported present.",
      "17": "same fix: commit ffd3987bbece in android-security-17.0.0_r1 at @@ -1072. The code at android-security-17.0.0_r2 shows both os_calloc calls in place."
     },
     "backport_notes": [
      "Self-contained two-line change with no shown dependencies. The same diff was applied on 14 through 17; only the hunk offset differs."
     ],
     "confidence": "high",
     "unknowns": [
      "The loop body that writes into scs_resp[0]/scs_resp[1] after line 1105 is not shown, so the exact indexing and number of writes are not visible.",
      "Whether a matching dialog token requires the station to have sent an SCS Request first is not shown.",
      "The meaning of the '5/7 lines of the patched region present' resolver figure is not explained. The 17 r2 code shown confirms the fix is present there."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-49880": {
     "cve": "CVE-2026-49880",
     "summary": "Adds a p_dataBuf_len field to the T4T NFCEE control block, records the allocated size at each allocation, and checks rd_offset + p_data->len against it before the memcpy in nfa_t4tnfcee_store_rx_buf. It also adds length underflow checks in nfa_t4tnfcee_check_sw and nfa_t4tnfcee_store_cc_info and NULL checks on the nfa_mem_co_alloc results.",
     "component": "platform/packages/modules/Nfc, libnfc-nci NFA T4T NFCEE (NDEF NFCEE) read/write handling (libnfc-nci/src/nfa/ndefnfcee/t4t/nfa_nfcee_act.cc)",
     "weakness": "Missing bounds check leading to heap out-of-bounds write (plus integer/pointer underflow and unchecked allocation results in adjacent code)",
     "root_cause": "nfa_t4tnfcee_store_rx_buf copied p_data->len bytes of incoming T4T NFCEE read data into nfa_t4tnfcee_cb.p_dataBuf at nfa_t4tnfcee_cb.rd_offset and then advanced rd_offset. It never compared the resulting range to the buffer's allocated size. The buffer is allocated in nfa_t4tnfcee_handle_file_operations with lenDataToBeRead (and in nfa_t4tnfcee_store_cc_info with p_data->len), and the control block kept no record of that size. A response whose accumulated length exceeded the allocation therefore wrote past the heap buffer. Adjacent issues: nfa_t4tnfcee_check_sw computed p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE) without checking that len >= T4T_RSP_STATUS_WORDS_SIZE (pointer underflow). nfa_t4tnfcee_store_cc_info advanced ccInfo by jumpToFirstTLV without checking that p_data->len was large enough (uint16 underflow, per the commit message). The nfa_mem_co_alloc results for p_dataBuf were used without a NULL check.",
     "fix_analysis": [
      "libnfc-nci/src/nfa/include/nfa_nfcee_int.h: tNFA_T4TNFCEE_CB gains uint32_t p_dataBuf_len, the allocated size of p_dataBuf.",
      "nfa_nfcee_act.cc:nfa_t4tnfcee_handle_file_operations: after nfa_mem_co_alloc(lenDataToBeRead), a NULL result sets p_dataBuf_len = 0 and status = NFC_STATUS_FAILED, calls nfa_t4tnfcee_notify_rx_evt() and breaks. Otherwise p_dataBuf_len = lenDataToBeRead is set before RW_T4tNfceeReadFile is issued.",
      "nfa_nfcee_act.cc:nfa_t4tnfcee_store_cc_info: in the branch that allocates p_dataBuf with p_data->len, the memcpy now runs only when the allocation succeeded, and p_dataBuf_len is set to p_data->len (0 otherwise). In the other branch, a new check rejects p_data->len < (0x07 + T4TNFCEE_SIZEOF_STATUS_BYTES) with a LOG(ERROR) and returns before ccInfo is advanced by jumpToFirstTLV.",
      "nfa_nfcee_act.cc:nfa_t4tnfcee_store_rx_buf: the memcpy and the rd_offset increment are now guarded by ((uint32_t)rd_offset + p_data->len) <= p_dataBuf_len. On failure it logs, sets nfa_t4tnfcee_cb.status = NFA_STATUS_FAILED and emits android_errorWriteLog(0x534e4554, \"508390497\") (new #include <log/log.h>).",
      "nfa_nfcee_act.cc:nfa_t4tnfcee_check_sw: when p_r_apdu->len < T4T_RSP_STATUS_WORDS_SIZE, it sets p_rwData->raw_frame.status = NFC_STATUS_FAILED and returns early, before the pointer arithmetic that subtracts T4T_RSP_STATUS_WORDS_SIZE.",
      "nfa_nfcee_act.cc:nfa_t4tnfcee_free_rx_buf and nfa_t4tnfcee_initialize_data: reset p_dataBuf_len to 0 together with p_dataBuf/rd_offset/dataLen, so the length never outlives the buffer."
     ],
     "completeness": [
      "The core OOB write is covered. Both allocation sites of p_dataBuf shown in the diff (nfa_t4tnfcee_handle_file_operations and nfa_t4tnfcee_store_cc_info) now record p_dataBuf_len, and both reset sites in the diff clear it. The memcpy in nfa_t4tnfcee_store_rx_buf is bounds-checked, and the addition is done in uint32_t, so uint16_t rd_offset + uint16_t len cannot wrap.",
      "On the overflow path, nfa_t4tnfcee_store_rx_buf only sets nfa_t4tnfcee_cb.status and logs. It does not advance rd_offset or notify, and the material does not show how the caller ends the read operation after this failure.",
      "In nfa_t4tnfcee_store_cc_info, a failed allocation sets p_dataBuf_len = 0 and returns without setting an error status. In the other branch, the new length check only guarantees 0x07 + T4TNFCEE_SIZEOF_STATUS_BYTES bytes. The TLV parsing past ccInfo that follows is not in the diff, so its bounds handling is not visible here.",
      "nfa_t4tnfcee_check_sw sets raw_frame.status = NFC_STATUS_FAILED and returns on a short APDU. The diff does not show how callers consume that status."
     ],
     "behavior_changes": [
      "Read data chunks that would exceed the allocated p_dataBuf are dropped. nfa_t4tnfcee_cb.status becomes NFA_STATUS_FAILED and an errorWriteLog entry (0x534e4554, \"508390497\") is emitted.",
      "Responses shorter than T4T_RSP_STATUS_WORDS_SIZE now fail in nfa_t4tnfcee_check_sw with raw_frame.status = NFC_STATUS_FAILED instead of being parsed.",
      "CC file data shorter than 0x07 + T4TNFCEE_SIZEOF_STATUS_BYTES is rejected with a LOG(ERROR) in nfa_t4tnfcee_store_cc_info.",
      "A failed allocation in nfa_t4tnfcee_handle_file_operations now reports NFC_STATUS_FAILED via nfa_t4tnfcee_notify_rx_evt instead of continuing with a NULL buffer."
     ],
     "preconditions": [
      "The code is in the NFA T4T NFCEE (NDEF NFCEE) read path for CC/NDEF files. The exact device and configuration conditions that enable this subsystem are not shown in the material.",
      "A read operation must be in progress (p_dataBuf allocated in nfa_t4tnfcee_handle_file_operations or nfa_t4tnfcee_store_cc_info), and the incoming read-file response data, accumulated via rd_offset, must exceed the allocated size. The commit message describes this as happening 'when reading data from T4T NFCEE'.",
      "The material does not show who can influence the response lengths (NFCC firmware, NFCEE, or another source)."
     ],
     "per_major": {
      "14": "not affected per the bulletin; the Nfc project is not present in Android 14 security tags (android-security-14.0.0_r30)",
      "15": "not affected per the bulletin; the Nfc project is not present in Android 15 security tags (android-security-15.0.0_r18)",
      "16": "same fix: commit 4f214cca6dff in android-security-16.0.0_r8, with an identical diff (same blob hashes af978aaba..11d58628d and e32d0e1be..ed95becf2); at android-security-16.0.0_r9, 8/8 patched lines present",
      "17": "same fix: commit ebcfc2564b95 in android-security-17.0.0_r1 (cherry-pick of dcbd63d5d860); at android-security-17.0.0_r2, 8/8 patched lines present"
     },
     "backport_notes": [
      "This is a single commit touching two files. The header change (new p_dataBuf_len in tNFA_T4TNFCEE_CB) must go in together with the .cc change. All allocation and reset sites of p_dataBuf in the target tree must also be updated, otherwise the check in nfa_t4tnfcee_store_rx_buf compares against a stale or zero length. The android_errorWriteLog call requires <log/log.h> (liblog)."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact source that can supply oversized read responses (NFCC firmware, NFCEE, host-side path) and the privilege needed to reach it.",
      "How callers of nfa_t4tnfcee_store_rx_buf and nfa_t4tnfcee_check_sw react to the new failure statuses (the dispatch code in nfa_t4tnfcee_handle_t4t_evt is not in the material).",
      "Bounds handling of the TLV parsing that follows the new length check in nfa_t4tnfcee_store_cc_info (not in the diff).",
      "Whether code outside the diff hunks writes into p_dataBuf in any other place."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 2,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-49885": {
     "cve": "CVE-2026-49885",
     "summary": "Adds an underflow guard in rw_t4t_set_ber_tlv() so data_length is only computed when p_t4t->max_update_size exceeds the ODO/DDO data_header, and makes rw_t4t_update_file() free the C-APDU GKI buffer when rw_t4t_set_ber_tlv() fails.",
     "component": "platform/packages/modules/Nfc (libnfc-nci), Type 4 Tag reader/writer (libnfc-nci/src/nfc/tags/rw_t4t.cc); on Android 14/15 the same file lives in platform/system/nfc (src/nfc/tags/rw_t4t.cc)",
     "weakness": "Missing bounds check leading to unsigned integer underflow in a length computation (plus a memory leak on the error path)",
     "root_cause": "In rw_t4t_set_ber_tlv(), when the requested write length does not fit in p_t4t->max_update_size, the code realigns to MLc and computes data_length = p_t4t->max_update_size - data_header, where data_header = RW_T4T_ODO_DDO_HEADER_MIN_LENGTH + length_size. Nothing checked that max_update_size was larger than data_header, so a small max_update_size could make the subtraction underflow (per the commit message). The material does not show how data_length is consumed afterwards. Separately, rw_t4t_update_file() returned the result of rw_t4t_set_ber_tlv() directly, so a false return left the already allocated p_c_apdu GKI buffer unfreed.",
     "fix_analysis": [
      "libnfc-nci/src/nfc/tags/rw_t4t.cc:rw_t4t_set_ber_tlv(): this is the length == 0 branch, where length is reset to T4T_MAX_LENGTH_LC and then found to be larger than max_update_size. After length = p_t4t->max_update_size, a new check 'if (p_t4t->max_update_size <= data_header)' logs an error and returns false before data_length = p_t4t->max_update_size - data_header is computed.",
      "libnfc-nci/src/nfc/tags/rw_t4t.cc:rw_t4t_set_ber_tlv(): the same check is added in the else branch (explicit length, where length + data_header > max_update_size) before the same subtraction.",
      "libnfc-nci/src/nfc/tags/rw_t4t.cc:rw_t4t_update_file(): on the MV 3.0 / NDEF size > 0x7FFF path, 'return rw_t4t_set_ber_tlv(p_c_apdu, p, length);' is replaced with a check. When rw_t4t_set_ber_tlv() fails, it calls GKI_freebuf(p_c_apdu) and returns false; otherwise it returns true."
     ],
     "completeness": [
      "Both branches in rw_t4t_set_ber_tlv() that subtract data_header from max_update_size are guarded. The check uses <=, so a max_update_size equal to data_header (zero payload) is also rejected.",
      "The two other branches (T4T_MAX_LENGTH_LC - data_header, and length += data_header) do not subtract from max_update_size and are left unchanged. T4T_MAX_LENGTH_LC - data_header assumes the constant is larger than the header; the material does not show the constant's value, and the fix does not touch that branch.",
      "The GKI_freebuf wrapper in rw_t4t_update_file() runs on every false return from rw_t4t_set_ber_tlv(). The material does not show whether there were other false-returning paths before this change, or whether any of them already frees p_c_apdu itself.",
      "The fix checks the value at the point where it is used. It does not change how p_t4t->max_update_size is set or validated earlier."
     ],
     "behavior_changes": [
      "When max_update_size <= data_header, a T4T write via the BER-TLV (ODO/DDO) path now fails with the ERROR log 'max_update_size too small for ODO/DDO header'. Before the fix, it went on to compute an underflowed data_length.",
      "rw_t4t_update_file() now frees the C-APDU buffer and returns false when rw_t4t_set_ber_tlv() fails, instead of leaking it."
     ],
     "preconditions": [
      "The code is reached from rw_t4t_update_file() when an MV 3.0 tag is detected and the NDEF message to write is larger than 0x7FFF (per the surrounding log messages in the diff).",
      "p_t4t->max_update_size must be no larger than data_header (RW_T4T_ODO_DDO_HEADER_MIN_LENGTH + length_size, where length_size is RW_T4T_BER_TLV_LENGTH_2_BYTES or RW_T4T_BER_TLV_LENGTH_3_BYTES). The material does not show how max_update_size is set.",
      "An NFC write to a Type 4 tag must be in progress. Per index search, no callers were found outside the Nfc component (the search may be incomplete)."
     ],
     "per_major": {
      "14": "same fix, applied to platform/system/nfc src/nfc/tags/rw_t4t.cc (commit 90576eadff36, android-security-14.0.0_r29). The added lines are identical; only the surrounding context differs (DLOG_IF logging, '%s - ' log prefix). 8/8 lines present at r30.",
      "15": "same fix, applied to platform/system/nfc src/nfc/tags/rw_t4t.cc (commit f01d5b0889f5, android-security-15.0.0_r17). Identical added lines. 8/8 lines present at r18.",
      "16": "same fix, applied to platform/packages/modules/Nfc libnfc-nci/src/nfc/tags/rw_t4t.cc (commit 9c0ae67d8733, android-security-16.0.0_r8). 8/8 lines present at r9.",
      "17": "same fix, platform/packages/modules/Nfc commit 0dc8fad01628 in android-security-17.0.0_r1 (cherry-pick of 91208e26395b). 8/8 lines present at r2."
     },
     "backport_notes": [
      "Single-commit fix. The file sits in platform/system/nfc on Android 14/15 and in platform/packages/modules/Nfc/libnfc-nci on Android 16/17, so between branches only the path and hunk offsets change. The context on 14 uses different logging macros (DLOG_IF), but the added lines use LOG(ERROR) << StringPrintf, which is how they appear in the 14 backport too."
     ],
     "confidence": "high",
     "unknowns": [
      "The declared type of data_length and how the underflowed value is used downstream (the material shows only the computation, not its later use in the C-APDU).",
      "Where p_t4t->max_update_size comes from and whether an attacker can influence it.",
      "Whether rw_t4t_set_ber_tlv() had other false-returning paths before this change, and whether any of them already freed p_c_apdu.",
      "Which of the two bugs (498891727, 508389525) is the underflow and which is the leak."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-49937": {
     "cve": "CVE-2026-49937",
     "summary": "libfmq's MessageQueueBase now treats a read/write pointer distance larger than the queue size as pointer corruption (synchronized flavor only) and rejects beginRead() requests for more messages than getQuantumCount() (synchronized flavor only).",
     "component": "platform/system/libfmq, include/fmq/MessageQueueBase.h (Fast Message Queue read path)",
     "weakness": "Missing bounds check on shared read/write pointers and the requested read size (information disclosure per the bulletin; an out-of-bounds read is the likely consequence but the material does not show it)",
     "root_cause": "MessageQueueBase::availableToReadBytes() loaded mWritePtr and mReadPtr and rejected only the case writePtr < readPtr. Otherwise it returned writePtr - readPtr unconditionally. If the pointers were inconsistent so that the difference exceeded mDesc->getSize(), the function reported more readable bytes than the queue holds. beginRead() also had no check that nMessages fits within getQuantumCount(). The commit reapplies an earlier change that had been reverted (revert commit 11165074cdd9). Per the commit message, the reapplied version restricts the beginRead() check to kSynchronizedReadWrite because the unsync flavor is expected to overflow when readers are too slow.",
     "fix_analysis": [
      "include/fmq/MessageQueueBase.h:availableToReadBytes(): computes queueSizeBytes = mDesc->getSize() and availableBytes = (writePtr >= readPtr) ? writePtr - readPtr : SIZE_MAX. The corruption branch now triggers when writePtr < readPtr OR (flavor == kSynchronizedReadWrite && availableBytes > queueSizeBytes). In that branch it logs the pointers and the queue size, calls mErrorHandler(Error::POINTER_CORRUPTION, ...) if one is set, and returns 0. Otherwise it returns availableBytes.",
      "include/fmq/MessageQueueBase.h:beginRead(): adds an early check, for flavor == kSynchronizedReadWrite only, that nMessages <= getQuantumCount(). If the check fails it logs an error and returns false before *result is initialized.",
      "The commit message says tests for beginRead() and for unsync overflow behaviour were added, but the shown diff changes only include/fmq/MessageQueueBase.h (1 file changed)."
     ],
     "completeness": [
      "Both new checks are gated on flavor == kSynchronizedReadWrite. For the unsync flavor, availableToReadBytes() still returns writePtr - readPtr with only the writePtr < readPtr check, and beginRead() has no nMessages cap. The commit message says this is intentional because overflows are expected in that flavor.",
      "Only the read path (availableToReadBytes, beginRead) changes. The write path is not modified in this diff (commitWrite is visible in the context; availableToWriteBytes and beginWrite are not shown), so the material does not show whether a symmetric check is needed there.",
      "The check in availableToReadBytes() uses mDesc->getSize() (bytes), while the check in beginRead() uses getQuantumCount() (messages)."
     ],
     "behavior_changes": [
      "Synchronized queues whose pointer distance exceeds the queue size now report 0 readable bytes and log an error that includes the queue size. On 16 and 17 they also invoke the registered mErrorHandler with Error::POINTER_CORRUPTION. On 15 they set *errorDetected. On 14 they only log.",
      "beginRead() on a synchronized queue now returns false, with an error log, when nMessages > getQuantumCount(). read() calls beginRead(), so read() also fails in that case.",
      "On Android 14, 15 and 16 the beginRead() rejection also calls hardware::details::errorWriteLog(0x534e4554, \"514861024\"). The Android 17 commit does not include this line.",
      "The new checks do not apply to the unsync flavor. The only change for those queues is that the corruption log message (writePtr < readPtr) now includes the queue size."
     ],
     "preconditions": [
      "A process reads from a MessageQueueBase of flavor kSynchronizedReadWrite via read() or beginRead() (read() calls beginRead(), per the code context).",
      "The mWritePtr/mReadPtr values seen by the reader are inconsistent with the queue size (writePtr - readPtr > mDesc->getSize()), or a caller passes an nMessages larger than getQuantumCount(). FMQ read/write pointers and the ring buffer live in memory shared with the peer process (general platform knowledge)."
     ],
     "per_major": {
      "14": "adapted fix (452c5e918cde, android-security-14.0.0_r29): same two checks. availableToReadBytes() on this branch has no mErrorHandler, so the error message is built as a std::string and only logged. beginRead() also adds errorWriteLog(0x534e4554, \"514861024\"). Resolver: 6/8 lines of the patched region present at r30.",
      "15": "adapted fix (6d316edf3cc8, android-security-15.0.0_r17): same checks, applied to the availableToReadBytes() variant that sets *errorDetected = Error::POINTER_CORRUPTION. beginRead() includes the errorWriteLog line. Resolver: 6/8 lines present at r18.",
      "16": "same fix (3aa82fe2d0a8, android-security-16.0.0_r8) plus the errorWriteLog line in beginRead(). Resolver: 6/8 lines present at r9.",
      "17": "same fix (f727482ff0c6, android-security-17.0.0_r1), without the errorWriteLog line. The code context at android-security-17.0.0_r2 shows the new availableToReadBytes() logic in place. Resolver: 6/8 lines of the patched region present."
     },
     "backport_notes": [
      "Single header-only change. The only differences between branches are how availableToReadBytes() reports errors (mErrorHandler on 16/17, errorDetected out-param on 15, log only on 14) and the optional errorWriteLog line in beginRead() on 14 to 16. Keep the flavor == kSynchronizedReadWrite gate: the commit message says the unsync flavor is expected to overflow, and this commit reapplies a change that had been reverted (11165074cdd9)."
     ],
     "confidence": "medium",
     "unknowns": [
      "The material does not show the write-side functions (availableToWriteBytes/beginWrite), so whether they have a similar bound is unknown.",
      "The body of beginRead() after the new check is not shown, so how an oversized nMessages was handled before the fix (e.g. whether a MemTransaction beyond the buffer could be produced) is not shown.",
      "The reason the original change was reverted is not stated.",
      "The resolver's '6/8 lines present' figure is not explained. The r2 context confirms the availableToReadBytes() change, but the beginRead() region at r2 is not shown.",
      "The test changes mentioned in the commit message (and the three Cherrypick-From commits) are not part of the shown diff.",
      "The concrete trigger behind the bug report (how the pointers become inconsistent in practice) is not shown."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 6,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-55266": {
     "cve": "CVE-2026-55266",
     "summary": "Rewrites the partition handling in the qsort copy in libufdt's vendor sysdeps so it recurses on the smaller partition and iterates on the larger one, bounding recursion depth to O(log n).",
     "component": "platform/system/libufdt, sysdeps/libufdt_sysdeps_vendor.c (vendor qsort)",
     "weakness": "Uncontrolled recursion (stack exhaustion) in qsort partition recursion",
     "root_cause": "The qsort implementation in sysdeps/libufdt_sysdeps_vendor.c always recursed on the left partition (pb - pa) and iterated (goto loop) on the right partition (pd - pc), whatever their sizes. With inputs that repeatedly produce a large left partition, recursion depth can grow linearly with the number of elements, so a large or adversarially ordered array can exhaust the stack (DoS per bulletin; the commit message cites stack overflow risk on large or adversarial inputs).",
     "fix_analysis": [
      "sysdeps/libufdt_sysdeps_vendor.c:qsort adds a local 'int l'. After the vecswap calls it computes l = pb - pa (left partition bytes) and r = pd - pc (right partition bytes) instead of reusing r for both.",
      "If l < r: it calls qsort(a, l / es, es, cmp) recursively when l > es, then, if r > es, sets a = pn - r and n = r / es and does goto loop (iterating on the larger right part).",
      "Otherwise: it calls qsort(pn - r, r / es, es, cmp) recursively when r > es, then, if l > es, sets n = l / es and does goto loop (iterating on the larger left part; 'a' is unchanged).",
      "The recursive call is always made on the smaller partition, so recursion depth is bounded by O(log n). The stale comment '/* qsort(pn - r, r / es, es, cmp); */' is removed."
     ],
     "completeness": [
      "Covers the only recursion site in this qsort. In both the l < r and l >= r branches it now recurses only on the smaller side.",
      "Pivot selection (med3), the n < 7 insertion sort path and swap handling are unchanged. Only stack depth is addressed, not worst-case running time.",
      "Partition sizes l, r and d remain 'int' values holding pointer differences; the fix does not change these types.",
      "Only the vendor sysdeps copy is touched. The material shows no other qsort implementation in libufdt."
     ],
     "behavior_changes": [
      "No API change: the sorted output is the same. Only the order in which disjoint sub-partitions are processed, and so the maximum stack depth, differs.",
      "Stack usage on large or skewed inputs drops from up to linear to logarithmic in the number of elements."
     ],
     "preconditions": [
      "This qsort must be the one used by the libufdt build in question. The material does not show which builds select sysdeps/libufdt_sysdeps_vendor.c.",
      "A code path must call this qsort with a large or adversarially ordered array. The specific caller inside libufdt is not shown in the material.",
      "Per index search, the only hits were bionic's own qsort tests and bionic/libc/bionic/fts.c, which concern bionic's qsort and not this vendor copy."
     ],
     "per_major": {
      "14": "same fix: platform/system/libufdt bbc615c85bf1 in android-security-14.0.0_r29, identical hunk content (line offsets 98/159 instead of 100/161); 7/8 lines of the patched region present at android-security-14.0.0_r30.",
      "15": "same fix: platform/system/libufdt 109d68930129 in android-security-15.0.0_r17, same hunk content and blob indexes as Android 14; 7/8 lines present at android-security-15.0.0_r18.",
      "16": "same fix: platform/system/libufdt 8dfd47aab1f2 in android-security-16.0.0_r8, identical to the Android 17 diff (same blob indexes); 7/8 lines present at android-security-16.0.0_r9.",
      "17": "same fix: platform/system/libufdt 70c20864187d in android-security-17.0.0_r1 (cherry-pick, Change-Id I260075b5280433ae59b61edef9b30cb6610bd02f); 7/8 lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "The fix is one self-contained hunk in qsort() of sysdeps/libufdt_sysdeps_vendor.c, with no other dependencies shown. Google shipped identical hunk content on 14 through 17, differing only by a 2-line offset on 14 and 15."
     ],
     "confidence": "high",
     "unknowns": [
      "Which libufdt function(s) call this qsort, and with what data. The material does not show the caller.",
      "Which builds or devices actually link this vendor qsort rather than a libc qsort.",
      "The concrete input that triggers deep recursion. Details of bug 509980995 are not provided.",
      "Why the resolver reports 7/8 rather than 8/8 lines of the patched region at the latest security tags. The code context shown at android-security-17.0.0_r2 covers only the new declaration, not the rewritten block."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-55270": {
     "cve": "CVE-2026-55270",
     "summary": "Adds a `wrappedCallback == null` guard in GsmCdmaPhone.dialInternal and ImsPhone.dialInternal so that USSD requests (which carry a non-null ResultReceiver) can no longer trigger in-call MMI supplementary-service actions (for example accept, hold, swap, conference) when the USSD string matches an in-call MMI code.",
     "component": "platform/frameworks/opt/telephony, Phone dial / USSD handling (GsmCdmaPhone, ImsPhone)",
     "weakness": "Missing check on the request type: the USSD request path was not told apart from ordinary dialing before the in-call MMI dispatcher ran, so a USSD string could act as a local call-control command.",
     "root_cause": "Both GsmCdmaPhone.dialInternal(String, DialArgs, ResultReceiver) and ImsPhone.dialInternal(String, DialArgs, ResultReceiver) are shared by the normal dial path (wrappedCallback == null) and the USSD path (handleUssdRequest with a non-null ResultReceiver, as in the commit message and the tests). Before the fix, on Android 17 the \"handle in-call MMI first\" block ran for any non-emergency dial string. A USSD request whose string matched an in-call MMI code (for example \"2\" with a ringing call, as in the added tests) therefore reached handleInCallMmiCommands and call-tracker actions such as acceptCall, hold, swap or conference, instead of being handled only as a USSD/MMI network request.",
     "fix_analysis": [
      "src/java/com/android/internal/telephony/GsmCdmaPhone.java:dialInternal(String, DialArgs, ResultReceiver): the condition guarding the in-call MMI block changes from `if (!dialArgs.isEmergency)` to `if (!dialArgs.isEmergency && wrappedCallback == null)`. When a ResultReceiver is supplied (USSD path), neither the ignoreIncallMmiForEmergency early return nor handleInCallMmiCommands runs. Execution falls through to GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get(), wrappedCallback) and the normal MMI/USSD processing.",
      "src/java/com/android/internal/telephony/imsphone/ImsPhone.java:dialInternal(String, DialArgs, ResultReceiver): same change. `if (!dialArgs.isEmergency && wrappedCallback == null)` now guards the ignoreIncallMmiForEmergency/mCT.isInEmergencyCall() early return and handleInCallMmiCommands(newDialString).",
      "tests/telephonytests/.../GsmCdmaPhoneTest.java:testHandleUssdRequestWithInCallMmiCode: with a ringing call in INCOMING state, handleUssdRequest(\"2\", mockCallback) must return true and mCT.acceptCall() must never be called.",
      "tests/telephonytests/.../imsphone/ImsPhoneTest.java:testHandleUssdRequestWithInCallMmiCode: the same scenario on ImsPhone must throw CallStateException with message Phone.CS_FALLBACK and must never call mImsCT.acceptCall(anyInt())."
     ],
     "completeness": [
      "Both phone implementations that share the dialInternal(..., ResultReceiver) overload are patched: GsmCdmaPhone and ImsPhone.",
      "The guard checks whether wrappedCallback is non-null, not an explicit 'is USSD' flag, so any caller passing a ResultReceiver is excluded from in-call MMI handling. The dialInternal(String, DialArgs) overload in GsmCdmaPhone and ImsPhone.dial still pass null, so ordinary dialing keeps the in-call MMI behaviour.",
      "The USSD string still reaches GsmMmiCode.newFromDialString with the callback, so network MMI/USSD processing is unchanged. Only the local call-control shortcut is blocked.",
      "In the Android 17 code shape, the new condition also skips the `ignoreIncallMmiForEmergency() && isInEmergencyCall()` early return for USSD requests. On 14 and 15, and in both branches on 16, the block had no such logic, so there the fix only guards handleInCallMmiCommands."
     ],
     "behavior_changes": [
      "A USSD request whose dial string matches an in-call MMI code no longer triggers in-call call-control actions (accept per the tests; hold, swap, conference per the commit message). It is passed on as an MMI/USSD request instead.",
      "On ImsPhone, the new test asserts that such a USSD request (with a ringing call) throws CallStateException(CS_FALLBACK), and that acceptCall is not called.",
      "During an emergency call with ignoreIncallMmiForEmergency enabled (Android 17 shape), a USSD request is no longer dropped with 'ignore InCall MMI command during emergency call'. It goes on to MMI processing instead."
     ],
     "preconditions": [
      "A caller reaches Phone.handleUssdRequest on GsmCdmaPhone or ImsPhone with a ResultReceiver, i.e. the USSD request path (the tests call mPhoneUT.handleUssdRequest / mImsPhoneUT.handleUssdRequest directly).",
      "The USSD string, after PhoneNumberUtils.stripSeparators, matches an in-call MMI code recognised by handleInCallMmiCommands.",
      "A call exists in a state where that MMI code has an effect (the tests use a ringing call in INCOMING state, where '2' would lead to acceptCall).",
      "dialArgs.isEmergency is false (on 14, 15 and the non-flagged branch of 16, the in-call MMI check did not test isEmergency)."
     ],
     "per_major": {
      "14": "adapted fix (a702397eed29, android-security-14.0.0_r29): in GsmCdmaPhone the block sits under isPhoneTypeGsm() and has no isEmergency condition, so the change is `if (wrappedCallback == null && handleInCallMmiCommands(newDialString))`. ImsPhone gets the same form. Same tests added.",
      "15": "adapted fix (92836c48ba6a, android-security-15.0.0_r17): same shape as 14, `wrappedCallback == null && handleInCallMmiCommands(newDialString)` in both GsmCdmaPhone (under isPhoneTypeGsm()) and ImsPhone. Same tests added.",
      "16": "adapted fix (ee04a37583c0, android-security-16.0.0_r8): both files branch on mFeatureFlags.skipMmiCodeCheckForEmergencyCall(), and the guard is added to both branches: `!dialArgs.isEmergency && wrappedCallback == null && handleInCallMmiCommands(...)` and `wrappedCallback == null && handleInCallMmiCommands(...)`. Same tests added.",
      "17": "same fix (802f8f5c9920, android-security-17.0.0_r1): one unified block, `if (!dialArgs.isEmergency && wrappedCallback == null)`, wraps the ignoreIncallMmiForEmergency early return and handleInCallMmiCommands in both GsmCdmaPhone and ImsPhone. The code at android-security-17.0.0_r2 shows the patched condition in place in both files."
     },
     "backport_notes": [
      "Single commit with no dependency. The only adaptation is matching the local shape of the in-call MMI block (whether it has isPhoneTypeGsm(), skipMmiCodeCheckForEmergencyCall or ignoreIncallMmiForEmergency branches). Every branch that calls handleInCallMmiCommands in the ResultReceiver overload of dialInternal must get the `wrappedCallback == null` guard, in both GsmCdmaPhone and ImsPhone.",
      "The added tests rely on TelephonyTest fixtures (mCT, mGsmCdmaCall, mRingingCall, mImsCT, replaceInstance). On heavily customised trees, check that these mocks exist before carrying the tests over."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show which upper-layer entry point (for example TelephonyManager.sendUssdRequest) reaches handleUssdRequest, or which permission that entry point requires. The privilege boundary crossed is therefore inferred only from the bulletin's EoP classification.",
      "The material does not show whether any caller other than handleUssdRequest passes a non-null ResultReceiver into dialInternal. Such callers would also lose in-call MMI handling.",
      "The body of handleInCallMmiCommands (the exact set of codes and the actions they trigger) is not in the material.",
      "The material does not show the code path that produces CallStateException(CS_FALLBACK) on ImsPhone.",
      "The per-major facts say '6/8 lines of the patched region present' without explaining what that means. The Android 17 r2 context shows the patched condition itself present in both source files."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-55279": {
     "cve": "CVE-2026-55279",
     "summary": "ImageManager::MapAllImages in libfiemap now logs an error and returns false when the metadata directory does not exist, instead of silently returning true, so first-stage init no longer treats a non-existent or invalid DSU slot as a successfully mapped, running DSU.",
     "component": "platform/system/fs/fs_mgr, libfiemap (ImageManager, used by first-stage init for DSU image mapping)",
     "weakness": "Incorrect return value / improper handling of a missing-resource condition (error reported as success), leading to a wrong system state and denial of service",
     "root_cause": "In libfiemap/image_manager.cpp, ImageManager::MapAllImages began with `if (!MetadataExists(metadata_dir_)) return true;`. A missing metadata directory was therefore reported to the caller as a successful mapping of all images. Per the commit message, when first-stage init was given an invalid or non-existent DSU slot (for example \".\"), this success return made init assume the DSU images were mapped and running, so it set ro.gsid.image_running=1; gatekeeperd then applied a GSI user ID offset, producing a persistent lockout of the host PIN (DoS).",
     "fix_analysis": [
      "libfiemap/image_manager.cpp : ImageManager::MapAllImages: the early-return for `!MetadataExists(metadata_dir_)` is changed from `return true` to `LOG(ERROR) << \"Metadata directory does not exist: \" << metadata_dir_; return false;`. The caller now receives a failure for a missing metadata directory, consistent with the existing `return false` when OpenMetadata fails, so init does not proceed as if a DSU were mapped.",
      "Single-commit fix; no other files or functions changed. The rest of MapAllImages (OpenMetadata, init callback with block device partition names, CreateLogicalPartitions) is unchanged."
     ],
     "completeness": [
      "Covers only the missing-metadata-directory path in ImageManager::MapAllImages; the OpenMetadata failure path already returned false and is untouched.",
      "The fix does not validate the DSU slot name itself (e.g. reject \".\"); it relies on the metadata directory for a bogus slot not existing. The init-side logic that sets ro.gsid.image_running based on the MapAllImages result is not part of this diff and is not shown in the material.",
      "Other ImageManager entry points that may check MetadataExists are not shown in the material, so whether they share a similar success-on-missing-metadata return cannot be judged from what is provided."
     ],
     "behavior_changes": [
      "MapAllImages now returns false (previously true) when metadata_dir_ does not exist.",
      "A new LOG(ERROR) line 'Metadata directory does not exist: <metadata_dir_>' is emitted in that case.",
      "Any caller that previously relied on MapAllImages succeeding as a no-op when no metadata exists will now observe a failure; per the commit message, the intended effect is that first-stage init does not mark a DSU as running for an invalid slot."
     ],
     "preconditions": [
      "ImageManager::MapAllImages is invoked (per the commit message, by first-stage init during DSU handling) with a metadata_dir_ that does not exist, which happens when an invalid or non-existent DSU slot such as \".\" is supplied.",
      "How an attacker or user supplies the invalid DSU slot to init is not shown in the material (unknown)."
     ],
     "per_major": {
      "14": "not affected per the bulletin; platform/system/fs/fs_mgr is not present in android-security-14.0.0_r30; no fix applied.",
      "15": "not affected per the bulletin; project not present in android-security-15.0.0_r18; no fix applied.",
      "16": "not affected per the bulletin; project not present in android-security-16.0.0_r9; no fix applied.",
      "17": "same fix: commit 666f09f0529c (cherry-pick of edb7e21425c1, Change-Id I103689be4b65f4e95ff9f44f261debc7d46ae9e7) in android-security-17.0.0_r1; all 3 lines of the patched region present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Trivial 2-line change in ImageManager::MapAllImages; if porting to a tree where libfiemap lives in a different project path, apply the same change to the MetadataExists early-return and verify that no local caller depends on the old success-on-missing-metadata behavior."
     ],
     "confidence": "high",
     "unknowns": [
      "The first-stage init code that calls MapAllImages and sets ro.gsid.image_running, and the gatekeeperd GSI user ID offset logic, are not in the material; the DoS chain is known only from the commit message.",
      "How the invalid DSU slot value (e.g. \".\") can be supplied, and with what privilege, is not shown.",
      "Whether other ImageManager methods have the same return-true-on-missing-metadata pattern is not shown.",
      "Whether equivalent libfiemap code exists in Android 14 to 16 under a different project path is not shown; the material only states the platform/system/fs/fs_mgr project is absent from those security tags."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 1,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-55286": {
     "cve": "CVE-2026-55286",
     "summary": "Adds an early length check in stpropnci_process() (ST NFC HAL, libstpropnci) that drops and logs any NCI message whose payloadlen exceeds MAX_NCI_MESSAGE_LEN.",
     "component": "platform/hardware/st/nfc, libstpropnci (ST NFC HAL proprietary NCI processing library, INfc::write() path)",
     "weakness": "Missing bounds check leading to out-of-bounds write (unbounded memcpy into fixed-size buffer)",
     "root_cause": "Per the commit message, the ST NFC HAL's INfc::write() implementation did not check the length of incoming payloads. A payload longer than MAX_NCI_MESSAGE_LEN therefore reached an unbounded memcpy into a fixed-size buffer and wrote out of bounds over global state variables. stpropnci_process() had no check of payloadlen against MAX_NCI_MESSAGE_LEN. The material does not show the exact memcpy site or which buffer is the destination.",
     "fix_analysis": [
      "libstpropnci/src/stpropnci.cc:stpropnci_process(): the new check `if (payloadlen > MAX_NCI_MESSAGE_LEN)` sits after the existing early-return block, while reentry_lock is still held. It logs via LOG_E (\"Dropping oversized NCI message: %d > %d\"), unlocks reentry_lock and returns ret. The oversized message is never processed further.",
      "The check comes before the `if (!stpropnci_state.passthrough_mode)` branch and does not depend on dir_from_upper. It therefore applies in both passthrough modes and to both message directions handled by stpropnci_process()."
     ],
     "completeness": [
      "Covers: every message that gets past the earlier early-return block in stpropnci_process() is now bounded by MAX_NCI_MESSAGE_LEN, whatever the passthrough mode or direction.",
      "Leaves out: the fix rejects only payloads that are too long overall. It does not check minimum lengths or per-field lengths. Per index search, downstream handlers such as stpropnci_process_uid_and_sak_steps index payload[3] and payload[6] and size a copy from payload[6] with no visible reference to payloadlen (see potential_variants)."
     ],
     "behavior_changes": [
      "NCI messages longer than MAX_NCI_MESSAGE_LEN are now dropped by the library (it returns ret without processing them) and an error line is logged. Previously they were processed."
     ],
     "preconditions": [
      "The device uses the ST NFC HAL with libstpropnci (hardware/st/nfc). The patched file is absent from the Android 14, 15 and 16 security tags.",
      "A compromised client of the HAL's INfc::write() (per the commit message) sends a payload longer than MAX_NCI_MESSAGE_LEN."
     ],
     "per_major": {
      "14": "not affected per the bulletin; code absent (libstpropnci/src/stpropnci.cc not present at android-security-14.0.0_r30)",
      "15": "not affected per the bulletin; code absent (libstpropnci/src/stpropnci.cc not present at android-security-15.0.0_r18)",
      "16": "not affected per the bulletin; code absent (libstpropnci/src/stpropnci.cc not present at android-security-16.0.0_r9)",
      "17": "same fix: commit bbb2d21c4d50 (cherry-pick of 867b2f4b7d87) in android-security-17.0.0_r1; all 4 checked lines of the patched region present at android-security-17.0.0_r2"
     },
     "backport_notes": [
      "Single commit adding 6 lines. It uses MAX_NCI_MESSAGE_LEN and LOG_E, which already exist in the library. Relevant only to trees that carry hardware/st/nfc/libstpropnci (absent from the 14, 15 and 16 security tags)."
     ],
     "confidence": "medium",
     "unknowns": [
      "The exact memcpy site and its destination buffer are not shown. It may be stpropnci_state.tmpbuff / pumpstate.msgPool.payload, which stpropnci_init sets up, but the material does not confirm this. The destination buffer's size is not shown either.",
      "The value of ret at the new return point and the condition of the preceding early-return block are not shown.",
      "Whether stpropnci_init() must have run for the vulnerable path to be reached is not shown.",
      "How INfc::write() calls stpropnci_process(), whether the HAL does any length validation itself, and whether all handler paths (std/prop/prop_st/prop_android) are reached through stpropnci_process() is not shown."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 7,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58815": {
     "cve": "CVE-2026-58815",
     "summary": "Changes the stride-5 metering-region loops in DistortionMapper, RotateAndCropMapper and ZoomRatioMapper from `j < entry.count` to `j + 5 <= entry.count` so that a metering-region entry whose element count is not a multiple of 5 no longer causes a heap out-of-bounds read and write past the end of the metadata entry.",
     "component": "platform/frameworks/av, cameraserver (services/camera/libcameraservice/device3 metadata mappers)",
     "weakness": "Missing bounds check: loop condition did not account for the 5-element stride, leading to heap out-of-bounds read and write",
     "root_cause": "Each mapper iterates over the metering-region tags in kMeteringRegionsToCorrect and treats the entry as consecutive 5-tuples (coordinates plus weight). The loops were written as `for (j = 0; j < entry.count; j += 5)` and then read `entry.data.i32[j + 4]` as the weight and passed `entry.data.i32 + j` to coordinate transform code (e.g. mapCorrectedToRaw in DistortionMapper::correctCaptureRequest, transformPoints and swapRectToMinFirst in RotateAndCropMapper::updateCaptureRequest). When entry.count is not a multiple of 5 (for example 6), the last iteration starts at an index with fewer than 5 remaining elements, so the weight read and the coordinate processing go past the end of the entry's buffer. Per the commit message, the trigger is a CaptureRequest containing a metering region with such an element count. The added tests check that, after the fix, element 5 of a 6-element entry is left unchanged.",
     "fix_analysis": [
      "services/camera/libcameraservice/device3/DistortionMapper.cpp: correctCaptureRequest and correctCaptureResult: loop condition changed to `j + 5 <= e.count`, so an iteration only runs when a full 5-tuple remains before the weight read and the coordinate mapping call (mapCorrectedToRaw on the request side).",
      "services/camera/libcameraservice/device3/RotateAndCropMapper.cpp: updateCaptureRequest and updateCaptureResult: loop condition changed to `i + 5 <= entry.count` ahead of the weight read and the transform (transformPoints and swapRectToMinFirst on the request side).",
      "services/camera/libcameraservice/device3/ZoomRatioMapper.cpp: separateZoomFromCropLocked and combineZoomAndCropLocked: loop condition changed to `j + 5 <= entry.count` ahead of the weight read and region scaling.",
      "Tests added (DistortionMapperTest, RotateAndCropMapperTest, ZoomRatioTest: MeteringRegionsBoundsTest): first write a 10-element AE_REGIONS entry as poison, then overwrite it with a 6-element entry whose 6th element is 999, run the request mapper, and assert count is still 6 and element 5 is still 999.",
      "No new error is returned and the entry is not resized; trailing elements that do not form a complete 5-tuple are simply skipped."
     ],
     "completeness": [
      "All six stride-5 metering-region loops in the three mapper source files touched by the diff are fixed, covering both the request and the result direction.",
      "The commit message also names a `correctMeteringRegions` location, but no such function appears in the diff or the provided code context; whether that refers to one of the patched loops or to code in another file is not shown by the material.",
      "The adjacent kRectsToCorrect loop in DistortionMapper::correctCaptureRequest uses `e.count / 4` as the rect count, which rounds down and does not have the same stride problem.",
      "The fix tolerates malformed counts rather than rejecting them (no BAD_VALUE is returned)."
     ],
     "behavior_changes": [
      "Metering-region entries whose element count is not a multiple of 5 now have their trailing partial tuple left unmodified by the mappers instead of being processed with out-of-bounds memory access; entries with counts that are multiples of 5 behave identically to before.",
      "No new error codes, logs, or metadata rewrites are introduced."
     ],
     "preconditions": [
      "A capture request (or capture result) containing one of the kMeteringRegionsToCorrect tags (e.g. ANDROID_CONTROL_AE_REGIONS, as used in the tests) with an element count that is not a multiple of 5.",
      "For DistortionMapper::correctCaptureRequest: the mapper's calibration mapping must be valid (mapperInfo->mValidMapping) and ANDROID_DISTORTION_CORRECTION_MODE must be present and not OFF.",
      "For RotateAndCropMapper: a rotate-and-crop mode must be active (updateCaptureResult returns early when ANDROID_SCALER_ROTATE_AND_CROP is absent or NONE; the request-side test uses ROTATE_AND_CROP_90).",
      "For ZoomRatioMapper paths: the test calls updateCaptureRequest with a 2x ANDROID_SCALER_CROP_REGION so that regions are actually rescaled.",
      "The code runs inside cameraserver; per the bulletin this is rated High EoP."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/av 6654633902f8 in android-security-14.0.0_r29, identical one-line changes to the same six loops (only hunk line offsets differ, e.g. ZoomRatioMapper at 349/387 and RotateAndCropMapper at 162/291) plus the same three tests.",
      "15": "same fix: platform/frameworks/av ff3f3a6b8194 in android-security-15.0.0_r17, identical changes with slightly different hunk offsets (DistortionMapper 145/184, RotateAndCropMapper 165/294, ZoomRatioMapper 352/390) plus the same tests.",
      "16": "same fix: platform/frameworks/av aff9120ec0b8 in android-security-16.0.0_r8, identical to the Android 17 diff including hunk offsets and test additions.",
      "17": "same fix: platform/frameworks/av 77f8ddbbd65b in android-security-17.0.0_r1 (cherry-pick of cc78e7aa1be9); the android-security-17.0.0_r2 code context shows the `j + 5 <= e.count` / `i + 5 <= entry.count` conditions in DistortionMapper::correctCaptureRequest and RotateAndCropMapper::updateCaptureRequest (the ZoomRatioMapper loops are not in the provided excerpt)."
     },
     "backport_notes": [
      "Single self-contained commit: six one-token loop-condition changes in three mapper files; on older or vendor-modified trees, check every `+= 5` loop over kMeteringRegionsToCorrect in these files uses the `+ 5 <=` form (the commit message also mentions a `correctMeteringRegions` site not present in this diff).",
      "The resolver reports 7/8 patched-region lines present in every latest security tag (14 r30, 15 r18, 16 r9, 17 r2); the 17 r2 code context shows the fixed conditions in DistortionMapper and RotateAndCropMapper, so this may be a matching artifact, but verify all six loop conditions directly when confirming a build."
     ],
     "confidence": "high",
     "unknowns": [
      "What the commit message's `correctMeteringRegions` refers to; no such function appears in the diff or provided context.",
      "Which caller path was used in the original report; the index results for updateCaptureRequest are noisy (CaptureSequencer::updateCaptureRequest and a Java method of the same name are unrelated), and the Camera3OutputUtils.cpp sendCaptureResult chunk shown does not include the mapper call.",
      "Which of the six loops were reachable in the original report; the added tests exercise only the request-side paths with ANDROID_CONTROL_AE_REGIONS.",
      "Whether malformed metering-region entries are validated or rejected elsewhere before or after the mappers.",
      "The loop bodies of DistortionMapper::correctCaptureResult and the ZoomRatioMapper loops are not shown in the material.",
      "Why the resolver counts only 7/8 lines of the patched region as present in the latest tags."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 7,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58834": {
     "cve": "CVE-2026-58834",
     "summary": "Adds an argument check in DevicePolicyManagerService.setPermissionGrantState so only GRANTED, DENIED or DEFAULT grant states are accepted. It also wraps the boot-time policy re-application calls in DevicePolicyEngine.reapplyAllPoliciesOnBootLocked in try/catch, so a bad persisted policy no longer crashes system_server.",
     "component": "platform/frameworks/base, DevicePolicyManagerService / DevicePolicyEngine (services/devicepolicy)",
     "weakness": "Missing input validation (an unvalidated enum-like int is persisted to disk), plus an unhandled exception during boot-time policy re-application",
     "root_cause": "Per the commit message, setPermissionGrantState accepted an out-of-range grantState and the value was saved to disk. On later boots, DevicePolicyEngine.reapplyAllPoliciesOnBootLocked called enforcePolicy for persisted global and local policies with no exception handling. On 15/16/17 this applies to policies that are not marked shouldSkipEnforcementIfNotChanged(). Enforcing the out-of-range value threw an uncaught IllegalArgumentException in system_server. Because the value was persisted, every boot failed the same way (a boot loop that needed a factory reset, per the commit message).",
     "fix_analysis": [
      "DevicePolicyManagerService.java: setPermissionGrantState now calls Preconditions.checkArgument(grantState == PERMISSION_GRANT_STATE_GRANTED || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED || grantState == PERMISSION_GRANT_STATE_DEFAULT). The call sits right after Objects.requireNonNull(callback) and before getCallerIdentity / checkCanExecuteOrThrowUnsafe. An invalid value throws IllegalArgumentException to the caller. In the visible hunk the check has no flag condition, although the commit message says the check applies when the coexistence flag is enabled.",
      "DevicePolicyEngine.java: reapplyAllPoliciesOnBootLocked now wraps each enforcePolicy(policyDefinition, policyValue, UserHandle.USER_ALL) call (global loop) and each enforcePolicy(policyDefinition, policyValue, userId) call (per-user local loop) in try { } catch (Exception e) { Slogf.wtf(...) }. A failing policy is logged and the loop moves on to the remaining policies.",
      "DevicePolicyManagerTest.java: adds testSetPermissionGrantState_coexistence_invalidState_throwsException. The test sets a device owner and asserts IllegalArgumentException for grantState 999."
     ],
     "completeness": [
      "Input validation covers only the grantState parameter of setPermissionGrantState. It is placed before caller identity resolution, and the visible hunk shows no condition around it.",
      "The try/catch only covers the two enforcePolicy calls inside reapplyAllPoliciesOnBootLocked. The material does not show other enforcePolicy call sites, and this commit does not touch them.",
      "The fix does not remove or sanitize an invalid grant state that was already persisted. Such an entry is now caught and logged at boot instead of crashing, but the diff does not clean it up.",
      "catch (Exception e) is broad: any runtime failure in enforcePolicy during boot is now logged with wtf instead of failing boot."
     ],
     "behavior_changes": [
      "setPermissionGrantState now throws IllegalArgumentException for any grantState other than GRANTED, DENIED or DEFAULT. This happens before getCallerIdentity and checkCanExecuteOrThrowUnsafe.",
      "During boot, a policy whose enforcement throws is logged via Slogf.wtf and skipped instead of aborting system_server. Depending on configuration, Log.wtf can add a DropBox report or terminate the process (general platform knowledge)."
     ],
     "preconditions": [
      "The caller must be able to invoke DevicePolicyManager.setPermissionGrantState, for example a BYOD work-profile DPC per the commit message.",
      "The invalid value must be persisted. The commit message links this to the coexistence flag being enabled.",
      "The crash happens on a later system_server boot, when reapplyAllPoliciesOnBootLocked re-enforces the stored policy."
     ],
     "per_major": {
      "14": "adapted fix, platform/frameworks/base 057ff07691a6 in android-security-14.0.0_r29: same checkArgument and same try/catch. The Android 14 loops have no shouldSkipEnforcementIfNotChanged() guard and iterate mLocalPolicies by index (keyAt). 8/8 lines present at r30.",
      "15": "adapted fix, platform/frameworks/base 49e1a4ba935f in android-security-15.0.0_r17: identical logic. The local-policy loop iterates by index over mLocalPolicies, not over the Set<Integer> userIds copy used on 17. 8/8 lines present at r18.",
      "16": "adapted fix, platform/frameworks/base f4e7001b21fb in android-security-16.0.0_r8: identical logic, same loop shape as 15. 8/8 lines present at r9.",
      "17": "same fix, platform/frameworks/base c715c992cad0 in android-security-17.0.0_r1 (Cherrypick-From lists two internal commits). 8/8 lines present at r2."
     },
     "backport_notes": [
      "The two parts are independent and small. The checkArgument goes right after Objects.requireNonNull(callback) in setPermissionGrantState. The try/catch wraps the two enforcePolicy calls in reapplyAllPoliciesOnBootLocked, whatever the loop shape on the branch. None of the shown diffs adds an import, so confirm that Preconditions and Slogf are available in both files on your branch."
     ],
     "confidence": "high",
     "unknowns": [
      "Where exactly enforcePolicy throws for an out-of-range grant state (the enforcement callback is not in the material).",
      "Why the commit message ties the check to the coexistence flag while the visible hunk shows no condition.",
      "Whether other enforcePolicy call sites outside reapplyAllPoliciesOnBootLocked can hit the same exception at runtime.",
      "Whether any migration or cleanup of previously persisted invalid values exists elsewhere."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58841": {
     "cve": "CVE-2026-58841",
     "summary": "Makes VirtualAudioController.startListening register the AudioPlaybackDetector unconditionally instead of only when an IAudioConfigChangedCallback is supplied, so the deferred silence-injection policy update recovers correctly (per the commit message).",
     "component": "platform/frameworks/base, services/companion virtual device audio (VirtualAudioController)",
     "weakness": "Logic error: conditional registration of a required listener (missing callback registration leading to a skipped security policy update)",
     "root_cause": "In services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java, startListening() registered both mAudioPlaybackDetector and mAudioRecordingDetector inside `if (configChangedCallback != null)`. When a caller started listening with a null IAudioConfigChangedCallback, the playback detector was never registered. According to the commit message, this left the deferred silence-injection policy update unable to recover, so the policy update was skipped. stopListening() unregisters both detectors unconditionally, so the asymmetry existed only on the registration side.",
     "fix_analysis": [
      "VirtualAudioController.java:startListening(): moves `mAudioPlaybackDetector.register(/* callback= */ this);` out of the `if (configChangedCallback != null)` block. It now runs on every startListening() call, after mListening is set and the UID sets are cleared under mLock.",
      "VirtualAudioController.java:startListening(): keeps `mAudioRecordingDetector.register(/* callback= */ this);` conditional on configChangedCallback being non-null.",
      "Single one-line move; no other files changed. The commit lists `atest VirtualAudioControllerTest` as its test."
     ],
     "completeness": [
      "Covers the only registration site shown: startListening() now always registers the playback detector. This matches stopListening(), which already unregistered both detectors unconditionally.",
      "Recording detector registration remains gated on configChangedCallback != null. The material does not show whether that gating has any policy implication.",
      "The fix only changes registration. The playback callback logic and the deferred policy update itself are not shown or modified, so the correctness of that path cannot be checked from the material.",
      "The 'Already listening' branch still only logs via Slog.e and continues; the fix does not change it."
     ],
     "behavior_changes": [
      "AudioPlaybackDetector is now registered for every startListening() call, including calls without an IAudioConfigChangedCallback, so VirtualAudioController receives playback callbacks in all cases.",
      "Sessions that previously had no playback detector registered now get more callbacks. The diff adds no new error codes or API surface changes."
     ],
     "preconditions": [
      "A VirtualAudioController instance exists for a virtual device's audio.",
      "startListening() is invoked with a null IAudioConfigChangedCallback. The material does not show the exact caller or whether a non-system app can reach this configuration."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/base 8ded15ca0499 in android-security-14.0.0_r29, the same one-line move at a different line offset (hunk @@ -94). 5/5 patched lines present at android-security-14.0.0_r30.",
      "15": "same fix: platform/frameworks/base a46c94ad2ccc in android-security-15.0.0_r17, identical change (hunk @@ -102). 5/5 patched lines present at android-security-15.0.0_r18.",
      "16": "same fix: platform/frameworks/base 3184e06e737a in android-security-16.0.0_r8, identical change (hunk @@ -100). 5/5 patched lines present at android-security-16.0.0_r9.",
      "17": "same fix: platform/frameworks/base 1412cbcc0c10 in android-security-17.0.0_r1, cherry-picked from commit 26bbdd921d94 (Change-Id I2af61fc32fb2d19e68037fdb8a10a23dc4b37071). 5/5 patched lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Self-contained one-line move in startListening(). It applies cleanly to any branch where both register() calls sit inside the configChangedCallback null check. On the target branch, check that stopListening() unregisters mAudioPlaybackDetector unconditionally so register and unregister stay balanced."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show the concrete security consequence of the skipped silence-injection policy update. Only the bulletin rating (High, EoP) and the commit message are available.",
      "The material does not show which caller passes a null configChangedCallback or whether it is reachable from an untrusted app.",
      "The material does not show the AudioPlaybackCallback handler or which code performs the deferred silence-injection policy update."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58854": {
     "cve": "CVE-2026-58854",
     "summary": "Adds isRemote() checks, plus nullptr checks where none existed, before the mediatuner service static_casts caller-supplied ITunerFilter/ITunerDemux/ITunerLnb binder objects to its local TunerXxx/TunerHidlXxx implementation classes. Remote proxies are now rejected with Result::INVALID_ARGUMENT.",
     "component": "platform/frameworks/av, services/tuner (mediatuner daemon, AIDL and HIDL backends)",
     "weakness": "Type confusion from an unchecked downcast of a binder interface pointer (missing input validation, leading to an out-of-bounds read of member fields)",
     "root_cause": "Several mediatuner AIDL server methods take an interface pointer argument from the client (shared_ptr<ITunerFilter>, shared_ptr<ITunerDemux>, shared_ptr<ITunerLnb>). They static_cast it without any check to the service's own implementation class (TunerFilter, TunerDemux, TunerLnb, or TunerHidlFilter, TunerHidlDemux, TunerHidlLnb) and then call getHalFilter() or getId(). Nothing verified that the object was actually a local implementation. Per the commit message, a client could pass a remote proxy or its own stub for that interface. The service then read member variables out of bounds relative to the proxy allocation, which caused type confusion and memory corruption in the mediatuner process. Affected methods: TunerDemux::getAvSyncHwId, TunerDescrambler::setDemuxSource/addPid/removePid, TunerDvr::attachFilter/detachFilter, TunerFilter::setDataSource, TunerFrontend::setLnb, and the HIDL-backend equivalents in services/tuner/hidl. getAvSyncHwId and setDemuxSource also had no nullptr check.",
     "fix_analysis": [
      "Single commit 073ae498a43f (cherry-picked from two internal changes, Change-Id Id786837e7dda012109bedf46b95b5e133f898ae3). Every call site that static_casts a client-supplied interface pointer now calls isRemote() first. If the object is a remote proxy, it returns ::ndk::ScopedAStatus::fromServiceSpecificError(Result::INVALID_ARGUMENT).",
      "services/tuner/TunerDemux.cpp:TunerDemux::getAvSyncHwId and services/tuner/hidl/TunerHidlDemux.cpp:TunerHidlDemux::getAvSyncHwId: new guard `tunerFilter == nullptr || tunerFilter->isRemote()` before static_cast<TunerFilter*>/<TunerHidlFilter*>(...)->getHalFilter(). TunerHidlDemux.cpp also gains `#include <aidl/android/hardware/tv/tuner/Result.h>` and `using ::aidl::android::hardware::tv::tuner::Result;`, which brings the AIDL Result type into scope there.",
      "services/tuner/TunerDescrambler.cpp and services/tuner/hidl/TunerHidlDescrambler.cpp: setDemuxSource gets `in_tunerDemux == nullptr || in_tunerDemux->isRemote()` before static_cast<TunerDemux*>/<TunerHidlDemux*>(...)->getId(). addPid and removePid get `in_optionalSourceFilter != nullptr && in_optionalSourceFilter->isRemote()`. The argument is optional, so nullptr is still allowed and maps to a null HAL filter as before.",
      "services/tuner/TunerDvr.cpp and services/tuner/hidl/TunerHidlDvr.cpp: attachFilter and detachFilter extend the existing `in_filter == nullptr` check to `|| in_filter->isRemote()`.",
      "services/tuner/TunerFilter.cpp:TunerFilter::setDataSource and services/tuner/hidl/TunerHidlFilter.cpp:TunerHidlFilter::setDataSource: the existing nullptr check is extended with `|| filter->isRemote()`. The check runs under mLock, before the mShared check.",
      "services/tuner/TunerFrontend.cpp:TunerFrontend::setLnb and services/tuner/hidl/TunerHidlFrontend.cpp:TunerHidlFrontend::setLnb: the existing nullptr check is extended with `|| lnb->isRemote()` before static_cast<TunerLnb*>/<TunerHidlLnb*>(lnb.get())->getId()."
     ],
     "completeness": [
      "Covers all 8 AIDL-backend and 8 HIDL-backend methods in the diff where a client-supplied ITunerFilter, ITunerDemux or ITunerLnb is downcast: getAvSyncHwId, setDemuxSource, addPid, removePid, attachFilter, detachFilter, setDataSource, setLnb.",
      "The guard checks isRemote() only. It does not verify the concrete local type of a non-remote object.",
      "getAvSyncHwId and setDemuxSource previously had no nullptr check at all. The fix adds one in the same condition.",
      "Other TunerDemux methods that take interface arguments are not in the diff. One example is a setFrontendDataSource(ITunerFrontend) overload, which DemuxClient calls per index search. Their bodies are not in the material, so whether they downcast or were already guarded is unknown."
     ],
     "behavior_changes": [
      "The listed methods now return the service-specific error Result::INVALID_ARGUMENT when the passed ITunerFilter/ITunerDemux/ITunerLnb is a binder proxy rather than a local object.",
      "TunerDemux::getAvSyncHwId, TunerHidlDemux::getAvSyncHwId, TunerDescrambler::setDemuxSource and TunerHidlDescrambler::setDemuxSource now return INVALID_ARGUMENT for a nullptr argument instead of dereferencing it.",
      "Clients that pass back objects obtained from the same mediatuner service are expected to be unaffected. addPid and removePid still accept nullptr as the optional source filter."
     ],
     "preconditions": [
      "The device runs the mediatuner service (services/tuner), and the caller can obtain ITunerDvr/ITunerDemux/ITunerFilter/ITunerDescrambler/ITunerFrontend objects from it. The commit states that unprivileged apps could reach these methods.",
      "The caller supplies a binder object for the interface argument that is not one of the service's own local objects (a proxy or custom stub).",
      "Per index search, the app-facing API path runs from frameworks/base/media/java/android/media/tv/tuner/Tuner.java (Tuner.getAvSyncHwId) through the android_media_tv_Tuner.cpp JNI to DemuxClient, which holds the ITunerDemux binder."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/av f8520e699d18 in android-security-14.0.0_r29. Hunk content matches the 17 commit; hunk line offsets differ in TunerDemux/TunerDescrambler/TunerDvr/TunerFilter/TunerFrontend. 8/8 patched lines present at android-security-14.0.0_r30.",
      "15": "same fix: platform/frameworks/av 7ccb7033d428 in android-security-15.0.0_r17. Hunk content matches the 17 commit; only the TunerFilter.cpp blob indices differ. 8/8 patched lines present at android-security-15.0.0_r18.",
      "16": "same fix: platform/frameworks/av 183c2e3a4198 in android-security-16.0.0_r8, identical diff. 8/8 patched lines present at android-security-16.0.0_r9.",
      "17": "same fix: platform/frameworks/av 073ae498a43f in android-security-17.0.0_r1. 8/8 patched lines present at android-security-17.0.0_r2."
     },
     "backport_notes": [
      "Single self-contained commit with the same hunk content on 14 through 17. When porting to a customised tree, make sure every site that static_casts a client-supplied ITunerFilter/ITunerDemux/ITunerLnb gets the guard. Also make sure TunerHidlDemux.cpp gains the Result.h include and using-declaration; this is the only file where the commit adds them."
     ],
     "confidence": "high",
     "unknowns": [
      "The bodies of other mediatuner methods that take interface arguments (e.g. TunerDemux::setFrontendDataSource(ITunerFrontend)) are not in the material. It is unknown whether they also downcast and whether they were already guarded.",
      "Whether any local (non-remote) implementation of these interfaces other than the expected TunerXxx/TunerHidlXxx class could reach the fixed methods is not shown. One example would be an AIDL-backend object handed to a HIDL-backend method.",
      "Which of the two cherry-picked internal changes contributed which hunks is not shown.",
      "Which tuner HAL backend (AIDL or HIDL) is active on a given device, and therefore which set of files is live, is not shown."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58856": {
     "cve": "CVE-2026-58856",
     "summary": "Adds a range check on the slot index, a null check on the slot's GraphicBuffer, and a check that the buffer is tracked in mBuffers before use, all inside DeprecatedCamera3StreamSplitter::returnOutputBufferLocked. It also makes outputSlots a reference instead of a copy, so changes to the slots persist.",
     "component": "platform/frameworks/av, cameraserver libcameraservice device3 stream splitter (DeprecatedCamera3StreamSplitter / Camera3StreamSplitter)",
     "weakness": "Missing bounds check (out-of-bounds read) on an externally supplied vector index, plus missing null and map-membership checks on the buffer read from that index",
     "root_cause": "In returnOutputBufferLocked (services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp), the slot index was used directly to index the outputSlots vector (`buffer = outputSlots[slot]`) with no range check. The commit message calls this index app-supplied, and the caller shown in the context passes a slot obtained from the output producer's dequeueBuffer. The resulting sp<GraphicBuffer> was then dereferenced (`buffer->getId()`) without a null check. The id was passed to `mBuffers[...]` operator[] and the result was dereferenced right away, without checking that the id was tracked. The commit message says this could lead to an out-of-bounds read and type confusion. Separately, `auto outputSlots = *mOutputSlots[from]` copied the slot vector, so changes to the slots (such as `outputSlots[slot] = nullptr` in the detach path) did not persist.",
     "fix_analysis": [
      "DeprecatedCamera3StreamSplitter.cpp:DeprecatedCamera3StreamSplitter::returnOutputBufferLocked: `auto outputSlots` becomes `auto& outputSlots`, so it binds to the vector owned by mOutputSlots[from] instead of a copy.",
      "Same function: right after taking the reference, a slot with `slot < 0 || static_cast<size_t>(slot) >= outputSlots.size()` is rejected with SP_LOGE and an early return, before any indexing.",
      "Same function: after `buffer = outputSlots[slot]`, the function returns early with SP_LOGE if `buffer == nullptr`, which prevents the `buffer->getId()` dereference.",
      "Same function: `mBuffers[buffer->getId()]` is replaced with `mBuffers.find(buffer->getId())`, with an early return and SP_LOGE if the id is not tracked. `tracker` is then bound from `it->second`.",
      "The existing `mOutputSlots[from] == nullptr` check (output removed) is kept ahead of the new checks."
     ],
     "completeness": [
      "Covers the read of outputSlots indexed by the caller-provided slot in returnOutputBufferLocked, and both follow-on dereferences in that function (null buffer and untracked id).",
      "The caller shown at lines 717-725 (calls dequeueBuffer, then returnOutputBufferLocked with the slot it got) is protected because the check is in the callee.",
      "Because outputSlots is now a reference, `outputSlots[slot] = nullptr` in the detach path (line 768) now clears the splitter's own slot. The commit message describes this as making slot modifications persist.",
      "Only returnOutputBufferLocked is changed. The material does not show whether other functions in this file, or a non-deprecated splitter on 16/17, index per-output slot vectors with producer-supplied slots, so that is not assessed here."
     ],
     "behavior_changes": [
      "Three new early-return paths, each logged with SP_LOGE: slot out of range, null buffer in the slot, buffer id not in mBuffers. In these cases the fence is not merged and the rest of the function (detach and release handling) does not run for that buffer.",
      "mBuffers is no longer accessed through operator[] with an unknown id.",
      "Detaching an output buffer now nulls the entry in the splitter's own slot vector (before, only a local copy was changed)."
     ],
     "preconditions": [
      "Reached in cameraserver when the stream splitter returns a buffer to an output IGraphicBufferProducer. In the caller shown, the slot comes from that producer's dequeueBuffer (line 718). The commit message describes the slot index as app-supplied.",
      "mOutputSlots[from] must be non-null (output not yet removed) for the code to reach the indexing.",
      "On Android 14/15 the same logic is in Camera3StreamSplitter.cpp, not in the deprecated/ file."
     ],
     "per_major": {
      "14": "adapted fix: the same hunk is applied to services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp (Camera3StreamSplitter::returnOutputBufferLocked), commit d74fdb8ae7d4 in android-security-14.0.0_r29, marked RESTRICT AUTOMERGE.",
      "15": "adapted fix: the same hunk is applied to services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp, commit de6bd248af67 in android-security-15.0.0_r17, marked RESTRICT AUTOMERGE.",
      "16": "same fix: services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp, commit 6e240fe4061a in android-security-16.0.0_r8.",
      "17": "same fix: DeprecatedCamera3StreamSplitter.cpp, commit db4f7fd08e40 in android-security-17.0.0_r1 (cherry-pick of internal cf6bc17a7eee)."
     },
     "backport_notes": [
      "A single hunk in a single file. On 14 and 15, which do not have the deprecated/ file, Google applied the same hunk to device3/Camera3StreamSplitter.cpp."
     ],
     "confidence": "high",
     "unknowns": [
      "Whether a non-deprecated splitter implementation on Android 16/17 has the same unchecked indexing. For those branches the material only shows the deprecated/ file.",
      "Whether other functions in the splitter index the per-output slot vector with producer-supplied slots. Only returnOutputBufferLocked is shown.",
      "Whether returnOutputBufferLocked has callers other than the dequeueBuffer path shown. The index search returned none, but its results may be incomplete.",
      "Whether the file already includes the header that defines PRIu64 on every branch.",
      "Which cameraservice_test coverage was added, if any. Only the Test: line is given."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2026-58859": {
     "cve": "CVE-2026-58859",
     "summary": "Changes catch (Exception) to catch (Throwable) in Ts43PhoneNumberRetriever.fetchPhoneNumber and adds a new catch (Throwable) in the Ts43PhoneNumberController fetch method, so a StackOverflowError from JSON parsing of a server response no longer escapes and crashes the process.",
     "component": "platform/packages/modules/Telephony, TS.43 entitlement phone number retrieval (Ts43PhoneNumberRetriever / Ts43PhoneNumberController)",
     "weakness": "Uncaught error (java.lang.Error not covered by catch (Exception)) triggered by unbounded recursion on untrusted deeply nested JSON input (uncontrolled recursion / improper error handling)",
     "root_cause": "Per the commit message, a deeply nested JSON response from the TS.43 server causes unbounded recursion in JSONTokener during the phone number fetch. The tests model this as a StackOverflowError thrown from Ts43Operation.getPhoneNumber in step 3 (getPhoneNumberWithToken). A StackOverflowError is a java.lang.Error, not an Exception, so the existing catch (Exception e) in Ts43PhoneNumberRetriever.fetchPhoneNumber did not catch it. The caller in Ts43PhoneNumberController only caught ServiceEntitlementException, so the Error escaped and crashed the process. In the controller, the per-subscription in-progress flag (mIsTs43QueryInProgressPerSub) is set before the try block. An escaping Error skipped queryCompleted, so that state was not released, as the new controller test shows.",
     "fix_analysis": [
      "framework/java/com/android/internal/telephony/Ts43PhoneNumberRetriever.java:fetchPhoneNumber: the fallback handler catch (Exception e) becomes catch (Throwable e). It logs and returns null, so any Error (including a StackOverflowError) becomes a null result. ServiceEntitlementException is still caught first and rethrown unchanged.",
      "framework/java/com/android/internal/telephony/Ts43PhoneNumberController.java (the fetch method that calls mTs43PhoneNumberRetriever.fetchPhoneNumber(subId), around line 220): a new catch (Throwable t) is added after catch (ServiceEntitlementException e). It logs and calls queryCompleted(subId), which releases the per-sub in-progress state, so later fetches for that subId are not skipped. Unlike the ServiceEntitlementException path, it does not call handleFetchFailure.",
      "Tests: Ts43PhoneNumberRetrieverTest.testFetchPhoneNumber_Failure_ThrowsThrowable (getPhoneNumber throws StackOverflowError, fetchPhoneNumber returns null) and Ts43PhoneNumberControllerTest.testFetch_unexpectedError_releasesLock (the first fetch throws StackOverflowError, the second fetch still runs and sets the number)."
     ],
     "completeness": [
      "The fix only contains the failure. This commit does not bound or change the JSON parsing itself (JSONTokener recursion depth). The deep recursion still happens, and the resulting StackOverflowError is now caught and turned into a null result.",
      "Both layers are covered. The retriever catches Throwable inside fetchPhoneNumber. The controller catches Throwable around the whole fetch/format/set sequence, so Errors raised in formatNumber or setTs43PhoneNumber (other than the already handled NoSuchMethodError) are also contained and the per-sub lock is released.",
      "Only the TS.43 phone number path in this module changes. This commit does not touch any other users of the same entitlement/JSON parsing code, and the material does not show them."
     ],
     "behavior_changes": [
      "An Error during phone number retrieval now makes fetchPhoneNumber return null (logged as an unexpected exception) instead of crashing the process.",
      "In the controller, an unexpected Throwable is now logged and followed by queryCompleted(subId), which releases the in-progress state. handleFetchFailure is not called for it, unlike ServiceEntitlementException.",
      "Catching Throwable also swallows other Errors (for example OutOfMemoryError) in this path. They are now logged and treated as a failed fetch."
     ],
     "preconditions": [
      "TS.43 phone number fetch must be enabled for the subscription, and the carrier config KEY_ENTITLEMENT_SERVER_URL_STRING must provide a server URL (otherwise Ts43PhoneNumberRetriever.getServerUrl returns null). Per the tests, the controller starts the fetch on a carrier config change while the network is available.",
      "Steps before step 3 must succeed: an active SubscriptionInfo is found and getAuthToken returns a non-empty token.",
      "The server side of the TS.43 exchange returns a deeply nested JSON body, per the commit message (\"server-triggered\")."
     ],
     "per_major": {
      "14": "not affected per the bulletin; code absent: the patched files are not in android-security-14.0.0_r30",
      "15": "not affected per the bulletin; code absent: the patched files are not in android-security-15.0.0_r18",
      "16": "not affected per the bulletin; code absent: the patched files are not in android-security-16.0.0_r9",
      "17": "same fix: commit e04c40c70a08 (cherry-pick of de8c73c03104, Change-Id Ieef53664f3a25a2286c24d0b12c3132cfe94f562) in android-security-17.0.0_r1; all 8/8 lines of the patched region are present at android-security-17.0.0_r2"
     },
     "backport_notes": [
      "A single self-contained commit: one changed catch clause in the retriever, one new catch block in the controller, plus tests. It only applies to trees that contain Ts43PhoneNumberRetriever/Ts43PhoneNumberController in packages/modules/Telephony. These files are absent in the 14, 15 and 16 security tags."
     ],
     "confidence": "high",
     "unknowns": [
      "Where exactly the JSONTokener recursion happens (presumably inside Ts43Operation.getPhoneNumber or the service entitlement library) is not shown, nor whether that parser was hardened separately.",
      "The name of the controller method that contains the patched try block is not visible in the provided context.",
      "The body of handleFetchFailure, and whether it clears the in-progress flag, is not shown.",
      "The material does not say which process hosts Ts43PhoneNumberController, so it does not show what crashed.",
      "Whether the fix is also delivered through a module update is not shown in the material."
     ],
     "meta": {
      "generated": "2026-10-06",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    }
   }
  }
 },
 "bulletin": {
  "url": "https://source.android.com/docs/security/bulletin/2026/2026-10-01",
  "latest_version": "1.1",
  "latest_revision": {
   "version": "1.1",
   "date": "October 8, 2026",
   "notes": "AOSP links added"
  },
  "revisions": [
   {
    "version": "1.0",
    "date": "October 5, 2026",
    "notes": "Bulletin Published"
   },
   {
    "version": "1.1",
    "date": "October 8, 2026",
    "notes": "AOSP links added"
   }
  ],
  "tracked_since": "2026-10-05",
  "changes_since_tracking": [],
  "out_of_scope_rows": {},
  "note": "changes are only visible from `tracked_since`; earlier revisions of the bulletin cannot be reconstructed. Out-of-scope rows (vendor closed-source, kernel) have no public AOSP code to resolve."
 }
}