Commit message: None
CVE: CVE-2018-6178
CWE: CWE-254
Vulnerability description: Eliding from the wrong side in an infobar in DevTools in Google Chrome prior to 68.0.3440.75 allowed an attacker who convinced a user to install a malicious extension to Hide Chrome Security UI via a crafted Chrome Extension.

Project: Chrome

bool GlobalConfirmInfoBar::DelegateProxy::Accept() {
  base::WeakPtr<GlobalConfirmInfoBar> info_bar = global_info_bar_;
  if (info_bar) {
    info_bar->OnInfoBarRemoved(info_bar_, false);
    info_bar->delegate_->Accept();
  }
  if (info_bar)
      info_bar->Close();
  return true;
}

Project: Chrome

bool GlobalConfirmInfoBar::DelegateProxy::Cancel() {
  base::WeakPtr<GlobalConfirmInfoBar> info_bar = global_info_bar_;
  if (info_bar) {
    info_bar->OnInfoBarRemoved(info_bar_, false);
    info_bar->delegate_->Cancel();
  }
  if (info_bar)
      info_bar->Close();
  return true;
}

Project: Chrome

void GlobalConfirmInfoBar::Close() {
  delete this;
}

Project: Chrome

GlobalConfirmInfoBar::DelegateProxy::DelegateProxy(
    base::WeakPtr<GlobalConfirmInfoBar> global_info_bar)
    : info_bar_(nullptr),
      global_info_bar_(global_info_bar) {
}

Project: Chrome

void GlobalConfirmInfoBar::DelegateProxy::Detach() {
  global_info_bar_.reset();
}

Project: Chrome

base::string16 GlobalConfirmInfoBar::DelegateProxy::GetButtonLabel(
    InfoBarButton button) const {
  return global_info_bar_ ? global_info_bar_->delegate_->GetButtonLabel(button)
                          : base::string16();
}

Project: Chrome

 int GlobalConfirmInfoBar::DelegateProxy::GetButtons() const {
   return global_info_bar_ ? global_info_bar_->delegate_->GetButtons()
                           : 0;
}

Project: Chrome

base::string16 GlobalConfirmInfoBar::DelegateProxy::GetLinkText() const {
  return global_info_bar_ ? global_info_bar_->delegate_->GetLinkText()
                          : base::string16();
}

Project: Chrome

GURL GlobalConfirmInfoBar::DelegateProxy::GetLinkURL() const {
  return global_info_bar_ ? global_info_bar_->delegate_->GetLinkURL()
                          : GURL();
}

Project: Chrome

base::string16 GlobalConfirmInfoBar::DelegateProxy::GetMessageText() const {
  return global_info_bar_ ? global_info_bar_->delegate_->GetMessageText()
                           : base::string16();
 }

Project: Chrome

GlobalConfirmInfoBar::GlobalConfirmInfoBar(
    std::unique_ptr<ConfirmInfoBarDelegate> delegate)
    : delegate_(std::move(delegate)),
      browser_tab_strip_tracker_(this, nullptr, nullptr),
      is_closing_(false),
      weak_factory_(this) {
  browser_tab_strip_tracker_.Init();
}

Project: Chrome

void GlobalConfirmInfoBar::DelegateProxy::InfoBarDismissed() {
  base::WeakPtr<GlobalConfirmInfoBar> info_bar = global_info_bar_;
  if (info_bar) {
    info_bar->OnInfoBarRemoved(info_bar_, false);
    info_bar->delegate_->InfoBarDismissed();
  }
  if (info_bar)
      info_bar->Close();
}

Project: Chrome

bool GlobalConfirmInfoBar::DelegateProxy::LinkClicked(
    WindowOpenDisposition disposition) {
  return global_info_bar_ ?
      global_info_bar_->delegate_->LinkClicked(disposition) : false;
}

Project: Chrome

