CVE-2026-0020 AI-generated analysis
platform/frameworks/base, package manager manifest parsing (ParsedPermissionUtils, parsePermission / parsePermissionTree / parsePermissionGroup)
Package manifest parsing now trims leading/trailing whitespace from <permission>, <permission-tree> and <permission-group> names in ParsedPermissionUtils, so a declared name is stored in trimmed form rather than as written in the manifest.
Root cause
ParsedPermissionUtils.parsePermission, parsePermissionTree and parsePermissionGroup stored the android:name string from the manifest as-is, so a name with leading or trailing whitespace stayed on the ParsedPermissionImpl / ParsedPermissionGroupImpl object unchanged. The diff does not show which consumer mishandled such names. It only shows that the parser never normalized them.
How the fix works
- services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java:parsePermission (Android 14 path): after the knownCerts / restricted-flag handling and before PermissionInfo.fixProtectionLevel is applied, adds permission.setName(permission.getName().trim()). The protection-flag validation and parseAllMetaData later in the same function therefore see the trimmed name.
- ParsedPermissionUtils.java:parsePermissionTree: adds permission.setName(permission.getName().trim()). On Android 14 the trim comes after a block ending in '+ permission.getName());' (the 14 diff does not show that block's content) and immediately before setProtectionLevel(PROTECTION_NORMAL).setTree(true). On Android 15/16 it comes right after sa.recycle() and before the indexOf('.') name checks, so those checks run on the trimmed name.
- ParsedPermissionUtils.java:parsePermissionGroup: appends .setName(permissionGroup.getName().trim()) to the builder chain inside the try block (after setFlags), before the TypedArray is recycled.
- No new error is introduced: a padded name is trimmed silently, not rejected.
Completeness
- Covers the three declared-name paths in ParsedPermissionUtils: <permission>, <permission-tree> and <permission-group>.
- Only String.trim() is applied: leading/trailing whitespace is removed, while interior whitespace and other unusual characters are neither touched nor rejected.
- Placement of the permission-tree trim differs between majors. On 15/16 it comes before the indexOf('.') checks. On 14 it comes after the preceding check block. Because the 15/16 check tests 'index > 0', leading whitespace can change its result, so on 14 that check may run on the untrimmed name.
- The diff does not touch other manifest strings, such as the android:permissionGroup attribute on <permission>, <uses-permission> names or the knownCerts string. Whether those need the same treatment is not shown.
Behavior changes
- Permission, permission-tree and permission-group names declared with leading/trailing whitespace are now stored in trimmed form.
- No new parse error or rejection: the names are trimmed silently.
Per major
- Android 14: Adapted fix (d7a73fb8bfc2, android-security-14.0.0_r25; RESTRICT AUTOMERGE, Cherrypick-From 2c0bf3261ca5, Change-Id I673ad83d05c9825177967e4f0a960e8841610b71). Same three trim() calls, but in services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java, and the permission-tree trim is placed after the preceding check block instead of before the name checks. At android-security-14.0.0_r29 the resolver reports 7/8 lines of the patched region present (the 14 patch has 4 insertions versus 6 in 15/16). The trim in parsePermission is visible at line 147 in the r29 code.
- Android 15: Same fix (4fa32d4fef90, android-security-15.0.0_r13) in core/java/com/android/internal/pm/pkg/component/ParsedPermissionUtils.java. The permission-tree trim is placed before the indexOf('.') checks. 8/8 lines present at android-security-15.0.0_r17.
- Android 16: Same fix (e770e9f02341, android-security-16.0.0_r4), same content as the 15 patch at the core/java/com/android/internal/pm path with shifted line numbers. 8/8 lines present at android-security-16.0.0_r8.
- Android 17: Not affected per the bulletin (not listed). The resolver checked only the services/core/java path, which is absent at android-security-17.0.0_r1. On 15/16 the file lives under core/java/com/android/internal/pm/pkg/component/, so that absence alone does not show the patch state on 17.
Unknowns
- Which consumer of the permission or group name mishandled whitespace-padded names, and so the exact EoP mechanism.
- Whether other manifest-derived strings (e.g. the android:permissionGroup attribute on <permission>, <uses-permission> names) are trimmed elsewhere or need the same treatment.
- What the Android 14 check block before the permission-tree trim contains, why the 14 cherry-pick places the trim differently from 15/16, and what explains the 7/8 line match at android-security-14.0.0_r29.
- The patch state of ParsedPermissionUtils on Android 17 (only the 14 path was checked).
- Downstream effects of trimming (e.g. on duplicate or ownership handling), which the material does not show.