CVE-2025-26429 AI-generated analysis
platform/frameworks/base, services/core AppOps (com.android.server.appop.AppOpsService)
Adds a cap of about 2000 (NUM_ATTRIBUTED_OP_ENTRY_THRESHOLD) on the total number of attributed op entries that AppOpsService packs into the OpEntry list returned for IAppOpsService#getPackagesForOpsForDevice, so the reply is less likely to exceed the binder transaction limit.
Root cause
The helper in AppOpsService.java that builds the List<OpEntry> result loops over pkgOps or over the requested ops[] array, calling getOpEntryForResult(curOp). It added every OpEntry with no limit. Each OpEntry carries its attributed op entries (per attribution tag). Per the commit message, when an app uses many attribution tags across many ops, the PackageOps payload for IAppOpsService#getPackagesForOpsForDevice exceeds the binder transaction limit. The new constant's Javadoc says the cap is there to avoid TransactionTooLargeException.
How the fix works
- AppOpsService.java (class constants): adds private static final int NUM_ATTRIBUTED_OP_ENTRY_THRESHOLD = 2000, documented as the upper limit of attributed op entries returned in one binder transaction. Per the commit message, it was sized assuming each attribution tag is 50 bytes long.
- AppOpsService.java (result-building helper calling getOpEntryForResult): adds int totalAttributedOpEntryCount = 0 before the two loops. Both branches work the same way. Before building each entry the loop runs `if (totalAttributedOpEntryCount > NUM_ATTRIBUTED_OP_ENTRY_THRESHOLD) break;`. It then builds the OpEntry, adds it to resOps, and adds opEntry.getAttributedOpEntries().size() to the counter. The two branches are ops == null (all ops of the package) and ops != null (requested ops only).
- After both loops, if the counter is over the threshold the helper logs Slog.w(TAG, ...) saying the result is throttled and may be due to a DoS attack. It then returns resOps, which may be truncated. No exception is thrown and no new return code is added.
Completeness
- Both enumeration paths of the helper are bounded (all ops when ops == null, and the explicit ops[] list), and they share the same counter.
- The check runs before an OpEntry is added and uses a strict `>`. So the total can go past 2000 by the size of the last entry added, and a single OpEntry with many attributed entries is still added in full. The cap is enforced between ops, not inside one op's attributed entries.
- The cap counts entries; it does not measure parcel bytes. Per the commit message it assumes 50-byte attribution tags, so longer tags leave less margin.
- Only this helper is changed. The material does not show whether other IAppOpsService methods return attributed entries through a different code path.
- The fix does not limit how many attribution tags or attributed ops a caller can store. It only throttles the returned result.
Behavior changes
- Callers of getPackagesForOpsForDevice (and any other caller of the same helper) may get a truncated OpEntry list once the running attributed op entry count passes 2000. The remaining ops for that package are left out silently.
- A new Slog.w message with tag "AppOps" is logged when the threshold is exceeded.
- No API, error code, or permission change.
Per major
- Android 14: same fix: commit 22a375717e61 in android-security-14.0.0_r20 (cherry-pick, Change-Id I43cd4b9774dbe554edcec296c4b8a3d7fc60c85c). At android-security-14.0.0_r29 the full patched region (8/8 lines) is present.
- Android 15: adapted fix: commit 0f3c01c326b6 in android-security-15.0.0_r8. Same logic, but the helper calls getOpEntryForResult(curOp, persistentDeviceId) and the surrounding context differs. At android-security-15.0.0_r17, 8/8 lines are present.
- Android 16: not affected (not listed by the bulletin). The patched region is present (8/8 lines) at android-security-16.0.0_r8.
- Android 17: not affected (not listed by the bulletin). The patched region is present (8/8 lines) at android-security-17.0.0_r1.
Unknowns
- The diff hunks do not show the name of the patched helper method, or the full list of IAppOpsService entry points that call it.
- Whether untrusted apps can call getPackagesForOpsForDevice without a privileged permission is not shown.
- The material does not show which process receives the exception on the caller side.
- The Android 14 hunk does not show whether the ops[] branch there also has an opRestrictsRead check.