CVE-2026-113008
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/ui/autofill/at_memory_suggestion_controller.cc |
modified | |
ifchrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc |
modified | |
GetAnchorFrameTokenchrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc |
modified | |
ifchrome/browser/ui/autofill/autofill_popup_controller_impl.cc |
modified | |
switchcomponents/autofill/core/browser/ui/autofill_external_delegate.cc |
modified |
Files Changed
chrome/browser/ui/autofill/autofill_suggestion_controller_test_base.hcomponents/autofill/core/browser/foundations/autofill_client.ccchrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_unittest.ccchrome/browser/ui/autofill/popup_controller_common.hchrome/browser/ui/autofill/chrome_autofill_client.cccomponents/autofill/core/browser/ui/autofill_external_delegate_unittest.ccchrome/browser/ui/autofill/autofill_popup_controller_impl_mac_unittest.mmcomponents/autofill/ios/browser/autofill_agent_unittest.mmcomponents/autofill/core/browser/ui/autofill_external_delegate.hchrome/browser/ui/autofill/autofill_suggestion_controller.cccomponents/autofill/core/browser/ui/payments/omnibox_autofill_delegate_unittest.cccomponents/autofill/core/browser/ui/mock_autofill_suggestion_delegate.hchrome/browser/ui/autofill/popup_controller_common.cccomponents/autofill/core/browser/ui/test_autofill_external_delegate.ccchrome/browser/ui/android/autofill/at_memory_bottom_sheet_bridge_unittest.cccomponents/password_manager/core/browser/password_autofill_manager.hchrome/browser/ui/autofill/autofill_suggestion_controller_test_base.cccomponents/password_manager/core/browser/password_manual_fallback_flow.hcomponents/autofill/core/browser/ui/autofill_external_delegate.cccomponents/autofill/core/browser/foundations/autofill_client.hchrome/browser/ui/passwords/password_generation_popup_controller_impl.ccchrome/browser/ui/autofill/autofill_popup_controller_impl.ccchrome/browser/ui/autofill/at_memory_suggestion_controller_unittest.cccomponents/password_manager/core/browser/password_autofill_manager.cccomponents/autofill/core/browser/ui/payments/omnibox_autofill_delegate.hchrome/browser/ui/autofill/autofill_suggestion_controller_unittest.cccomponents/autofill/core/browser/ui/payments/omnibox_autofill_delegate.ccchrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cccomponents/autofill/core/browser/ui/test_autofill_external_delegate.hchrome/browser/ui/autofill/at_memory_suggestion_controller.cccomponents/autofill/core/browser/ui/autofill_suggestion_delegate.hcomponents/autofill/ios/browser/autofill_agent.mmcomponents/password_manager/core/browser/password_manual_fallback_flow_unittest.ccchrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.ccchrome/browser/ui/autofill/chrome_autofill_client_interactive_uitest.cccomponents/password_manager/core/browser/password_manual_fallback_flow.cc
Patch
From bf1633dbb56cf28aee80ccd4d9eba3549c409415 Mon Sep 17 00:00:00 2001 From: Christoph Schwering <[email protected]> Date: Sat, 19 Sep 2026 15:48:40 -0700 Subject: [PATCH] [Autofill] Pass FormGlobalId and FieldGlobalId to suggestion delegates This CL replaces Popup{ControllerCommon,OpenArgs}::anchor_frame_token with Popup{ControllerCommon,OpenArgs}::form_id Popup{ControllerCommon,OpenArgs}::field_id and passes them to AutofillSuggestionDelegate::Did{Accept,Select}Suggestion(). The CL is a no-op: The role of `anchor_frame_token` is now filled by `field_id.frame_token`. And the parameters are not used yet in Did{Accept,Select}Suggestion(). This is in preparation for crrev.com/c/8422781. TAG=agy CONV=87860559-e016-44b4-81dd-8635b7409a43 Bug: 563089510, 553128833 Change-Id: If311adbb6f47ccd685eec72ebcb73c5cc04af0e1 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8419078 Reviewed-by: Mohamed Amir Yosef <[email protected]> Commit-Queue: Christoph Schwering <[email protected]> Cr-Commit-Position: refs/heads/main@{#1701425} --- diff --git a/chrome/browser/ui/autofill/at_memory_suggestion_controller.cc b/chrome/browser/ui/autofill/at_memory_suggestion_controller.cc index 01606b6..859fef4 100644 --- a/chrome/browser/ui/autofill/at_memory_suggestion_controller.cc +++ b/chrome/browser/ui/autofill/at_memory_suggestion_controller.cc @@ -92,8 +92,10 @@ Suggestion suggestion = suggestions_[index]; if (delegate_) { delegate_->DidAcceptSuggestion( - suggestion, AutofillSuggestionDelegate::SuggestionMetadata{ - .multi_index = {static_cast<size_t>(index)}}); + suggestion, + AutofillSuggestionDelegate::SuggestionMetadata{ + .multi_index = {static_cast<size_t>(index)}}, + controller_common_.form_id, controller_common_.field_id); } } @@ -171,7 +173,7 @@ const LocalFrameToken& AtMemorySuggestionController::GetAnchorFrameToken() const { - return controller_common_.anchor_frame_token; + return controller_common_.field_id.frame_token; } void AtMemorySuggestionController::HideViewAndDie() { @@ -290,9 +292,11 @@ Suggestion suggestion = parent_suggestion.children[child_position]; if (delegate_) { delegate_->DidAcceptSuggestion( - suggestion, AutofillSuggestionDelegate::SuggestionMetadata{ - .multi_index = {static_cast<size_t>(parent_position), - static_cast<size_t>(child_position)}}); + suggestion, + AutofillSuggestionDelegate::SuggestionMetadata{ + .multi_index = {static_cast<size_t>(parent_position), + static_cast<size_t>(child_position)}}, + controller_common_.form_id, controller_common_.field_id); } } diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc index e4b856a..ff83f370 100644 --- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc @@ -593,8 +593,10 @@ mouse_metrics_recorder_->RecordAccepted(suggestions_filling_product_); } delegate_->DidAcceptSuggestion( - suggestion, AutofillSuggestionDelegate::SuggestionMetadata{ - .multi_index = {static_cast<size_t>(index)}}); + suggestion, + AutofillSuggestionDelegate::SuggestionMetadata{ + .multi_index = {static_cast<size_t>(index)}}, + controller_common_.form_id, controller_common_.field_id); } bool AutofillKeyboardAccessoryControllerImpl::RemoveSuggestion(int index) { @@ -741,7 +743,7 @@ } content::RenderFrameHost* rfh = FindRenderFrameHostByToken( - *web_contents_, controller_common_.anchor_frame_token); + *web_contents_, controller_common_.field_id.frame_token); if (!rfh) { Hide(SuggestionHidingReason::kNoFrameHasFocus); return; @@ -855,7 +857,7 @@ const LocalFrameToken& AutofillKeyboardAccessoryControllerImpl::GetAnchorFrameToken() const { - return controller_common_.anchor_frame_token; + return controller_common_.field_id.frame_token; } bool AutofillKeyboardAccessoryControllerImpl::HasSuggestions() const { @@ -1029,7 +1031,8 @@ if (mouse_metrics_recorder_) { mouse_metrics_recorder_->RecordSelected(suggestions_filling_product_); } - delegate_->DidSelectSuggestion(suggestion); + delegate_->DidSelectSuggestion(suggestion, controller_common_.form_id, + controller_common_.field_id); } else { delegate_->ClearPreviewedForm(); } diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc index 9be4b1b..60a24350 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc @@ -331,7 +331,7 @@ } content::RenderFrameHost* rfh = FindRenderFrameHostByToken( - *web_contents_, controller_common_.anchor_frame_token); + *web_contents_, controller_common_.field_id.frame_token); if (!rfh) { Hide(SuggestionHidingReason::kNoFrameHasFocus); return; @@ -468,7 +468,7 @@ const LocalFrameToken& AutofillPopupControllerImpl::GetAnchorFrameToken() const { - return controller_common_.anchor_frame_token; + return controller_common_.field_id.frame_token; } bool AutofillPopupControllerImpl::IsViewVisibilityAcceptingThresholdEnabled() @@ -571,7 +571,9 @@ base::UmaHistogramEnumeration("Autofill.SuggestionAccepted.Method", accept_method); - delegate_->DidAcceptSuggestion(suggestion, GetSuggestionMetadata(index)); + delegate_->DidAcceptSuggestion(suggestion, GetSuggestionMetadata(index), + controller_common_.form_id, + controller_common_.field_id); } AutofillSuggestionDelegate::SuggestionUiMetadata @@ -930,7 +932,9 @@ } any_suggestion_selected_ = true; - delegate_->DidSelectSuggestion(GetSuggestionAt(index)); + delegate_->DidSelectSuggestion(GetSuggestionAt(index), + controller_common_.form_id, + controller_common_.field_id); } void AutofillPopupControllerImpl::UnselectSuggestion() { diff --git a/chrome/browser/ui/autofill/autofill_suggestion_controller.cc b/chrome/browser/ui/autofill/autofill_suggestion_controller.cc index 5ddaf13..641314c 100644 --- a/chrome/browser/ui/autofill/autofill_suggestion_controller.cc +++ b/chrome/browser/ui/autofill/autofill_suggestion_controller.cc @@ -78,7 +78,7 @@ int32_t form_control_ax_id, AutofillSuggestionTriggerSource trigger_source) { if (previous && previous->MayRecycle(delegate, web_contents, - controller_common.anchor_frame_token, + controller_common.field_id.frame_token, trigger_source)) { previous->Recycle(std::move(controller_common), form_control_ax_id); return previous; diff --git a/chrome/browser/ui/autofill/autofill_suggestion_controller_test_base.cc b/chrome/browser/ui/autofill/autofill_suggestion_controller_test_base.cc index dd51e99..1a1e295 100644 --- a/chrome/browser/ui/autofill/autofill_suggestion_controller_test_base.cc +++ b/chrome/browser/ui/autofill/autofill_suggestion_controller_test_base.cc @@ -50,7 +50,8 @@ : AutofillSuggestionControllerForTestBase( external_delegate, web_contents, - PopupControllerCommon(frame_token, + PopupControllerCommon(FormGlobalId(frame_token, FormRendererId()), + FieldGlobalId(frame_token, FieldRendererId()), element_bounds, base::i18n::UNKNOWN_DIRECTION)) {} diff --git a/chrome/browser/ui/autofill/autofill_suggestion_controller_test_base.h b/chrome/browser/ui/autofill/autofill_suggestion_controller_test_base.h index 882913f..d037578 100644 --- a/chrome/browser/ui/autofill/autofill_suggestion_controller_test_base.h +++ b/chrome/browser/ui/autofill/autofill_suggestion_controller_test_base.h @@ -272,11 +272,16 @@ const AutofillSuggestionDelegate::SuggestionUiMetadata&), (override)); MOCK_METHOD(void, OnSuggestionsHidden, (SuggestionHidingReason), (override)); - MOCK_METHOD(void, DidSelectSuggestion, (const Suggestion&), (override)); + MOCK_METHOD(void, + DidSelectSuggestion, + (const Suggestion&, const FormGlobalId&, const FieldGlobalId&), + (override)); MOCK_METHOD(void, DidAcceptSuggestion, (const Suggestion&, - const AutofillSuggestionDelegate::SuggestionMetadata&), + const AutofillSuggestionDelegate::SuggestionMetadata&, + const FormGlobalId&, + const FieldGlobalId&), (override)); MOCK_METHOD(bool, RemoveSuggestion, (const Suggestion&), (override)); MOCK_METHOD(void, OnTabSelected, (TabbedPaneTabType), (override)); diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc index 7ac6d9aa..b12118cc 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.cc +++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc @@ -1445,7 +1445,7 @@ suggestion_controller_ = AutofillSuggestionController::GetOrCreate( suggestion_controller_, delegate, web_contents(), PopupControllerCommon( - open_args.anchor_frame_token, element_bounds_in_screen_space, + open_args.form_id, open_args.field_id, element_bounds_in_screen_space, open_args.text_direction, open_args.anchor_type, open_args.show_tabbed_popup, open_args.prefer_prev_arrow_side_on_suggestions_update), diff --git a/chrome/browser/ui/autofill/popup_controller_common.cc b/chrome/browser/ui/autofill/popup_controller_common.cc index fd4393d..1497f1a5 100644 --- a/chrome/browser/ui/autofill/popup_controller_common.cc +++ b/chrome/browser/ui/autofill/popup_controller_common.cc @@ -11,13 +11,15 @@ namespace autofill { PopupControllerCommon::PopupControllerCommon( - LocalFrameToken anchor_frame_token, + FormGlobalId form_id, + FieldGlobalId field_id, gfx::RectF element_bounds, base::i18n::TextDirection text_direction, PopupAnchorType anchor_type, bool show_tabbed_popup, bool prefer_prev_arrow_side_on_suggestions_update) - : anchor_frame_token(std::move(anchor_frame_token)), + : form_id(std::move(form_id)), + field_id(std::move(field_id)), element_bounds(std::move(element_bounds)), text_direction(text_direction), anchor_type(anchor_type), diff --git a/chrome/browser/ui/autofill/popup_controller_common.h b/chrome/browser/ui/autofill/popup_controller_common.h index 85050ea8..3fc2a636 100644 --- a/chrome/browser/ui/autofill/popup_controller_common.h +++ b/chrome/browser/ui/autofill/popup_controller_common.h @@ -18,7 +18,8 @@ struct PopupControllerCommon { public: PopupControllerCommon( - LocalFrameToken anchor_frame_token, + FormGlobalId form_id, + FieldGlobalId field_id, gfx::RectF element_bounds, base::i18n::TextDirection text_direction, PopupAnchorType anchor_type = PopupAnchorType::kField, @@ -31,9 +32,9 @@ ~PopupControllerCommon(); - // The frame in which the popup is anchored. Typically this is the frame of - // the field on which the user triggered Autofill. - LocalFrameToken anchor_frame_token; + // The form and field in which the popup is anchored. + FormGlobalId form_id; + FieldGlobalId field_id; // The bounds of the DOM element that is the focus of the popup. // These coordinates are in screen space. diff --git a/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc b/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc index cd519b8e..3e4463c 100644 --- a/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc +++ b/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc @@ -139,7 +139,10 @@ autofill::FormControlType::kInputPassword)), generation_element_id_(ui_data.generation_element_id), max_length_(ui_data.max_length), - controller_common_(autofill::LocalFrameToken(*frame->GetFrameToken()), + controller_common_(ui_data.form_data.global_id(), + autofill::FieldGlobalId( + autofill::LocalFrameToken(*frame->GetFrameToken()), + ui_data.generation_element_id), bounds, ui_data.text_direction), state_(kOfferGeneration), diff --git a/components/autofill/core/browser/foundations/autofill_client.cc b/components/autofill/core/browser/foundations/autofill_client.cc index 447d2aa..aaa3881 100644 --- a/components/autofill/core/browser/foundations/autofill_client.cc +++ b/components/autofill/core/browser/foundations/autofill_client.cc @@ -46,7 +46,8 @@ AutofillClient::PopupOpenArgs::PopupOpenArgs() = default; AutofillClient::PopupOpenArgs::PopupOpenArgs( - LocalFrameToken anchor_frame_token, + FormGlobalId form_id, + FieldGlobalId field_id, const gfx::RectF& element_bounds, base::i18n::TextDirection text_direction, std::vector<Suggestion> suggestions, @@ -56,7 +57,8 @@ bool show_tabbed_popup, bool prefer_prev_arrow_side_on_suggestions_update, std::u16string search_bar_initial_value) - : anchor_frame_token(std::move(anchor_frame_token)), + : form_id(std::move(form_id)), + field_id(std::move(field_id)), element_bounds(element_bounds), text_direction(text_direction), suggestions(std::move(suggestions)), diff --git a/components/autofill/core/browser/foundations/autofill_client.h b/components/autofill/core/browser/foundations/autofill_client.h index 9874a25..ad42d57 100644 --- a/components/autofill/core/browser/foundations/autofill_client.h +++ b/components/autofill/core/browser/foundations/autofill_client.h @@ -289,7 +289,8 @@ // Required arguments to create a dropdown showing autofill suggestions. struct PopupOpenArgs { PopupOpenArgs(); - PopupOpenArgs(LocalFrameToken anchor_frame_token, + PopupOpenArgs(FormGlobalId form_id, + FieldGlobalId field_id, const gfx::RectF& element_bounds, base::i18n::TextDirection text_direction, std::vector<Suggestion> suggestions, @@ -304,9 +305,9 @@ PopupOpenArgs& operator=(const PopupOpenArgs&); PopupOpenArgs& operator=(PopupOpenArgs&&); ~PopupOpenArgs(); - // The frame which the popup is anchored to. Typically this is the frame of - // the field on which the user triggered Autofill. - LocalFrameToken anchor_frame_token; + // The form and field to which the popup is anchored. + FormGlobalId form_id; + FieldGlobalId field_id; // TODO(crbug.com/340817507): Update this member name since bounds can now // refer to the caret bounds and elements gives the idea of HTML elements // only. diff --git a/components/autofill/core/browser/ui/autofill_external_delegate.cc b/components/autofill/core/browser/ui/autofill_external_delegate.cc index 7291464..316d62e8 100644 --- a/components/autofill/core/browser/ui/autofill_external_delegate.cc +++ b/components/autofill/core/browser/ui/autofill_external_delegate.cc @@ -607,7 +607,7 @@ #endif AutofillClient::PopupOpenArgs open_args( - trigger_field->global_id().frame_token, + last_query_.form_id, trigger_field->global_id(), should_use_caret_bounds ? gfx::RectF(caret_bounds_) : trigger_field->bounds(), trigger_field->text_direction(), std::move(suggestions), trigger_source_, @@ -744,7 +744,9 @@ } void AutofillExternalDelegate::DidSelectSuggestion( - const Suggestion& suggestion) { + const Suggestion& suggestion, + const FormGlobalId& form_id, + const FieldGlobalId& field_id) { ClearPreviewedForm(); switch (suggestion.type) { @@ -906,7 +908,9 @@ void AutofillExternalDelegate::DidAcceptSuggestion( const Suggestion& suggestion, - const SuggestionMetadata& metadata) { + const SuggestionMetadata& metadata, + const FormGlobalId& form_id, + const FieldGlobalId& field_id) { CHECK(suggestion.IsAcceptable()); // TODO(crbug.com/552871965): Extract the logging here to a separate function. base::UmaHistogramEnumeration("Autofill.Suggestions.AcceptedType", diff --git a/components/autofill/core/browser/ui/autofill_external_delegate.h b/components/autofill/core/browser/ui/autofill_external_delegate.h index 2ea75fb..0f8662a 100644 --- a/components/autofill/core/browser/ui/autofill_external_delegate.h +++ b/components/autofill/core/browser/ui/autofill_external_delegate.h @@ -79,9 +79,13 @@ bool OnFilterChanged(const std::u16string& filter) override; bool OnSearchSubmitted(const std::u16string& filter) override; bool IsSearching() const override; - void DidSelectSuggestion(const Suggestion& suggestion) override; + void DidSelectSuggestion(const Suggestion& suggestion, + const FormGlobalId& form_id, + const FieldGlobalId& field_id) override; void DidAcceptSuggestion(const Suggestion& suggestion, - const SuggestionMetadata& metadata) override; + const SuggestionMetadata& metadata, + const FormGlobalId& form_id, + const FieldGlobalId& field_id) override; bool RemoveSuggestion(const Suggestion& suggestion) override; void ClearPreviewedForm() override; diff --git a/components/autofill/core/browser/ui/autofill_suggestion_delegate.h b/components/autofill/core/browser/ui/autofill_suggestion_delegate.h index ee33d84e..6e4c396 100644 --- a/components/autofill/core/browser/ui/autofill_suggestion_delegate.h +++ b/components/autofill/core/browser/ui/autofill_suggestion_delegate.h @@ -103,11 +103,15 @@ // Called when the autofill `suggestion` has been temporarily selected (e.g., ... (file diff truncated)
Regression Test / PoC
diff --git a/chrome/browser/ui/android/autofill/at_memory_bottom_sheet_bridge_unittest.cc b/chrome/browser/ui/android/autofill/at_memory_bottom_sheet_bridge_unittest.cc
index f09f169..4e590763 100644
--- a/chrome/browser/ui/android/autofill/at_memory_bottom_sheet_bridge_unittest.cc
+++ b/chrome/browser/ui/android/autofill/at_memory_bottom_sheet_bridge_unittest.cc
@@ -9,6 +9,7 @@
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/ui/autofill/at_memory_suggestion_controller.h"
#include "chrome/test/base/testing_profile.h"
+#include "components/autofill/core/common/autofill_test_util.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,7 +24,8 @@
: AtMemorySuggestionController(
nullptr,
nullptr,
- PopupControllerCommon({},
+ PopupControllerCommon(test::MakeFormGlobalId(),
+ test::MakeFieldGlobalId(),
gfx::RectF(),
base::i18n::UNKNOWN_DIRECTION)) {}
MOCK_METHOD(void, OnDismissed, (), (override));
@@ -39,6 +41,7 @@
}
content::BrowserTaskEnvironment task_environment_;
+ autofill::test::AutofillUnitTestEnvironment autofill_environment_;
TestingProfile profile_;
std::unique_ptr<ui::WindowAndroid::ScopedWindowAndroidForTesting> window_;
std::unique_ptr<MockAtMemorySuggestionController> controller_;
diff --git a/chrome/browser/ui/autofill/at_memory_suggestion_controller_unittest.cc b/chrome/browser/ui/autofill/at_memory_suggestion_controller_unittest.cc
index 659c034..3095f10a 100644
--- a/chrome/browser/ui/autofill/at_memory_suggestion_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/at_memory_suggestion_controller_unittest.cc
@@ -13,6 +13,7 @@
#include "components/autofill/core/browser/suggestions/suggestion_hiding_reason.h"
#include "components/autofill/core/browser/suggestions/suggestion_type.h"
#include "components/autofill/core/browser/ui/mock_autofill_suggestion_delegate.h"
+#include "components/autofill/core/common/autofill_test_util.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_renderer_host.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -26,6 +27,16 @@
using ::testing::ElementsAreArray;
using ::testing::Eq;
+FormGlobalId MakeFormGlobalId(AutofillManager& manager) {
+ return FormGlobalId(manager.driver().GetFrameToken(),
+ test::MakeFormRendererId());
+}
+
+FieldGlobalId MakeFieldGlobalId(AutofillManager& manager) {
+ return FieldGlobalId(manager.driver().GetFrameToken(),
+ test::MakeFieldRendererId());
+}
+
class MockAtMemoryBottomSheetBridge : public AtMemoryBottomSheetBridge {
public:
explicit MockAtMemoryBottomSheetBridge(
@@ -49,7 +60,8 @@
if (!suggestion_controller_) {
auto* controller = new AtMemorySuggestionController(
manager.external_delegate().GetWeakPtrForTest(), &GetWebContents(),
- PopupControllerCommon(manager.driver().GetFrameToken(), {},
+ PopupControllerCommon(MakeFormGlobalId(manager),
+ MakeFieldGlobalId(manager), {},
base::i18n::UNKNOWN_DIRECTION));
suggestion_controller_ = controller->GetWeakPtr();
}
@@ -167,7 +179,8 @@
AutofillSuggestionController::GetOrCreate(
/*previous=*/nullptr,
manager1.external_delegate().GetWeakPtrForTest(), web_contents(),
- PopupControllerCommon(manager1.driver().GetFrameToken(), {},
+ PopupControllerCommon(MakeFormGlobalId(manager1),
+ MakeFieldGlobalId(manager1), {},
base::i18n::UNKNOWN_DIRECTION),
/*form_control_ax_id=*/0,
AutofillSuggestionTriggerSource::kAtMemoryDoubleCtrl);
@@ -184,7 +197,8 @@
AutofillSuggestionController::GetOrCreate(
controller1_weak, manager2.external_delegate().GetWeakPtrForTest(),
web_contents(),
- PopupControllerCommon(manager2.driver().GetFrameToken(), {},
+ PopupControllerCommon(MakeFormGlobalId(manager2),
+ MakeFieldGlobalId(manager2), {},
base::i18n::UNKNOWN_DIRECTION),
/*form_control_ax_id=*/0,
AutofillSuggestionTriggerSource::kAtMemoryDoubleCtrl);
@@ -203,7 +217,8 @@
AutofillSuggestionController::GetOrCreate(
/*previous=*/nullptr,
manager1.external_delegate().GetWeakPtrForTest(), web_contents(),
- PopupControllerCommon(manager1.driver().GetFrameToken(), {},
+ PopupControllerCommon(MakeFormGlobalId(manager1),
+ MakeFieldGlobalId(manager1), {},
base::i18n::UNKNOWN_DIRECTION),
/*form_control_ax_id=*/0,
AutofillSuggestionTriggerSource::kAtMemoryDoubleCtrl);
@@ -212,7 +227,8 @@
AutofillSuggestionController::GetOrCreate(
controller1_weak, manager1.external_delegate().GetWeakPtrForTest(),
web_contents(),
- PopupControllerCommon(manager1.driver().GetFrameToken(), {},
+ PopupControllerCommon(MakeFormGlobalId(manager1),
+ MakeFieldGlobalId(manager1), {},
base::i18n::UNKNOWN_DIRECTION),
/*form_control_ax_id=*/0,
AutofillSuggestionTriggerSource::kAtMemoryDoubleCtrl);
@@ -236,7 +252,8 @@
suggestions[0],
testing::Field(
&AutofillSuggestionDelegate::SuggestionMetadata::multi_index,
- std::vector<size_t>{0})));
+ std::vector<size_t>{0}),
+ _, _));
client().suggestion_controller(manager()).AcceptSuggestion(
/*index=*/0, AutofillMetrics::SuggestionAcceptedMethod::kTap);
@@ -248,7 +265,9 @@
testing::NiceMock<MockAutofillSuggestionDelegate> mock_delegate;
auto* controller = new AtMemorySuggestionController(
mock_delegate.GetWeakPtr(), web_contents(),
- PopupControllerCommon({}, gfx::RectF(), base::i18n::UNKNOWN_DIRECTION));
+ PopupControllerCommon(MakeFormGlobalId(manager()),
+ MakeFieldGlobalId(manager()), gfx::RectF(),
+ base::i18n::UNKNOWN_DIRECTION));
auto mock_bridge =
std::make_unique<MockAtMemoryBottomSheetBridge>(controller);
@@ -281,7 +300,8 @@
parent,
testing::Field(
&AutofillSuggestionDelegate::SuggestionMetadata::multi_index,
- std::vector<size_t>{0})));
+ std::vector<size_t>{0}),
+ _, _));
controller->OnSuggestionAccepted(0);
// OnChildSuggestionsShown routes to OnSuggestionsShown with parent metadata.
@@ -296,7 +316,8 @@
child,
testing::Field(
&AutofillSuggestionDelegate::SuggestionMetadata::multi_index,
- std::vector<size_t>{0, 0})));
+ std::vector<size_t>{0, 0}),
+ _, _));
controller->OnChildSuggestionSelected(0, 0);
// IsSearching routes to IsSearching on delegate.
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_unittest.cc b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_unittest.cc
index 6905193..bd6a32e 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_unittest.cc
@@ -1186,8 +1186,11 @@
1)));
client().suggestion_controller(manager()).Recycle(
- PopupControllerCommon(manager().driver().GetFrameToken(), {},
- base::i18n::UNKNOWN_DIRECTION),
+ PopupControllerCommon(FormGlobalId(manager().driver().GetFrameToken(),
+ test::MakeFormRendererId()),
+ FieldGlobalId(manager().driver().GetFrameToken(),
+ test::MakeFieldRendererId()),
+ {}, base::i18n::UNKNOWN_DIRECTION),
/*form_control_ax_id=*/0);
ShowSuggestions(manager(), {test::CreateAutofillSuggestion(
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac_unittest.mm b/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac_unittest.mm
index 4221a0f..64ff954 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac_unittest.mm
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac_unittest.mm
@@ -11,6 +11,7 @@
#import "chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h"
#import "components/autofill/core/browser/suggestions/suggestion.h"
#import "components/autofill/core/browser/suggestions/suggestion_type.h"
+#import "components/autofill/core/common/autofill_test_util.h"
#import "testing/gmock/include/gmock/gmock.h"
#import "testing/gtest/include/gtest/gtest.h"
#import "ui/gfx/geometry/rect_f.h"
@@ -41,9 +42,11 @@
: AutofillPopupControllerImplMac(
external_delegate,
web_contents,
- PopupControllerCommon(frame_token,
- element_bounds,
- base::i18n::UNKNOWN_DIRECTION)) {}
+ PopupControllerCommon(
+ FormGlobalId(frame_token, test::MakeFormRendererId()),
+ FieldGlobalId(frame_token, test::MakeFieldRendererId()),
+ element_bounds,
+ base::i18n::UNKNOWN_DIRECTION)) {}
~AutofillPopupControllerImplMacForTesting() override = default;
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc
index 5ec88031..d2208e5 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc
@@ -522,7 +522,7 @@
EXPECT_CALL(manager().external_delegate(),
DidAcceptSuggestion(
- _, EqualsSuggestionMetadata({.multi_index = {0, 0}})));
+ _, EqualsSuggestionMetadata({.multi_index = {0, 0}}), _, _));
task_environment()->FastForwardBy(base::Milliseconds(1000));
sub_controller->AcceptSuggestion(
@@ -1179,10 +1179,12 @@
ShowSuggestions(manager(),
{Suggestion(u"main_text", SuggestionType::kAddressEntry)});
- EXPECT_CALL(manager().external_delegate(),
- DidAcceptSuggestion(
- _, EqualsSuggestionMetadata(
- {.multi_index = {0}, .from_search_result = true})));
+ EXPECT_CALL(
+ manager().external_delegate(),
+ DidAcceptSuggestion(_,
+ EqualsSuggestionMetadata(
+ {.multi_index = {0}, .from_search_result = true}),
+ _, _));
controller.SetFilter(AutofillPopupController::StringFilter(u"main_text"),
AutofillPopupController::FilterSource::kInputChanged);
diff --git a/chrome/browser/ui/autofill/autofill_suggestion_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_suggestion_controller_unittest.cc
index 8412e26..24f2d9ab 100644
--- a/chrome/browser/ui/autofill/autofill_suggestion_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_suggestion_controller_unittest.cc
@@ -40,6 +40,7 @@
#include "components/autofill/core/browser/ui/autofill_external_delegate.h"
#include "components/autofill/core/browser/ui/autofill_suggestion_delegate.h"
#include "components/autofill/core/common/aliases.h"
+#include "components/autofill/core/common/autofill_test_util.h"
#include "components/autofill/core/common/unique_ids.h"
#include "components/input/native_web_keyboard_event.h"
#include "components/prefs/pref_service.h"
@@ -264,11 +265,14 @@
TEST_F(AutofillSuggestionControllerTest, GetOrCreate) {
auto create_controller = [&](gfx::RectF bounds) {
+ LocalFrameToken frame_token(*main_frame()->GetFrameToken());
return AutofillSuggestionController::GetOrCreate(
client().suggestion_controller(manager()).GetWeakPtr(),
manager().external_delegate().GetWeakPtrForTest(), web_contents(),
- PopupControllerCommon(LocalFrameToken(*main_frame()->GetFrameToken()),
- std::move(bounds), base::i18n::UNKNOWN_DIRECTION),
+ PopupControllerCommon(
+ FormGlobalId(frame_token, test::MakeFormRendererId()),
+ FieldGlobalId(frame_token, test::MakeFieldRendererId()),
+ std::move(bounds), base::i18n::UNKNOWN_DIRECTION),
/*form_control_ax_id=*/0,
AutofillSuggestionTriggerSource::kUnspecified);
};
@@ -333,12 +337,15 @@
SuggestionType::kAutocompleteEntry});
// Now show a new popup with the same controller, but with fewer items.
+ LocalFrameToken frame_token(*main_frame()->GetFrameToken());
base::WeakPtr<AutofillSuggestionController> controller =
AutofillSuggestionController::GetOrCreate(
client().suggestion_controller(manager()).GetWeakPtr(),
manager().external_delegate().GetWeakPtrForTest(), web_contents(),
- PopupControllerCommon(LocalFrameToken(*main_frame()->GetFrameToken()),
- gfx::RectF(), base::i18n::UNKNOWN_DIRECTION),
+ PopupControllerCommon(
+ FormGlobalId(frame_token, test::MakeFormRendererId()),
+ FieldGlobalId(frame_token, test::MakeFieldRendererId()),
+ gfx::RectF(), base::i18n::UNKNOWN_DIRECTION),
/*form_control_ax_id=*/0,
AutofillSuggestionTriggerSource::kUnspecified);
EXPECT_EQ(0, controller->GetLineCount());
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client_interactive_uitest.cc b/chrome/browser/ui/autofill/chrome_autofill_client_interactive_uitest.cc
index f2de98e..bbeb5f9 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client_interactive_uitest.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client_interactive_uitest.cc
@@ -25,6 +25,7 @@
#include "components/autofill/core/browser/metrics/autofill_settings_metrics.h"
#include "components/autofill/core/browser/suggestions/suggestion.h"
#include "components/autofill/core/browser/suggestions/suggestion_type.h"
+#include "components/autofill/core/browser/test_utils/autofill_form_test_util.h"
#include "components/autofill/core/browser/test_utils/autofill_test_util.h"
#include "components/autofill/core/browser/ui/autofill_external_delegate.h"
#include "components/autofill/core/browser/ui/popup_open_enums.h"
@@ -133,12 +134,12 @@
}
AutofillClient::SuggestionUiSessionId ShowSuggestions(
+ const FormGlobalId& form_id,
const FieldGlobalId& field_id,
const gfx::RectF& bounds) {
return client()->ShowAutofillSuggestions(
ChromeAutofillClient::PopupOpenArgs(
- field_id.frame_token, bounds,
- base::i18n::TextDirection::LEFT_TO_RIGHT,
+ form_id, field_id, bounds, base::i18n::TextDirection::LEFT_TO_RIGHT,
{Suggestion(u"test", SuggestionType::kAutocompleteEntry)},
AutofillSuggestionTriggerSource::kFormControlElementClicked,
/*form_control_ax_id=*/0, PopupAnchorType::kField),
@@ -179,16 +180,19 @@
// that the IPH is hidden and the Autofill Popup is successfully shown.
... (truncated)
Original Bug Report
Cross-origin Popup hijacking
A compromised, unfocused cross-origin frame can silently overwrite AED::last_query_ while an Autofill popup is open and thus redirect autofills to itself.
The attack works as follows:
- A legitimate popup is open.
- The attacking renderer now starts an infinite loop of
AutofillDriver::AskForValuesToFill()calls, where theNth call- sets
AED::last_query_synchronously; - starts an asynchronous database lookup for Autocomplete during the suggestion generation, which buys the attacker time;
- cancels the database query from the
N-1th call and thus avoids aHideSuggestions()call that’d hide the legitimate popup.
- sets
- The user selects or accepts a suggestion, which attempts to fill the form and field stored in
AED::last_query_, which is the attackers form and field. The attacker has, already before step 2, set up a form such as
where the<input autocomplete="section-foo transaction-currency> <input autocomplete="section-foo cc-number> <input autocomplete="section-foo cc-exp> <input autocomplete="section-foo cc-csc>transaction-currencyfield is the trigger field for the maliciousAskForValuesToFill()events and thecc-*fields are the harvester fields that’ll receive the credit card data, and thesection-fooconvincesFormFillerto fill all these fields.
While I haven’t tested it, the attack should also work for addresses as well as other filling products, provided we can get the fields into the same section (that shouldn’t be a problem though because credit card fields are the only ones with special treatment in that regard).
More material:
- Video: http://screencast/cast/NjQwMTk3OTQ1NzczMjYwOHwwMDExZjJiMi01MQ
- More details: https://docs.google.com/document/d/1-jusxiNv03JpMkUk0N9Esh0GUeVmmWxqExOGAz-a95A/edit?tab=t.0
- Patch for reproductoin: attached