diff --git a/source/row_common.cc b/source/row_common.cc index f80745760..7d462dd08 100644 --- a/source/row_common.cc +++ b/source/row_common.cc @@ -3663,7 +3663,8 @@ void ARGBAffineRow_C(const uint8_t* src_argb, int x = (int)(uv[0]); int y = (int)(uv[1]); *(uint32_t*)(dst_argb) = - *(const uint32_t*)(src_argb + y * src_argb_stride + x * 4); + *(const uint32_t*)(src_argb + (ptrdiff_t)y * src_argb_stride + + (ptrdiff_t)x * 4); dst_argb += 4; uv[0] += uv_dudv[2]; uv[1] += uv_dudv[3]; diff --git a/source/scale.cc b/source/scale.cc index a78356328..a1fd63d27 100644 --- a/source/scale.cc +++ b/source/scale.cc @@ -1947,6 +1947,14 @@ int ScalePlane(const uint8_t* src, int dst_width, int dst_height, enum FilterMode filtering) { + // Reject dimensions larger than 32768 (or smaller than -32768 for height). + // This prevents FixedDiv signed integer overflows that can lead to division + // by zero/overflow crashes (SIGFPE on x86) or incorrect step calculations. + if (!src || src_width <= 0 || src_height == 0 || + src_width > 32768 || src_height < -32768 || src_height > 32768 || + !dst || dst_width <= 0 || dst_height <= 0) { + return -1; + } // Simplify filtering when possible. filtering = ScaleFilterReduce(src_width, src_height, dst_width, dst_height, filtering); @@ -2047,6 +2055,14 @@ int ScalePlane_16(const uint16_t* src, int dst_width, int dst_height, enum FilterMode filtering) { + // Reject dimensions larger than 32768 (or smaller than -32768 for height). + // This prevents FixedDiv signed integer overflows that can lead to division + // by zero/overflow crashes (SIGFPE on x86) or incorrect step calculations. + if (!src || src_width <= 0 || src_height == 0 || + src_width > 32768 || src_height < -32768 || src_height > 32768 || + !dst || dst_width <= 0 || dst_height <= 0) { + return -1; + } // Simplify filtering when possible. filtering = ScaleFilterReduce(src_width, src_height, dst_width, dst_height, filtering); @@ -2151,6 +2167,14 @@ int ScalePlane_12(const uint16_t* src, int dst_width, int dst_height, enum FilterMode filtering) { + // Reject dimensions larger than 32768 (or smaller than -32768 for height). + // This prevents FixedDiv signed integer overflows that can lead to division + // by zero/overflow crashes (SIGFPE on x86) or incorrect step calculations. + if (!src || src_width <= 0 || src_height == 0 || + src_width > 32768 || src_height < -32768 || src_height > 32768 || + !dst || dst_width <= 0 || dst_height <= 0) { + return -1; + } // Simplify filtering when possible. filtering = ScaleFilterReduce(src_width, src_height, dst_width, dst_height, filtering); diff --git a/unit_test/scale_plane_test.cc b/unit_test/scale_plane_test.cc index 7d38c4d18..b04dda10c 100644 --- a/unit_test/scale_plane_test.cc +++ b/unit_test/scale_plane_test.cc @@ -636,4 +636,53 @@ TEST_F(LibYUVScaleTest, ScalePlaneVertical_IntStrideOverflow) { delete[] dst; } +TEST_F(LibYUVScaleTest, ScalePlane_InvalidInputs) { + uint8_t src[16] = {0}; + uint8_t dst[16] = {0}; + + // NULL src/dst + EXPECT_EQ(-1, ScalePlane(nullptr, 4, 4, 4, dst, 4, 4, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane(src, 4, 4, 4, nullptr, 4, 4, 4, kFilterNone)); + + // Width/height <= 0 (except src_height which can be negative but not 0) + EXPECT_EQ(-1, ScalePlane(src, 4, 0, 4, dst, 4, 4, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane(src, 4, -1, 4, dst, 4, 4, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane(src, 4, 4, 0, dst, 4, 4, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane(src, 4, 4, 4, dst, 4, 0, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane(src, 4, 4, 4, dst, 4, -1, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane(src, 4, 4, 4, dst, 4, 4, 0, kFilterNone)); + EXPECT_EQ(-1, ScalePlane(src, 4, 4, 4, dst, 4, 4, -1, kFilterNone)); + + // Width/height too large (> 32768) + EXPECT_EQ(-1, ScalePlane(src, 4, 32769, 4, dst, 4, 4, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane(src, 4, 4, 32769, dst, 4, 4, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane(src, 4, 4, -32769, dst, 4, 4, 4, kFilterNone)); + + // Valid edge cases + EXPECT_EQ(0, ScalePlane(src, 4, 1, 1, dst, 4, 1, 1, kFilterNone)); + EXPECT_EQ(0, ScalePlane(src, 4, 1, -1, dst, 4, 1, 1, kFilterNone)); +} + +TEST_F(LibYUVScaleTest, ScalePlane_16_InvalidInputs) { + uint16_t src[16] = {0}; + uint16_t dst[16] = {0}; + + EXPECT_EQ(-1, ScalePlane_16(nullptr, 4, 4, 4, dst, 4, 4, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane_16(src, 4, 4, 4, nullptr, 4, 4, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane_16(src, 4, 0, 4, dst, 4, 4, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane_16(src, 4, 32769, 4, dst, 4, 4, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane_16(src, 4, 4, -32769, dst, 4, 4, 4, kFilterNone)); +} + +TEST_F(LibYUVScaleTest, ScalePlane_12_InvalidInputs) { + uint16_t src[16] = {0}; + uint16_t dst[16] = {0}; + + EXPECT_EQ(-1, ScalePlane_12(nullptr, 4, 4, 4, dst, 4, 4, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane_12(src, 4, 4, 4, nullptr, 4, 4, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane_12(src, 4, 0, 4, dst, 4, 4, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane_12(src, 4, 32769, 4, dst, 4, 4, 4, kFilterNone)); + EXPECT_EQ(-1, ScalePlane_12(src, 4, 4, -32769, dst, 4, 4, 4, kFilterNone)); +} + } // namespace libyuv