From 984a8d0a74d76a486698fcf39afa24e3b995b9f2 Mon Sep 17 00:00:00 2001 From: Wan-Teh Chang Date: Wed, 29 Jul 2026 16:05:27 -0700 Subject: [PATCH] scale_argb: Harden entry points against large dims Reject dimensions that overflow the internal fixed-point (dimension << 16) and FixedDiv arithmetic in scale_argb entry points: - ARGBScale and ARGBScaleClip: add the missing src_width and src_height bounds so both are rejected in each direction before reaching ScaleARGB. Add a unit test covering the ARGBScale / ARGBScaleClip paths. Test: libyuv_unittest --gtest_filter=*.ARGBScaleDimensionOverflow Co-authored-by: Timothy Nikkel Bug: chromium:531172025 Change-Id: I49577c675725f7d86895ade7eaead826373bd197 --- source/scale_argb.cc | 17 +++++++++-------- unit_test/scale_argb_test.cc | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/source/scale_argb.cc b/source/scale_argb.cc index 8758d79c2..bf9275c75 100644 --- a/source/scale_argb.cc +++ b/source/scale_argb.cc @@ -697,14 +697,14 @@ static int ScaleARGB(const uint8_t* src, if (clip_x) { int64_t clipf = (int64_t)(clip_x)*dx; x += (clipf & 0xffff); - src += (clipf >> 16) * 4; - dst += clip_x * 4; + src += (ptrdiff_t)(clipf >> 16) * 4; + dst += (ptrdiff_t)clip_x * 4; } if (clip_y) { int64_t clipf = (int64_t)(clip_y)*dy; y += (clipf & 0xffff); - src += (clipf >> 16) * (ptrdiff_t)src_stride; - dst += clip_y * (ptrdiff_t)dst_stride; + src += (ptrdiff_t)(clipf >> 16) * src_stride; + dst += (ptrdiff_t)clip_y * dst_stride; } // Special case for integer step values. @@ -779,7 +779,8 @@ int ARGBScaleClip(const uint8_t* src_argb, int clip_width, int clip_height, enum FilterMode filtering) { - if (!src_argb || src_width == 0 || src_height == 0 || src_height == INT_MIN || + if (!src_argb || src_width == 0 || src_width > 32768 || src_width < -32768 || + src_height == 0 || src_height > 32768 || src_height < -32768 || !dst_argb || dst_width <= 0 || dst_height <= 0 || clip_x < 0 || clip_y < 0 || clip_width > 32768 || clip_height > 32768 || (clip_x + clip_width) > dst_width || @@ -802,9 +803,9 @@ int ARGBScale(const uint8_t* src_argb, int dst_width, int dst_height, enum FilterMode filtering) { - if (!src_argb || src_width == 0 || src_height == 0 || src_height == INT_MIN || - src_width > 32768 || src_height > 32768 || !dst_argb || dst_width <= 0 || - dst_height <= 0) { + if (!src_argb || src_width == 0 || src_width > 32768 || src_width < -32768 || + src_height == 0 || src_height > 32768 || src_height < -32768 || + !dst_argb || dst_width <= 0 || dst_height <= 0) { return -1; } return ScaleARGB(src_argb, src_stride_argb, src_width, src_height, dst_argb, diff --git a/unit_test/scale_argb_test.cc b/unit_test/scale_argb_test.cc index 3d3e36fc5..5d5b5e88b 100644 --- a/unit_test/scale_argb_test.cc +++ b/unit_test/scale_argb_test.cc @@ -9,6 +9,7 @@ */ #include +#include #include #include "../unit_test/unit_test.h" @@ -597,4 +598,37 @@ TEST_F(LibYUVScaleTest, ARGBTest4x) { free_aligned_buffer_page_end(orig_pixels); } +// ARGBScale and ARGBScaleClip reach ScaleARGB, which accepts negative width +// (horizontal mirror) and height (flip) and takes Abs()/flips to positive +// before forming (src_height - 1) << 16 and the step +// dx = FixedDiv(Abs(src_width), dst_width) -- both must fit in a signed 16.16 +// value. Verify oversize width and height are rejected in both directions. +TEST_F(LibYUVScaleTest, ARGBScaleDimensionOverflow) { + int width = 16; + int height = 40000; + align_buffer_page_end(src, width * height); + align_buffer_page_end(dst, width * height); + memset(src, 0, width * height); + + EXPECT_EQ(-1, ARGBScale(src, 16, 1, 32769, dst, 16, 1, 1, kFilterBilinear)); + EXPECT_EQ(-1, ARGBScale(src, 16, 1, -40000, dst, 16, 1, 1, kFilterBilinear)); + EXPECT_EQ(-1, ARGBScale(src, 16, 1, 40000, dst, 16, 1, 1, kFilterBilinear)); + EXPECT_EQ(-1, + ARGBScale(src, 40000, 40000, 1, dst, 16, 1, 1, kFilterBilinear)); + EXPECT_EQ(-1, + ARGBScale(src, 40000, -40000, 1, dst, 16, 1, 1, kFilterBilinear)); + + EXPECT_EQ(-1, ARGBScaleClip(src, 16, 1, 40000, dst, 16, 1, 1, 0, 0, 1, 1, + kFilterBilinear)); + EXPECT_EQ(-1, ARGBScaleClip(src, 16, 1, -40000, dst, 16, 1, 1, 0, 0, 1, 1, + kFilterBilinear)); + EXPECT_EQ(-1, ARGBScaleClip(src, 40000, 40000, 1, dst, 16, 1, 1, 0, 0, 1, 1, + kFilterBilinear)); + EXPECT_EQ(-1, ARGBScaleClip(src, 40000, -40000, 1, dst, 16, 1, 1, 0, 0, 1, 1, + kFilterBilinear)); + + free_aligned_buffer_page_end(src); + free_aligned_buffer_page_end(dst); +} + } // namespace libyuv