void GlobalConfirmInfoBar::MaybeAddInfoBar(content::WebContents* web_contents) {
  InfoBarService* infobar_service =
      InfoBarService::FromWebContents(web_contents);
  DCHECK(infobar_service);
  if (ContainsKey(proxies_, infobar_service))
    return;

  std::unique_ptr<GlobalConfirmInfoBar::DelegateProxy> proxy(
      new GlobalConfirmInfoBar::DelegateProxy(weak_factory_.GetWeakPtr()));
  GlobalConfirmInfoBar::DelegateProxy* proxy_ptr = proxy.get();
  infobars::InfoBar* added_bar = infobar_service->AddInfoBar(
      infobar_service->CreateConfirmInfoBar(std::move(proxy)));

  if (!added_bar) {
    if (!is_closing_) {
      is_closing_ = true;

      base::SequencedTaskRunnerHandle::Get()->PostTask(
          FROM_HERE,
          base::Bind(&GlobalConfirmInfoBar::Close, weak_factory_.GetWeakPtr()));
    }
    return;
  }

  proxy_ptr->info_bar_ = added_bar;
  proxies_[infobar_service] = proxy_ptr;
  infobar_service->AddObserver(this);
}

Project: Chrome

void GlobalConfirmInfoBar::OnInfoBarRemoved(infobars::InfoBar* info_bar,
                                            bool animate) {
  for (auto it : proxies_) {
    if (it.second->info_bar_ == info_bar) {
      OnManagerShuttingDown(info_bar->owner());
      break;
    }
  }
}

Project: Chrome

void GlobalConfirmInfoBar::OnManagerShuttingDown(
    infobars::InfoBarManager* manager) {
  manager->RemoveObserver(this);
  proxies_.erase(manager);
}

Project: Chrome

base::WeakPtr<GlobalConfirmInfoBar> GlobalConfirmInfoBar::Show(
    std::unique_ptr<ConfirmInfoBarDelegate> delegate) {
  GlobalConfirmInfoBar* info_bar =
      new GlobalConfirmInfoBar(std::move(delegate));
  return info_bar->weak_factory_.GetWeakPtr();
}

Project: Chrome

void GlobalConfirmInfoBar::TabChangedAt(content::WebContents* web_contents,
                                        int index,
                                        TabChangeType change_type) {
  MaybeAddInfoBar(web_contents);
}

Project: Chrome

void GlobalConfirmInfoBar::TabInsertedAt(TabStripModel* tab_strip_model,
                                         content::WebContents* web_contents,
                                         int index,
                                         bool foreground) {
  MaybeAddInfoBar(web_contents);
}

Project: Chrome

GlobalConfirmInfoBar::DelegateProxy::~DelegateProxy() {
}

Project: Chrome

GlobalConfirmInfoBar::~GlobalConfirmInfoBar() {
  while (!proxies_.empty()) {
    auto it = proxies_.begin();
    it->second->Detach();
    it->first->RemoveObserver(this);
    it->first->RemoveInfoBar(it->second->info_bar_);
    proxies_.erase(it);
  }
}

Project: Chrome

ExtensionDevToolsInfoBar* ExtensionDevToolsInfoBar::Create(
    const std::string& extension_id,
    const std::string& extension_name,
    ExtensionDevToolsClientHost* client_host,
    const base::Closure& dismissed_callback) {
  ExtensionInfoBars::iterator it =
      g_extension_info_bars.Get().find(extension_id);
  ExtensionDevToolsInfoBar* infobar = nullptr;
  if (it != g_extension_info_bars.Get().end())
    infobar = it->second;
  else
    infobar = new ExtensionDevToolsInfoBar(extension_id, extension_name);
  infobar->callbacks_[client_host] = dismissed_callback;
  return infobar;
}

Project: Chrome

ExtensionDevToolsInfoBar::ExtensionDevToolsInfoBar(
    const std::string& extension_id,
    const std::string& extension_name)
    : extension_id_(extension_id) {
  g_extension_info_bars.Get()[extension_id] = this;

  auto delegate = std::make_unique<ExtensionDevToolsInfoBarDelegate>(
      base::Bind(&ExtensionDevToolsInfoBar::InfoBarDismissed,
                 base::Unretained(this)),
      extension_name);
  infobar_ = GlobalConfirmInfoBar::Show(std::move(delegate));
}

