CVE-2024-49741 AI-generated analysis
platform/frameworks/base, system_server AppWidgetService (services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java)
Adds hard caps in AppWidgetServiceImpl of 20 hosts per (uid, package) and 200 widgets per host, evicting the oldest host or widget before a new one is added so an app cannot grow the service's host/widget state without bound.
Root cause
AppWidgetServiceImpl kept every Host created for a calling package in mHosts and every Widget in mWidgets with no upper bound. The host lookup/creation path simply did `host = new Host(); host.id = id; mHosts.add(host)` whenever a HostId was not already known, and addWidgetLocked unconditionally did `mWidgets.add(widget)`. A single package could therefore create an arbitrary number of host ids and an arbitrary number of widgets per host, growing the service's in-memory state. The bulletin classifies this as a High severity DoS.
How the fix works
- AppWidgetServiceImpl.java: adds two constants, MAX_NUMBER_OF_HOSTS_PER_PACKAGE = 20 and MAX_NUMBER_OF_WIDGETS_PER_HOST = 200.
- AppWidgetServiceImpl.java, host lookup/creation helper (hunk at ~line 1805, the function that does `host = new Host(); mHosts.add(host)`; its name is not in the diff header): before creating a new Host, calls the new ensureHostCountBeforeAddLocked(id).
- AppWidgetServiceImpl.java:ensureHostCountBeforeAddLocked(HostId): collects all entries of mHosts whose id.uid equals hostId.uid and whose id.packageName equals hostId.packageName. While that list has >= 20 entries, it removes the first one (oldest in mHosts order) via the existing deleteHostLocked().
- AppWidgetServiceImpl.java:addWidgetLocked(Widget): calls the new ensureWidgetCountBeforeAddLocked(widget) before mWidgets.add(widget).
- AppWidgetServiceImpl.java:ensureWidgetCountBeforeAddLocked(Widget): returns early if widget.host or widget.host.id is null. Otherwise it collects all mWidgets whose host.id equals the new widget's host.id and, while that list has >= 200 entries, removes the first one (oldest) via the existing removeWidgetLocked().
- The diff introduces no new locking.
Completeness
- Covers both growth dimensions visible in the diff: number of Host objects per (uid, packageName) and number of Widget objects per HostId.
- The host cap is per package, not global: the total number of hosts is still bounded only by 20 times the number of packages that call the service. The widget cap is per host, so one package may still hold up to 20 * 200 widgets.
- ensureWidgetCountBeforeAddLocked is skipped when widget.host or widget.host.id is null; such widgets are not counted or limited.
- ensureHostCountBeforeAddLocked calls host.id.packageName.equals(...) without a null check on host.id.packageName; behaviour with a null packageName is not shown in the material.
- Limits are enforced only when a host or widget is created. The material does not show whether they also apply when existing state is restored or loaded.
- No other data structures (e.g. provider records) are capped by this change.
Behavior changes
- When a package already has 20 hosts and creates a new HostId, the oldest matching host is silently deleted via deleteHostLocked; no error is returned to the caller.
- When a host already has 200 widgets and another is added, the oldest widget in that host is silently removed via removeWidgetLocked; no error is returned.
- Apps that use more than 20 host ids, or more than 200 widgets in one host, will lose their oldest entries when new ones are added.
Per major
- Android 14: same fix: commit 38cb08e0b3ae in android-security-14.0.0_r16 (cherry-pick of 65736bec809f); 8/8 lines of the patched region present at android-security-14.0.0_r29.
- Android 15: adapted fix: commit 047bc1ce62f8 in android-security-15.0.0_r4. The logic is identical, with @NonNull final parameter annotations and different line offsets (2057/2065/3383); 8/8 lines present at android-security-15.0.0_r17.
- 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 name of the function containing the host-creation hunk is not shown in the diff header.
- Which specific binder calls the PoC used to create hosts/widgets.
- Whether widgets restored from persisted state pass through addWidgetLocked and are therefore subject to the new cap.
- Whether hosts and widgets are persisted to appwidgets.xml, and so whether the growth also affects persisted state.
- What deleteHostLocked does with the host's widgets (only the start of its loop over host.widgets is shown).
- Which lock the callers of the new *Locked helpers hold.
- Behaviour if host.id.packageName is null in ensureHostCountBeforeAddLocked.