Commit message: None
CVE: CVE-2016-1690
Vulnerability description: The Autofill implementation in Google Chrome before 51.0.2704.63 mishandles the interaction between field updates and JavaScript code that triggers a frame deletion, which allows remote attackers to cause a denial of service (use-after-free) or possibly have unspecified other impact via a crafted web site, a different vulnerability than CVE-2016-1701.

Project: Chrome

void PasswordAutofillAgent::DidCommitProvisionalLoad(
    bool is_new_navigation, bool is_same_page_navigation) {
  if (is_same_page_navigation) {
    OnSamePageNavigationCompleted();
  }
}

Project: Chrome

bool DoesFormContainAmbiguousOrEmptyNames(
    const PasswordFormFillData& fill_data) {
  return (fill_data.username_field.name == fill_data.password_field.name) ||
         (fill_data.password_field.name ==
              base::ASCIIToUTF16(kDummyPasswordField) &&
          (!FillDataContainsFillableUsername(fill_data) ||
           fill_data.username_field.name ==
               base::ASCIIToUTF16(kDummyUsernameField)));
}

Project: Chrome

void PasswordAutofillAgent::FrameDetached() {
  if (render_frame()->GetWebFrame()->parent() &&
      ProvisionallySavedPasswordIsValid()) {
    Send(new AutofillHostMsg_InPageNavigation(routing_id(),
                                              *provisionally_saved_form_));
  }
  FrameClosing();
}

Project: Chrome

bool IsPasswordField(const FormFieldData& field) {
  return (field.form_control_type == "password");
}

Project: Chrome

bool IsUnownedPasswordFormVisible(blink::WebFrame* frame,
                                  const GURL& action,
                                  const GURL& origin,
                                  const FormData& form_data,
                                  const FormsPredictionsMap& form_predictions) {
  std::unique_ptr<PasswordForm> unowned_password_form(
      CreatePasswordFormFromUnownedInputElements(*frame, nullptr,
                                                 &form_predictions));
  if (!unowned_password_form)
    return false;
  std::vector<blink::WebFormControlElement> control_elements =
      form_util::GetUnownedAutofillableFormFieldElements(
          frame->document().all(), nullptr);
  if (!form_util::IsSomeControlElementVisible(control_elements))
    return false;

#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
  const bool action_is_empty = action == origin;
  bool forms_are_same =
      action_is_empty ? form_data.SameFormAs(unowned_password_form->form_data)
                      : action == unowned_password_form->action;
  return forms_are_same;
#else  // OS_MACOSX or OS_ANDROID
  return action == unowned_password_form->action;
#endif
}

Project: Chrome

bool PasswordAutofillAgent::OriginCanAccessPasswordManager(
    const blink::WebSecurityOrigin& origin) {
  return origin.canAccessPasswordManager();
}

Project: Chrome

void PasswordAutofillAgent::ProvisionallySavePassword(
    std::unique_ptr<PasswordForm> password_form,
    ProvisionallySaveRestriction restriction) {
  if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD &&
                         password_form->password_value.empty() &&
                         password_form->new_password_value.empty())) {
    return;
  }
  provisionally_saved_form_ = std::move(password_form);
}

Project: Chrome

void PasswordAutofillAgent::PasswordValueGatekeeper::RegisterElement(
    blink::WebInputElement* element) {
  if (was_user_gesture_seen_)
    ShowValue(element);
  else
    elements_.push_back(*element);
}

Project: Chrome

void PasswordAutofillAgent::SendPasswordForms(bool only_visible) {
  std::unique_ptr<RendererSavePasswordProgressLogger> logger;
  if (logging_state_active_) {
    logger.reset(new RendererSavePasswordProgressLogger(this, routing_id()));
    logger->LogMessage(Logger::STRING_SEND_PASSWORD_FORMS_METHOD);
    logger->LogBoolean(Logger::STRING_ONLY_VISIBLE, only_visible);
  }

  blink::WebFrame* frame = render_frame()->GetWebFrame();
  blink::WebSecurityOrigin origin = frame->document().getSecurityOrigin();
  if (logger) {
    logger->LogURL(Logger::STRING_SECURITY_ORIGIN,
                   GURL(origin.toString().utf8()));
  }
  if (!OriginCanAccessPasswordManager(origin)) {
    if (logger) {
      logger->LogMessage(Logger::STRING_SECURITY_ORIGIN_FAILURE);
    }
    return;
  }

  if (form_util::IsWebpageEmpty(frame)) {
    if (logger) {
      logger->LogMessage(Logger::STRING_WEBPAGE_EMPTY);
    }
    return;
  }

  blink::WebVector<blink::WebFormElement> forms;
  frame->document().forms(forms);
  if (logger)
    logger->LogNumber(Logger::STRING_NUMBER_OF_ALL_FORMS, forms.size());

  std::vector<PasswordForm> password_forms;
  for (const blink::WebFormElement& form : forms) {
    if (only_visible) {
      bool is_form_visible = form_util::AreFormContentsVisible(form);
      if (logger) {
        LogHTMLForm(logger.get(), Logger::STRING_FORM_FOUND_ON_PAGE, form);
        logger->LogBoolean(Logger::STRING_FORM_IS_VISIBLE, is_form_visible);
      }

      if (!is_form_visible)
        continue;
    }

    std::unique_ptr<PasswordForm> password_form(
        CreatePasswordFormFromWebForm(form, nullptr, &form_predictions_));
    if (password_form) {
      if (logger) {
        logger->LogPasswordForm(Logger::STRING_FORM_IS_PASSWORD,
                                *password_form);
      }
      password_forms.push_back(*password_form);
    }
  }

  bool add_unowned_inputs = true;
  if (only_visible) {
    std::vector<blink::WebFormControlElement> control_elements =
        form_util::GetUnownedAutofillableFormFieldElements(
            frame->document().all(), nullptr);
    add_unowned_inputs =
        form_util::IsSomeControlElementVisible(control_elements);
    if (logger) {
      logger->LogBoolean(Logger::STRING_UNOWNED_INPUTS_VISIBLE,
                         add_unowned_inputs);
    }
  }
  if (add_unowned_inputs) {
    std::unique_ptr<PasswordForm> password_form(
        CreatePasswordFormFromUnownedInputElements(*frame, nullptr,
                                                   &form_predictions_));
    if (password_form) {
      if (logger) {
        logger->LogPasswordForm(Logger::STRING_FORM_IS_PASSWORD,
                                *password_form);
      }
      password_forms.push_back(*password_form);
    }
  }

  if (password_forms.empty() && !only_visible) {
    return;
  }

  if (only_visible) {
    blink::WebFrame* main_frame = render_frame()->GetWebFrame()->top();
    bool did_stop_loading = !main_frame || !main_frame->isLoading();
    Send(new AutofillHostMsg_PasswordFormsRendered(routing_id(), password_forms,
                                                   did_stop_loading));
  } else {
    Send(new AutofillHostMsg_PasswordFormsParsed(routing_id(), password_forms));
  }
}

