{
 "month": "2024-08",
 "generated": "2026-10-06T12:05+00:00",
 "majors": {
  "14": {
   "counts": {
    "announced": 11,
    "certain": 11,
    "probable": 0,
    "not_published": 0,
    "not_covered": 0,
    "awaiting": 0
   },
   "advisories": [
    {
     "cve": "CVE-2023-20971",
     "osv_id": "ASB-A-225880325",
     "source": "osv",
     "announced": "2024-08-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a missing early return in PermissionManagerServiceImpl.removePermission() so that a non-dynamic permission is no longer removed from the registry after the \"Not allowed to modify non-dynamic permission\" check fails.",
      "confidence": "high",
      "backport_notes": [
       "Single one-line change; on older branches (12, 12L, 13 are also listed as affected) locate the `if (!bp.isDynamic())` branch in removePermission() and add the return after the Slog.wtf call, keeping it inside the mLock synchronized block."
      ],
      "meta": {
       "generated": "2026-10-04",
       "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": [
      "change_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r9",
      "date": "2024-06-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r9",
      "date": "2024-06-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "6c22d6c1e69676c5c68d21928aa5486bfd1bd131",
       "tag": "android-security-14.0.0_r9",
       "provenance": "security_tag",
       "method": "change_id",
       "confidence": "certain",
       "evidence": "ref 6c22d6c1e696",
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 59,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2024-34727",
     "osv_id": "ASB-A-287184435",
     "source": "osv",
     "announced": "2024-08-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds discovery-attribute length checks to sdpu_compare_uuid_with_attr (system/stack/sdp/sdp_utils.cc). A UUID is now compared with a tSDP_DISC_ATTR only when SDP_DISC_ATTR_LEN matches the UUID size (2, 4 or 16 bytes). Otherwise the function logs an error and returns false.",
      "confidence": "medium",
      "backport_notes": [
       "Self-contained change in one function. It uses SDP_DISC_ATTR_LEN, Uuid::kNumBytes16/32/128 and LOG(ERROR); base/logging.h is already included in sdp_utils.cc.",
       "The bulletin lists Android 13 as affected, but the material has no 13 commit. The same diff may apply to system/stack/sdp/sdp_utils.cc there if the function body matches the pre-fix form shown."
      ],
      "meta": {
       "generated": "2026-10-04",
       "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_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "6afad4b377b5bc3f38b28296e746b674173f99d8",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2024-34731",
     "osv_id": "ASB-A-319210610",
     "source": "osv",
     "announced": "2024-08-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Replaces raw object pointers used as libbinder_ndk death-recipient cookies with tracked, validated cookie objects (keyed maps, weak_ptr wrappers, onUnlinked-owned cookies) in libmediatranscoding, the health AIDL HAL default impl, the neuralnetworks AIDL utils and keystore2 apc_compat, so a late binderDied callback no longer dereferences a freed object.",
      "confidence": "high",
      "backport_notes": [
       "The fix is four independent commits in three projects, tied together by bug 319210610; apply all of them. The health and keystore2 changes require AIBinder_DeathRecipient_setOnUnlinked in libbinder_ndk.",
       "No 'Fix in fork' section was provided, so no per-file fork verdict can be reported."
      ],
      "meta": {
       "generated": "2026-10-04",
       "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_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/av",
       "sha": "4b68b00993849b6a7f0e6d075bc2c8bb2e184e61",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/hardware/interfaces",
       "sha": "0ff19d1f89614fce9454fb415bcbfcbcf3caf76e",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/hardware/interfaces",
       "sha": "d63d09261806f7f1aa01406867f2a9e169356fca",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/system/nfc",
       "sha": "1037992b9abcde1e3560bd895f62644a68563b3d",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/system/security",
       "sha": "d3805312d73433e34ef69a645b553a2969c5dc93",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 5,
     "projects": [
      "platform/frameworks/av",
      "platform/hardware/interfaces",
      "platform/system/nfc",
      "platform/system/security"
     ]
    },
    {
     "cve": "CVE-2024-34734",
     "osv_id": "ASB-A-304772709",
     "source": "osv",
     "announced": "2024-08-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "SystemUI's Quick Settings footer now routes the \"active apps\" (foreground services) button click through ActivityStarter.dismissKeyguardThenExecute, so the foreground services dialog opens only after the keyguard is dismissed instead of opening directly while the screen is locked.",
      "confidence": "high",
      "backport_notes": [
       "The change is self-contained in SystemUI but changes the FooterActionsViewModel and Factory constructors. ActivityStarter is already used elsewhere in the footer stack (FooterActionsTestUtils.footerActionsInteractor already took an ActivityStarter), so a new binding is likely not needed. Any code that constructs FooterActionsViewModel directly must be updated.",
       "The bulletin lists Android 13 as affected, but the material contains no Android 13 commit or code. Whether the 13 footer uses FooterActionsViewModel or an older code path (and so needs an adapted fix) is unknown."
      ],
      "meta": {
       "generated": "2026-10-04",
       "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-14.0.0_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "207584fb6f820eba14251251d7e9331bfd57adb8",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2024-34736",
     "osv_id": "ASB-A-288549440",
     "source": "osv",
     "announced": "2024-08-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "StagefrightRecorder::setupVideoEncoder now forces zero B-layers (bLayers = 0) in the temporal-layering \"ts-schema\" when the audio source is AUDIO_SOURCE_MIC and the video source is VIDEO_SOURCE_SURFACE, which disables B-frame layering for the screen-recorder-with-microphone use case.",
      "confidence": "medium",
      "backport_notes": [
       "This is a self-contained 5-line insertion inside the existing `if (tsLayers > 1)` block of setupVideoEncoder, and it uses the mAudioSource and mVideoSource members. The material does not show the 12, 12L or 13 code, so applicability there needs to be checked."
      ],
      "meta": {
       "generated": "2026-10-04",
       "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_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/av",
       "sha": "6cfd048292b2cc706811a22c9078208cfa8e6d24",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/av"
     ]
    },
    {
     "cve": "CVE-2024-34737",
     "osv_id": "ASB-A-283103220",
     "source": "osv",
     "announced": "2024-08-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a CountQuotaTracker to ActivityClientController so that an app may change the PiP aspect ratio via setPictureInPictureParams/enterPictureInPictureMode at most 60 times per minute; excess requests throw IllegalStateException.",
      "confidence": "high",
      "backport_notes": [
       "Requires com.android.server.utils.quota.CountQuotaTracker, Categorizer and Category in services; keep the tracker construction outside mGlobalLock (QuotaTracker ctor uses the AM lock) and keep the time window at or above QuotaTracker#MIN_WINDOW_SIZE_MS. Bulletin lists 12, 12L and 13 as affected but their fix commits are not in the material.",
       "wmtests that change the aspect ratio via setPictureInPictureParams may need the tracker disabled (setEnabled(false)) as done in WindowOrganizerTests.testChangePipParams, since the quota check causes an NPE in that test setup."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 9,
       "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_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "8b473b3f79642f42eeeffbfe572df6c6cbe9d79e",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2024-34738",
     "osv_id": "ASB-A-336323279",
     "source": "osv",
     "announced": "2024-08-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "AppOpsService now filters restricted-read app ops out of collectOps() results unless the caller holds GET_APP_OPS_STATS, and verifyIncomingOp() accepts any of MANAGE_APPOPS, GET_APP_OPS_STATS or MANAGE_APP_OPS_MODES instead of only MANAGE_APPOPS for restricted ops.",
      "confidence": "high",
      "backport_notes": [
       "Single commit. The Java-side changes use Manifest.permission.GET_APP_OPS_STATS, MANAGE_APP_OPS_MODES and AppOpsManager.opRestrictsRead. On a 14 branch that has the NUM_ATTRIBUTED_OP_ENTRY_THRESHOLD logic in collectOps, place the restricted-op skip before the threshold check, as in android-security-14.0.0_r29.",
       "Test named in the commit: atest AppOpsTest#testRestrictedSettingsOpsRead (test source not included in this diff)."
      ],
      "meta": {
       "generated": "2026-10-04",
       "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_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "21d764807b3dcd402d63e2b4c9fbae1c9965400a",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2024-34740",
     "osv_id": "ASB-A-307288067",
     "source": "osv",
     "announced": "2024-08-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "BinaryXmlSerializer.attributeBytesHex and attributeBytesBase64 now throw IOException when the byte array is longer than 65535 (MAX_UNSIGNED_SHORT) instead of writing a truncated 16-bit length followed by the full payload; a later commit linked by the same bug id caps the checksum signature in ApkChecksums.verifySignature at 35 * 1024 bytes.",
      "confidence": "medium",
      "backport_notes": [
       "Apply modules-utils 700c28908051 first (the functional fix; it requires FastDataOutput.MAX_UNSIGNED_SHORT to exist in the target branch), then the base test commit; the ApkChecksums/PackageInstallerSession commit has no code dependency on the serializer change in the diffs but is linked by the same bug id. frameworks/libs/modules-utils is a static Java library compiled into the framework and mainline modules, so consumers must be rebuilt to pick up the change (general platform knowledge)."
      ],
      "meta": {
       "generated": "2026-10-04",
       "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_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r28",
      "date": "2026-06-01",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "e8b6505647be558ed3a167a1e13c53dfc227d22b",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/frameworks/libs/modules-utils",
       "sha": "700c28908051ceb55e1456d2d21229bc17c6895a",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/frameworks/base",
       "sha": "716a1c65c273259afcd8d8d3c6c9a20dbd6c7199",
       "tag": "android-security-14.0.0_r28",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 3,
     "multi_tag_fix": true,
     "projects": [
      "platform/frameworks/base",
      "platform/frameworks/libs/modules-utils"
     ]
    },
    {
     "cve": "CVE-2024-34741",
     "osv_id": "ASB-A-318683640",
     "source": "osv",
     "announced": "2024-08-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "WindowState.setForceHideNonSystemOverlayWindowIfNeeded now classifies a window by getBaseType() instead of mAttrs.type. Per the commit title 'Hide SAW subwindows', this means subwindows of system-alert-window (SAW) or toast parents are also force-hidden when a top window hides overlays through Window#setHideOverlayWindows.",
      "confidence": "high",
      "backport_notes": [
       "A self-contained 3-line change in WindowState.setForceHideNonSystemOverlayWindowIfNeeded. It replaces mAttrs.type with getBaseType() in the two type checks and depends on nothing that the pre-fix code does not already reference."
      ],
      "meta": {
       "generated": "2026-10-04",
       "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_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "abfaf702ef833dc4d374492d45c615c6e6de7f01",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2024-34742",
     "osv_id": "ASB-A-335232744",
     "source": "osv",
     "announced": "2024-08-01",
     "severity": "High",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Makes DeviceOwnerReadWriter.shouldWrite() in OwnersData always return true, so the device owner persistence file (device_owners2.xml) is always written. Before, it was written only when a device owner, system update policy or system update info was set.",
      "confidence": "medium",
      "backport_notes": [
       "A single one-line change with no dependencies: in OwnersData.java, make DeviceOwnerReadWriter.shouldWrite() return true."
      ],
      "meta": {
       "generated": "2026-10-04",
       "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_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "688e5c3012eb0a4ea88361588cf5026c10e4a42c",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2024-34743",
     "osv_id": "ASB-A-336648613",
     "source": "osv",
     "announced": "2024-08-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Changes the sanitization loop in SurfaceFlinger::setTransactionState to iterate ComposerState entries by reference (auto&) instead of by value, so layer_state_t::sanitize(permissions) actually strips privileged fields from the states that are later applied.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained commit. The production change is one token (`auto` -> `auto&`) in the ComposerState loop of SurfaceFlinger::setTransactionState: check that this loop's variable is a reference. The test changes depend on UIDFaker and WindowInfosListenerUtils being available in Credentials_test.cpp."
      ],
      "meta": {
       "generated": "2026-10-04",
       "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_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/native",
       "sha": "3f85323b27d95a57bfa87cbf68dd4a143f9f88ad",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/native"
     ]
    }
   ],
   "tags": [
    "android-security-14.0.0_r11"
   ],
   "unannounced": [],
   "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-2023-20971": {
     "cve": "CVE-2023-20971",
     "summary": "Adds a missing early return in PermissionManagerServiceImpl.removePermission() so that a non-dynamic permission is no longer removed from the registry after the \"Not allowed to modify non-dynamic permission\" check fails.",
     "component": "platform/frameworks/base, services/core PermissionManagerServiceImpl (permission registry)",
     "weakness": "Missing early return after a failed validity check (improper error handling): the non-dynamic check only logged and did not stop the operation.",
     "root_cause": "In services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java, removePermission(String permName) looks up the Permission from mRegistry and, if !bp.isDynamic(), logs Slog.wtf(\"Not allowed to modify non-dynamic permission ...\") but then falls through to mRegistry.removePermission(permName) and mPackageManagerInt.writeSettings(false). Per the commit message only dynamic permissions are supposed to be removable, but the code let a caller that passes mRegistry.enforcePermissionTree(permName, callingUid) remove a non-dynamic permission from the registry and persist that change.",
     "fix_analysis": [
      "PermissionManagerServiceImpl.java:removePermission - a single `return;` is added inside the `if (!bp.isDynamic())` branch, after the Slog.wtf log, so the method exits (still inside synchronized (mLock)) before mRegistry.removePermission(permName) is called and before mPackageManagerInt.writeSettings(false) runs.",
      "The existing pre-checks are unchanged: instant apps are still rejected with SecurityException, mRegistry.enforcePermissionTree(permName, callingUid) is still enforced, and a null Permission still returns early."
     ],
     "completeness": [
      "The fix covers only removePermission(); it makes the non-dynamic branch actually terminate the operation.",
      "The sibling addPermission() path in the same file already throws SecurityException for a non-dynamic existing permission (lines 667-669 in the r29 context), so no equivalent gap is visible there.",
      "The non-dynamic case still logs Slog.wtf and returns silently rather than throwing; the code retains the comment 'TODO: switch this back to SecurityException', so callers receive no error signal."
     ],
     "behavior_changes": [
      "removePermission() on a non-dynamic permission is now a no-op (after a Slog.wtf log): the permission stays in mRegistry and settings are not rewritten.",
      "No new exception or error code is introduced; the caller cannot distinguish the rejected call from a successful one."
     ],
     "preconditions": [
      "Caller reaches PermissionManagerServiceImpl.removePermission(permName) and is not an instant app.",
      "The call passes mRegistry.enforcePermissionTree(permName, callingUid).",
      "permName resolves to an existing Permission in mRegistry whose isDynamic() is false."
     ],
     "per_major": {
      "14": "same fix: commit 6c22d6c1e696 (Change-Id Ie2f43663bc71a06ffadb868d2d0eea5ee78f76e5) in android-security-14.0.0_r9; at android-security-14.0.0_r29 all 3 lines of the patched region are present.",
      "15": "not affected (not listed by the bulletin); at android-security-15.0.0_r17 the patched region (3/3 lines) is present.",
      "16": "not affected (not listed by the bulletin); at android-security-16.0.0_r8 the patched region (3/3 lines) is present.",
      "17": "not affected (not listed by the bulletin); services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java is absent at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Single one-line change; on older branches (12, 12L, 13 are also listed as affected) locate the `if (!bp.isDynamic())` branch in removePermission() and add the return after the Slog.wtf call, keeping it inside the mLock synchronized block."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show the fix commits for Android 12, 12L and 13 that the bulletin lists as affected.",
      "The material does not show the Binder-facing callers of removePermission() or any test accompanying the change (commit says Test: manual).",
      "The exact semantics of mRegistry.enforcePermissionTree() are not shown."
     ],
     "meta": {
      "generated": "2026-10-04",
      "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-2024-34727": {
     "cve": "CVE-2024-34727",
     "summary": "Adds discovery-attribute length checks to sdpu_compare_uuid_with_attr (system/stack/sdp/sdp_utils.cc). A UUID is now compared with a tSDP_DISC_ATTR only when SDP_DISC_ATTR_LEN matches the UUID size (2, 4 or 16 bytes). Otherwise the function logs an error and returns false.",
     "component": "platform/packages/modules/Bluetooth, Bluetooth stack SDP (system/stack/sdp)",
     "weakness": "Missing length check leading to an out-of-bounds read (heap-buffer overflow) during the comparison",
     "root_cause": "sdpu_compare_uuid_with_attr chose the comparison width only from the local Uuid's shortest representation size (GetShortestRepresentationSize). It never checked the discovery attribute's encoded length (SDP_DISC_ATTR_LEN(p_attr->attr_len_type)). On the 128-bit path it ran memcmp over Uuid::kNumBytes128 (16) bytes of p_attr->attr_value.v.array whatever the attribute's actual size. The commit message says a fuzzer found a heap-buffer overflow (an out-of-bounds comparison) and that it comes from comparing a 128-bit UUID with a discovery attribute of some other, invalid size. The 16-bit and 32-bit paths also read attr_value.v.u16 and v.u32 without checking that the attribute held a 2-byte or 4-byte value.",
     "fix_analysis": [
      "system/stack/sdp/sdp_utils.cc:sdpu_compare_uuid_with_attr, len == 2 case: compares uuid.As16Bit() with p_attr->attr_value.v.u16 only when SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == Uuid::kNumBytes16. Otherwise it logs 'invalid length for discovery attribute' and returns false.",
      "Same function, len == 4 case: compares uuid.As32Bit() with p_attr->attr_value.v.u32 only when SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == Uuid::kNumBytes32. Otherwise it logs and returns false.",
      "Same function, 128-bit fallthrough: before the existing memcmp of Uuid::kNumBytes128 bytes against p_attr->attr_value.v.array, it now requires SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == Uuid::kNumBytes128. Otherwise it logs and returns false.",
      "Single-commit fix that touches only this function (22 insertions, 2 deletions). It makes no header or data-structure changes."
     ],
     "completeness": [
      "Covers all three comparison widths (2, 4 and 16 bytes) inside sdpu_compare_uuid_with_attr by gating each one on the attribute's encoded length.",
      "The fix adds length checks only. The material does not show whether the attribute's type is checked anywhere else.",
      "Only this function changes. The neighbouring sdpu_compare_uuid_arrays (named in the context header) is not touched. Its body is not shown, so the material does not show whether it needs similar handling.",
      "Sizes that do not match are no longer compared: for example, a 16-bit local UUID against an attribute whose length is not 2 now returns false. Before the fix, the code compared it against attr_value.v.u16."
     ],
     "behavior_changes": [
      "sdpu_compare_uuid_with_attr now returns false (no match) whenever the discovery attribute's length differs from the local UUID's shortest representation size. Before the fix it compared anyway.",
      "Each mismatch now emits the LOG(ERROR) message 'invalid length for discovery attribute'.",
      "No API, data-structure or wire-format changes."
     ],
     "preconditions": [
      "A tSDP_DISC_ATTR must reach sdpu_compare_uuid_with_attr with an attr_len_type length that does not match the size of the UUID being compared. Per the commit message, the problematic case is a 128-bit UUID compared with an attribute of a different, invalid size.",
      "The call paths into sdpu_compare_uuid_with_attr and the origin of the attribute data are not shown in the material (none were found per index search)."
     ],
     "per_major": {
      "14": "Same fix: commit 6afad4b377b5 landed in android-security-14.0.0_r11 (cherry-picked from internal commit 7bbdb139bf91, Ignore-AOSP-First). At android-security-14.0.0_r29, 5 of 7 lines of the patched region are present. The material does not show what differs in the other lines.",
      "15": "Not affected per the bulletin. At android-security-15.0.0_r17, 5 of 7 lines of the patched region are present. The material does not show the exact code.",
      "16": "Not affected per the bulletin. At android-security-16.0.0_r8, 4 of 7 lines of the patched region are present. The material does not show the exact code.",
      "17": "Not affected per the bulletin. At android-security-17.0.0_r1, 4 of 7 lines of the patched region are present. The material does not show the exact code."
     },
     "backport_notes": [
      "Self-contained change in one function. It uses SDP_DISC_ATTR_LEN, Uuid::kNumBytes16/32/128 and LOG(ERROR); base/logging.h is already included in sdp_utils.cc.",
      "The bulletin lists Android 13 as affected, but the material has no 13 commit. The same diff may apply to system/stack/sdp/sdp_utils.cc there if the function body matches the pre-fix form shown."
     ],
     "confidence": "medium",
     "unknowns": [
      "Callers of sdpu_compare_uuid_with_attr and the exact path that reaches it (not shown; index search found none).",
      "Where tSDP_DISC_ATTR data comes from, and the allocation size of attr_value.v.array (how far the pre-fix memcmp could over-read).",
      "Whether the attribute type (as opposed to length) is checked before this comparison.",
      "What the partial line matches on 14 r29 and on 15, 16 and 17 mean for the exact code present.",
      "The Android 13 fix commit and status (listed as affected but not in the material)."
     ],
     "meta": {
      "generated": "2026-10-04",
      "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-2024-34731": {
     "cve": "CVE-2024-34731",
     "summary": "Replaces raw object pointers used as libbinder_ndk death-recipient cookies with tracked, validated cookie objects (keyed maps, weak_ptr wrappers, onUnlinked-owned cookies) in libmediatranscoding, the health AIDL HAL default impl, the neuralnetworks AIDL utils and keystore2 apc_compat, so a late binderDied callback no longer dereferences a freed object.",
     "component": "platform/frameworks/av (media/module/libmediatranscoding TranscodingResourcePolicy); platform/hardware/interfaces (health/aidl/default Health/LinkedCallback, neuralnetworks/aidl/utils ProtectCallback DeathMonitor); platform/system/security (keystore2/apc_compat ConfuiAidlCompatSession)",
     "weakness": "Use-after-free (death recipient callback dereferencing a stale cookie pointer; lifetime race between object destruction/unlink and binderDied delivery)",
     "root_cause": "In all four components the cookie passed to AIBinder_linkToDeath was a raw pointer to an object: `this` for TranscodingResourcePolicy and ConfuiAidlCompatSession, a raw LinkedCallback* in the health HAL and a raw DeathMonitor* in NNAPI utils. The death callbacks (TranscodingResourcePolicy::BinderDiedCallback, OnCallbackDiedWrapped, DeathMonitor::serviceDied(void*), binderDiedCallbackAidl) cast it back and used it. At most they checked for null; none checked that the object was still alive. The health commit message says an onBinderDied callback can still arrive after AIBinder_unlinkToDeath(). In the health HAL, the LinkedCallback destructor unlinked and then freed the very object that a pending callback would use. Nothing validated that the cookie still referred to a live object, so the callback could operate on freed memory.",
     "fix_analysis": [
      "frameworks/av media/module/libmediatranscoding/TranscodingResourcePolicy.cpp: adds TranscodingResourcePolicyCookie and a file-static std::map<uintptr_t, unique_ptr<cookie>> sCookies, with sCookieKeyCounter and sCookiesMutex. registerSelf() now allocates a cookie, assigns it an integer key and stores it in sCookies. It also records the key in the per-instance mCookieKeys set, guarded by the new mCookieKeysLock (both declared in include/media/TranscodingResourcePolicy.h). It then passes the integer key, not `this`, to AIBinder_linkToDeath.",
      "frameworks/av TranscodingResourcePolicy::BinderDiedCallback: takes sCookiesMutex and looks the key up in sCookies. Only if it is found does it call policy->unregisterSelf() and erase the entry; an unknown key is ignored. ~TranscodingResourcePolicy(): under sCookiesMutex, erases every sCookies entry whose key is in mCookieKeys before calling unregisterSelf(), so a later death notification finds nothing. unregisterSelf(): the AIBinder_unlinkToDeath call is removed. Per the commit message, dropping the last strong ref to the binder unlinks it.",
      "hardware/interfaces health/aidl/default/Health.cpp: adds onCallbackUnlinked(void*), which deletes the LinkedCallback, and registers it with AIBinder_DeathRecipient_setOnUnlinked in Health::Health. Ownership of the cookie moves to the death recipient, so it is freed in the onUnlinked callback. callbacks_ (include/health-impl/Health.h) changes from vector<unique_ptr<LinkedCallback>> to map<LinkedCallback*, shared_ptr<IHealthInfoCallback>>. registerCallback returns STATUS_UNEXPECTED_NULL if LinkedCallback::Make fails. unregisterCallback calls AIBinder_unlinkToDeath explicitly, with the map key as the cookie, and erases the entry. OnHealthInfoChanged iterates the map and erases dead entries.",
      "hardware/interfaces health/aidl/default/LinkedCallback.cpp/.h: Make returns a raw LinkedCallback*, with ownership passed to the death recipient. The destructor that called AIBinder_unlinkToDeath is removed. callback_ becomes weak_ptr<IHealthInfoCallback>, and OnCallbackDied only calls service()->unregisterCallback if the weak_ptr can be promoted.",
      "hardware/interfaces neuralnetworks/aidl/utils/src/ProtectCallback.cpp: adds anonymous-namespace sCookiesMutex, sCookieKeyCounter and std::map<uintptr_t, weak_ptr<DeathMonitor>> sCookies. DeathHandler::create allocates a key under the lock and constructs DeathMonitor(key), using the new constructor and kCookieKey in include/nnapi/hal/aidl/ProtectCallback.h. It registers the monitor and passes the key to AIBinder_linkToDeath; ~DeathHandler unlinks with the key. DeathMonitor::serviceDied(void*) looks the key up under the lock, erases it, promotes the weak_ptr and only then calls serviceDied(); a missing key or a failed promotion is logged and ignored. The new ~DeathMonitor erases its key under the lock, and copy/move are deleted. test/DeviceTest.cpp is updated to pass getCookieKey().",
      "system/security keystore2/apc_compat/apc_compat.cpp ConfuiAidlCompatSession: adds DeathRecipientCookie, which holds a weak_ptr<ConfuiAidlCompatSession>. promptUserConfirmation allocates one cookie per linkToDeath call, deletes it if linking fails, and tracks it in deathRecipientCookie_ (a std::set<void*> under deathRecipientCookie_lock_). finalize() copies the tracked cookies out and unlinks each one outside the lock. serviceDied() clears the set, and the new serviceUnlinked(cookie) erases one entry. binderDiedCallbackAidl casts to DeathRecipientCookie, promotes the weak_ptr and calls serviceDied only if the session is still alive. The new binderUnlinkedCallbackAidl, installed with AIBinder_DeathRecipient_setOnUnlinked in the constructor, calls serviceUnlinked and deletes the cookie."
     ],
     "completeness": [
      "All four death-recipient cookie sites linked to bug 319210610 are changed so that the callback validates the cookie, or safely promotes it, before touching the owner. The raw `this`/raw-pointer cookie pattern is removed from each.",
      "libmediatranscoding: in registerSelf(), sCookieKeyCounter++ and sCookies.emplace() run without holding sCookiesMutex; only the mCookieKeys insertion takes mCookieKeysLock. BinderDiedCallback and the destructor, by contrast, modify sCookies under sCookiesMutex. registerSelf is a private method, and the material does not show which lock its callers hold. The fix also drops AIBinder_unlinkToDeath entirely and relies on the binder reference being released in unregisterSelf.",
      "health HAL: OnHealthInfoChanged erases dead entries from callbacks_ without calling AIBinder_unlinkToDeath; the LinkedCallback is then freed only when the death recipient's onUnlinked fires. The health and keystore2 fixes depend on AIBinder_DeathRecipient_setOnUnlinked being available.",
      "NNAPI utils: serviceDied(void*) erases the key on the first notification, so each cookie is consumed once. Only the NDK path is tracked (code comment: 'Only used with ndk').",
      "keystore2: serviceDied() clears deathRecipientCookie_ without unlinking; the cookies for the dead binder are freed by binderUnlinkedCallbackAidl when binder delivers onUnlinked."
     ],
     "behavior_changes": [
      "health Health::registerCallback now fails with STATUS_UNEXPECTED_NULL when LinkedCallback::Make (AIBinder_linkToDeath) fails, instead of storing a null entry.",
      "health Health::unregisterCallback logs a WARNING if AIBinder_unlinkToDeath fails with a status other than OK/DEAD_OBJECT. OnHealthInfoChanged logs at DEBUG when a callback result is neither OK nor dead.",
      "libmediatranscoding no longer calls AIBinder_unlinkToDeath in unregisterSelf. BinderDiedCallback logs 'BinderDiedCallback unregistering TranscodingResourcePolicy'.",
      "NNAPI DeathMonitor::serviceDied logs and ignores death notifications whose cookie key is unknown or whose DeathMonitor can no longer be promoted.",
      "keystore2 ConfuiAidlCompatSession: finalize() unlinks all cookies accumulated from multiple promptUserConfirmation calls. Death notifications that arrive after the session is gone are logged and ignored."
     ],
     "preconditions": [
      "A process holding one of these objects has linked a death recipient to a remote binder, and that remote dies while the owning object is being destroyed or unlinked. The remotes are: media.resource_observer for TranscodingResourcePolicy (per the commit test steps); an IHealthInfoCallback client for the health HAL; an NN HAL device for the NNAPI DeathHandler; and the ConfirmationUI AIDL HAL for keystore2 apc_compat.",
      "The exact trigger, and which component the bulletin's High EoP rating refers to, are not shown in the material."
     ],
     "per_major": {
      "14": "same fix: four commits (frameworks/av 4b68b0099384, hardware/interfaces 0ff19d1f8961 and d63d09261806, system/security d3805312d734) landed in android-security-14.0.0_r11. At android-security-14.0.0_r29 the system/security patched region is fully present (8/8 lines), and the r29 code context shows the av and hardware/interfaces changes in place.",
      "15": "not affected (not listed by the bulletin); at android-security-15.0.0_r17, 7/8 lines of the patched region are present.",
      "16": "not affected (not listed by the bulletin); at android-security-16.0.0_r8, 7/8 lines of the patched region are present.",
      "17": "not affected (not listed by the bulletin); at android-security-17.0.0_r1, 7/8 lines of the patched region are present."
     },
     "backport_notes": [
      "The fix is four independent commits in three projects, tied together by bug 319210610; apply all of them. The health and keystore2 changes require AIBinder_DeathRecipient_setOnUnlinked in libbinder_ndk.",
      "No 'Fix in fork' section was provided, so no per-file fork verdict can be reported."
     ],
     "confidence": "high",
     "unknowns": [
      "Which of the four components the bulletin's High EoP rating is attributed to, and the concrete trigger.",
      "Whether registerSelf() in TranscodingResourcePolicy is always invoked under a lock that serializes it against BinderDiedCallback and the destructor, given that sCookies is modified there without sCookiesMutex.",
      "What the one missing line of the patched region on 15/16/17 is.",
      "How the fix was applied on the other affected branches (12, 12L, 13), including whether AIBinder_DeathRecipient_setOnUnlinked is usable there."
     ],
     "meta": {
      "generated": "2026-10-04",
      "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-2024-34734": {
     "cve": "CVE-2024-34734",
     "summary": "SystemUI's Quick Settings footer now routes the \"active apps\" (foreground services) button click through ActivityStarter.dismissKeyguardThenExecute, so the foreground services dialog opens only after the keyguard is dismissed instead of opening directly while the screen is locked.",
     "component": "platform/frameworks/base, SystemUI Quick Settings footer actions (FooterActionsViewModel)",
     "weakness": "Missing lock-state (keyguard) check before presenting an action-capable dialog from the lockscreen",
     "root_cause": "In packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt, the click handler for the foreground services (\"active apps\") footer button called footerActionsInteractor.showForegroundServicesDialog(expandable) directly; the only thing before it in the hunk is an early return. Nothing checked the lock state. Per the commit message, this meant the active apps dialog could be shown while the screen was locked, which made a VPN app killable from the lockscreen.",
     "fix_analysis": [
      "FooterActionsViewModel.kt: the class constructor and its inner Factory gain a new ActivityStarter dependency (private val activityStarter: ActivityStarter). Factory.create() passes it to the view model.",
      "FooterActionsViewModel.kt, foreground services click handler: the direct call to footerActionsInteractor.showForegroundServicesDialog(expandable) is replaced by activityStarter.dismissKeyguardThenExecute({ footerActionsInteractor.showForegroundServicesDialog(expandable); false }, null /* cancelAction */, true /* afterKeyguardGone */). Per the commit message, if the screen is locked the user is prompted to unlock, and the dialog opens only after a successful unlock. No cancel action is set.",
      "packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt: adds a shared mockActivityStarter, passes it to the FooterActionsViewModel constructor, and makes footerActionsInteractor() use the same mock as its default activityStarter."
     ],
     "completeness": [
      "Only the foreground services button click in FooterActionsViewModel is wrapped in dismissKeyguardThenExecute. FooterActionsInteractor.showForegroundServicesDialog itself is unchanged, so any other caller of that interactor method would not get the keyguard gate. The material shows no such caller.",
      "The sibling security button handler (onSecurityButtonClicked -> footerActionsInteractor.showDeviceMonitoringDialog) and the observeDeviceMonitoringDialogRequests path are not gated. The material does not show whether that dialog offers any state-changing action, so this is noted only as untouched, not as a flaw.",
      "The fix relies on dismissKeyguardThenExecute to gate the dialog. The dialog itself adds no further check."
     ],
     "behavior_changes": [
      "When the device is locked, tapping the Quick Settings footer 'active apps' button now prompts the user to unlock. The foreground services dialog opens only after a successful unlock (afterKeyguardGone = true). No cancel action is set (cancelAction = null).",
      "The FooterActionsViewModel and FooterActionsViewModel.Factory constructor signatures change (new ActivityStarter parameter). This affects Dagger injection and any test or OEM code that constructs them directly."
     ],
     "preconditions": [
      "The device is on the lockscreen with Quick Settings reachable, per the commit message (lockscreen scenario).",
      "At least one app is running a foreground service, so the footer 'active apps' button is shown. The commit message cites a VPN app.",
      "The Quick Settings footer is rendered through FooterActionsViewModel. Per index search, the Compose FooterActions composable uses it, and QuickSettingsSceneViewModel uses it through FooterActionsViewModel.Factory."
     ],
     "per_major": {
      "14": "same fix: commit 207584fb6f82 (cherry-picked from d7628d5621c9, Change-Id I384699d478e5abcee3a165afc45211b9ed96334a) in android-security-14.0.0_r11. At android-security-14.0.0_r29 the patched region is fully present (8/8 lines).",
      "15": "not affected (not listed by the bulletin); the patched region is fully present at android-security-15.0.0_r17 (8/8 lines).",
      "16": "not affected (not listed by the bulletin); the patched region is fully present at android-security-16.0.0_r8 (8/8 lines).",
      "17": "not affected (not listed by the bulletin); the patched region is fully present at android-security-17.0.0_r1 (8/8 lines)."
     },
     "backport_notes": [
      "The change is self-contained in SystemUI but changes the FooterActionsViewModel and Factory constructors. ActivityStarter is already used elsewhere in the footer stack (FooterActionsTestUtils.footerActionsInteractor already took an ActivityStarter), so a new binding is likely not needed. Any code that constructs FooterActionsViewModel directly must be updated.",
      "The bulletin lists Android 13 as affected, but the material contains no Android 13 commit or code. Whether the 13 footer uses FooterActionsViewModel or an older code path (and so needs an adapted fix) is unknown."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact name of the patched click handler and its full guard condition are not shown in the diff hunk.",
      "The Android 13 fix commit and how it was adapted, if at all.",
      "Whether the foreground services dialog offers actions beyond stopping apps; the material only mentions a VPN app being killable.",
      "Whether any legacy (non-ViewModel) footer path on affected branches also opens the foreground services dialog.",
      "How dismissKeyguardThenExecute behaves when the device is already unlocked (whether the dialog opens immediately)."
     ],
     "meta": {
      "generated": "2026-10-04",
      "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-2024-34736": {
     "cve": "CVE-2024-34736",
     "summary": "StagefrightRecorder::setupVideoEncoder now forces zero B-layers (bLayers = 0) in the temporal-layering \"ts-schema\" when the audio source is AUDIO_SOURCE_MIC and the video source is VIDEO_SOURCE_SURFACE, which disables B-frame layering for the screen-recorder-with-microphone use case.",
     "component": "platform/frameworks/av, media/libmediaplayerservice (StagefrightRecorder, MediaRecorder video encoder setup)",
     "weakness": "unknown",
     "root_cause": "In media/libmediaplayerservice/StagefrightRecorder.cpp, setupVideoEncoder() works out the number of temporal layers (tsLayers) from the expected playback frame rate. When tsLayers > 1 it always requests up to two B-layers (bLayers = min(2, tsLayers - 1)) through the \"ts-schema\" format key \"android.generic.<pLayers>+<bLayers>\", and it sets \"android._prefer-b-frames\". The commit message says that screen recording (VIDEO_SOURCE_SURFACE) with microphone audio (AUDIO_SOURCE_MIC) does not play with audio and video in sync when B-frames are enabled. The material does not show how this maps to the bulletin's \"ID\" (information disclosure) classification.",
     "fix_analysis": [
      "media/libmediaplayerservice/StagefrightRecorder.cpp:StagefrightRecorder::setupVideoEncoder(): the fix adds `if (mAudioSource == AUDIO_SOURCE_MIC && mVideoSource == VIDEO_SOURCE_SURFACE) { bLayers = 0; }` inside the existing `if (tsLayers > 1)` block, right after `bLayers = std::min(2u, tsLayers - 1)`. For that use case pLayers becomes tsLayers and the ts-schema string becomes `android.generic.<tsLayers>+0`.",
      "The change carries a TODO (b/341121900) that describes it as a temporary workaround, to be removed once B frames are handled correctly in the screen recorder mic-only case.",
      "Single-commit fix: five added lines, no other files touched."
     ],
     "completeness": [
      "Only the exact combination mAudioSource == AUDIO_SOURCE_MIC && mVideoSource == VIDEO_SOURCE_SURFACE is affected. The commit message says INTERNAL (device) or MIC_AND_INTERNAL audio with screen recording keeps B-frame support on purpose.",
      "The `android._prefer-b-frames` key is still set from preferBFrames as before. Only the B-layer count in ts-schema is zeroed for the targeted case.",
      "Other combinations of audio and video source are unchanged and still get up to two B-layers when tsLayers > 1.",
      "The commit is explicitly a workaround (TODO to remove). It does not fix the underlying B-frame handling in the screen-recorder path."
     ],
     "behavior_changes": [
      "For recordings with audio source MIC and video source SURFACE, the encoder is configured with ts-schema android.generic.N+0 (no B-layers) instead of android.generic.(N-b)+b.",
      "No new error codes or API behavior changes are visible in the diff. This is purely an encoder configuration change."
     ],
     "preconditions": [
      "The code path is reached when a MediaRecorder recording with video is set up and StagefrightRecorder::setupVideoEncoder() runs. Per index search, the JNI MediaRecorder bindings in frameworks/base are a client of this recorder, but the exact call path is not shown.",
      "The temporal-layering block runs only when tsLayers > 1. That depends on the computed max playback frame rate compared with maxBaseLayerFps (ro.media.recorder-max-base-layer-fps, or the default derived from kMinTypicalDisplayRefreshingRate).",
      "The new branch triggers only when mAudioSource == AUDIO_SOURCE_MIC and mVideoSource == VIDEO_SOURCE_SURFACE (screen recording with microphone)."
     ],
     "per_major": {
      "14": "same fix: cherry-picked as 6cfd048292b2 into android-security-14.0.0_r11 (bug 288549440). All 5 patched lines are present at android-security-14.0.0_r29.",
      "15": "not affected (not listed by the bulletin). The patched lines are present at android-security-15.0.0_r17.",
      "16": "not affected (not listed by the bulletin). The patched lines are present at android-security-16.0.0_r8.",
      "17": "not affected (not listed by the bulletin). The patched lines are present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "This is a self-contained 5-line insertion inside the existing `if (tsLayers > 1)` block of setupVideoEncoder, and it uses the mAudioSource and mVideoSource members. The material does not show the 12, 12L or 13 code, so applicability there needs to be checked."
     ],
     "confidence": "medium",
     "unknowns": [
      "How the A/V desync with B-frames amounts to the bulletin's High-severity information disclosure. The diff and commit message describe only a sync problem.",
      "Whether the underlying B-frame issue referenced by TODO b/341121900 was later fixed and this workaround removed on any branch. The patched lines are still present through android-security-17.0.0_r1.",
      "Whether matching changes were made on the encoder or MediaCodecSource side. Only this one commit is provided.",
      "Whether the encoder emits no B-frames at all given that android._prefer-b-frames is still set.",
      "Whether the patch applies cleanly to Android 12, 12L and 13 trees."
     ],
     "meta": {
      "generated": "2026-10-04",
      "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-2024-34737": {
     "cve": "CVE-2024-34737",
     "summary": "Adds a CountQuotaTracker to ActivityClientController so that an app may change the PiP aspect ratio via setPictureInPictureParams/enterPictureInPictureMode at most 60 times per minute; excess requests throw IllegalStateException.",
     "component": "platform/frameworks/base, WindowManager / ActivityTaskManager (ActivityClientController, Picture-in-Picture)",
     "weakness": "Missing rate limiting (uncontrolled resource consumption through an unthrottled app-facing binder API)",
     "root_cause": "ActivityClientController.setPictureInPictureParams and enterPictureInPictureMode accepted PictureInPictureParams aspect ratio changes from apps without any frequency limit. Per the commit message, an app could flood PiP resizing requests this way and freeze the PiP window. Per index search, ActivityRecord.setPictureInPictureParams copies params and calls getTask().getRootTask().onPictureInPictureParamsChanged(); the material does not show the controller-to-ActivityRecord path.",
     "fix_analysis": [
      "services/core/java/com/android/server/wm/ActivityClientController.java: adds field mSetPipAspectRatioQuotaTracker (CountQuotaTracker, @VisibleForTesting) with constants SET_PIP_ASPECT_RATIO_LIMIT = 60 and SET_PIP_ASPECT_RATIO_TIME_WINDOW_MS = 60_000 (comment notes the window cannot be smaller than QuotaTracker#MIN_WINDOW_SIZE_MS).",
      "ActivityClientController.ensureSetPipAspectRatioQuotaTracker(): new helper that lazily constructs the CountQuotaTracker with Categorizer.SINGLE_CATEGORIZER and sets the count limit for Category.SINGLE_CATEGORY. It is invoked before entering synchronized (mGlobalLock) because the QuotaTracker constructor uses the AM lock (deadlock avoidance, per code comment and commit message).",
      "ActivityClientController.enterPictureInPictureMode and ActivityClientController.setPictureInPictureParams: both call ensureSetPipAspectRatioQuotaTracker() after Binder.clearCallingIdentity() and before acquiring mGlobalLock.",
      "ActivityClientController.ensureValidPictureInPictureActivityParams(): after the 'activity supports PiP' check and before the min/max aspect ratio validation, if r.pictureInPictureArgs.hasSetAspectRatio() && params.hasSetAspectRatio() && the two aspect ratios differ, calls mSetPipAspectRatioQuotaTracker.noteEvent(userId, r.packageName, \"setPipAspectRatio\"); when noteEvent returns false it throws IllegalStateException(caller + \": Too many PiP aspect ratio change requests from \" + r.packageName), aborting the request.",
      "services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java: testChangePipParams disables the tracker via setEnabled(false) when non-null, because the quota check causes an NPE in the test setup."
     ],
     "completeness": [
      "Covers both binder entry points shown calling ensureValidPictureInPictureActivityParams: enterPictureInPictureMode and setPictureInPictureParams.",
      "Only aspect ratio changes are counted; requests that change other PictureInPictureParams fields are not counted by the quota.",
      "The first aspect ratio set (when r.pictureInPictureArgs has no aspect ratio yet) and repeated requests with an identical aspect ratio are not counted.",
      "Lazy initialization of mSetPipAspectRatioQuotaTracker is an unsynchronized null check on a plain field; concurrent first calls may construct two trackers.",
      "Other paths that supply PictureInPictureParams (e.g. launch-into-PiP via ActivityOptions.makeLaunchIntoPip seen in ApiDemos per index search) are not shown in the material to pass through this check."
     ],
     "behavior_changes": [
      "An app that changes the PiP aspect ratio more than 60 times within a 60 second window now gets an IllegalStateException from setPictureInPictureParams / enterPictureInPictureMode, where previously the request was accepted.",
      "A CountQuotaTracker instance is created on the first enterPictureInPictureMode/setPictureInPictureParams call, outside the WM lock.",
      "Legitimate apps changing aspect ratio more than 60 times per minute will hit the limit."
     ],
     "preconditions": [
      "Device supports PiP (Activity.enterPictureInPictureMode / setPictureInPictureParams return early otherwise, per index search of Activity.java).",
      "Caller's activity passes ensureValidPictureInPictureActivityParams (activity supports picture-in-picture); reachable from apps via Activity -> ActivityClient -> IActivityClientController per index search.",
      "Repeated requests carrying a different aspect ratio than the one already stored in ActivityRecord.pictureInPictureArgs."
     ],
     "per_major": {
      "14": "Same fix: commit 8b473b3f7964 (cherry-picked from 8d814cc3b2fc, Change-Id Icb7dd17bbf7df573a9bb28f3dc56e90e78384f4f) in android-security-14.0.0_r11; at android-security-14.0.0_r29 the patched region is fully present (8/8 lines).",
      "15": "Not affected (not listed by the bulletin); the patched region is present at android-security-15.0.0_r17 (8/8 lines).",
      "16": "Not affected (not listed by the bulletin); 7/8 lines of the patched region present at android-security-16.0.0_r8.",
      "17": "Not affected (not listed by the bulletin); 7/8 lines of the patched region present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Requires com.android.server.utils.quota.CountQuotaTracker, Categorizer and Category in services; keep the tracker construction outside mGlobalLock (QuotaTracker ctor uses the AM lock) and keep the time window at or above QuotaTracker#MIN_WINDOW_SIZE_MS. Bulletin lists 12, 12L and 13 as affected but their fix commits are not in the material.",
      "wmtests that change the aspect ratio via setPictureInPictureParams may need the tracker disabled (setEnabled(false)) as done in WindowOrganizerTests.testChangePipParams, since the quota check causes an NPE in that test setup."
     ],
     "confidence": "high",
     "unknowns": [
      "Fix commits for Android 12, 12L and 13 are not in the material.",
      "Whether ensureValidPictureInPictureActivityParams has callers other than the two shown entry points is not shown.",
      "Which user ID UserHandle.getCallingUserId() yields there, since it runs after Binder.clearCallingIdentity(), and therefore how the quota is keyed across users, is not shown.",
      "The controller code after validation (how params reach ActivityRecord and the PiP organizer) and the exact resize/freeze mechanism are not shown beyond the commit message.",
      "Which line of the patched region differs in Android 16 and 17 is not shown."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 9,
      "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-2024-34738": {
     "cve": "CVE-2024-34738",
     "summary": "AppOpsService now filters restricted-read app ops out of collectOps() results unless the caller holds GET_APP_OPS_STATS, and verifyIncomingOp() accepts any of MANAGE_APPOPS, GET_APP_OPS_STATS or MANAGE_APP_OPS_MODES instead of only MANAGE_APPOPS for restricted ops.",
     "component": "platform/frameworks/base, AppOps (services/core/java/com/android/server/appop/AppOpsService.java)",
     "weakness": "Missing authorization check (restricted-read app op state returned to callers without the required privileged permission)",
     "root_cause": "Ops flagged restrictRead (AppOpsManager.opRestrictsRead) were checked in verifyIncomingOp(), which enforced MANAGE_APPOPS for a restricted op. The result builder collectOps(Ops pkgOps, int[] ops) did no permission check at all. When ops == null it added every Op of the package, and when an ops array was given it added every matching Op. So restricted-read op entries could appear in the results it built regardless of the caller's permissions. Separately, verifyIncomingOp only accepted MANAGE_APPOPS and rejected other privileged appops permission holders.",
     "fix_analysis": [
      "AppOpsService.java:collectOps: computes shouldReturnRestrictedAppOps = mContext.checkPermission(GET_APP_OPS_STATS, Binder.getCallingPid(), Binder.getCallingUid()) == PERMISSION_GRANTED once per call.",
      "AppOpsService.java:collectOps (ops == null branch): skips any Op where opRestrictsRead(curOp.op) is true and the caller lacks GET_APP_OPS_STATS, before getOpEntryForResult is called.",
      "AppOpsService.java:collectOps (explicit ops[] branch): applies the same skip to each non-null Op found in pkgOps, before resOps is allocated or appended.",
      "AppOpsService.java:verifyIncomingOp: for opRestrictsRead(op), replaces enforcePermission(MANAGE_APPOPS) with a check that the caller holds at least one of MANAGE_APPOPS, GET_APP_OPS_STATS or MANAGE_APP_OPS_MODES. Otherwise it throws a SecurityException listing the three permissions.",
      "AppOpInfo.java (restrictRead javadoc) and AppOpsManager.java:opRestrictsRead javadoc: comment-only changes from 'manage appops permission' to 'privileged appops permission'."
     ],
     "completeness": [
      "Covers both branches of collectOps (all ops and explicit op list), so every result path that goes through collectOps filters restricted ops for callers without GET_APP_OPS_STATS.",
      "The two checks are not symmetric. The collectOps filter keys only on GET_APP_OPS_STATS, while verifyIncomingOp also accepts MANAGE_APPOPS or MANAGE_APP_OPS_MODES. A caller holding only MANAGE_APPOPS or MANAGE_APP_OPS_MODES passes verifyIncomingOp for a restricted op but still has that op filtered out of collectOps results.",
      "The commit message mentions READ and WRITE access issues, but the diff only changes read-side paths (collectOps, verifyIncomingOp). No write/set path is modified in this commit.",
      "The material does not show the callers of collectOps or any other code paths that build OpEntry results for restricted ops, so coverage of those paths cannot be judged."
     ],
     "behavior_changes": [
      "Callers without GET_APP_OPS_STATS no longer see restricted-read ops in results built by collectOps. Such entries are silently left out instead of causing an error.",
      "verifyIncomingOp becomes more permissive for restricted ops: holders of GET_APP_OPS_STATS or MANAGE_APP_OPS_MODES are accepted in addition to MANAGE_APPOPS.",
      "The SecurityException message from verifyIncomingOp changes to list the three accepted permissions.",
      "Callers holding only MANAGE_APPOPS (without GET_APP_OPS_STATS) now get restricted ops filtered out of collectOps results, where previously those ops were returned."
     ],
     "preconditions": [
      "Caller can invoke an AppOpsService Binder entry point that builds results via collectOps (which entry points do this is not shown in the material).",
      "Caller lacks GET_APP_OPS_STATS.",
      "Target package has state for at least one op whose AppOpInfo.restrictRead is true."
     ],
     "per_major": {
      "14": "same fix: commit 21d764807b3d in android-security-14.0.0_r11 (cherry-pick of e31c33ea3586). At android-security-14.0.0_r29 the collectOps filter is present, with an additional NUM_ATTRIBUTED_OP_ENTRY_THRESHOLD limit interleaved (6/8 patched lines present).",
      "15": "not affected (not listed by the bulletin); at android-security-15.0.0_r17, 5/8 lines of the patched region are present.",
      "16": "not affected (not listed by the bulletin); at android-security-16.0.0_r8, 5/8 lines of the patched region are present.",
      "17": "not affected (not listed by the bulletin); at android-security-17.0.0_r1, 5/8 lines of the patched region are present."
     },
     "backport_notes": [
      "Single commit. The Java-side changes use Manifest.permission.GET_APP_OPS_STATS, MANAGE_APP_OPS_MODES and AppOpsManager.opRestrictsRead. On a 14 branch that has the NUM_ATTRIBUTED_OP_ENTRY_THRESHOLD logic in collectOps, place the restricted-op skip before the threshold check, as in android-security-14.0.0_r29.",
      "Test named in the commit: atest AppOpsTest#testRestrictedSettingsOpsRead (test source not included in this diff)."
     ],
     "confidence": "high",
     "unknowns": [
      "Which Binder entry points call collectOps, and whether they call verifyIncomingOp first (not shown in the material).",
      "What the 'WRITE operation access' part of the commit message refers to. No write-path change appears in this diff, so whether a companion commit exists is unknown.",
      "Which specific ops have restrictRead set in this release.",
      "Whether the Android 13 fix (13 is listed as affected by the bulletin) is identical, and whether the dependencies exist on 13. No 13 commit is in the material."
     ],
     "meta": {
      "generated": "2026-10-04",
      "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-2024-34740": {
     "cve": "CVE-2024-34740",
     "summary": "BinaryXmlSerializer.attributeBytesHex and attributeBytesBase64 now throw IOException when the byte array is longer than 65535 (MAX_UNSIGNED_SHORT) instead of writing a truncated 16-bit length followed by the full payload; a later commit linked by the same bug id caps the checksum signature in ApkChecksums.verifySignature at 35 * 1024 bytes.",
     "component": "platform/frameworks/libs/modules-utils (BinaryXmlSerializer), platform/frameworks/base (BinaryXmlTest, services/core pm ApkChecksums / PackageInstallerSession)",
     "weakness": "Missing bounds check leading to integer truncation of a length field (byte[] length written with writeShort)",
     "root_cause": "In java/com/android/modules/utils/BinaryXmlSerializer.java, attributeBytesHex() and attributeBytesBase64() emitted the attribute as: type byte, interned name, then mOut.writeShort(value.length) followed by mOut.write(value). The length was never validated against the 16-bit field, so a byte[] longer than 65535 produced a length prefix that did not match the number of bytes actually written. The commit message (\"avoid Integer overflow\") and the diff show the missing check; the bulletin rates the issue High/EoP.",
     "fix_analysis": [
      "modules-utils 700c28908051, BinaryXmlSerializer.java:attributeBytesHex and attributeBytesBase64: imports FastDataOutput.MAX_UNSIGNED_SHORT and, after writing the type byte and the interned name but before writeShort(value.length), throws IOException(\"...input size (N) exceeds maximum allowed size (65535)\") when value.length > MAX_UNSIGNED_SHORT, so the written length prefix always matches the payload length.",
      "frameworks/base e8b6505647be, core/tests/coretests/src/android/util/BinaryXmlTest.java: adds testAttributeBytes_BinaryDataOverflow (65536 bytes must throw IOException for both methods) and testAttributeBytesHex_MaximumBinaryData / testAttributeBytesBase64_MaximumBinaryData (exactly 65535 bytes must succeed). Test-only; depends on the modules-utils change.",
      "frameworks/base 716a1c65c273 (android-security-14.0.0_r28, also Bug 480126173), services/core/java/com/android/server/pm/ApkChecksums.java:verifySignature: adds MAX_SIGNATURE_SIZE_BYTES = 35 * 1024 and throws SignatureException(\"Invalid signature\") when signature is null or longer than that, before the checksums blob is built. PackageInstallerSession.java:setChecksums only changes the IllegalArgumentException text to include e.getMessage()."
     ],
     "completeness": [
      "The check covers both byte[] attribute writers in BinaryXmlSerializer (attributeBytesHex, attributeBytesBase64), the only two writeShort(value.length) sites shown in the diff.",
      "The check is placed after mOut.writeByte(ATTRIBUTE | TYPE_...) and mOut.writeInternedUTF(name) have already been emitted, so when it throws, a partial attribute header (type byte plus name, no length/data) remains in the output stream.",
      "The fix rejects oversized input rather than widening the length field; no wire format or parser-side change is in the material.",
      "Other attribute writers (attribute(), writeInternedUTF/writeUTF paths) are not touched by this commit; whether FastDataOutput enforces its own limit there is not shown in the material.",
      "The ApkChecksums.verifySignature cap applies to verifySignature callers such as setChecksums; it was added in a later security tag (r28) than the serializer fix (r11)."
     ],
     "behavior_changes": [
      "BinaryXmlSerializer.attributeBytesHex / attributeBytesBase64 now throw IOException for arrays longer than 65535 bytes (previously wrote a truncated length).",
      "ApkChecksums.verifySignature now throws SignatureException(\"Invalid signature\") for a null signature or one longer than 35 * 1024 bytes; PackageInstallerSession.setChecksums surfaces an oversized signature as IllegalArgumentException(\"Can't verify signature: Invalid signature\").",
      "No change to the binary XML wire format or reader is shown."
     ],
     "preconditions": [
      "A caller must pass a byte[] longer than 65535 bytes to attributeBytesHex or attributeBytesBase64 on a binary serializer (Xml.newBinarySerializer() / TypedXmlSerializer).",
      "For the ApkChecksums path: PackageInstallerSession.setChecksums is a Binder entry point gated by appOps.checkPackage against the installer package and assertCallerIsOwnerOrRoot, and accepts a caller-controlled byte[] signature stored in PerFileChecksum; where that signature is later serialized is not shown."
     ],
     "per_major": {
      "14": "same fix: modules-utils 700c28908051 and base test e8b6505647be landed in android-security-14.0.0_r11; ApkChecksums hardening 716a1c65c273 landed in android-security-14.0.0_r28; at r29 the patched region is fully present (8/8 lines).",
      "15": "not affected per the bulletin (not listed); the patched region is present (8/8 lines) at android-security-15.0.0_r17.",
      "16": "not affected per the bulletin (not listed); the patched region is present (8/8 lines) at android-security-16.0.0_r8.",
      "17": "not affected per the bulletin (not listed); the patched region is present (8/8 lines) at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Apply modules-utils 700c28908051 first (the functional fix; it requires FastDataOutput.MAX_UNSIGNED_SHORT to exist in the target branch), then the base test commit; the ApkChecksums/PackageInstallerSession commit has no code dependency on the serializer change in the diffs but is linked by the same bug id. frameworks/libs/modules-utils is a static Java library compiled into the framework and mainline modules, so consumers must be rebuilt to pick up the change (general platform knowledge)."
     ],
     "confidence": "medium",
     "unknowns": [
      "Which production caller passes attacker-influenced byte[] data to attributeBytesHex/attributeBytesBase64 and how a mismatched length leads to the EoP rated by the bulletin.",
      "Whether the ApkChecksums signature is ever written via BinaryXmlSerializer, and why that commit shares the bug id.",
      "Whether FastDataOutput.writeUTF / writeInternedUTF already bound string lengths (only the MAX_UNSIGNED_SHORT constant is shown).",
      "Why 35 * 1024 was chosen as MAX_SIGNATURE_SIZE_BYTES beyond the comment calling it arbitrary."
     ],
     "meta": {
      "generated": "2026-10-04",
      "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-2024-34741": {
     "cve": "CVE-2024-34741",
     "summary": "WindowState.setForceHideNonSystemOverlayWindowIfNeeded now classifies a window by getBaseType() instead of mAttrs.type. Per the commit title 'Hide SAW subwindows', this means subwindows of system-alert-window (SAW) or toast parents are also force-hidden when a top window hides overlays through Window#setHideOverlayWindows.",
     "component": "platform/frameworks/base, WindowManager (services/core/java/com/android/server/wm/WindowState.java)",
     "weakness": "Incorrect attribute used in a policy check: the window's own type was used instead of its base type, so subwindows bypassed the hide-overlay-windows policy",
     "root_cause": "setForceHideNonSystemOverlayWindowIfNeeded decided whether the 'hide non-system overlay windows' policy applies to a window by testing mAttrs.type against isSystemAlertWindowType() and TYPE_TOAST. A subwindow attached to a SAW parent has its own subwindow type, so the early return fired and the subwindow was not hidden. The TYPE_APPLICATION_OVERLAY system-overlay exemption was also evaluated on mAttrs.type. Per the commit message, SAW subwindows could therefore stay shown while the top window had overlays hidden through Window#setHideOverlayWindows.",
     "fix_analysis": [
      "services/core/java/com/android/server/wm/WindowState.java:setForceHideNonSystemOverlayWindowIfNeeded: adds `final int baseType = getBaseType();` and uses baseType in the first early-return check (`!isSystemAlertWindowType(baseType) && baseType != TYPE_TOAST`).",
      "Same function: the system-application-overlay exemption (`baseType == TYPE_APPLICATION_OVERLAY && mAttrs.isSystemApplicationOverlay() && mSession.mCanCreateSystemApplicationOverlay`) is now also evaluated on baseType.",
      "The rest of the function is unchanged: when the force-hide state changes, it calls hide(true, true) or show(true, true). Per index search, WindowManagerService.updateNonSystemOverlayWindowsVisibilityIfNeeded calls this function for every window through mRoot.forAllWindows, so the subwindows affected by the change are now hidden and shown in the same pass."
     ],
     "completeness": [
      "The fix covers the classification point used by the hide-overlay-windows mechanism (setForceHideNonSystemOverlayWindowIfNeeded). The mSession.mCanAddInternalSystemWindow bypass is unchanged.",
      "The sibling function setHiddenWhileSuspended in the same file already uses getBaseType() in the r29 context, so the suspended-app path is consistent with this fix.",
      "No other callers or policy checks were modified in this commit.",
      "This is a single-commit fix. The referenced test is CtsWindowManagerDeviceWindow:HideOverlayWindowsTest."
     ],
     "behavior_changes": [
      "Windows whose base type is a system alert window type or TYPE_TOAST, owned by a session without mCanAddInternalSystemWindow, are now hidden (hide(true, true)) while any window with hideNonSystemOverlayWindowsWhenVisible() is shown. They are shown again when that state clears. This now includes such subwindows.",
      "The system application overlay exemption is now evaluated on the base type, so it also applies to such subwindows.",
      "No new error codes or API changes. This is a visibility policy change inside WindowManagerService."
     ],
     "preconditions": [
      "A window with SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS (set via Window#setHideOverlayWindows) becomes visible. WindowManagerService.updateNonSystemOverlayWindowsVisibilityIfNeeded then walks all windows and calls setForceHideNonSystemOverlayWindowIfNeeded (per index search).",
      "A SAW-type or toast parent window exists from a session without mCanAddInternalSystemWindow, and it has an attached subwindow.",
      "Per index search, a Settings test verifies that HideNonSystemOverlayMixin adds SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS on start. This makes it one in-platform user of the mechanism."
     ],
     "per_major": {
      "14": "Same fix: commit abfaf702ef83 in android-security-14.0.0_r11 (cherry-pick of c37bc9147086). At android-security-14.0.0_r29 the function uses baseType for both checks.",
      "15": "Not affected per the bulletin. At android-security-15.0.0_r17, 3/5 lines of the patched region are present, the same ratio as 14 r29. This is consistent with the fix being present.",
      "16": "Not affected per the bulletin. At android-security-16.0.0_r8, 3/5 lines of the patched region are present, consistent with the fix being present.",
      "17": "Not affected per the bulletin. At android-security-17.0.0_r1, 3/5 lines of the patched region are present, consistent with the fix being present."
     },
     "backport_notes": [
      "A self-contained 3-line change in WindowState.setForceHideNonSystemOverlayWindowIfNeeded. It replaces mAttrs.type with getBaseType() in the two type checks and depends on nothing that the pre-fix code does not already reference."
     ],
     "confidence": "high",
     "unknowns": [
      "The commit identifiers and code shape for Android 12, 12L and 13 (listed as affected) are not in the material.",
      "The actual code at the 15/16/17 tags is not shown. Only the 3/5 line-match measurement is given.",
      "The implementation of getBaseType() is not shown in the material."
     ],
     "meta": {
      "generated": "2026-10-04",
      "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-2024-34742": {
     "cve": "CVE-2024-34742",
     "summary": "Makes DeviceOwnerReadWriter.shouldWrite() in OwnersData always return true, so the device owner persistence file (device_owners2.xml) is always written. Before, it was written only when a device owner, system update policy or system update info was set.",
     "component": "platform/frameworks/base, services/devicepolicy (device policy owner state persistence, OwnersData)",
     "weakness": "Incomplete persistence condition: shouldWrite() did not cover all the state that writeInner() serializes, so persisted device policy state could be lost. The bulletin classifies it as DoS.",
     "root_cause": "In services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java, DeviceOwnerReadWriter.shouldWrite() returned true only if mDeviceOwner, mSystemUpdatePolicy or mSystemUpdateInfo was non-null. writeInner() also serializes other state. mDeviceOwnerTypes (TAG_DEVICE_OWNER_TYPE entries) is visible, and there is more content after line 385 that the material does not show. If the three checked fields were all null while other state existed, shouldWrite() returned false and the file was not written, so that state was not persisted. The commit was tested by upgrading from T-QPR3 (\"Test: Manual, upgrading from T-QPR3\").",
     "fix_analysis": [
      "OwnersData.java:DeviceOwnerReadWriter.shouldWrite(): the three-field null check is replaced with `return true;`. The device owner file is now always written, whichever fields are populated.",
      "writeInner() and the read path are unchanged. What gets written is the same; only the decision whether to write changes."
     ],
     "completeness": [
      "Because the condition is now unconditional, the fix covers every field writeInner() serializes for the device owner file, not just mDeviceOwnerTypes.",
      "Only DeviceOwnerReadWriter is changed. The material shows neither the sibling profile owner read/writer nor what the FileReadWriter base class does when shouldWrite() returns false, so it cannot show whether a similar condition exists elsewhere."
     ],
     "behavior_changes": [
      "device_owners2.xml is now written on every device owner write, including when there is no device owner, system update policy or system update info. In that case it holds whatever writeInner() produces for the populated fields, e.g. device owner types.",
      "Possibly more disk writes in the device policy service. The diff changes no API and no error codes."
     ],
     "preconditions": [
      "OwnersData's DeviceOwnerReadWriter persists owner state while mDeviceOwner, mSystemUpdatePolicy and mSystemUpdateInfo are all null and other serialized state (e.g. mDeviceOwnerTypes) is present.",
      "The commit was tested manually by upgrading from T-QPR3."
     ],
     "per_major": {
      "14": "Same fix: commit 688e5c3012eb in android-security-14.0.0_r11 (cherry-pick of internal 3abc0742, Change-Id I7a7dba56). At android-security-14.0.0_r29 the code shows `return true;` in shouldWrite() (1/3 lines of the patched region).",
      "15": "Not affected per the bulletin. android-security-15.0.0_r17 has 2/3 lines of the patched region; the material does not explain this.",
      "16": "Not affected per the bulletin. android-security-16.0.0_r8 has 1/3 lines of the patched region; the code at this tag is not shown.",
      "17": "Not affected per the bulletin. android-security-17.0.0_r1 has 1/3 lines of the patched region; the code at this tag is not shown."
     },
     "backport_notes": [
      "A single one-line change with no dependencies: in OwnersData.java, make DeviceOwnerReadWriter.shouldWrite() return true."
     ],
     "confidence": "medium",
     "unknowns": [
      "The material does not show the exact user-visible DoS effect, i.e. what fails when the device owner file is not written.",
      "The material does not show what the FileReadWriter base class does when shouldWrite() returns false (skip the write or delete the existing file).",
      "The material does not explain why android-security-15.0.0_r17 has 2/3 lines of the patched region while 14, 16 and 17 have 1/3, or how the 15/16/17 code came to its current form.",
      "The material does not show whether the profile owner counterpart has a similar condition."
     ],
     "meta": {
      "generated": "2026-10-04",
      "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-2024-34743": {
     "cve": "CVE-2024-34743",
     "summary": "Changes the sanitization loop in SurfaceFlinger::setTransactionState to iterate ComposerState entries by reference (auto&) instead of by value, so layer_state_t::sanitize(permissions) actually strips privileged fields from the states that are later applied.",
     "component": "platform/frameworks/native, SurfaceFlinger (services/surfaceflinger)",
     "weakness": "Ineffective permission enforcement: sanitization applied to a copy of the data (range-for by value), leaving the real transaction state unsanitized (missing permission check in effect)",
     "root_cause": "In services/surfaceflinger/SurfaceFlinger.cpp, SurfaceFlinger::setTransactionState computes the caller's permissions via LayerStatePermissions::getTransactionPermissions(originPid, originUid) and then loops `for (auto composerState : states) { composerState.state.sanitize(permissions); }`. Because the loop variable is declared `auto` (by value), each iteration operates on a copy of the ComposerState. sanitize() cleared privileged fields on the copy, which was then discarded. The original entries in `states` stayed unsanitized, so permission-gated layer state from an unprivileged caller was not removed. The trusted-overlay flag is the example exercised in the test.",
     "fix_analysis": [
      "services/surfaceflinger/SurfaceFlinger.cpp:SurfaceFlinger::setTransactionState: the loop is changed to `for (auto& composerState : states)`, so composerState.state.sanitize(permissions) mutates the actual elements of the `states` Vector. This one-line change is the only production code change.",
      "services/surfaceflinger/tests/Credentials_test.cpp:TEST_F(CredentialsTest, TransactionPermissionTest): the test is fixed so it actually exercises the path. Previously `Transaction().setTrustedOverlay(surfaceControl, true)` was built but never applied, and the waitForWindowInfosPredicate results were not asserted. Now the unprivileged attempt runs under `UIDFaker f{AID_BIN}` and calls `.apply(/*synchronous=*/true)`. The privileged attempt under AID_SYSTEM also applies synchronously. Both predicate waits are wrapped in ASSERT_TRUE, which verifies that the layer is not trusted after the unprivileged attempt and is trusted after the privileged one."
     ],
     "completeness": [
      "Covers the single ComposerState sanitization loop in setTransactionState. After the change, all entries in `states` are sanitized according to the caller's permissions, for every field that layer_state_t::sanitize handles (not only trusted overlay).",
      "The DisplayState loop and the inputWindowCommands / eEarlyWakeup permission checks in the same function are not touched by the diff. At android-security-14.0.0_r29 the display loop iterates by reference (`DisplayState& display`).",
      "The fix does not alter what layer_state_t::sanitize removes. If sanitize itself omits a privileged field, this change does not address that (not shown in the material).",
      "At android-security-14.0.0_r29 the code context shows the `auto&` form in place, confirming the fix persisted in the Android 14 security branch."
     ],
     "behavior_changes": [
      "Permission-gated layer state fields set by callers that lack the matching permission are now actually stripped before the transaction is applied. Such requests fail silently, with no new error code, consistent with the test comment 'This should fail silently'.",
      "Privileged callers (e.g. AID_SYSTEM in the test) are unaffected.",
      "CredentialsTest.TransactionPermissionTest now applies transactions synchronously and asserts the results, so it can fail where previously it was effectively a no-op."
     ],
     "preconditions": [
      "Caller can submit a SurfaceFlinger transaction (SurfaceFlinger::setTransactionState) containing ComposerState entries with permission-gated layer_state_t fields, while lacking the permission that LayerStatePermissions::getTransactionPermissions would grant for them.",
      "Per index search, setTransactionState is also wrapped by TestableSurfaceFlinger in services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h."
     ],
     "per_major": {
      "14": "same fix: commit 3f85323b27d9 in android-security-14.0.0_r11 (cherry-pick of 04e41761914c3c3aaca965103be3679b7a7af76f), a one-line `auto` -> `auto&` change plus a test fix. The code at android-security-14.0.0_r29 shows the `auto&` loop present.",
      "15": "not affected per the bulletin. 5/8 lines of the patched region present at android-security-15.0.0_r17. The loop form in this branch is not shown.",
      "16": "not affected per the bulletin. 5/8 lines of the patched region present at android-security-16.0.0_r8. The loop form in this branch is not shown.",
      "17": "not affected per the bulletin. 5/8 lines of the patched region present at android-security-17.0.0_r1. The loop form in this branch is not shown."
     },
     "backport_notes": [
      "Single self-contained commit. The production change is one token (`auto` -> `auto&`) in the ComposerState loop of SurfaceFlinger::setTransactionState: check that this loop's variable is a reference. The test changes depend on UIDFaker and WindowInfosListenerUtils being available in Credentials_test.cpp."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact set of fields cleared by layer_state_t::sanitize(permissions) and the LayerStatePermissions::getTransactionPermissions logic are not included in the material.",
      "Whether the Android 15/16/17 branches contain the `auto&` form is not shown textually. Android 14 r29, which has the fix, also shows only 5/8 lines.",
      "The production callers that reach setTransactionState are not shown in the material.",
      "Which specific privileged field(s) motivated bugs 336648041 and 336648613, beyond the trusted-overlay case exercised by the test."
     ],
     "meta": {
      "generated": "2026-10-04",
      "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."
     }
    }
   }
  },
  "15": {
   "counts": {
    "announced": 0,
    "certain": 0,
    "probable": 0,
    "not_published": 0,
    "not_covered": 0,
    "awaiting": 0
   },
   "advisories": [],
   "tags": [],
   "unannounced": [],
   "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": {}
  },
  "16": {
   "counts": {
    "announced": 0,
    "certain": 0,
    "probable": 0,
    "not_published": 0,
    "not_covered": 0,
    "awaiting": 0
   },
   "advisories": [],
   "tags": [],
   "unannounced": [],
   "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": {}
  },
  "17": {
   "counts": {
    "announced": 0,
    "certain": 0,
    "probable": 0,
    "not_published": 0,
    "not_covered": 0,
    "awaiting": 0
   },
   "advisories": [],
   "tags": [],
   "unannounced": [],
   "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": {}
  }
 },
 "bulletin": {
  "url": "https://source.android.com/docs/security/bulletin/2024-08-01",
  "latest_version": "1.1",
  "latest_revision": {
   "version": "1.1",
   "date": "October 24, 2024",
   "notes": "Updated CVE table"
  },
  "revisions": [
   {
    "version": "1.0",
    "date": "August 5, 2024",
    "notes": "Bulletin Published."
   },
   {
    "version": "1.1",
    "date": "October 24, 2024",
    "notes": "Updated CVE table"
   }
  ],
  "tracked_since": "2026-09-30",
  "changes_since_tracking": [],
  "out_of_scope_rows": {
   "Arm components": 2,
   "Imagination Technologies": 1,
   "Kernel": 1,
   "MediaTek components": 1,
   "Qualcomm closed-source components": 7,
   "Qualcomm components": 20
  },
  "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."
 }
}