Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2a75f716 authored by Pinyao Ting's avatar Pinyao Ting
Browse files

Enforce hard limits on hosts per package and widgets per host.

Bug: 353240784
Change-Id: I60ee7faf57ed719f93cafad212fef24964dec99f
Test: manually verified with PoC app that at most 20 hosts can exists
Flag: EXEMPT CVE
parent 37262db5
Loading
Loading
Loading
Loading
+49 −1
Original line number Diff line number Diff line
@@ -217,6 +217,15 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
    // See {@link Provider#pendingDeletedWidgetIds}.
    private static final String PENDING_DELETED_IDS_ATTR = "pending_deleted_ids";

    // Hard limit of number of hosts an app can create, note that the app that hosts the widgets
    // can have multiple instances of {@link AppWidgetHost}, typically in respect to different
    // surfaces in the host app.
    // @see AppWidgetHost
    // @see AppWidgetHost#mHostId
    private static final int MAX_NUMBER_OF_HOSTS_PER_PACKAGE = 20;
    // Hard limit of number of widgets can be pinned by a host.
    private static final int MAX_NUMBER_OF_WIDGETS_PER_HOST = 200;

    // Handles user and package related broadcasts.
    // See {@link #registerBroadcastReceiver}
    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -2275,7 +2284,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
        if (host != null) {
            return host;
        }

        ensureHostCountBeforeAddLocked(id);
        host = new Host();
        host.id = id;
        mHosts.add(host);
@@ -2283,6 +2292,24 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
        return host;
    }

    /**
     * Ensures that the number of hosts for a package is less than the maximum number of hosts per
     * package. If the number of hosts is greater than the maximum number of hosts per package, then
     * removes the oldest host.
     */
    private void ensureHostCountBeforeAddLocked(@NonNull final HostId hostId) {
        final List<Host> hosts = new ArrayList<>();
        for (Host host : mHosts) {
            if (host.id.uid == hostId.uid
                    && host.id.packageName.equals(hostId.packageName)) {
                hosts.add(host);
            }
        }
        while (hosts.size() >= MAX_NUMBER_OF_HOSTS_PER_PACKAGE) {
            deleteHostLocked(hosts.remove(0));
        }
    }

    private void deleteHostLocked(Host host) {
        if (DEBUG) {
            Slog.i(TAG, "deleteHostLocked() " + host);
@@ -3573,11 +3600,32 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
        if (DEBUG) {
            Slog.i(TAG, "addWidgetLocked() " + widget);
        }
        ensureWidgetCountBeforeAddLocked(widget);
        mWidgets.add(widget);

        onWidgetProviderAddedOrChangedLocked(widget);
    }

    /**
     * Ensures that the widget count for the widget's host is not greater than the maximum
     * number of widgets per host. If the count is greater than the maximum, removes oldest widgets
     * from the host until the count is less than or equal to the maximum.
     */
    private void ensureWidgetCountBeforeAddLocked(@NonNull final Widget widget) {
        if (widget.host == null || widget.host.id == null) {
            return;
        }
        final List<Widget> widgetsInSameHost = new ArrayList<>();
        for (Widget w : mWidgets) {
            if (w.host != null && widget.host.id.equals(w.host.id)) {
                widgetsInSameHost.add(w);
            }
        }
        while (widgetsInSameHost.size() >= MAX_NUMBER_OF_WIDGETS_PER_HOST) {
            removeWidgetLocked(widgetsInSameHost.remove(0));
        }
    }

    /**
     * Checks if the provider is assigned and updates the mWidgetPackages to track packages
     * that have bound widgets.