app_list: Fix OpenSearchResult UAF
Move search_controller_->OpenResult() call to the last because
opening a result could be self destructing via ViewClosing if
the result opens a window. This was fine when ViewClosing is an
asynchronous mojo call. It is a problem now because the mojo call
is replaced with a synchronous C++ call.
Bug: 964762
Change-Id: Ia18a4ad0b08791321d1058b73ff4b4cf36027be8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1618569
Reviewed-by: Alex Newcomer <newcomer@chromium.org>
Commit-Queue: Xiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#661409}
diff --git a/chrome/browser/ui/app_list/app_list_client_impl.cc b/chrome/browser/ui/app_list/app_list_client_impl.cc
index 472d97f..ebd5a317 100644
--- a/chrome/browser/ui/app_list/app_list_client_impl.cc
+++ b/chrome/browser/ui/app_list/app_list_client_impl.cc
@@ -107,8 +107,6 @@
if (!result)
return;
- search_controller_->OpenResult(result, event_flags);
-
// Send training signal to search controller.
search_controller_->Train(result_id,
app_list::RankingItemTypeFromSearchResult(*result));
@@ -122,6 +120,9 @@
RecordSearchResultOpenTypeHistogram(
launched_from, result->GetSearchResultType(), IsTabletMode());
+
+ // OpenResult may cause |result| to be deleted.
+ search_controller_->OpenResult(result, event_flags);
}
void AppListClientImpl::InvokeSearchResultAction(const std::string& result_id,
diff --git a/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc b/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
index 83e2365..f22a963 100644
--- a/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
+++ b/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
@@ -151,6 +151,50 @@
}
}
+// Test that OpenSearchResult that dismisses app list runs fine without
+// user-after-free.
+IN_PROC_BROWSER_TEST_F(AppListClientImplBrowserTest, OpenSearchResult) {
+ AppListClientImpl* client = AppListClientImpl::GetInstance();
+ ASSERT_TRUE(client);
+
+ // Associate |client| with the current profile.
+ client->UpdateProfile();
+
+ // Show the launcher.
+ client->ShowAppList();
+
+ AppListModelUpdater* model_updater = test::GetModelUpdater(client);
+ ASSERT_TRUE(model_updater);
+ app_list::SearchController* search_controller = client->search_controller();
+ ASSERT_TRUE(search_controller);
+
+ // Any app that opens a window to dismiss app list is good enough for this
+ // test.
+ const std::string app_title = "chromium";
+ const std::string app_result_id =
+ "chrome-extension://mgndgikekgjfcpckkfioiadnlibdjbkf/";
+
+ // Search by title and the app must present in the results.
+ model_updater->UpdateSearchBox(base::ASCIIToUTF16(app_title),
+ true /* initiated_by_user */);
+ ASSERT_TRUE(search_controller->FindSearchResult(app_result_id));
+
+ // Open the app result.
+ client->OpenSearchResult(
+ app_result_id, ui::EF_NONE,
+ ash::mojom::AppListLaunchedFrom::kLaunchedFromSearchBox,
+ ash::mojom::AppListLaunchType::kAppSearchResult, 0);
+
+ // App list should be dismissed.
+ EXPECT_FALSE(client->app_list_target_visibility());
+
+ // Needed to let AppLaunchEventLogger finish its work on worker thread.
+ // Otherwise, its |weak_factory_| is released on UI thread and causing
+ // the bound WeakPtr to fail sequence check on a worker thread.
+ // TODO(crbug.com/965065): Remove after fixing AppLaunchEventLogger.
+ content::RunAllTasksUntilIdle();
+}
+
// Test that browser launch time is recorded is recorded in preferences.
// This is important for suggested apps sorting.
IN_PROC_BROWSER_TEST_F(AppListClientImplBrowserTest,