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

Commit 34984a2e authored by Matías Hernández's avatar Matías Hernández Committed by Android (Google) Code Review
Browse files

Merge "Fix allowlist token issues" into sc-v2-dev

parents 59b194f6 5d107bcd
Loading
Loading
Loading
Loading
+38 −9
Original line number Original line Diff line number Diff line
@@ -2519,8 +2519,11 @@ public class Notification implements Parcelable
        if (mAllowlistToken == null) {
        if (mAllowlistToken == null) {
            mAllowlistToken = processAllowlistToken;
            mAllowlistToken = processAllowlistToken;
        }
        }
        // Propagate this token to all pending intents that are unmarshalled from the parcel.
        // Propagate this token to all pending intents that are unmarshalled from the parcel,
        // or keep the one we're already propagating, if that's the case.
        if (!parcel.hasClassCookie(PendingIntent.class)) {
            parcel.setClassCookie(PendingIntent.class, mAllowlistToken);
            parcel.setClassCookie(PendingIntent.class, mAllowlistToken);
        }


        when = parcel.readLong();
        when = parcel.readLong();
        creationTime = parcel.readLong();
        creationTime = parcel.readLong();
@@ -2976,10 +2979,25 @@ public class Notification implements Parcelable
                }
                }
            });
            });
        }
        }
        try {
            boolean mustClearCookie = false;
            if (!parcel.hasClassCookie(Notification.class)) {
                // This is the "root" notification, and not an "inner" notification (including
                // publicVersion or anything else that might be embedded in extras). So we want
                // to use its token for every inner notification (might be null).
                parcel.setClassCookie(Notification.class, mAllowlistToken);
                mustClearCookie = true;
            }
            try {
            try {
                // IMPORTANT: Add marshaling code in writeToParcelImpl as we
                // IMPORTANT: Add marshaling code in writeToParcelImpl as we
                // want to intercept all pending events written to the parcel.
                // want to intercept all pending events written to the parcel.
                writeToParcelImpl(parcel, flags);
                writeToParcelImpl(parcel, flags);
            } finally {
                if (mustClearCookie) {
                    parcel.removeClassCookie(Notification.class, mAllowlistToken);
                }
            }

            synchronized (this) {
            synchronized (this) {
                // Must be written last!
                // Must be written last!
                parcel.writeArraySet(allPendingIntents);
                parcel.writeArraySet(allPendingIntents);
@@ -2994,7 +3012,10 @@ public class Notification implements Parcelable
    private void writeToParcelImpl(Parcel parcel, int flags) {
    private void writeToParcelImpl(Parcel parcel, int flags) {
        parcel.writeInt(1);
        parcel.writeInt(1);


        parcel.writeStrongBinder(mAllowlistToken);
        // Always use the same token as the root notification (might be null).
        IBinder rootNotificationToken = (IBinder) parcel.getClassCookie(Notification.class);
        parcel.writeStrongBinder(rootNotificationToken);

        parcel.writeLong(when);
        parcel.writeLong(when);
        parcel.writeLong(creationTime);
        parcel.writeLong(creationTime);
        if (mSmallIcon == null && icon != 0) {
        if (mSmallIcon == null && icon != 0) {
@@ -3350,13 +3371,21 @@ public class Notification implements Parcelable
     * Sets the token used for background operations for the pending intents associated with this
     * Sets the token used for background operations for the pending intents associated with this
     * notification.
     * notification.
     *
     *
     * This token is automatically set during deserialization for you, you usually won't need to
     * Note: Should <em>only</em> be invoked by NotificationManagerService, since this is normally
     * call this unless you want to change the existing token, if any.
     * populated by unparceling (and also used there). Any other usage is suspect.
     *
     *
     * @hide
     * @hide
     */
     */
    public void setAllowlistToken(@Nullable IBinder token) {
    public void overrideAllowlistToken(IBinder token) {
        mAllowlistToken = token;
        mAllowlistToken = token;
        if (publicVersion != null) {
            publicVersion.overrideAllowlistToken(token);
        }
    }

    /** @hide */
    public IBinder getAllowlistToken() {
        return mAllowlistToken;
    }
    }


    /**
    /**
+22 −0
Original line number Original line Diff line number Diff line
@@ -651,6 +651,28 @@ public final class Parcel {
        return mClassCookies != null ? mClassCookies.get(clz) : null;
        return mClassCookies != null ? mClassCookies.get(clz) : null;
    }
    }


    /** @hide */
    public void removeClassCookie(Class clz, Object expectedCookie) {
        if (mClassCookies != null) {
            Object removedCookie = mClassCookies.remove(clz);
            if (removedCookie != expectedCookie) {
                Log.wtf(TAG, "Expected to remove " + expectedCookie + " (with key=" + clz
                        + ") but instead removed " + removedCookie);
            }
        } else {
            Log.wtf(TAG, "Expected to remove " + expectedCookie + " (with key=" + clz
                    + ") but no cookies were present");
        }
    }

    /**
     * Whether {@link #setClassCookie} has been called with the specified {@code clz}.
     * @hide
     */
    public boolean hasClassCookie(Class clz) {
        return mClassCookies != null && mClassCookies.containsKey(clz);
    }

    /** @hide */
    /** @hide */
    public final void adoptClassCookies(Parcel from) {
    public final void adoptClassCookies(Parcel from) {
        mClassCookies = from.mClassCookies;
        mClassCookies = from.mClassCookies;
+49 −0
Original line number Original line Diff line number Diff line
@@ -16,15 +16,20 @@


package android.os;
package android.os;


import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;


import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.Presubmit;
import android.util.Log;


import androidx.test.runner.AndroidJUnit4;
import androidx.test.runner.AndroidJUnit4;


import org.junit.Test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.RunWith;


import java.util.ArrayList;

@Presubmit
@Presubmit
@RunWith(AndroidJUnit4.class)
@RunWith(AndroidJUnit4.class)
public class ParcelTest {
public class ParcelTest {
@@ -110,4 +115,48 @@ public class ParcelTest {
            assertEquals(string, p.readString16());
            assertEquals(string, p.readString16());
        }
        }
    }
    }

    @Test
    public void testClassCookies() {
        Parcel p = Parcel.obtain();
        assertThat(p.hasClassCookie(ParcelTest.class)).isFalse();

        p.setClassCookie(ParcelTest.class, "string_cookie");
        assertThat(p.hasClassCookie(ParcelTest.class)).isTrue();
        assertThat(p.getClassCookie(ParcelTest.class)).isEqualTo("string_cookie");

        p.removeClassCookie(ParcelTest.class, "string_cookie");
        assertThat(p.hasClassCookie(ParcelTest.class)).isFalse();
        assertThat(p.getClassCookie(ParcelTest.class)).isEqualTo(null);

        p.setClassCookie(ParcelTest.class, "to_be_discarded_cookie");
        p.recycle();
        assertThat(p.getClassCookie(ParcelTest.class)).isNull();
    }

    @Test
    public void testClassCookies_removeUnexpected() {
        Parcel p = Parcel.obtain();

        assertLogsWtf(() -> p.removeClassCookie(ParcelTest.class, "not_present"));

        p.setClassCookie(ParcelTest.class, "value");

        assertLogsWtf(() -> p.removeClassCookie(ParcelTest.class, "different"));
        assertThat(p.getClassCookie(ParcelTest.class)).isNull(); // still removed

        p.recycle();
    }

    private static void assertLogsWtf(Runnable test) {
        ArrayList<Log.TerribleFailure> wtfs = new ArrayList<>();
        Log.TerribleFailureHandler oldHandler = Log.setWtfHandler(
                (tag, what, system) -> wtfs.add(what));
        try {
            test.run();
        } finally {
            Log.setWtfHandler(oldHandler);
        }
        assertThat(wtfs).hasSize(1);
    }
}
}
+16 −2
Original line number Original line Diff line number Diff line
@@ -592,7 +592,7 @@ public class NotificationManagerService extends SystemService {


    private static final int MY_UID = Process.myUid();
    private static final int MY_UID = Process.myUid();
    private static final int MY_PID = Process.myPid();
    private static final int MY_PID = Process.myPid();
    private static final IBinder ALLOWLIST_TOKEN = new Binder();
    static final IBinder ALLOWLIST_TOKEN = new Binder();
    protected RankingHandler mRankingHandler;
    protected RankingHandler mRankingHandler;
    private long mLastOverRateLogTime;
    private long mLastOverRateLogTime;
    private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
    private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
@@ -4230,7 +4230,7 @@ public class NotificationManagerService extends SystemService {
                    // Remove background token before returning notification to untrusted app, this
                    // Remove background token before returning notification to untrusted app, this
                    // ensures the app isn't able to perform background operations that are
                    // ensures the app isn't able to perform background operations that are
                    // associated with notification interactions.
                    // associated with notification interactions.
                    notification.setAllowlistToken(null);
                    notification.overrideAllowlistToken(null);
                    return new StatusBarNotification(
                    return new StatusBarNotification(
                            sbn.getPackageName(),
                            sbn.getPackageName(),
                            sbn.getOpPkg(),
                            sbn.getOpPkg(),
@@ -6214,6 +6214,15 @@ public class NotificationManagerService extends SystemService {
                    + " trying to post for invalid pkg " + pkg + " in user " + incomingUserId);
                    + " trying to post for invalid pkg " + pkg + " in user " + incomingUserId);
        }
        }


        IBinder allowlistToken = notification.getAllowlistToken();
        if (allowlistToken != null && allowlistToken != ALLOWLIST_TOKEN) {
            throw new SecurityException(
                    "Unexpected allowlist token received from " + callingUid);
        }
        // allowlistToken is populated by unparceling, so it can be null if the notification was
        // posted from inside system_server. Ensure it's the expected value.
        notification.overrideAllowlistToken(ALLOWLIST_TOKEN);

        checkRestrictedCategories(notification);
        checkRestrictedCategories(notification);


        // Fix the notification as best we can.
        // Fix the notification as best we can.
@@ -6958,6 +6967,11 @@ public class NotificationManagerService extends SystemService {
        @Override
        @Override
        public void run() {
        public void run() {
            synchronized (mNotificationLock) {
            synchronized (mNotificationLock) {
                // allowlistToken is populated by unparceling, so it will be absent if the
                // EnqueueNotificationRunnable is created directly by NMS (as we do for group
                // summaries) instead of via notify(). Fix that.
                r.getNotification().overrideAllowlistToken(ALLOWLIST_TOKEN);

                final Long snoozeAt =
                final Long snoozeAt =
                        mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
                        mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
                                r.getUser().getIdentifier(),
                                r.getUser().getIdentifier(),
+350 −4

File changed.

Preview size limit exceeded, changes collapsed.