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

Commit 692f8c93 authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Enforcing a maximum depth on nested RemoteViews calls

An unchecked read from parcel can lead to StackOverflowError

Test: am instrument -w -e class android.widget.RemoteViewsTest com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
Bug: 26755067
Change-Id: I36ea253846d5c823899097821270dcfca2472b65
parent ac4a8b7f
Loading
Loading
Loading
Loading
+23 −8
Original line number Diff line number Diff line
@@ -42,11 +42,13 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
import android.os.StrictMode;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -91,6 +93,12 @@ public class RemoteViews implements Parcelable, Filter {
     */
    static final String EXTRA_REMOTEADAPTER_APPWIDGET_ID = "remoteAdapterAppWidgetId";

    /**
     * Maximum depth of nested views calls from {@link #addView(int, RemoteViews)} and
     * {@link #RemoteViews(RemoteViews, RemoteViews)}.
     */
    private static final int MAX_NESTED_VIEWS = 10;

    /**
     * Application that hosts the remote views.
     *
@@ -1538,11 +1546,11 @@ public class RemoteViews implements Parcelable, Filter {
            }
        }

        ViewGroupAction(Parcel parcel, BitmapCache bitmapCache, ApplicationInfo info) {
        ViewGroupAction(Parcel parcel, BitmapCache bitmapCache, ApplicationInfo info, int depth) {
            viewId = parcel.readInt();
            boolean nestedViewsNull = parcel.readInt() == 0;
            if (!nestedViewsNull) {
                nestedViews = new RemoteViews(parcel, bitmapCache, info);
                nestedViews = new RemoteViews(parcel, bitmapCache, info, depth);
            } else {
                nestedViews = null;
            }
@@ -2209,10 +2217,16 @@ public class RemoteViews implements Parcelable, Filter {
     * @param parcel
     */
    public RemoteViews(Parcel parcel) {
        this(parcel, null, null);
        this(parcel, null, null, 0);
    }

    private RemoteViews(Parcel parcel, BitmapCache bitmapCache, ApplicationInfo info, int depth) {
        if (depth > MAX_NESTED_VIEWS
                && (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID)) {
            throw new IllegalArgumentException("Too many nested views.");
        }
        depth++;

    private RemoteViews(Parcel parcel, BitmapCache bitmapCache, ApplicationInfo info) {
        int mode = parcel.readInt();

        // We only store a bitmap cache in the root of the RemoteViews.
@@ -2245,7 +2259,8 @@ public class RemoteViews implements Parcelable, Filter {
                            mActions.add(new ReflectionAction(parcel));
                            break;
                        case ViewGroupAction.TAG:
                            mActions.add(new ViewGroupAction(parcel, mBitmapCache, mApplication));
                            mActions.add(new ViewGroupAction(parcel, mBitmapCache, mApplication,
                                    depth));
                            break;
                        case ReflectionActionWithoutParams.TAG:
                            mActions.add(new ReflectionActionWithoutParams(parcel));
@@ -2293,8 +2308,8 @@ public class RemoteViews implements Parcelable, Filter {
            }
        } else {
            // MODE_HAS_LANDSCAPE_AND_PORTRAIT
            mLandscape = new RemoteViews(parcel, mBitmapCache, info);
            mPortrait = new RemoteViews(parcel, mBitmapCache, mLandscape.mApplication);
            mLandscape = new RemoteViews(parcel, mBitmapCache, info, depth);
            mPortrait = new RemoteViews(parcel, mBitmapCache, mLandscape.mApplication, depth);
            mApplication = mPortrait.mApplication;
            mLayoutId = mPortrait.getLayoutId();
        }
@@ -2318,7 +2333,7 @@ public class RemoteViews implements Parcelable, Filter {
        p.setDataPosition(0);
        mIsRoot = true;

        RemoteViews rv = new RemoteViews(p, mBitmapCache.clone(), mApplication);
        RemoteViews rv = new RemoteViews(p, mBitmapCache.clone(), mApplication, 0);
        rv.mIsRoot = true;

        p.recycle();
+41 −7
Original line number Diff line number Diff line
@@ -179,13 +179,8 @@ public class RemoteViewsTest {
        ViewAppliedListener listener = new ViewAppliedListener();
        views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);

        boolean exceptionThrown = false;
        try {
        exception.expect(Exception.class);
        listener.waitAndGetView();
        } catch (Exception e) {
            exceptionThrown = true;
        }
        assertTrue(exceptionThrown);
    }

    @Test
@@ -332,4 +327,43 @@ public class RemoteViewsTest {
            return mView;
        }
    }

    @Test
    public void nestedAddViews() {
        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
        for (int i = 0; i < 10; i++) {
            RemoteViews parent = new RemoteViews(mPackage, R.layout.remote_views_test);
            parent.addView(R.id.layout, views);
            views = parent;
        }
        views.clone();

        views = new RemoteViews(mPackage, R.layout.remote_views_test);
        for (int i = 0; i < 11; i++) {
            RemoteViews parent = new RemoteViews(mPackage, R.layout.remote_views_test);
            parent.addView(R.id.layout, views);
            views = parent;
        }
        exception.expect(IllegalArgumentException.class);
        views.clone();
    }

    @Test
    public void nestedLandscapeViews() {
        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
        for (int i = 0; i < 10; i++) {
            views = new RemoteViews(views,
                    new RemoteViews(mPackage, R.layout.remote_views_test));
        }
        views.clone();

        views = new RemoteViews(mPackage, R.layout.remote_views_test);
        for (int i = 0; i < 11; i++) {
            RemoteViews parent = new RemoteViews(mPackage, R.layout.remote_views_test);
            parent.addView(R.id.layout, views);
            views = parent;
        }
        exception.expect(IllegalArgumentException.class);
        views.clone();
    }
}