Chrome · Messages
CVE-2025-5066
Logic Error in Messages
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Files Changed
chrome/android/javatests/BUILD.gnchrome/android/javatests/src/org/chromium/chrome/browser/messages/MessageTest.javachrome/android/javatests/src/org/chromium/chrome/browser/messages/OWNERScomponents/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerMediator.java
Patch
From 95729cec0565596f159af487d0bceeb82a7755b8 Mon Sep 17 00:00:00 2001 From: Lijin Shen <[email protected]> Date: Thu, 03 Apr 2025 15:02:33 -0700 Subject: [PATCH] Add tap protection to message ui Disallow any touch event as soon as the animation starts. The message should become clickable again once the tap protection period ends. Bug: 356658477 Change-Id: I3522cb07e0b9a4c6fbe9f88cbe12777ffc41b5d5 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6411166 Reviewed-by: Aishwarya Rajesh <[email protected]> Commit-Queue: Lijin Shen <[email protected]> Reviewed-by: Theresa Sullivan <[email protected]> Cr-Commit-Position: refs/heads/main@{#1442451} --- diff --git a/chrome/android/javatests/BUILD.gn b/chrome/android/javatests/BUILD.gn index 49c8aa56..efe5e69 100644 --- a/chrome/android/javatests/BUILD.gn +++ b/chrome/android/javatests/BUILD.gn @@ -1527,6 +1527,7 @@ "src/org/chromium/chrome/browser/locale/LocaleManagerReferralTest.java", "src/org/chromium/chrome/browser/locale/LocaleManagerTest.java", "src/org/chromium/chrome/browser/login/ChromeHttpAuthHandlerTest.java", + "src/org/chromium/chrome/browser/messages/MessageTest.java", "src/org/chromium/chrome/browser/modaldialog/ChromeTabModalPresenterTest.java", "src/org/chromium/chrome/browser/modaldialog/ModalDialogViewRenderTest.java", "src/org/chromium/chrome/browser/multiwindow/MultiWindowIntegrationTest.java", diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/messages/MessageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/messages/MessageTest.java new file mode 100644 index 0000000..675a46a --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/messages/MessageTest.java @@ -0,0 +1,105 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.messages; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; + +import androidx.test.filters.SmallTest; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.FakeTimeTestRule; +import org.chromium.base.ThreadUtils; +import org.chromium.base.test.util.Batch; +import org.chromium.base.test.util.CallbackHelper; +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.chrome.browser.ChromeTabbedActivity; +import org.chromium.chrome.browser.flags.ChromeSwitches; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.ChromeTabbedActivityTestRule; +import org.chromium.chrome.test.R; +import org.chromium.components.messages.MessageBannerProperties; +import org.chromium.components.messages.MessageDispatcher; +import org.chromium.components.messages.MessageDispatcherProvider; +import org.chromium.components.messages.MessagesTestHelper; +import org.chromium.components.messages.PrimaryActionClickBehavior; +import org.chromium.ui.modelutil.PropertyModel; + +import java.util.concurrent.TimeoutException; + +/** Integration test of Message. */ +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +@Batch(Batch.PER_CLASS) +public class MessageTest { + @ClassRule + public static ChromeTabbedActivityTestRule sActivityTestRule = + new ChromeTabbedActivityTestRule(); + + @Rule public FakeTimeTestRule mFakeTimeTestRule = new FakeTimeTestRule(); + + private ChromeTabbedActivity mActivity; + private MessageDispatcher mMessageDispatcher; + + @Before + public void setUp() { + sActivityTestRule.startMainActivityOnBlankPage(); + mActivity = sActivityTestRule.getActivity(); + mMessageDispatcher = + ThreadUtils.runOnUiThreadBlocking( + () -> MessageDispatcherProvider.from(mActivity.getWindowAndroid())); + } + + @After + public void tearDown() { + MessagesTestHelper.enableTapProtectionDuration(-1); + } + + /** + * Test that message is not clickable within tap protection period and becomes clickable once it + * ends. + */ + @Test + @SmallTest + public void testTapProtection() throws TimeoutException { + MessagesTestHelper.enableTapProtectionDuration(500); + CallbackHelper helper = new CallbackHelper(); + PropertyModel model = + ThreadUtils.runOnUiThreadBlocking( + () -> + new PropertyModel.Builder(MessageBannerProperties.ALL_KEYS) + .with(MessageBannerProperties.TITLE, "Test title") + .with(MessageBannerProperties.PRIMARY_BUTTON_TEXT, "Action") + .with(MessageBannerProperties.ON_DISMISSED, (v) -> {}) + .with( + MessageBannerProperties.ON_PRIMARY_ACTION, + () -> { + helper.notifyCalled(); + return PrimaryActionClickBehavior + .DISMISS_IMMEDIATELY; + }) + .build()); + ThreadUtils.runOnUiThreadBlocking( + () -> { + mMessageDispatcher.enqueueWindowScopedMessage(model, true); + }); + onView(withId(R.id.message_primary_button)).check(matches(isDisplayed())); + onView(withId(R.id.message_primary_button)).perform(click()); + Assert.assertEquals("Not clickable with tap protection period", 0, helper.getCallCount()); + mFakeTimeTestRule.advanceMillis(1500); + onView(withId(R.id.message_primary_button)).perform(click()); + helper.waitForNext("Should able to click when tap protection period ends"); + } +} diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/messages/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/messages/OWNERS new file mode 100644 index 0000000..12c1e52 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/messages/OWNERS @@ -0,0 +1 @@ +file://components/messages/OWNERS \ No newline at end of file diff --git a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerMediator.java b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerMediator.java index 7d04e76a..dd43d31 100644 --- a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerMediator.java +++ b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerMediator.java @@ -7,6 +7,7 @@ import static org.chromium.components.browser_ui.widget.gesture.SwipeGestureListener.ScrollDirection.DOWN; import static org.chromium.components.browser_ui.widget.gesture.SwipeGestureListener.ScrollDirection.UP; import static org.chromium.components.messages.MessageBannerProperties.CONTENT_ALPHA; +import static org.chromium.components.messages.MessageBannerProperties.IS_WITHIN_TAP_PROTECTION_PERIOD_SUPPLIER; import static org.chromium.components.messages.MessageBannerProperties.MARGIN_TOP; import static org.chromium.components.messages.MessageBannerProperties.TRANSLATION_X; import static org.chromium.components.messages.MessageBannerProperties.TRANSLATION_Y; @@ -21,7 +22,10 @@ import androidx.annotation.IntDef; import org.chromium.base.MathUtils; +import org.chromium.base.ResettersForTesting; +import org.chromium.base.TimeUtils; import org.chromium.base.supplier.Supplier; +import org.chromium.build.BuildConfig; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; import org.chromium.components.browser_ui.widget.animation.CancelAwareAnimatorListener; @@ -55,6 +59,8 @@ int GESTURE = 3; } + private static final long TAP_PROTECTION_DURATION_MS = 500; + private static final int ENTER_DURATION_MS = 550; private static final int EXIT_DURATION_MS = 350; private static final TimeInterpolator TRANSLATION_ENTER_INTERPOLATOR = @@ -63,6 +69,8 @@ Interpolators.EMPHASIZED_DECELERATE; private static final TimeInterpolator EXIT_INTERPOLATOR = Interpolators.EMPHASIZED_DECELERATE; + private static long sTapProtectionDurationMsForTesting; + private final PropertyModel mModel; private final Supplier<Integer> mMaxTranslationYSupplier; private final Supplier<Integer> mTopOffsetSupplier; @@ -132,6 +140,20 @@ mModel.set(TRANSLATION_Y, mModel.get(MARGIN_TOP) - mDefaultMarginTop); mModel.set(MARGIN_TOP, mDefaultMarginTop); } + if (toIndex == Position.FRONT + && (!BuildConfig.IS_FOR_TEST || sTapProtectionDurationMsForTesting > 0)) { + long startTimestamp = TimeUtils.elapsedRealtimeMillis(); + long protectionDuration = + sTapProtectionDurationMsForTesting > 0 + ? sTapProtectionDurationMsForTesting + : TAP_PROTECTION_DURATION_MS; + mModel.set(
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/components/messages/android/test/java/src/org/chromium/components/messages/MessagesTestHelper.java b/components/messages/android/test/java/src/org/chromium/components/messages/MessagesTestHelper.java
index c1bbb27cb..66a5e45 100644
--- a/components/messages/android/test/java/src/org/chromium/components/messages/MessagesTestHelper.java
+++ b/components/messages/android/test/java/src/org/chromium/components/messages/MessagesTestHelper.java
@@ -150,6 +150,14 @@
return ((SingleActionMessage) messageStateHandler).getModelForTesting();
}
+ /**
+ * Enable tap protection duration in Test environment, which is disabled by default in Test
+ * environment.
+ */
+ public static void enableTapProtectionDuration(long duration) {
+ MessageBannerMediator.setTapProtectionDurationMsForTesting(duration);
+ }
+
@NativeMethods
interface Natives {
void onMessageEnqueued(long nativeMessagesTestHelper);
Loading diff…
Original Bug Report
reported by [email protected]
Android Chrome External Navigation Bubble Tapjacking
Steps to reproduce the problem
- Make sure “com.sec.android.app.sbrowser” is installed on your Android device. (https://play.google.com/store/apps/details?id=com.sec.android.app.sbrowser)
- Open Chrome and visit - http://bugtest.unaux.com/bubble.html
- Click on the red box 3 times
- Notice, that “Samsung Browser” is triggered accidentally and inside it “http://evil.com” is opened.
Problem Description
Previously I reported issue 356038470 “Tapjacking on Intent chooser dialog box” which got marked as duplicate, so I got another way to perform browser downgrade attack using the External Navigation bubble tapjacking, which prompts user’s to open any installed apps using INTENT redirects.
If an attacker tricks user’s into clicking 2-3 times on the webpage on a specific point then the user’s will accidentally trigger the INTENT redirect and end up opening any malicious INTENTS.
Summary
Android Chrome External Navigation Bubble Tapjacking
Custom Questions
Reporter credit:
Mohit Raj (shadow2639)
Additional Data
Category: Security
Chrome Channel: Stable
Regression: N/A
References
On This Page