diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc index 1eb6c5f7d43ce..3ce2b2097775d 100644 --- a/components/autofill/content/renderer/password_generation_agent.cc +++ b/components/autofill/content/renderer/password_generation_agent.cc @@ -76,7 +76,9 @@ FieldRendererId FindConfirmationPasswordFieldId( void CopyElementValueToOtherInputElements( const WebInputElement& element, - std::vector& elements) { + std::vector elements) { + // `elements` is taken by value because SetAutofillValue() below dispatches + // synchronous JS events that may free the caller's underlying buffer. for (WebInputElement& it : elements) { if (element != it) { it.SetAutofillValue(element.Value()); @@ -401,8 +403,13 @@ void PasswordGenerationAgent::GeneratedPasswordAccepted( // Preview needs to be cleared before filling to be removed correctly. password_agent_->autofill_agent().ClearPreviewedForm(); - for (blink::WebInputElement& password_element : - current_generation_item_->password_elements_) { + // Copy elements to local variables to avoid UAF if current_generation_item_ + // is replaced by re-entrant JS triggered from SetAutofillValue() below. + std::vector password_elements = + current_generation_item_->password_elements_; + blink::WebInputElement generation_element = + current_generation_item_->generation_element_; + for (blink::WebInputElement& password_element : password_elements) { ScopedUpdatingOtherPasswordFields auto_reset_update_confirmation_password( this); password_element.SetAutofillValue(blink::WebString::FromUtf16(password)); @@ -418,13 +425,11 @@ void PasswordGenerationAgent::GeneratedPasswordAccepted( } password_agent_->TrackAutofilledElement(password_element); } - CHECK(std::ranges::contains(current_generation_item_->password_elements_, - current_generation_item_->generation_element_)); + CHECK(std::ranges::contains(password_elements, generation_element)); - std::optional presaved_form_data = CreateFormDataToPresave( - current_generation_item_->generation_element_, /*form_cache=*/{}); - const std::u16string generated_password = - current_generation_item_->generation_element_.Value().Utf16(); + std::optional presaved_form_data = + CreateFormDataToPresave(generation_element, /*form_cache=*/{}); + const std::u16string generated_password = generation_element.Value().Utf16(); if (presaved_form_data) { CHECK(!generated_password.empty()); GetPasswordGenerationDriver().PresaveGeneratedPassword(*presaved_form_data, @@ -433,8 +438,7 @@ void PasswordGenerationAgent::GeneratedPasswordAccepted( // Call UpdateStateForTextChange after the corresponding PasswordFormManager // is notified that the password was generated. - for (const blink::WebInputElement& password_element : - current_generation_item_->password_elements_) { + for (const blink::WebInputElement& password_element : password_elements) { // Needed to notify password_autofill_agent that the content of the field // has changed. Without this we will overwrite the generated // password with an Autofilled password when saving.