The overlay viewport end coordinates are computed from the viewport
origin and dimensions using 32-bit unsigned arithmetic. Large input
values can cause these calculations to wrap around before the resulting
coordinates are passed to SetOverlayViewPort().

SetOverlayViewPort() packs the viewport coordinates into 16-bit
register fields. The X coordinates are additionally adjusted by +2
and +1 before being written. Validate the coordinate calculations
for 32-bit wraparound and ensure that the adjusted coordinates fit
within their 16-bit register fields before calling
SetOverlayViewPort().

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Danila Chernetsov <[email protected]>
---
 drivers/video/fbdev/kyro/fbdev.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/drivers/video/fbdev/kyro/fbdev.c b/drivers/video/fbdev/kyro/fbdev.c
index d756b3603fa6..133c91716c49 100644
--- a/drivers/video/fbdev/kyro/fbdev.c
+++ b/drivers/video/fbdev/kyro/fbdev.c
@@ -369,6 +369,9 @@ static int kyro_dev_overlay_create(u32 ulWidth,
 
 static int kyro_dev_overlay_viewport_set(u32 x, u32 y, u32 ulWidth, u32 
ulHeight)
 {
+       u32 right;
+       u32 bottom;
+
        if (deviceInfo.ulOverlayOffset == 0)
                /* probably haven't called CreateOverlay yet */
                return -EINVAL;
@@ -378,11 +381,30 @@ static int kyro_dev_overlay_viewport_set(u32 x, u32 y, 
u32 ulWidth, u32 ulHeight
            (x < 2 && ulWidth + 2 == 0))
                return -EINVAL;
 
+       /*
+        * SetOverlayViewPort() adjusts X coordinates by +2 (left) and +1
+        * (right) before packing them into 16-bit register fields.
+        */
+       if (x > U16_MAX - 2 || y > U16_MAX)
+               return -EINVAL;
+
+       right = x + ulWidth;
+       bottom = y + ulHeight;
+
+       if (right < x || bottom < y)
+               return -EINVAL;
+
+       right--;
+       bottom--;
+
+       if (right > U16_MAX - 1 || bottom > U16_MAX)
+               return -EINVAL;
+
        /* Stop Ramdac Output */
        DisableRamdacOutput(deviceInfo.pSTGReg);
 
        SetOverlayViewPort(deviceInfo.pSTGReg,
-                          x, y, x + ulWidth - 1, y + ulHeight - 1);
+                       x, y, right, bottom);
 
        EnableOverlayPlane(deviceInfo.pSTGReg);
        /* Start Ramdac Output */
-- 
2.25.1

Reply via email to