Project: Chrome

ExtensionDevToolsInfoBarDelegate::ExtensionDevToolsInfoBarDelegate(
    const base::Closure& dismissed_callback,
    const std::string& client_name)
    : ConfirmInfoBarDelegate(),
      client_name_(base::UTF8ToUTF16(client_name)),
      dismissed_callback_(dismissed_callback) {}

Project: Chrome

base::string16 ExtensionDevToolsInfoBarDelegate::GetMessageText() const {
   return l10n_util::GetStringFUTF16(IDS_DEV_TOOLS_INFOBAR_LABEL, client_name_);
 }

Project: Chrome

void ExtensionDevToolsInfoBarDelegate::InfoBarDismissed() {
  DCHECK(!dismissed_callback_.is_null());
  base::ResetAndReturn(&dismissed_callback_).Run();
}

Project: Chrome

void ExtensionDevToolsInfoBar::InfoBarDismissed() {
  std::map<ExtensionDevToolsClientHost*, base::Closure> copy = callbacks_;
  for (const auto& pair : copy)
    pair.second.Run();
}

Project: Chrome

void ExtensionDevToolsInfoBar::Remove(
    ExtensionDevToolsClientHost* client_host) {
  callbacks_.erase(client_host);
  if (callbacks_.empty())
    delete this;
}

Project: Chrome

bool ExtensionDevToolsInfoBarDelegate::ShouldExpire(
    const NavigationDetails& details) const {
  return false;
}

Project: Chrome

ExtensionDevToolsInfoBar::~ExtensionDevToolsInfoBar() {
  g_extension_info_bars.Get().erase(extension_id_);
  if (infobar_)
    infobar_->Close();
}

Project: Chrome

ExtensionDevToolsInfoBarDelegate::~ExtensionDevToolsInfoBarDelegate() {}

Project: Chrome

void ConfirmInfoBar::ButtonPressed(views::Button* sender,
                                   const ui::Event& event) {
  if (!owner())
    return;  // We're closing; don't call anything, it might access the owner.
  ConfirmInfoBarDelegate* delegate = GetDelegate();
  if (sender == ok_button_) {
    if (delegate->Accept())
      RemoveSelf();
  } else if (sender == cancel_button_) {
    if (delegate->Cancel())
      RemoveSelf();
  } else {
    InfoBarView::ButtonPressed(sender, event);
  }
}

Project: Chrome

int ConfirmInfoBar::ContentMinimumWidth() const {
  return label_->GetMinimumSize().width() + link_->GetMinimumSize().width() +
      NonLabelWidth();
}

Project: Chrome

views::MdTextButton* ConfirmInfoBar::CreateButton(
    ConfirmInfoBarDelegate::InfoBarButton type) {
  auto* button =
      views::MdTextButton::Create(this, GetDelegate()->GetButtonLabel(type));
  button->SetProperty(
      views::kMarginsKey,
      new gfx::Insets(ChromeLayoutProvider::Get()->GetDistanceMetric(
                          DISTANCE_TOAST_CONTROL_VERTICAL),
                      0));
  AddChildView(button);
  button->SizeToPreferredSize();
  return button;
}

Project: Chrome

std::unique_ptr<infobars::InfoBar> InfoBarService::CreateConfirmInfoBar(
    std::unique_ptr<ConfirmInfoBarDelegate> delegate) {
#if defined(OS_MACOSX)
  if (views_mode_controller::IsViewsBrowserCocoa())
    return InfoBarService::CreateConfirmInfoBarCocoa(std::move(delegate));
#endif
  return std::make_unique<ConfirmInfoBar>(std::move(delegate));
}

Project: Chrome

