CVE-2026-28611 AI-generated analysis
platform/packages/apps/Nfc (Android 15) / platform/packages/modules/Nfc (Android 16), NfcService binder interface (INfcAdapter.Stub)
Adds a caller-UID-to-package-name verification (new NfcPermissions.checkPackage backed by AppOpsManager.checkPackage) at the start of the NfcAdapterService binder methods enable, disable and setObserveMode, so a caller can no longer pass an arbitrary package name into NFC authorization decisions.
Root cause
NfcAdapterService.enable(String pkg), disable(boolean, String pkg) and setObserveMode(boolean, String packageName) in src/com/android/nfc/NfcService.java take a package name from the binder caller and use it directly in authorization. enable and disable call isDeviceOrProfileOwner(Binder.getCallingUid(), pkg), which delegates to NfcPermissions.isDeviceOwner/isProfileOwner; isProfileOwner calls DevicePolicyManager.isProfileOwnerApp(packageName) (per the shown context). enable also compares pkg against R.array.nfc_allow_list. setObserveMode passes packageName to mCardEmulationManager.isPreferredServicePackageNameForUser and to wallet role comparisons (per index excerpt). Nothing checked that the supplied package actually belongs to the calling UID, so the string was trusted as the caller's identity.
How the fix works
- src/com/android/nfc/NfcPermissions.java: adds an AppOpsManager field, set in the constructor via mContext.getSystemService(AppOpsManager.class), and a new method checkPackage(int uid, String pkgName). The method throws SecurityException when pkgName is null and otherwise calls mAppOpsManager.checkPackage(uid, pkgName).
- src/com/android/nfc/NfcService.java: NfcAdapterService.enable(String pkg) now calls mNfcPermissions.checkPackage(Binder.getCallingUid(), pkg) as its first statement, before isDeviceOrProfileOwner and the admin permission check.
- src/com/android/nfc/NfcService.java: NfcAdapterService.disable(boolean saveState, String pkg) gets the same checkPackage call as its first statement.
- src/com/android/nfc/NfcService.java: NfcAdapterService.setObserveMode(boolean enable, String packageName) gets the same checkPackage call as its first statement, before the isNfcEnabled check.
- tests/unit/src/com/android/nfc/NfcServiceTest.java: setUp mocks mPackageManager.getPackageUid(PKG_NAME, 0) to return Binder.getCallingUid(), and testSetObserveMode_nfcDisabled now passes PKG_NAME instead of null.
- Android 16 commit ebbca6f8125e (packages/modules/Nfc): removes the aconfig flag check_passed_in_package and makes the checkPackage calls unconditional in enable, disable, setObserveMode, updateDiscoveryTechnology, setReaderMode and indicateDataMigration in NfcNci/src/com/android/nfc/NfcService.java. The test gains an AppOpsManager mock.
Completeness
- On Android 15 the check covers exactly three binder methods: enable, disable and setObserveMode. The Android 16 version of the change covers six methods (adding updateDiscoveryTechnology, setReaderMode and indicateDataMigration). The Android 15 material does not show whether those three extra methods exist with a package-name parameter in the 15 tree.
- The check comes before any other logic in each method, so it also applies to privileged callers (SYSTEM_UID, NFC_UID, ROOT_UID). The material shows no bypass for them.
- A null package in setObserveMode, which before was only logged for non-privileged callers (per the index excerpt), now causes a SecurityException.
- The fix relies on AppOpsManager.checkPackage semantics, so the correctness of the UID-to-package binding itself is left to the platform.
Behavior changes
- enable, disable and setObserveMode now throw SecurityException, before any other processing, when the supplied package name is null or does not belong to the calling UID.
- setObserveMode with a null package now throws SecurityException before the isNfcEnabled check. The unit test that passed null with NFC disabled (and expected false) now passes PKG_NAME.
- NfcPermissions now gets AppOpsManager from the Context in its constructor, and checkPackage depends on it. The diff adds no null check.
Per major
- Android 14: Not affected per the bulletin. The resolver reports 7/8 lines of the patched region present at android-security-14.0.0_r29. The material does not show the 14 code, so it cannot confirm whether the checkPackage calls are there.
- Android 15: Same fix: platform/packages/apps/Nfc d914feee6a9b in android-security-15.0.0_r17 adds unconditional checkPackage calls in enable, disable and setObserveMode (8/8 lines present). The AOSP android-15.0.0_r36 tree shows the same calls guarded by Flags.checkPassedInPackage() (per index search), so the security branch carries the unflagged form.
- Android 16: Adapted fix: platform/packages/modules/Nfc ebbca6f8125e in android-security-16.0.0_r8 is an aconfig flag cleanup. It makes the existing, previously flag-guarded checkPackage calls unconditional in six methods (enable, disable, setObserveMode, updateDiscoveryTechnology, setReaderMode, indicateDataMigration) in NfcNci/src/com/android/nfc/NfcService.java. 5/8 lines of the patched region present.
- Android 17: Not affected: not listed by the bulletin. The project is not present in this major's security tags.
Unknowns
- Whether updateDiscoveryTechnology, setReaderMode and indicateDataMigration exist with a package-name parameter in the Android 15 tree and remain unchecked there.
- The exact privilege gained with a spoofed package name. The bulletin says EoP, High; the context shows device/profile-owner, allowlist and preferred-service decisions keyed on the string.
- Why Android 14 is reported as not affected while 7/8 lines of the patched region are present at android-security-14.0.0_r29.