CVE-2024-49742 AI-generated analysis
platform/packages/apps/Settings, notification listener access confirmation (CDM / NLS flow)
NotificationAccessConfirmationActivity in Settings now verifies, before showing the grant dialog, that the requesting package declares a service resolving the NotificationListenerService intent action for the target user and that this service is protected by BIND_NOTIFICATION_LISTENER_SERVICE, finishing the activity otherwise, and it drops the onBackPressed override that prevented dismissal.
Root cause
NotificationAccessConfirmationActivity receives a component name and user id via EXTRA_COMPONENT_NAME / EXTRA_USER_ID (NotificationAccessConfirmationActivityContract) and, on user approval, calls mNm.setNotificationListenerAccessGranted(mComponentName, true). Before the fix the only validation was in onAllow(): PackageManager.getServiceInfo(mComponentName, 0) and a comparison of serviceInfo.permission against BIND_NOTIFICATION_LISTENER_SERVICE. It never checked that the component declared an intent-filter for android.service.notification.NotificationListenerService, the lookup was not done for mUserId, and the check ran only after the dialog had been shown. The activity also overrode onBackPressed() to suppress finishing, so the back button did not dismiss the dialog.
How the fix works
- src/com/android/settings/notification/NotificationAccessConfirmationActivity.java:onCreate: after the existing early-exit checks and before building AlertController.AlertParams, the fix builds an Intent for NotificationListenerService.SERVICE_INTERFACE and calls getPackageManager().queryIntentServicesAsUser(NLSIntent, 0, mUserId). It walks the ResolveInfo list for an entry whose serviceInfo.packageName equals mComponentName.getPackageName(). If that entry's serviceInfo.permission is not BIND_NOTIFICATION_LISTENER_SERVICE, it logs, calls finish() and returns. Otherwise it sets hasNLSIntentFilter and breaks. If no entry matched, it logs 'lacks an intent-filter action', calls finish() and returns. Only then is the dialog created.
- src/com/android/settings/notification/NotificationAccessConfirmationActivity.java:onAllow: the previous getServiceInfo(mComponentName, 0) permission check and its NameNotFoundException handling are removed. onAllow now only calls mNm.setNotificationListenerAccessGranted(mComponentName, true) and finish(), relying on the onCreate validation.
- src/com/android/settings/notification/NotificationAccessConfirmationActivity.java: the onBackPressed() override that suppressed finishing on back press is deleted. cancel() still calls finish().
- tests/robotests/.../NotificationAccessConfirmationActivityTest.java: start_showsDialog is replaced by start_withMissingIntentFilter_finishes, which asserts that a package with no NLS service yields no dialog text and that activity.isFinishing() is true.
Completeness
- Covered: the activity refuses to show the grant dialog when the package has no service resolving the NotificationListenerService action for mUserId, or when the first such service in that package is not protected by BIND_NOTIFICATION_LISTENER_SERVICE. The query is now user-aware (queryIntentServicesAsUser with mUserId); the old check used getServiceInfo without a user.
- Limitation visible in the code: the match is by package name only (service.serviceInfo.packageName.equals(mComponentName.getPackageName())) followed by break. It does not compare the matched serviceInfo.name to mComponentName.getClassName(). If a package declares more than one service, the check validates the first NLS-resolving service of that package, while setNotificationListenerAccessGranted is still called with the full mComponentName. The old per-component getServiceInfo(mComponentName) permission check was removed rather than kept alongside the new check.
- The grant itself (mNm.setNotificationListenerAccessGranted) is unchanged. Any server-side validation in NotificationManagerService is not part of this commit and is not shown in the material.
Behavior changes
- The activity finishes immediately (no dialog) with a Slog.e when the package has no NotificationListenerService intent-filter for the target user, or when its NLS service lacks BIND_NOTIFICATION_LISTENER_SERVICE. Previously the dialog was shown and the permission mismatch was only logged on Allow.
- The back button now dismisses the confirmation activity (onBackPressed override removed).
- The service lookup is now done for mUserId instead of the caller's implicit user.
- The Robolectric test start_showsDialog is replaced by start_withMissingIntentFilter_finishes.
Per major
- Android 14: same fix: platform/packages/apps/Settings b0eec6fdfd5b in android-security-14.0.0_r16 (cherry-pick of 7ae59a42eb13, Change-Id Ib79c219c); patched region fully present (8/8 lines) at android-security-14.0.0_r29.
- Android 15: same fix: platform/packages/apps/Settings 334323abd571 in android-security-15.0.0_r4. The added and removed lines are identical; only hunk offsets and test-file context differ. 8/8 lines present at android-security-15.0.0_r17.
- Android 16: not affected (not listed by the bulletin); patched code present (8/8 lines) at android-security-16.0.0_r8.
- Android 17: not affected (not listed by the bulletin); patched code present (8/8 lines) at android-security-17.0.0_r1.
Unknowns
- The exact EoP consequence (what a non-NLS component could obtain once granted listener access) is not shown in the material.
- Which callers launch this activity in the affected versions (the commit title says CDM), and whether NotificationManagerService does its own validation in setNotificationListenerAccessGranted, are not shown.
- How queryIntentServicesAsUser with flags 0 treats disabled or otherwise filtered components is not shown.
- Whether 12/12L/13 received the same patch, and whether their code matches, is not shown in the per-major facts.