void ConfirmInfoBar::Layout() {
  InfoBarView::Layout();

  int x = StartX();
  Labels labels;
  labels.push_back(label_);
  labels.push_back(link_);
  AssignWidths(&labels, std::max(0, EndX() - x - NonLabelWidth()));

  ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get();

  label_->SetPosition(gfx::Point(x, OffsetY(label_)));
  if (!label_->text().empty())
    x = label_->bounds().right() +
        layout_provider->GetDistanceMetric(
            views::DISTANCE_RELATED_LABEL_HORIZONTAL);

  if (ok_button_) {
    ok_button_->SetPosition(gfx::Point(x, OffsetY(ok_button_)));
    x = ok_button_->bounds().right() +
        layout_provider->GetDistanceMetric(
            views::DISTANCE_RELATED_BUTTON_HORIZONTAL);
  }

  if (cancel_button_)
    cancel_button_->SetPosition(gfx::Point(x, OffsetY(cancel_button_)));

  link_->SetPosition(gfx::Point(EndX() - link_->width(), OffsetY(link_)));
}

Project: Chrome

void ConfirmInfoBar::LinkClicked(views::Link* source, int event_flags) {
  if (!owner())
    return;  // We're closing; don't call anything, it might access the owner.
  DCHECK_EQ(link_, source);
  if (GetDelegate()->LinkClicked(ui::DispositionFromEventFlags(event_flags)))
    RemoveSelf();
}

Project: Chrome

int ConfirmInfoBar::NonLabelWidth() const {
  ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get();

  const int label_spacing = layout_provider->GetDistanceMetric(
      views::DISTANCE_RELATED_LABEL_HORIZONTAL);
  const int button_spacing = layout_provider->GetDistanceMetric(
      views::DISTANCE_RELATED_BUTTON_HORIZONTAL);

  int width = (label_->text().empty() || (!ok_button_ && !cancel_button_))
                  ? 0
                  : label_spacing;
  if (ok_button_)
    width += ok_button_->width() + (cancel_button_ ? button_spacing : 0);
  width += cancel_button_ ? cancel_button_->width() : 0;
  return width + ((link_->text().empty() || !width) ? 0 : label_spacing);
}

Project: Chrome

ConfirmInfoBar::~ConfirmInfoBar() {
  elevation_icon_setter_.reset();
}

Project: Chrome

bool ConfirmInfoBarDelegate::Accept() {
  return true;
}

Project: Chrome

ConfirmInfoBarDelegate* ConfirmInfoBarDelegate::AsConfirmInfoBarDelegate() {
  return this;
}

Project: Chrome

bool ConfirmInfoBarDelegate::Cancel() {
  return true;
}

Project: Chrome

ConfirmInfoBarDelegate::ConfirmInfoBarDelegate()
    : InfoBarDelegate() {
}

Project: Chrome

bool ConfirmInfoBarDelegate::EqualsDelegate(InfoBarDelegate* delegate) const {
  ConfirmInfoBarDelegate* confirm_delegate =
      delegate->AsConfirmInfoBarDelegate();
  return confirm_delegate &&
      (confirm_delegate->GetMessageText() == GetMessageText());
}

Project: Chrome

base::string16 ConfirmInfoBarDelegate::GetButtonLabel(
    InfoBarButton button) const {
  return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
      IDS_APP_OK : IDS_APP_CANCEL);
}

Project: Chrome

    ConfirmInfoBarDelegate::GetInfoBarAutomationType() const {
   return CONFIRM_INFOBAR;
 }

Project: Chrome

GURL ConfirmInfoBarDelegate::GetLinkURL() const {
  return GURL();
}

Project: Chrome

bool ConfirmInfoBarDelegate::LinkClicked(WindowOpenDisposition disposition) {
  infobar()->owner()->OpenURL(GetLinkURL(), disposition);
  return false;
}

Project: Chrome

bool ConfirmInfoBarDelegate::OKButtonTriggersUACPrompt() const {
  return false;
}

Project: Chrome

ConfirmInfoBarDelegate::~ConfirmInfoBarDelegate() {
}