Chrome · Input
CVE-2026-14140
Logic Error in Input
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifcontent/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java |
modified |
Files Changed
content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
Patch
From c03d94e511860de8f90c092b28d7253f72a35dac Mon Sep 17 00:00:00 2001 From: Aaron Moss <[email protected]> Date: Thu, 28 May 2026 15:30:27 -0700 Subject: [PATCH] [a11y] Clamp cursor-following to viewport Ensure that cursor-following cannot be used to scroll outside the WebView. Bug: 514072607 Change-Id: I82729ae0837f12f91620adc599c3eff86ff9ef3d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7859114 Reviewed-by: Bo Liu <[email protected]> Commit-Queue: Aaron Moss <[email protected]> Cr-Commit-Position: refs/heads/main@{#1638003} --- diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java index 17ade2a..4adbbbe6 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java @@ -1593,8 +1593,10 @@ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA && Build.VERSION.SDK_INT_FULL >= Build.VERSION_CODES_FULL.BAKLAVA_1 && ContentFeatureList.sAccessibilityMagnificationFollowsFocus.isEnabled()) { - Rect nodePix = fromCssToDevicePix(nodeLeftDip, nodeTopDip, nodeRightDip, nodeBottomDip); - if (!nodePix.isEmpty()) { + Rect nodePix = + fromViewportDipToViewContentPix( + nodeLeftDip, nodeTopDip, nodeRightDip, nodeBottomDip, containerView); + if (nodePix != null && !nodePix.isEmpty()) { containerView.requestRectangleOnScreen( nodePix, /* immediate= */ false, @@ -1768,23 +1770,49 @@ } /** - * Converts bounds from CSS pixels to device pixels, accounting for page scale, device scale, - * and content Y offset. + * Converts bounds from device-independent pixels in viewport space to device pixels in + * view-content space, clamped to the visible rectangle of the container view. * - * @param left left X coordinate in CSS pixels - * @param top top Y coordinate in CSS pixels - * @param right right X coordinate in CSS pixels - * @param bottom bottom Y coordinate in CSS pixels - * @return {@link Rect} with the device pixel equivalents of the provided coordinates. + * @param left left X coordinate in Blink viewport-relative DIPs + * @param top top Y coordinate in Blink viewport-relative DIPs + * @param right right X coordinate in Blink viewport-relative DIPs + * @param bottom bottom Y coordinate in Blink viewport-relative DIPs + * @param containerView view to clamp coordinates to + * @return {@link Rect} with the device pixel equivalents of the provided coordinates in + * view-content space, clamped to the visible portion of the container view, or null if the + * bounds do not intersect the visible portion of the container view. */ - private Rect fromCssToDevicePix(float left, float top, float right, float bottom) { + private @Nullable Rect fromViewportDipToViewContentPix( + float left, float top, float right, float bottom, View containerView) { + // Get container view's visible area in view-content coordinates. + // Chrome team trial-and-error has determined that (inconsistently with other View + // documentation), "top left" in the View#getLocalVisibleRect is in content space rather + // than viewport space for the view. + Rect visibleRect = new Rect(); + if (!containerView.getLocalVisibleRect(visibleRect)) { + return null; // The container is entirely offscreen. + } + + // Scale bounds to device pixels in Android view coordinates. RenderCoordinatesImpl coords = mWebContents.getRenderCoordinates(); - final int topOffset = coords.getContentOffsetYPixInt(); - return new Rect( - (int) coords.fromLocalCssToPix(left), - ((int) coords.fromLocalCssToPix(top)) + topOffset, - (int) coords.fromLocalCssToPix(right), - ((int) coords.fromLocalCssToPix(bottom)) + topOffset); + final int topOffset = coords.getContentOffsetYPixInt(); // Offset for Chrome address bar. + final float scale = coords.getDeviceScaleFactor(); + Rect bounds = + new Rect( + (int) (left * scale), + (int) (top * scale) + topOffset, + (int) (right * scale), + (int) (bottom * scale) + topOffset); + + // Translate bounds to view-content coordinates by adding Android view scroll. This is a + // no-op for Chrome (which always reports zero scroll), but will adjust for WebView scroll. + bounds.offset(containerView.getScrollX(), containerView.getScrollY()); + + // Clamp to visible area and return clamped bounds in view-content coordinates. + if (!bounds.intersect(visibleRect)) { + return null; // The bounds are entirely offscreen. + } + return bounds; } /** @@ -1810,23 +1838,26 @@ // Convert caret bounds from CSS pixels to device pixels relative to root view. var caretCss = cursorAnchorInfo.insertionMarker; Rect caretPix = - fromCssToDevicePix( + fromViewportDipToViewContentPix( caretCss.x, caretCss.y, caretCss.x + caretCss.width, - caretCss.y + caretCss.height); + caretCss.y + caretCss.height, + containerView); - // Note: `SDK_INT_FULL` added in `BAKLAVA`, hence two checks. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA - && Build.VERSION.SDK_INT_FULL >= Build.VERSION_CODES_FULL.BAKLAVA_1) { - containerView.requestRectangleOnScreen( - caretPix, - /* immediate= */ false, - View.RECTANGLE_ON_SCREEN_REQUEST_SOURCE_TEXT_CURSOR); - } else { - // Fallback to previous API (where `requestRectangleOnScreen()` calls are assumed - // to come from text cursor moves). - containerView.requestRectangleOnScreen(caretPix); + if (caretPix != null) { + // Note: `SDK_INT_FULL` added in `BAKLAVA`, hence two checks. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA + && Build.VERSION.SDK_INT_FULL >= Build.VERSION_CODES_FULL.BAKLAVA_1) { + containerView.requestRectangleOnScreen( + caretPix, + /* immediate= */ false, + View.RECTANGLE_ON_SCREEN_REQUEST_SOURCE_TEXT_CURSOR); + } else { + // Fallback to previous API (where `requestRectangleOnScreen()` calls are + // assumed to come from text cursor moves). + containerView.requestRectangleOnScreen(caretPix); + } } } }
Loading diff…
Original Bug Report
The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.
References
On This Page