CVE-2024-0026 AI-generated analysis
platform/frameworks/base, system_server notification service (com.android.server.notification.SnoozeHelper)
SnoozeHelper.canSnooze now also counts the two persisted snoozed-notification maps against CONCURRENT_SNOOZE_LIMIT, and repostGroupSummary removes the reposted group summary from those persisted maps so they can no longer grow unbounded and cause a boot loop when serialized.
Root cause
SnoozeHelper keeps three maps: the in-memory mSnoozedNotifications (key to NotificationRecord) and two persisted maps, mPersistedSnoozedNotifications (key to trigger time) and mPersistedSnoozedNotificationsWithContext (key to context id), which survive reboots via XML. canSnooze(numberToSnooze) only compared mSnoozedNotifications.size() + numberToSnooze against CONCURRENT_SNOOZE_LIMIT, so the persisted maps were never bounded. In addition, repostGroupSummary removed the group summary only from mSnoozedNotifications and left its entries in the persisted maps, so persisted entries could accumulate while the in-memory count stayed under the limit. Per the commit message, serializing a huge number of persisted snoozed notifications caused a boot loop (DoS).
How the fix works
- services/core/java/com/android/server/notification/SnoozeHelper.java:canSnooze - the limit check is extended with a second condition: if mPersistedSnoozedNotifications.size() + mPersistedSnoozedNotificationsWithContext.size() + numberToSnooze exceeds CONCURRENT_SNOOZE_LIMIT, canSnooze returns false. Both checks are evaluated under mLock.
- services/core/java/com/android/server/notification/SnoozeHelper.java:repostGroupSummary - after mSnoozedNotifications.remove(groupSummaryKey), the key is normalized with getTrimmedString(groupSummaryKey) and removed from both mPersistedSnoozedNotificationsWithContext and mPersistedSnoozedNotifications, keeping persisted state consistent with in-memory state.
- services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java - adds testSnoozeLimit_maximumPersisted (loads CONCURRENT_SNOOZE_LIMIT entries via readXml and asserts canSnooze(1) is false while persisted lookups still work), extends repostGroupSummary_repostsSummary and adds snoozeWithContext_repostGroupSummary_removesPersisted to assert persisted entries are cleared on repost.
Completeness
- Covers: the admission check (canSnooze) now bounds both persisted maps in aggregate, and the repostGroupSummary path now cleans persisted entries for the summary key.
- The persisted maps are only bounded at snooze admission time; readXml itself (used in the new test to load entries) is not shown to enforce any limit on what it deserializes, so an already-oversized persisted file is not truncated by this diff.
- The commit message lists a third item, 'Prevent unpriviledged API calls that allow 3P apps to snooze notifications with context/criterion', but the diff touches only SnoozeHelper.java and its test; that change is not in this commit and is not shown in the material.
- Other removal paths in SnoozeHelper (cancel, repost of non-summary notifications, user/package cleanup) are not visible in the material, so whether they already clean the persisted maps cannot be judged from the diff.
Behavior changes
- canSnooze returns false when the combined count of persisted timed and context-snoozed notifications plus the requested number would exceed CONCURRENT_SNOOZE_LIMIT, even if the in-memory map is small; snooze requests are then refused.
- After repostGroupSummary, getSnoozeTimeForUnpostedNotification returns 0 and getSnoozeContextForUnpostedNotification returns null for the summary key (previously the stale persisted values remained).
Per major
- Android 14: same fix: commit a8fb9fe93efd in android-security-14.0.0_r5 (cherry-pick of 965ff2d3c548, Change-Id I3571fa9207b778def652130d3ca840183a9a8414); at android-security-14.0.0_r29 7/8 lines of the patched region are present.
- Android 15: not affected (the bulletin does not list Android 15); 7/8 lines of the patched region present at android-security-15.0.0_r17.
- Android 16: not affected (the bulletin does not list Android 16); 7/8 lines of the patched region present at android-security-16.0.0_r8.
- Android 17: not affected (the bulletin does not list Android 17); 7/8 lines of the patched region present at android-security-17.0.0_r1.
Unknowns
- The companion change for 'Prevent unpriviledged API calls that allow 3P apps to snooze notifications with context/criterion' referenced in the commit message is not in the material.
- The exact mechanism by which oversized persisted state causes a boot loop (where serialization/deserialization fails) is only stated in the commit message, not shown in code.
- Whether and how the fix was applied to Android 12, 12L and 13, which the bulletin lists as affected, is not in the material.