Project: Chrome

bool ShouldFillOnAccountSelect() {
  std::string group_name =
      base::FieldTrialList::FindFullName(kFillOnAccountSelectFieldTrialName);

  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kDisableFillOnAccountSelect)) {
    return false;
  }

  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kEnableFillOnAccountSelect) ||
      base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kEnableFillOnAccountSelectNoHighlighting)) {
    return true;
  }

  return group_name ==
             kFillOnAccountSelectFieldTrialEnabledWithHighlightGroup ||
         group_name ==
             kFillOnAccountSelectFieldTrialEnabledWithNoHighlightGroup;
}

Project: Chrome

bool PasswordAutofillAgent::ShowSuggestionPopup(
    const PasswordInfo& password_info,
    const blink::WebInputElement& user_input,
    bool show_all,
    bool show_on_password_field) {
  DCHECK(!user_input.isNull());
  blink::WebFrame* frame = user_input.document().frame();
  if (!frame)
    return false;

  blink::WebView* webview = frame->view();
  if (!webview)
    return false;

  if (user_input.isPasswordField() && !user_input.isAutofilled() &&
      !user_input.value().isEmpty()) {
    Send(new AutofillHostMsg_HidePopup(routing_id()));
    return false;
  }

  FormData form;
  FormFieldData field;
  form_util::FindFormAndFieldForFormControlElement(user_input, &form, &field);

  int options = 0;
  if (show_all)
    options |= SHOW_ALL;
  if (show_on_password_field)
    options |= IS_PASSWORD_FIELD;

  base::string16 username_string(
      user_input.isPasswordField()
          ? base::string16()
          : static_cast<base::string16>(user_input.value()));

  Send(new AutofillHostMsg_ShowPasswordSuggestions(
      routing_id(), password_info.key, field.text_direction, username_string,
      options,
      render_frame()->GetRenderView()->ElementBoundsInWindow(user_input)));
  username_query_prefix_ = username_string;
  return CanShowSuggestion(password_info.fill_data, username_string, show_all);
}

Project: Chrome

bool PasswordAutofillAgent::TextDidChangeInTextField(
    const blink::WebInputElement& element) {
  blink::WebInputElement mutable_element = element;  // We need a non-const.
  mutable_element.setAutofilled(false);

  WebInputToPasswordInfoMap::iterator iter =
      web_input_to_password_info_.find(element);
  if (iter != web_input_to_password_info_.end()) {
    iter->second.password_was_edited_last = false;
    if (iter->second.fill_data.wait_for_username)
      return false;
  }

  return ShowSuggestions(element, false, false);
}

Project: Chrome

void PasswordAutofillAgent::UpdateStateForTextChange(
    const blink::WebInputElement& element) {
  blink::WebInputElement mutable_element = element;  // We need a non-const.

  if (element.isTextField())
    nonscript_modified_values_[element] = element.value();

  blink::WebFrame* const element_frame = element.document().frame();
  if (!element_frame)
    return;
  DCHECK_EQ(element_frame, render_frame()->GetWebFrame());

  std::unique_ptr<PasswordForm> password_form;
  if (element.form().isNull()) {
    password_form = CreatePasswordFormFromUnownedInputElements(
        *element_frame, &nonscript_modified_values_, &form_predictions_);
  } else {
    password_form = CreatePasswordFormFromWebForm(
        element.form(), &nonscript_modified_values_, &form_predictions_);
  }
  ProvisionallySavePassword(std::move(password_form), RESTRICTION_NONE);

  if (element.isPasswordField()) {
    PasswordToLoginMap::iterator iter = password_to_username_.find(element);
    if (iter != password_to_username_.end()) {
      web_input_to_password_info_[iter->second].password_was_edited_last = true;
      mutable_element.setAutofilled(false);
    }
  }
}