RenderFrameHostImpl* RenderFrameHostManager::GetFrameHostForNavigation(
    const NavigationRequest& request) {
  DCHECK(!request.common_params().url.SchemeIs(url::kJavaScriptScheme))
      << "Don't call this method for JavaScript URLs as those create a "
         "temporary  NavigationRequest and we don't want to reset an ongoing "
         "navigation's speculative RFH.";

  RenderFrameHostImpl* navigation_rfh = nullptr;

  SiteInstance* current_site_instance = render_frame_host_->GetSiteInstance();
  scoped_refptr<SiteInstance> dest_site_instance =
      GetSiteInstanceForNavigationRequest(request);

  bool use_current_rfh = current_site_instance == dest_site_instance;

  bool notify_webui_of_rf_creation = false;
  if (use_current_rfh) {
     if (speculative_render_frame_host_) {
      // NavigationEntry stopped if needed. This is the case if the new
      // navigation was started from BeginNavigation. If the navigation was
      // started through the NavigationController, the NavigationController has
      // already updated its state properly, and doesn't need to be notified.
      if (speculative_render_frame_host_->navigation_handle() &&
          request.from_begin_navigation()) {
         frame_tree_node_->navigator()->DiscardPendingEntryIfNeeded(
             speculative_render_frame_host_->navigation_handle()
                 ->pending_nav_entry_id());
      }
      DiscardUnusedFrame(UnsetSpeculativeRenderFrameHost());
    }

    if (frame_tree_node_->IsMainFrame()) {
      UpdatePendingWebUIOnCurrentFrameHost(request.common_params().url,
                                           request.bindings());
    }

    navigation_rfh = render_frame_host_.get();

    DCHECK(!speculative_render_frame_host_);
  } else {

    if (!speculative_render_frame_host_ ||
        speculative_render_frame_host_->GetSiteInstance() !=
            dest_site_instance.get()) {
      CleanUpNavigation();
      bool success = CreateSpeculativeRenderFrameHost(current_site_instance,
                                                      dest_site_instance.get());
      DCHECK(success);
    }
    DCHECK(speculative_render_frame_host_);

    if (frame_tree_node_->IsMainFrame()) {
      bool changed_web_ui = speculative_render_frame_host_->UpdatePendingWebUI(
          request.common_params().url, request.bindings());
      speculative_render_frame_host_->CommitPendingWebUI();
      DCHECK_EQ(GetNavigatingWebUI(), speculative_render_frame_host_->web_ui());
      notify_webui_of_rf_creation =
          changed_web_ui && speculative_render_frame_host_->web_ui();
    }
    navigation_rfh = speculative_render_frame_host_.get();

    if (!render_frame_host_->IsRenderFrameLive()) {
      if (GetRenderFrameProxyHost(dest_site_instance.get())) {
        navigation_rfh->Send(
            new FrameMsg_SwapIn(navigation_rfh->GetRoutingID()));
      }
      CommitPending();

      if (notify_webui_of_rf_creation && render_frame_host_->web_ui()) {
        render_frame_host_->web_ui()->RenderFrameCreated(
            render_frame_host_.get());
        notify_webui_of_rf_creation = false;
      }
    }
  }
  DCHECK(navigation_rfh &&
         (navigation_rfh == render_frame_host_.get() ||
          navigation_rfh == speculative_render_frame_host_.get()));

  if (!navigation_rfh->IsRenderFrameLive()) {
    if (!ReinitializeRenderFrame(navigation_rfh))
      return nullptr;

    notify_webui_of_rf_creation = true;

    if (navigation_rfh == render_frame_host_.get()) {
      EnsureRenderFrameHostVisibilityConsistent();
      EnsureRenderFrameHostPageFocusConsistent();
      delegate_->NotifyMainFrameSwappedFromRenderManager(
          nullptr, render_frame_host_->render_view_host());
    }
  }

  if (notify_webui_of_rf_creation && GetNavigatingWebUI() &&
      frame_tree_node_->IsMainFrame()) {
    GetNavigatingWebUI()->RenderFrameCreated(navigation_rfh);
  }

  return navigation_rfh;
}


GURL SanitizeFrontendURL(const GURL& url,
                         const std::string& scheme,
                         const std::string& host,
                         const std::string& path,
                         bool allow_query_and_fragment) {
  std::vector<std::string> query_parts;
  std::string fragment;
  if (allow_query_and_fragment) {
    for (net::QueryIterator it(url); !it.IsAtEnd(); it.Advance()) {
      std::string value = SanitizeFrontendQueryParam(it.GetKey(),
          it.GetValue());
      if (!value.empty()) {
        query_parts.push_back(
             base::StringPrintf("%s=%s", it.GetKey().c_str(), value.c_str()));
       }
     }
    if (url.has_ref())
       fragment = '#' + url.ref();
   }
   std::string query =
      query_parts.empty() ? "" : "?" + base::JoinString(query_parts, "&");
  std::string constructed =
      base::StringPrintf("%s://%s%s%s%s", scheme.c_str(), host.c_str(),
                         path.c_str(), query.c_str(), fragment.c_str());
  GURL result = GURL(constructed);
  if (!result.is_valid())
    return GURL();
  return result;
}

Insufficient data validation in DevTools in Google Chrome prior to 64.0.3282.119 allowed a remote attacker to potentially leak user cross-origin data via a crafted Chrome Extension.


GURL SanitizeFrontendURL(const GURL& url,
                         const std::string& scheme,
                         const std::string& host,
                         const std::string& path,
                         bool allow_query_and_fragment) {
  std::vector<std::string> query_parts;
  std::string fragment;
  if (allow_query_and_fragment) {
    for (net::QueryIterator it(url); !it.IsAtEnd(); it.Advance()) {
      std::string value = SanitizeFrontendQueryParam(it.GetKey(),
          it.GetValue());
      if (!value.empty()) {
        query_parts.push_back(
             base::StringPrintf("%s=%s", it.GetKey().c_str(), value.c_str()));
       }
     }
    if (url.has_ref() && url.ref_piece().find('\'') == base::StringPiece::npos)
       fragment = '#' + url.ref();
   }
   std::string query =
      query_parts.empty() ? "" : "?" + base::JoinString(query_parts, "&");
  std::string constructed =
      base::StringPrintf("%s://%s%s%s%s", scheme.c_str(), host.c_str(),
                         path.c_str(), query.c_str(), fragment.c_str());
  GURL result = GURL(constructed);
  if (!result.is_valid())
    return GURL();
  return result;
}


bool WebGLRenderingContextBase::ValidateHTMLImageElement(
    const SecurityOrigin* security_origin,
    const char* function_name,
    HTMLImageElement* image,
    ExceptionState& exception_state) {
  if (!image || !image->CachedImage()) {
    SynthesizeGLError(GL_INVALID_VALUE, function_name, "no image");
    return false;
  }
  const KURL& url = image->CachedImage()->GetResponse().Url();
  if (url.IsNull() || url.IsEmpty() || !url.IsValid()) {
    SynthesizeGLError(GL_INVALID_VALUE, function_name, "invalid image");
    return false;
   }

   if (WouldTaintOrigin(image, security_origin)) {
    exception_state.ThrowSecurityError("The cross-origin image at " +
                                       url.ElidedString() +
                                       " may not be loaded.");
     return false;
   }
   return true;
}

Insufficient policy enforcement in WebGL in Google Chrome prior to 64.0.3282.119 allowed a remote attacker to potentially leak user redirect URL via a crafted HTML page.


bool WebGLRenderingContextBase::ValidateHTMLImageElement(
    const SecurityOrigin* security_origin,
    const char* function_name,
    HTMLImageElement* image,
    ExceptionState& exception_state) {
  if (!image || !image->CachedImage()) {
    SynthesizeGLError(GL_INVALID_VALUE, function_name, "no image");
    return false;
  }
  const KURL& url = image->CachedImage()->GetResponse().Url();
  if (url.IsNull() || url.IsEmpty() || !url.IsValid()) {
    SynthesizeGLError(GL_INVALID_VALUE, function_name, "invalid image");
    return false;
   }

   if (WouldTaintOrigin(image, security_origin)) {
    exception_state.ThrowSecurityError(
        "The image element contains cross-origin data, and may not be loaded.");
     return false;
   }
   return true;
}


bool IDNSpoofChecker::SafeToDisplayAsUnicode(base::StringPiece16 label,
                                             bool is_tld_ascii) {
  UErrorCode status = U_ZERO_ERROR;
  int32_t result =
      uspoof_check(checker_, label.data(),
                   base::checked_cast<int32_t>(label.size()), nullptr, &status);
  if (U_FAILURE(status) || (result & USPOOF_ALL_CHECKS))
    return false;

  icu::UnicodeString label_string(FALSE, label.data(),
                                  base::checked_cast<int32_t>(label.size()));

  if (deviation_characters_.containsSome(label_string))
    return false;

  result &= USPOOF_RESTRICTION_LEVEL_MASK;
  if (result == USPOOF_ASCII)
    return true;
  if (result == USPOOF_SINGLE_SCRIPT_RESTRICTIVE &&
      kana_letters_exceptions_.containsNone(label_string) &&
      combining_diacritics_exceptions_.containsNone(label_string)) {
    return !is_tld_ascii || !IsMadeOfLatinAlikeCyrillic(label_string);
  }

  if (non_ascii_latin_letters_.containsSome(label_string) &&
      !lgc_letters_n_ascii_.containsAll(label_string))
    return false;

  if (!tls_index.initialized())
    tls_index.Initialize(&OnThreadTermination);
  icu::RegexMatcher* dangerous_pattern =
      reinterpret_cast<icu::RegexMatcher*>(tls_index.Get());
  if (!dangerous_pattern) {
     dangerous_pattern = new icu::RegexMatcher(
        icu::UnicodeString(
            R"([^\p{scx=kana}\p{scx=hira}\p{scx=hani}])"
            R"([\u30ce\u30f3\u30bd\u30be])"
            R"([^\p{scx=kana}\p{scx=hira}\p{scx=hani}]|)"
            R"([^\p{scx=kana}\p{scx=hira}]\u30fc|^\u30fc|)"
            R"([^\p{scx=kana}][\u30fd\u30fe]|^[\u30fd\u30fe]|)"
            R"(^[\p{scx=kana}]+[\u3078-\u307a][\p{scx=kana}]+$|)"
             R"(^[\p{scx=hira}]+[\u30d8-\u30da][\p{scx=hira}]+$|)"
             R"([a-z]\u30fb|\u30fb[a-z]|)"
             R"([^\p{scx=latn}\p{scx=grek}\p{scx=cyrl}][\u0300-\u0339]|)"
            R"([ijl\u0131]\u0307)",
             -1, US_INV),
         0, status);
     tls_index.Set(dangerous_pattern);
  }
  dangerous_pattern->reset(label_string);
  return !dangerous_pattern->find();
}

Incorrect security UI in Omnibox in Google Chrome prior to 64.0.3282.119 allowed a remote attacker to spoof the contents of the Omnibox (URL bar) via a crafted HTML page.


bool IDNSpoofChecker::SafeToDisplayAsUnicode(base::StringPiece16 label,
                                             bool is_tld_ascii) {
  UErrorCode status = U_ZERO_ERROR;
  int32_t result =
      uspoof_check(checker_, label.data(),
                   base::checked_cast<int32_t>(label.size()), nullptr, &status);
  if (U_FAILURE(status) || (result & USPOOF_ALL_CHECKS))
    return false;

  icu::UnicodeString label_string(FALSE, label.data(),
                                  base::checked_cast<int32_t>(label.size()));

  if (deviation_characters_.containsSome(label_string))
    return false;

  result &= USPOOF_RESTRICTION_LEVEL_MASK;
  if (result == USPOOF_ASCII)
    return true;
  if (result == USPOOF_SINGLE_SCRIPT_RESTRICTIVE &&
      kana_letters_exceptions_.containsNone(label_string) &&
      combining_diacritics_exceptions_.containsNone(label_string)) {
    return !is_tld_ascii || !IsMadeOfLatinAlikeCyrillic(label_string);
  }

  if (non_ascii_latin_letters_.containsSome(label_string) &&
      !lgc_letters_n_ascii_.containsAll(label_string))
    return false;

  if (!tls_index.initialized())
    tls_index.Initialize(&OnThreadTermination);
  icu::RegexMatcher* dangerous_pattern =
      reinterpret_cast<icu::RegexMatcher*>(tls_index.Get());
  if (!dangerous_pattern) {
    // - Disallow dotless i (U+0131) followed by a combining mark.
     dangerous_pattern = new icu::RegexMatcher(
        icu::UnicodeString(
            R"([^\p{scx=kana}\p{scx=hira}\p{scx=hani}])"
            R"([\u30ce\u30f3\u30bd\u30be])"
            R"([^\p{scx=kana}\p{scx=hira}\p{scx=hani}]|)"
            R"([^\p{scx=kana}\p{scx=hira}]\u30fc|^\u30fc|)"
            R"([^\p{scx=kana}][\u30fd\u30fe]|^[\u30fd\u30fe]|)"
            R"(^[\p{scx=kana}]+[\u3078-\u307a][\p{scx=kana}]+$|)"
             R"(^[\p{scx=hira}]+[\u30d8-\u30da][\p{scx=hira}]+$|)"
             R"([a-z]\u30fb|\u30fb[a-z]|)"
             R"([^\p{scx=latn}\p{scx=grek}\p{scx=cyrl}][\u0300-\u0339]|)"
            R"(\u0131[\u0300-\u0339]|)"
            R"([ijl]\u0307)",
             -1, US_INV),
         0, status);
     tls_index.Set(dangerous_pattern);
  }
  dangerous_pattern->reset(label_string);
  return !dangerous_pattern->find();
}


void XSSAuditor::Init(Document* document,
                      XSSAuditorDelegate* auditor_delegate) {
  DCHECK(IsMainThread());
  if (state_ != kUninitialized)
    return;
  state_ = kFilteringTokens;

  if (Settings* settings = document->GetSettings())
    is_enabled_ = settings->GetXSSAuditorEnabled();

  if (!is_enabled_)
    return;

  document_url_ = document->Url().Copy();

  if (!document->GetFrame()) {
    is_enabled_ = false;
    return;
  }

  if (document_url_.IsEmpty()) {
    is_enabled_ = false;
    return;
  }

  if (document_url_.ProtocolIsData()) {
    is_enabled_ = false;
    return;
  }

  if (document->Encoding().IsValid())
    encoding_ = document->Encoding();

  if (DocumentLoader* document_loader =
          document->GetFrame()->Loader().GetDocumentLoader()) {
    const AtomicString& header_value =
        document_loader->GetResponse().HttpHeaderField(
            HTTPNames::X_XSS_Protection);
    String error_details;
    unsigned error_position = 0;
    String report_url;
    KURL xss_protection_report_url;

    ReflectedXSSDisposition xss_protection_header = ParseXSSProtectionHeader(
        header_value, error_details, error_position, report_url);

    if (xss_protection_header == kAllowReflectedXSS)
      UseCounter::Count(*document, WebFeature::kXSSAuditorDisabled);
    else if (xss_protection_header == kFilterReflectedXSS)
      UseCounter::Count(*document, WebFeature::kXSSAuditorEnabledFilter);
    else if (xss_protection_header == kBlockReflectedXSS)
      UseCounter::Count(*document, WebFeature::kXSSAuditorEnabledBlock);
    else if (xss_protection_header == kReflectedXSSInvalid)
      UseCounter::Count(*document, WebFeature::kXSSAuditorInvalid);

    did_send_valid_xss_protection_header_ =
        xss_protection_header != kReflectedXSSUnset &&
        xss_protection_header != kReflectedXSSInvalid;
    if ((xss_protection_header == kFilterReflectedXSS ||
          xss_protection_header == kBlockReflectedXSS) &&
         !report_url.IsEmpty()) {
       xss_protection_report_url = document->CompleteURL(report_url);
       if (MixedContentChecker::IsMixedContent(document->GetSecurityOrigin(),
                                               xss_protection_report_url)) {
         error_details = "insecure reporting URL for secure page";
        xss_protection_header = kReflectedXSSInvalid;
        xss_protection_report_url = KURL();
      }
    }
    if (xss_protection_header == kReflectedXSSInvalid) {
      document->AddConsoleMessage(ConsoleMessage::Create(
          kSecurityMessageSource, kErrorMessageLevel,
          "Error parsing header X-XSS-Protection: " + header_value + ": " +
              error_details + " at character position " +
              String::Format("%u", error_position) +
              ". The default protections will be applied."));
    }

    xss_protection_ = xss_protection_header;
    if (xss_protection_ == kReflectedXSSInvalid ||
        xss_protection_ == kReflectedXSSUnset) {
      xss_protection_ = kBlockReflectedXSS;
    }

    if (auditor_delegate)
      auditor_delegate->SetReportURL(xss_protection_report_url.Copy());

    EncodedFormData* http_body = document_loader->GetRequest().HttpBody();
    if (http_body && !http_body->IsEmpty())
      http_body_as_string_ = http_body->FlattenToString();
  }

  SetEncoding(encoding_);
}

XSS Auditor in Google Chrome prior to 64.0.3282.119, did not ensure the reporting URL was in the same origin as the page it was on, which allowed a remote attacker to obtain referrer details via a crafted HTML page.


void XSSAuditor::Init(Document* document,
                      XSSAuditorDelegate* auditor_delegate) {
  DCHECK(IsMainThread());
  if (state_ != kUninitialized)
    return;
  state_ = kFilteringTokens;

  if (Settings* settings = document->GetSettings())
    is_enabled_ = settings->GetXSSAuditorEnabled();

  if (!is_enabled_)
    return;

  document_url_ = document->Url().Copy();

  if (!document->GetFrame()) {
    is_enabled_ = false;
    return;
  }

  if (document_url_.IsEmpty()) {
    is_enabled_ = false;
    return;
  }

  if (document_url_.ProtocolIsData()) {
    is_enabled_ = false;
    return;
  }

  if (document->Encoding().IsValid())
    encoding_ = document->Encoding();

  if (DocumentLoader* document_loader =
          document->GetFrame()->Loader().GetDocumentLoader()) {
    const AtomicString& header_value =
        document_loader->GetResponse().HttpHeaderField(
            HTTPNames::X_XSS_Protection);
    String error_details;
    unsigned error_position = 0;
    String report_url;
    KURL xss_protection_report_url;

    ReflectedXSSDisposition xss_protection_header = ParseXSSProtectionHeader(
        header_value, error_details, error_position, report_url);

    if (xss_protection_header == kAllowReflectedXSS)
      UseCounter::Count(*document, WebFeature::kXSSAuditorDisabled);
    else if (xss_protection_header == kFilterReflectedXSS)
      UseCounter::Count(*document, WebFeature::kXSSAuditorEnabledFilter);
    else if (xss_protection_header == kBlockReflectedXSS)
      UseCounter::Count(*document, WebFeature::kXSSAuditorEnabledBlock);
    else if (xss_protection_header == kReflectedXSSInvalid)
      UseCounter::Count(*document, WebFeature::kXSSAuditorInvalid);

    did_send_valid_xss_protection_header_ =
        xss_protection_header != kReflectedXSSUnset &&
        xss_protection_header != kReflectedXSSInvalid;
    if ((xss_protection_header == kFilterReflectedXSS ||
          xss_protection_header == kBlockReflectedXSS) &&
         !report_url.IsEmpty()) {
       xss_protection_report_url = document->CompleteURL(report_url);
      if (!SecurityOrigin::Create(xss_protection_report_url)
               ->IsSameSchemeHostPort(document->GetSecurityOrigin())) {
        error_details =
            "reporting URL is not same scheme, host, and port as page";
        xss_protection_header = kReflectedXSSInvalid;
        xss_protection_report_url = KURL();
      }
       if (MixedContentChecker::IsMixedContent(document->GetSecurityOrigin(),
                                               xss_protection_report_url)) {
         error_details = "insecure reporting URL for secure page";
        xss_protection_header = kReflectedXSSInvalid;
        xss_protection_report_url = KURL();
      }
    }
    if (xss_protection_header == kReflectedXSSInvalid) {
      document->AddConsoleMessage(ConsoleMessage::Create(
          kSecurityMessageSource, kErrorMessageLevel,
          "Error parsing header X-XSS-Protection: " + header_value + ": " +
              error_details + " at character position " +
              String::Format("%u", error_position) +
              ". The default protections will be applied."));
    }

    xss_protection_ = xss_protection_header;
    if (xss_protection_ == kReflectedXSSInvalid ||
        xss_protection_ == kReflectedXSSUnset) {
      xss_protection_ = kBlockReflectedXSS;
    }

    if (auditor_delegate)
      auditor_delegate->SetReportURL(xss_protection_report_url.Copy());

    EncodedFormData* http_body = document_loader->GetRequest().HttpBody();
    if (http_body && !http_body->IsEmpty())
      http_body_as_string_ = http_body->FlattenToString();
  }

  SetEncoding(encoding_);
}


void TopSitesImpl::SetTopSites(const MostVisitedURLList& new_top_sites,
                               const CallLocation location) {
  DCHECK(thread_checker_.CalledOnValidThread());

  MostVisitedURLList top_sites(new_top_sites);
  size_t num_forced_urls = MergeCachedForcedURLs(&top_sites);
  AddPrepopulatedPages(&top_sites, num_forced_urls);

  TopSitesDelta delta;
  DiffMostVisited(cache_->top_sites(), top_sites, &delta);

  TopSitesBackend::RecordHistogram record_or_not =
      TopSitesBackend::RECORD_HISTOGRAM_NO;

  if (location == CALL_LOCATION_FROM_ON_GOT_MOST_VISITED_THUMBNAILS &&
      !histogram_recorded_) {
    size_t delta_size =
        delta.deleted.size() + delta.added.size() + delta.moved.size();
    UMA_HISTOGRAM_COUNTS_100("History.FirstSetTopSitesDeltaSize", delta_size);
    record_or_not = TopSitesBackend::RECORD_HISTOGRAM_YES;
    histogram_recorded_ = true;
  }

  bool should_notify_observers = false;
  if (!delta.deleted.empty() || !delta.added.empty() || !delta.moved.empty()) {
    backend_->UpdateTopSites(delta, record_or_not);
    should_notify_observers = true;
  }
  if (!should_notify_observers)
    should_notify_observers = DoTitlesDiffer(cache_->top_sites(), top_sites);

   cache_->SetTopSites(top_sites);

  if (!temp_images_.empty()) {
    for (const MostVisitedURL& mv : top_sites) {
      const GURL& canonical_url = cache_->GetCanonicalURL(mv.url);
      for (TempImages::iterator it = temp_images_.begin();
           it != temp_images_.end(); ++it) {
        if (canonical_url == cache_->GetCanonicalURL(it->first)) {
          bool success = SetPageThumbnailEncoded(
              mv.url, it->second.thumbnail.get(), it->second.thumbnail_score);
          if (success) {
            UMA_HISTOGRAM_ENUMERATION("Thumbnails.AddedToTopSites",
                                      THUMBNAIL_PROMOTED_TEMP_TO_REGULAR,
                                      THUMBNAIL_EVENT_COUNT);
          }
          temp_images_.erase(it);
          break;
        }
      }
    }
  }

  if (top_sites.size() - num_forced_urls >= kNonForcedTopSitesNumber)
    temp_images_.clear();

  ResetThreadSafeCache();
  ResetThreadSafeImageCache();

  if (should_notify_observers) {
    if (location == CALL_LOCATION_FROM_FORCED_URLS)
      NotifyTopSitesChanged(TopSitesObserver::ChangeReason::FORCED_URL);
    else
      NotifyTopSitesChanged(TopSitesObserver::ChangeReason::MOST_VISITED);
  }

}

Inappropriate implementation in New Tab Page in Google Chrome prior to 64.0.3282.119 allowed a local attacker to view website thumbnail images after clearing browser data via a crafted HTML page.


void TopSitesImpl::SetTopSites(const MostVisitedURLList& new_top_sites,
                               const CallLocation location) {
  DCHECK(thread_checker_.CalledOnValidThread());

  MostVisitedURLList top_sites(new_top_sites);
  size_t num_forced_urls = MergeCachedForcedURLs(&top_sites);
  AddPrepopulatedPages(&top_sites, num_forced_urls);

  TopSitesDelta delta;
  DiffMostVisited(cache_->top_sites(), top_sites, &delta);

  TopSitesBackend::RecordHistogram record_or_not =
      TopSitesBackend::RECORD_HISTOGRAM_NO;

  if (location == CALL_LOCATION_FROM_ON_GOT_MOST_VISITED_THUMBNAILS &&
      !histogram_recorded_) {
    size_t delta_size =
        delta.deleted.size() + delta.added.size() + delta.moved.size();
    UMA_HISTOGRAM_COUNTS_100("History.FirstSetTopSitesDeltaSize", delta_size);
    record_or_not = TopSitesBackend::RECORD_HISTOGRAM_YES;
    histogram_recorded_ = true;
  }

  bool should_notify_observers = false;
  if (!delta.deleted.empty() || !delta.added.empty() || !delta.moved.empty()) {
    backend_->UpdateTopSites(delta, record_or_not);
    should_notify_observers = true;
  }
  if (!should_notify_observers)
    should_notify_observers = DoTitlesDiffer(cache_->top_sites(), top_sites);

   cache_->SetTopSites(top_sites);
  cache_->ClearUnreferencedThumbnails();

  if (!temp_images_.empty()) {
    for (const MostVisitedURL& mv : top_sites) {
      const GURL& canonical_url = cache_->GetCanonicalURL(mv.url);
      for (TempImages::iterator it = temp_images_.begin();
           it != temp_images_.end(); ++it) {
        if (canonical_url == cache_->GetCanonicalURL(it->first)) {
          bool success = SetPageThumbnailEncoded(
              mv.url, it->second.thumbnail.get(), it->second.thumbnail_score);
          if (success) {
            UMA_HISTOGRAM_ENUMERATION("Thumbnails.AddedToTopSites",
                                      THUMBNAIL_PROMOTED_TEMP_TO_REGULAR,
                                      THUMBNAIL_EVENT_COUNT);
          }
          temp_images_.erase(it);
          break;
        }
      }
    }
  }

  if (top_sites.size() - num_forced_urls >= kNonForcedTopSitesNumber)
    temp_images_.clear();

  ResetThreadSafeCache();
  ResetThreadSafeImageCache();

  if (should_notify_observers) {
    if (location == CALL_LOCATION_FROM_FORCED_URLS)
      NotifyTopSitesChanged(TopSitesObserver::ChangeReason::FORCED_URL);
    else
      NotifyTopSitesChanged(TopSitesObserver::ChangeReason::MOST_VISITED);
  }

}


void WebUIExtension::Send(gin::Arguments* args) {
  blink::WebLocalFrame* frame;
  RenderFrame* render_frame;
  if (!ShouldRespondToRequest(&frame, &render_frame))
    return;

  std::string message;
  if (!args->GetNext(&message)) {
    args->ThrowError();
    return;
  }

  if (base::EndsWith(message, "RequiringGesture",
                     base::CompareCase::SENSITIVE) &&
      !blink::WebUserGestureIndicator::IsProcessingUserGesture(frame)) {
    NOTREACHED();
    return;
  }

  std::unique_ptr<base::ListValue> content;
  if (args->PeekNext().IsEmpty() || args->PeekNext()->IsUndefined()) {
    content.reset(new base::ListValue());
  } else {
    v8::Local<v8::Object> obj;
    if (!args->GetNext(&obj)) {
      args->ThrowError();
      return;
    }

     content = base::ListValue::From(V8ValueConverter::Create()->FromV8Value(
         obj, frame->MainWorldScriptContext()));
     DCHECK(content);
   }

  render_frame->Send(new FrameHostMsg_WebUISend(render_frame->GetRoutingID(),
                                                frame->GetDocument().Url(),
                                                message, *content));
}

Use after free in WebUI in Google Chrome prior to 64.0.3282.119 allowed a remote attacker to potentially exploit heap corruption via a crafted Chrome Extension.


void WebUIExtension::Send(gin::Arguments* args) {
  blink::WebLocalFrame* frame;
  RenderFrame* render_frame;
  if (!ShouldRespondToRequest(&frame, &render_frame))
    return;

  std::string message;
  if (!args->GetNext(&message)) {
    args->ThrowError();
    return;
  }

  if (base::EndsWith(message, "RequiringGesture",
                     base::CompareCase::SENSITIVE) &&
      !blink::WebUserGestureIndicator::IsProcessingUserGesture(frame)) {
    NOTREACHED();
    return;
  }

  std::unique_ptr<base::ListValue> content;
  if (args->PeekNext().IsEmpty() || args->PeekNext()->IsUndefined()) {
    content.reset(new base::ListValue());
  } else {
    v8::Local<v8::Object> obj;
    if (!args->GetNext(&obj)) {
      args->ThrowError();
      return;
    }

     content = base::ListValue::From(V8ValueConverter::Create()->FromV8Value(
         obj, frame->MainWorldScriptContext()));
     DCHECK(content);
    // The conversion of |obj| could have triggered arbitrary JavaScript code,
    // so check that the frame is still valid to avoid dereferencing a stale
    // pointer.
    if (frame != blink::WebLocalFrame::FrameForCurrentContext()) {
      NOTREACHED();
      return;
    }
   }

  render_frame->Send(new FrameHostMsg_WebUISend(render_frame->GetRoutingID(),
                                                frame->GetDocument().Url(),
                                                message, *content));
}


void MemBackendImpl::EvictIfNeeded() {
  if (current_size_ <= max_size_)
    return;

  int target_size = std::max(0, max_size_ - kDefaultEvictionSize);

   base::LinkNode<MemEntryImpl>* entry = lru_list_.head();
   while (current_size_ > target_size && entry != lru_list_.end()) {
     MemEntryImpl* to_doom = entry->value();
    entry = entry->next();
     if (!to_doom->InUse())
       to_doom->Doom();
   }
}

A double-eviction in the Incognito mode cache that lead to a user-after-free in Networking Disk Cache in Google Chrome prior to 66.0.3359.117 allowed a remote attacker to execute arbitrary code via a crafted HTML page.


void MemBackendImpl::EvictIfNeeded() {
  if (current_size_ <= max_size_)
    return;

  int target_size = std::max(0, max_size_ - kDefaultEvictionSize);

   base::LinkNode<MemEntryImpl>* entry = lru_list_.head();
   while (current_size_ > target_size && entry != lru_list_.end()) {
     MemEntryImpl* to_doom = entry->value();

    do {
      entry = entry->next();
      // It's possible that entry now points to a child of to_doom, and the
      // parent is about to be deleted. Skip past any child entries.
    } while (entry != lru_list_.end() && entry->value()->parent() == to_doom);

     if (!to_doom->InUse())
       to_doom->Doom();
   }
}


 int PDFiumEngine::GetVisiblePageIndex(FPDF_PAGE page) {
  for (int page_index : visible_pages_) {
     if (pages_[page_index]->GetPage() == page)
       return page_index;
   }
  return -1;
}

An iterator-invalidation bug in PDFium in Google Chrome prior to 66.0.3359.117 allowed a remote attacker to execute arbitrary code inside a sandbox via a crafted PDF file.


 int PDFiumEngine::GetVisiblePageIndex(FPDF_PAGE page) {
  // Copy visible_pages_ since it can change as a result of loading the page in
  // GetPage(). See https://crbug.com/822091.
  std::vector<int> visible_pages_copy(visible_pages_);
  for (int page_index : visible_pages_copy) {
     if (pages_[page_index]->GetPage() == page)
       return page_index;
   }
  return -1;
}


 void ServerWrapper::OnHttpRequest(int connection_id,
                                   const net::HttpServerRequestInfo& info) {
   server_->SetSendBufferSize(connection_id, kSendBufferSizeForDevTools);

   if (base::StartsWith(info.path, "/json", base::CompareCase::SENSITIVE)) {
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                            base::BindOnce(&DevToolsHttpHandler::OnJsonRequest,
                                           handler_, connection_id, info));
    return;
  }

  if (info.path.empty() || info.path == "/") {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        base::BindOnce(&DevToolsHttpHandler::OnDiscoveryPageRequest, handler_,
                       connection_id));
    return;
  }

  if (!base::StartsWith(info.path, "/devtools/",
                        base::CompareCase::SENSITIVE)) {
    server_->Send404(connection_id, kDevtoolsHttpHandlerTrafficAnnotation);
    return;
  }

  std::string filename = PathWithoutParams(info.path.substr(10));
  std::string mime_type = GetMimeType(filename);

  if (!debug_frontend_dir_.empty()) {
    base::FilePath path = debug_frontend_dir_.AppendASCII(filename);
    std::string data;
    base::ReadFileToString(path, &data);
    server_->Send200(connection_id, data, mime_type,
                     kDevtoolsHttpHandlerTrafficAnnotation);
    return;
  }

  if (bundles_resources_) {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        base::BindOnce(&DevToolsHttpHandler::OnFrontendResourceRequest,
                       handler_, connection_id, filename));
    return;
  }
  server_->Send404(connection_id, kDevtoolsHttpHandlerTrafficAnnotation);
}

A lack of host validation in DevTools in Google Chrome prior to 66.0.3359.117 allowed a remote attacker to execute arbitrary code via a crafted HTML page, if the user is running a remote DevTools debugging server.


 void ServerWrapper::OnHttpRequest(int connection_id,
                                   const net::HttpServerRequestInfo& info) {
  if (!RequestIsSafeToServe(info)) {
    Send500(connection_id,
            "Host header is specified and is not an IP address or localhost.");
    return;
  }

   server_->SetSendBufferSize(connection_id, kSendBufferSizeForDevTools);

   if (base::StartsWith(info.path, "/json", base::CompareCase::SENSITIVE)) {
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                            base::BindOnce(&DevToolsHttpHandler::OnJsonRequest,
                                           handler_, connection_id, info));
    return;
  }

  if (info.path.empty() || info.path == "/") {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        base::BindOnce(&DevToolsHttpHandler::OnDiscoveryPageRequest, handler_,
                       connection_id));
    return;
  }

  if (!base::StartsWith(info.path, "/devtools/",
                        base::CompareCase::SENSITIVE)) {
    server_->Send404(connection_id, kDevtoolsHttpHandlerTrafficAnnotation);
    return;
  }

  std::string filename = PathWithoutParams(info.path.substr(10));
  std::string mime_type = GetMimeType(filename);

  if (!debug_frontend_dir_.empty()) {
    base::FilePath path = debug_frontend_dir_.AppendASCII(filename);
    std::string data;
    base::ReadFileToString(path, &data);
    server_->Send200(connection_id, data, mime_type,
                     kDevtoolsHttpHandlerTrafficAnnotation);
    return;
  }

  if (bundles_resources_) {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        base::BindOnce(&DevToolsHttpHandler::OnFrontendResourceRequest,
                       handler_, connection_id, filename));
    return;
  }
  server_->Send404(connection_id, kDevtoolsHttpHandlerTrafficAnnotation);
}


IDNSpoofChecker::IDNSpoofChecker() {
  UErrorCode status = U_ZERO_ERROR;
  checker_ = uspoof_open(&status);
  if (U_FAILURE(status)) {
    checker_ = nullptr;
    return;
  }

  uspoof_setRestrictionLevel(checker_, USPOOF_HIGHLY_RESTRICTIVE);

  SetAllowedUnicodeSet(&status);

  int32_t checks = uspoof_getChecks(checker_, &status) | USPOOF_AUX_INFO;
  uspoof_setChecks(checker_, checks, &status);

  deviation_characters_ = icu::UnicodeSet(
      UNICODE_STRING_SIMPLE("[\\u00df\\u03c2\\u200c\\u200d]"), status);
  deviation_characters_.freeze();

  non_ascii_latin_letters_ =
      icu::UnicodeSet(UNICODE_STRING_SIMPLE("[[:Latin:] - [a-zA-Z]]"), status);
  non_ascii_latin_letters_.freeze();

  kana_letters_exceptions_ = icu::UnicodeSet(
      UNICODE_STRING_SIMPLE("[\\u3078-\\u307a\\u30d8-\\u30da\\u30fb-\\u30fe]"),
      status);
  kana_letters_exceptions_.freeze();
  combining_diacritics_exceptions_ =
      icu::UnicodeSet(UNICODE_STRING_SIMPLE("[\\u0300-\\u0339]"), status);
  combining_diacritics_exceptions_.freeze();

  cyrillic_letters_latin_alike_ = icu::UnicodeSet(
      icu::UnicodeString::fromUTF8("[асԁеһіјӏорԛѕԝхуъЬҽпгѵѡ]"), status);
  cyrillic_letters_latin_alike_.freeze();

  cyrillic_letters_ =
      icu::UnicodeSet(UNICODE_STRING_SIMPLE("[[:Cyrl:]]"), status);
  cyrillic_letters_.freeze();

  DCHECK(U_SUCCESS(status));
  lgc_letters_n_ascii_ = icu::UnicodeSet(
      UNICODE_STRING_SIMPLE("[[:Latin:][:Greek:][:Cyrillic:][0-9\\u002e_"
                            "\\u002d][\\u0300-\\u0339]]"),
      status);
  lgc_letters_n_ascii_.freeze();

  UParseError parse_error;
  diacritic_remover_.reset(icu::Transliterator::createFromRules(
      UNICODE_STRING_SIMPLE("DropAcc"),
      icu::UnicodeString::fromUTF8("::NFD; ::[:Nonspacing Mark:] Remove; ::NFC;"
                                   " ł > l; ø > o; đ > d;"),
      UTRANS_FORWARD, parse_error, status));

   extra_confusable_mapper_.reset(icu::Transliterator::createFromRules(
       UNICODE_STRING_SIMPLE("ExtraConf"),
      icu::UnicodeString::fromUTF8("[þϼҏ] > p; [ħнћңҥӈԧԩ] > h;"
                                    "[ĸκкқҝҟҡӄԟ] > k; [ŋп] > n; [ŧтҭ] > t;"
                                   "[ƅьҍв] > b;  [ωшщ] > w; [мӎ] > m;"
                                    "[єҽҿၔ] > e; ґ > r; ғ > f; [ҫင] > c;"
                                    "ұ > y; [χҳӽӿ] > x;"
 #if defined(OS_WIN)
                                    "ӏ > i;"
 #else
                                    "ӏ > l;"
 #endif
                                   "ԃ  > d; [ԍဌ] > g; ട > s; ၂ > j"),
       UTRANS_FORWARD, parse_error, status));
   DCHECK(U_SUCCESS(status))
       << "Spoofchecker initalization failed due to an error: "
      << u_errorName(status);
}

Missing confusable characters in Internationalization in Google Chrome prior to 66.0.3359.117 allowed a remote attacker to spoof the contents of the Omnibox (URL bar) via a crafted domain name.


IDNSpoofChecker::IDNSpoofChecker() {
  UErrorCode status = U_ZERO_ERROR;
  checker_ = uspoof_open(&status);
  if (U_FAILURE(status)) {
    checker_ = nullptr;
    return;
  }

  uspoof_setRestrictionLevel(checker_, USPOOF_HIGHLY_RESTRICTIVE);

  SetAllowedUnicodeSet(&status);

  int32_t checks = uspoof_getChecks(checker_, &status) | USPOOF_AUX_INFO;
  uspoof_setChecks(checker_, checks, &status);

  deviation_characters_ = icu::UnicodeSet(
      UNICODE_STRING_SIMPLE("[\\u00df\\u03c2\\u200c\\u200d]"), status);
  deviation_characters_.freeze();

  non_ascii_latin_letters_ =
      icu::UnicodeSet(UNICODE_STRING_SIMPLE("[[:Latin:] - [a-zA-Z]]"), status);
  non_ascii_latin_letters_.freeze();

  kana_letters_exceptions_ = icu::UnicodeSet(
      UNICODE_STRING_SIMPLE("[\\u3078-\\u307a\\u30d8-\\u30da\\u30fb-\\u30fe]"),
      status);
  kana_letters_exceptions_.freeze();
  combining_diacritics_exceptions_ =
      icu::UnicodeSet(UNICODE_STRING_SIMPLE("[\\u0300-\\u0339]"), status);
  combining_diacritics_exceptions_.freeze();

  cyrillic_letters_latin_alike_ = icu::UnicodeSet(
      icu::UnicodeString::fromUTF8("[асԁеһіјӏорԛѕԝхуъЬҽпгѵѡ]"), status);
  cyrillic_letters_latin_alike_.freeze();

  cyrillic_letters_ =
      icu::UnicodeSet(UNICODE_STRING_SIMPLE("[[:Cyrl:]]"), status);
  cyrillic_letters_.freeze();

  DCHECK(U_SUCCESS(status));
  lgc_letters_n_ascii_ = icu::UnicodeSet(
      UNICODE_STRING_SIMPLE("[[:Latin:][:Greek:][:Cyrillic:][0-9\\u002e_"
                            "\\u002d][\\u0300-\\u0339]]"),
      status);
  lgc_letters_n_ascii_.freeze();

  UParseError parse_error;
  diacritic_remover_.reset(icu::Transliterator::createFromRules(
      UNICODE_STRING_SIMPLE("DropAcc"),
      icu::UnicodeString::fromUTF8("::NFD; ::[:Nonspacing Mark:] Remove; ::NFC;"
                                   " ł > l; ø > o; đ > d;"),
      UTRANS_FORWARD, parse_error, status));

  //      U+04C8 (ӈ), U+04CA (ӊ), U+0527 (ԧ), U+0529 (ԩ)} => h
  //   - {U+03C9 (ω), U+0448 (ш), U+0449 (щ), U+0E1F (ฟ)} => w
  //   - {U+0D1F (ട), U+0E23 (ร)} => s
   extra_confusable_mapper_.reset(icu::Transliterator::createFromRules(
       UNICODE_STRING_SIMPLE("ExtraConf"),
      icu::UnicodeString::fromUTF8("[þϼҏ] > p; [ħнћңҥӈӊԧԩ] > h;"
                                    "[ĸκкқҝҟҡӄԟ] > k; [ŋп] > n; [ŧтҭ] > t;"
                                   "[ƅьҍв] > b;  [ωшщฟ] > w; [мӎ] > m;"
                                    "[єҽҿၔ] > e; ґ > r; ғ > f; [ҫင] > c;"
                                    "ұ > y; [χҳӽӿ] > x;"
 #if defined(OS_WIN)
                                    "ӏ > i;"
 #else
                                    "ӏ > l;"
 #endif
                                   "ԃ  > d; [ԍဌ] > g; [ടร] > s; ၂ > j"),
       UTRANS_FORWARD, parse_error, status));
   DCHECK(U_SUCCESS(status))
       << "Spoofchecker initalization failed due to an error: "
      << u_errorName(status);
}


 bool NavigateToUrlWithEdge(const base::string16& url) {
   base::string16 protocol_url = L"microsoft-edge:" + url;
   SHELLEXECUTEINFO info = { sizeof(info) };
  info.fMask = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI;
   info.lpVerb = L"open";
   info.lpFile = protocol_url.c_str();
   info.nShow = SW_SHOWNORMAL;
  if (::ShellExecuteEx(&info))
    return true;
  PLOG(ERROR) << "Failed to launch Edge for uninstall survey";
  return false;
}

Inappropriate setting of the SEE_MASK_FLAG_NO_UI flag in file downloads in Google Chrome prior to 66.0.3359.117 allowed a remote attacker to potentially bypass OS malware checks via a crafted HTML page.


 bool NavigateToUrlWithEdge(const base::string16& url) {
   base::string16 protocol_url = L"microsoft-edge:" + url;
   SHELLEXECUTEINFO info = { sizeof(info) };
  info.fMask = SEE_MASK_NOASYNC;
   info.lpVerb = L"open";
   info.lpFile = protocol_url.c_str();
   info.nShow = SW_SHOWNORMAL;
  if (::ShellExecuteEx(&info))
    return true;
  PLOG(ERROR) << "Failed to launch Edge for uninstall survey";
  return false;
}


void AddPasswordsAndFormsStrings(content::WebUIDataSource* html_source) {
  LocalizedString localized_strings[] = {
      {"passwordsAndAutofillPageTitle",
       IDS_SETTINGS_PASSWORDS_AND_AUTOFILL_PAGE_TITLE},
       {"autofill", IDS_SETTINGS_AUTOFILL},
       {"googlePayments", IDS_SETTINGS_GOOGLE_PAYMENTS},
       {"googlePaymentsCached", IDS_SETTINGS_GOOGLE_PAYMENTS_CACHED},
       {"addresses", IDS_SETTINGS_AUTOFILL_ADDRESSES_HEADING},
       {"addAddressTitle", IDS_SETTINGS_AUTOFILL_ADDRESSES_ADD_TITLE},
       {"editAddressTitle", IDS_SETTINGS_AUTOFILL_ADDRESSES_EDIT_TITLE},
      {"addressCountry", IDS_SETTINGS_AUTOFILL_ADDRESSES_COUNTRY},
      {"addressPhone", IDS_SETTINGS_AUTOFILL_ADDRESSES_PHONE},
      {"addressEmail", IDS_SETTINGS_AUTOFILL_ADDRESSES_EMAIL},
      {"removeAddress", IDS_SETTINGS_ADDRESS_REMOVE},
      {"creditCards", IDS_SETTINGS_AUTOFILL_CREDIT_CARD_HEADING},
      {"removeCreditCard", IDS_SETTINGS_CREDIT_CARD_REMOVE},
      {"clearCreditCard", IDS_SETTINGS_CREDIT_CARD_CLEAR},
      {"creditCardType", IDS_SETTINGS_AUTOFILL_CREDIT_CARD_TYPE_COLUMN_LABEL},
      {"creditCardExpiration", IDS_SETTINGS_CREDIT_CARD_EXPIRATION_DATE},
      {"creditCardName", IDS_SETTINGS_NAME_ON_CREDIT_CARD},
      {"creditCardNumber", IDS_SETTINGS_CREDIT_CARD_NUMBER},
      {"creditCardExpirationMonth", IDS_SETTINGS_CREDIT_CARD_EXPIRATION_MONTH},
      {"creditCardExpirationYear", IDS_SETTINGS_CREDIT_CARD_EXPIRATION_YEAR},
      {"creditCardExpired", IDS_SETTINGS_CREDIT_CARD_EXPIRED},
      {"editCreditCardTitle", IDS_SETTINGS_EDIT_CREDIT_CARD_TITLE},
       {"addCreditCardTitle", IDS_SETTINGS_ADD_CREDIT_CARD_TITLE},
       {"autofillDetail", IDS_SETTINGS_AUTOFILL_DETAIL},
       {"passwords", IDS_SETTINGS_PASSWORDS},
       {"passwordsAutosigninLabel",
        IDS_SETTINGS_PASSWORDS_AUTOSIGNIN_CHECKBOX_LABEL},
       {"passwordsAutosigninDescription",
       IDS_SETTINGS_PASSWORDS_AUTOSIGNIN_CHECKBOX_DESC},
      {"passwordsDetail", IDS_SETTINGS_PASSWORDS_DETAIL},
      {"savedPasswordsHeading", IDS_SETTINGS_PASSWORDS_SAVED_HEADING},
      {"passwordExceptionsHeading", IDS_SETTINGS_PASSWORDS_EXCEPTIONS_HEADING},
      {"deletePasswordException", IDS_SETTINGS_PASSWORDS_DELETE_EXCEPTION},
      {"removePassword", IDS_SETTINGS_PASSWORD_REMOVE},
      {"searchPasswords", IDS_SETTINGS_PASSWORD_SEARCH},
      {"showPassword", IDS_SETTINGS_PASSWORD_SHOW},
      {"hidePassword", IDS_SETTINGS_PASSWORD_HIDE},
      {"passwordDetailsTitle", IDS_SETTINGS_PASSWORDS_VIEW_DETAILS_TITLE},
      {"passwordViewDetails", IDS_SETTINGS_PASSWORD_DETAILS},
      {"editPasswordWebsiteLabel", IDS_SETTINGS_PASSWORDS_WEBSITE},
      {"editPasswordUsernameLabel", IDS_SETTINGS_PASSWORDS_USERNAME},
      {"editPasswordPasswordLabel", IDS_SETTINGS_PASSWORDS_PASSWORD},
      {"noAddressesFound", IDS_SETTINGS_ADDRESS_NONE},
      {"noCreditCardsFound", IDS_SETTINGS_CREDIT_CARD_NONE},
      {"noCreditCardsPolicy", IDS_SETTINGS_CREDIT_CARD_DISABLED},
      {"noPasswordsFound", IDS_SETTINGS_PASSWORDS_NONE},
      {"noExceptionsFound", IDS_SETTINGS_PASSWORDS_EXCEPTIONS_NONE},
      {"import", IDS_PASSWORD_MANAGER_IMPORT_BUTTON},
      {"exportMenuItem", IDS_SETTINGS_PASSWORDS_EXPORT_MENU_ITEM},
      {"undoRemovePassword", IDS_SETTINGS_PASSWORD_UNDO},
      {"passwordDeleted", IDS_SETTINGS_PASSWORD_DELETED_PASSWORD},
      {"exportPasswordsTitle", IDS_SETTINGS_PASSWORDS_EXPORT_TITLE},
      {"exportPasswordsDescription", IDS_SETTINGS_PASSWORDS_EXPORT_DESCRIPTION},
      {"exportPasswords", IDS_SETTINGS_PASSWORDS_EXPORT},
      {"exportingPasswordsTitle", IDS_SETTINGS_PASSWORDS_EXPORTING_TITLE},
      {"exportPasswordsTryAgain", IDS_SETTINGS_PASSWORDS_EXPORT_TRY_AGAIN},
      {"exportPasswordsFailTitle",
       IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TITLE},
      {"exportPasswordsFailTips",
       IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TIPS},
      {"exportPasswordsFailTipsEnoughSpace",
       IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TIP_ENOUGH_SPACE},
      {"exportPasswordsFailTipsAnotherFolder",
       IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TIP_ANOTHER_FOLDER}};

  html_source->AddString(
      "managePasswordsLabel",
      l10n_util::GetStringFUTF16(
          IDS_SETTINGS_PASSWORDS_MANAGE_PASSWORDS,
          base::ASCIIToUTF16(
              password_manager::kPasswordManagerAccountDashboardURL)));
  html_source->AddString("passwordManagerLearnMoreURL",
                         chrome::kPasswordManagerLearnMoreURL);
  html_source->AddString("manageAddressesUrl",
                         autofill::payments::GetManageAddressesUrl(0).spec());
  html_source->AddString("manageCreditCardsUrl",
                         autofill::payments::GetManageInstrumentsUrl(0).spec());

  AddLocalizedStringsBulk(html_source, localized_strings,
                          arraysize(localized_strings));
}

Confusing settings in Autofill in Google Chrome prior to 66.0.3359.117 allowed a remote attacker to obtain potentially sensitive information from process memory via a crafted HTML page.


void AddPasswordsAndFormsStrings(content::WebUIDataSource* html_source) {
  LocalizedString localized_strings[] = {
      {"passwordsAndAutofillPageTitle",
       IDS_SETTINGS_PASSWORDS_AND_AUTOFILL_PAGE_TITLE},
       {"autofill", IDS_SETTINGS_AUTOFILL},
       {"googlePayments", IDS_SETTINGS_GOOGLE_PAYMENTS},
       {"googlePaymentsCached", IDS_SETTINGS_GOOGLE_PAYMENTS_CACHED},
      {"autofillFormsLabel", IDS_SETTINGS_AUTOFILL_TOGGLE_LABEL},
       {"addresses", IDS_SETTINGS_AUTOFILL_ADDRESSES_HEADING},
       {"addAddressTitle", IDS_SETTINGS_AUTOFILL_ADDRESSES_ADD_TITLE},
       {"editAddressTitle", IDS_SETTINGS_AUTOFILL_ADDRESSES_EDIT_TITLE},
      {"addressCountry", IDS_SETTINGS_AUTOFILL_ADDRESSES_COUNTRY},
      {"addressPhone", IDS_SETTINGS_AUTOFILL_ADDRESSES_PHONE},
      {"addressEmail", IDS_SETTINGS_AUTOFILL_ADDRESSES_EMAIL},
      {"removeAddress", IDS_SETTINGS_ADDRESS_REMOVE},
      {"creditCards", IDS_SETTINGS_AUTOFILL_CREDIT_CARD_HEADING},
      {"removeCreditCard", IDS_SETTINGS_CREDIT_CARD_REMOVE},
      {"clearCreditCard", IDS_SETTINGS_CREDIT_CARD_CLEAR},
      {"creditCardType", IDS_SETTINGS_AUTOFILL_CREDIT_CARD_TYPE_COLUMN_LABEL},
      {"creditCardExpiration", IDS_SETTINGS_CREDIT_CARD_EXPIRATION_DATE},
      {"creditCardName", IDS_SETTINGS_NAME_ON_CREDIT_CARD},
      {"creditCardNumber", IDS_SETTINGS_CREDIT_CARD_NUMBER},
      {"creditCardExpirationMonth", IDS_SETTINGS_CREDIT_CARD_EXPIRATION_MONTH},
      {"creditCardExpirationYear", IDS_SETTINGS_CREDIT_CARD_EXPIRATION_YEAR},
      {"creditCardExpired", IDS_SETTINGS_CREDIT_CARD_EXPIRED},
      {"editCreditCardTitle", IDS_SETTINGS_EDIT_CREDIT_CARD_TITLE},
       {"addCreditCardTitle", IDS_SETTINGS_ADD_CREDIT_CARD_TITLE},
       {"autofillDetail", IDS_SETTINGS_AUTOFILL_DETAIL},
       {"passwords", IDS_SETTINGS_PASSWORDS},
      {"passwordsSavePasswordsLabel",
       IDS_SETTINGS_PASSWORDS_SAVE_PASSWORDS_TOGGLE_LABEL},
       {"passwordsAutosigninLabel",
        IDS_SETTINGS_PASSWORDS_AUTOSIGNIN_CHECKBOX_LABEL},
       {"passwordsAutosigninDescription",
       IDS_SETTINGS_PASSWORDS_AUTOSIGNIN_CHECKBOX_DESC},
      {"passwordsDetail", IDS_SETTINGS_PASSWORDS_DETAIL},
      {"savedPasswordsHeading", IDS_SETTINGS_PASSWORDS_SAVED_HEADING},
      {"passwordExceptionsHeading", IDS_SETTINGS_PASSWORDS_EXCEPTIONS_HEADING},
      {"deletePasswordException", IDS_SETTINGS_PASSWORDS_DELETE_EXCEPTION},
      {"removePassword", IDS_SETTINGS_PASSWORD_REMOVE},
      {"searchPasswords", IDS_SETTINGS_PASSWORD_SEARCH},
      {"showPassword", IDS_SETTINGS_PASSWORD_SHOW},
      {"hidePassword", IDS_SETTINGS_PASSWORD_HIDE},
      {"passwordDetailsTitle", IDS_SETTINGS_PASSWORDS_VIEW_DETAILS_TITLE},
      {"passwordViewDetails", IDS_SETTINGS_PASSWORD_DETAILS},
      {"editPasswordWebsiteLabel", IDS_SETTINGS_PASSWORDS_WEBSITE},
      {"editPasswordUsernameLabel", IDS_SETTINGS_PASSWORDS_USERNAME},
      {"editPasswordPasswordLabel", IDS_SETTINGS_PASSWORDS_PASSWORD},
      {"noAddressesFound", IDS_SETTINGS_ADDRESS_NONE},
      {"noCreditCardsFound", IDS_SETTINGS_CREDIT_CARD_NONE},
      {"noCreditCardsPolicy", IDS_SETTINGS_CREDIT_CARD_DISABLED},
      {"noPasswordsFound", IDS_SETTINGS_PASSWORDS_NONE},
      {"noExceptionsFound", IDS_SETTINGS_PASSWORDS_EXCEPTIONS_NONE},
      {"import", IDS_PASSWORD_MANAGER_IMPORT_BUTTON},
      {"exportMenuItem", IDS_SETTINGS_PASSWORDS_EXPORT_MENU_ITEM},
      {"undoRemovePassword", IDS_SETTINGS_PASSWORD_UNDO},
      {"passwordDeleted", IDS_SETTINGS_PASSWORD_DELETED_PASSWORD},
      {"exportPasswordsTitle", IDS_SETTINGS_PASSWORDS_EXPORT_TITLE},
      {"exportPasswordsDescription", IDS_SETTINGS_PASSWORDS_EXPORT_DESCRIPTION},
      {"exportPasswords", IDS_SETTINGS_PASSWORDS_EXPORT},
      {"exportingPasswordsTitle", IDS_SETTINGS_PASSWORDS_EXPORTING_TITLE},
      {"exportPasswordsTryAgain", IDS_SETTINGS_PASSWORDS_EXPORT_TRY_AGAIN},
      {"exportPasswordsFailTitle",
       IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TITLE},
      {"exportPasswordsFailTips",
       IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TIPS},
      {"exportPasswordsFailTipsEnoughSpace",
       IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TIP_ENOUGH_SPACE},
      {"exportPasswordsFailTipsAnotherFolder",
       IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TIP_ANOTHER_FOLDER}};

  html_source->AddString(
      "managePasswordsLabel",
      l10n_util::GetStringFUTF16(
          IDS_SETTINGS_PASSWORDS_MANAGE_PASSWORDS,
          base::ASCIIToUTF16(
              password_manager::kPasswordManagerAccountDashboardURL)));
  html_source->AddString("passwordManagerLearnMoreURL",
                         chrome::kPasswordManagerLearnMoreURL);
  html_source->AddString("manageAddressesUrl",
                         autofill::payments::GetManageAddressesUrl(0).spec());
  html_source->AddString("manageCreditCardsUrl",
                         autofill::payments::GetManageInstrumentsUrl(0).spec());

  AddLocalizedStringsBulk(html_source, localized_strings,
                          arraysize(localized_strings));
}


void AudioNode::Dispose() {
  DCHECK(IsMainThread());
#if DEBUG_AUDIONODE_REFERENCES
  fprintf(stderr, "[%16p]: %16p: %2d: AudioNode::dispose %16p\n", context(),
          this, Handler().GetNodeType(), handler_.get());
 #endif
   BaseAudioContext::GraphAutoLocker locker(context());
   Handler().Dispose();
  if (context()->HasRealtimeConstraint()) {
     context()->GetDeferredTaskHandler().AddRenderingOrphanHandler(
         std::move(handler_));
  } else {
    if (context()->ContextState() == BaseAudioContext::kRunning) {
      context()->GetDeferredTaskHandler().AddRenderingOrphanHandler(
          std::move(handler_));
    }
   }
 }

Use after free in WebAudio in Google Chrome prior to 65.0.3325.146 allowed a remote attacker to potentially exploit heap corruption via a crafted HTML page.


void AudioNode::Dispose() {
  DCHECK(IsMainThread());
#if DEBUG_AUDIONODE_REFERENCES
  fprintf(stderr, "[%16p]: %16p: %2d: AudioNode::dispose %16p\n", context(),
          this, Handler().GetNodeType(), handler_.get());
 #endif
   BaseAudioContext::GraphAutoLocker locker(context());
   Handler().Dispose();
  if (context()->ContextState() == BaseAudioContext::kRunning) {
     context()->GetDeferredTaskHandler().AddRenderingOrphanHandler(
         std::move(handler_));
   }
 }


 ScopedSharedBufferHandle WrapSharedMemoryHandle(
     const base::SharedMemoryHandle& memory_handle,
     size_t size,
    bool read_only) {
   if (!memory_handle.IsValid())
     return ScopedSharedBufferHandle();
   MojoPlatformHandle platform_handle;
  platform_handle.struct_size = sizeof(MojoPlatformHandle);
  platform_handle.type = kPlatformSharedBufferHandleType;
#if defined(OS_MACOSX) && !defined(OS_IOS)
  platform_handle.value =
      static_cast<uint64_t>(memory_handle.GetMemoryObject());
#else
  platform_handle.value =
      PlatformHandleValueFromPlatformFile(memory_handle.GetHandle());
#endif

   MojoPlatformSharedBufferHandleFlags flags =
       MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_NONE;
  if (read_only)
    flags |= MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_READ_ONLY;

   MojoSharedBufferGuid guid;
   guid.high = memory_handle.GetGUID().GetHighForSerialization();
  guid.low = memory_handle.GetGUID().GetLowForSerialization();
  MojoHandle mojo_handle;
  MojoResult result = MojoWrapPlatformSharedBufferHandle(
      &platform_handle, size, &guid, flags, &mojo_handle);
  CHECK_EQ(result, MOJO_RESULT_OK);

   return ScopedSharedBufferHandle(SharedBufferHandle(mojo_handle));
 }

Incorrect use of mojo::WrapSharedMemoryHandle in Mojo in Google Chrome prior to 65.0.3325.146 allowed a remote attacker who had compromised the renderer process to perform an out of bounds memory write via a crafted HTML page.


 ScopedSharedBufferHandle WrapSharedMemoryHandle(
     const base::SharedMemoryHandle& memory_handle,
     size_t size,
    UnwrappedSharedMemoryHandleProtection protection) {
   if (!memory_handle.IsValid())
     return ScopedSharedBufferHandle();
   MojoPlatformHandle platform_handle;
  platform_handle.struct_size = sizeof(MojoPlatformHandle);
  platform_handle.type = kPlatformSharedBufferHandleType;
#if defined(OS_MACOSX) && !defined(OS_IOS)
  platform_handle.value =
      static_cast<uint64_t>(memory_handle.GetMemoryObject());
#else
  platform_handle.value =
      PlatformHandleValueFromPlatformFile(memory_handle.GetHandle());
#endif

   MojoPlatformSharedBufferHandleFlags flags =
       MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_NONE;
  if (protection == UnwrappedSharedMemoryHandleProtection::kReadOnly)
    flags |= MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_HANDLE_IS_READ_ONLY;

   MojoSharedBufferGuid guid;
   guid.high = memory_handle.GetGUID().GetHighForSerialization();
  guid.low = memory_handle.GetGUID().GetLowForSerialization();
  MojoHandle mojo_handle;
  MojoResult result = MojoWrapPlatformSharedBufferHandle(
      &platform_handle, size, &guid, flags, &mojo_handle);
  CHECK_EQ(result, MOJO_RESULT_OK);

   return ScopedSharedBufferHandle(SharedBufferHandle(mojo_handle));
 }


bool VaapiJpegDecoder::Initialize(const base::RepeatingClosure& error_uma_cb) {
  vaapi_wrapper_ = VaapiWrapper::Create(VaapiWrapper::kDecode,
                                        VAProfileJPEGBaseline, error_uma_cb);
  if (!vaapi_wrapper_) {
    VLOGF(1) << "Failed initializing VAAPI";
    return false;
  }
  return true;
}

Lack of CSP enforcement on WebUI pages in Bink in Google Chrome prior to 65.0.3325.146 allowed an attacker who convinced a user to install a malicious extension to bypass content security policy via a crafted Chrome Extension.


bool VaapiJpegDecoder::Initialize(const base::RepeatingClosure& error_uma_cb) {


void DoCanonicalizeRef(const CHAR* spec,
                       const Component& ref,
                       CanonOutput* output,
                       Component* out_ref) {
  if (ref.len < 0) {
    *out_ref = Component();
    return;
  }

  output->push_back('#');
  out_ref->begin = output->length();

  int end = ref.end();
  for (int i = ref.begin; i < end; i++) {
    if (spec[i] == 0) {
      continue;
    } else if (static_cast<UCHAR>(spec[i]) < 0x20) {
      AppendEscapedChar(static_cast<unsigned char>(spec[i]), output);
    } else if (static_cast<UCHAR>(spec[i]) < 0x80) {
       output->push_back(static_cast<char>(spec[i]));
     } else {
      unsigned code_point;
      ReadUTFChar(spec, &i, end, &code_point);
      AppendUTF8Value(code_point, output);
     }
   }

  out_ref->len = output->length() - out_ref->begin;
}

Insufficient encoding of URL fragment identifiers in Blink in Google Chrome prior to 65.0.3325.146 allowed a remote attacker to perform a DOM based XSS attack via a crafted HTML page.


void DoCanonicalizeRef(const CHAR* spec,
                       const Component& ref,
                       CanonOutput* output,
                       Component* out_ref) {
  if (ref.len < 0) {
    *out_ref = Component();
    return;
  }

  output->push_back('#');
  out_ref->begin = output->length();

  int end = ref.end();
  for (int i = ref.begin; i < end; i++) {
    if (spec[i] == 0) {
      continue;
    } else if (static_cast<UCHAR>(spec[i]) < 0x20) {
      AppendEscapedChar(static_cast<unsigned char>(spec[i]), output);
    } else if (static_cast<UCHAR>(spec[i]) < 0x80) {
       output->push_back(static_cast<char>(spec[i]));
     } else {
      AppendUTF8EscapedChar(spec, &i, end, output);
     }
   }

  out_ref->len = output->length() - out_ref->begin;
}


IDNSpoofChecker::IDNSpoofChecker() {
  UErrorCode status = U_ZERO_ERROR;
  checker_ = uspoof_open(&status);
  if (U_FAILURE(status)) {
    checker_ = nullptr;
    return;
  }

  uspoof_setRestrictionLevel(checker_, USPOOF_HIGHLY_RESTRICTIVE);

  SetAllowedUnicodeSet(&status);

  int32_t checks = uspoof_getChecks(checker_, &status) | USPOOF_AUX_INFO;
  uspoof_setChecks(checker_, checks, &status);

  deviation_characters_ = icu::UnicodeSet(
      UNICODE_STRING_SIMPLE("[\\u00df\\u03c2\\u200c\\u200d]"), status);
  deviation_characters_.freeze();

  non_ascii_latin_letters_ =
      icu::UnicodeSet(UNICODE_STRING_SIMPLE("[[:Latin:] - [a-zA-Z]]"), status);
  non_ascii_latin_letters_.freeze();

  kana_letters_exceptions_ = icu::UnicodeSet(
      UNICODE_STRING_SIMPLE("[\\u3078-\\u307a\\u30d8-\\u30da\\u30fb-\\u30fe]"),
      status);
  kana_letters_exceptions_.freeze();
  combining_diacritics_exceptions_ =
      icu::UnicodeSet(UNICODE_STRING_SIMPLE("[\\u0300-\\u0339]"), status);
  combining_diacritics_exceptions_.freeze();

  cyrillic_letters_latin_alike_ = icu::UnicodeSet(
      icu::UnicodeString::fromUTF8("[асԁеһіјӏорԛѕԝхуъЬҽпгѵѡ]"), status);
  cyrillic_letters_latin_alike_.freeze();

  cyrillic_letters_ =
      icu::UnicodeSet(UNICODE_STRING_SIMPLE("[[:Cyrl:]]"), status);
  cyrillic_letters_.freeze();

  DCHECK(U_SUCCESS(status));
  lgc_letters_n_ascii_ = icu::UnicodeSet(
      UNICODE_STRING_SIMPLE("[[:Latin:][:Greek:][:Cyrillic:][0-9\\u002e_"
                            "\\u002d][\\u0300-\\u0339]]"),
      status);
  lgc_letters_n_ascii_.freeze();

  UParseError parse_error;
  diacritic_remover_.reset(icu::Transliterator::createFromRules(
      UNICODE_STRING_SIMPLE("DropAcc"),
      icu::UnicodeString::fromUTF8("::NFD; ::[:Nonspacing Mark:] Remove; ::NFC;"
                                   " ł > l; ø > o; đ > d;"),
       UTRANS_FORWARD, parse_error, status));

   extra_confusable_mapper_.reset(icu::Transliterator::createFromRules(
       UNICODE_STRING_SIMPLE("ExtraConf"),
      icu::UnicodeString::fromUTF8(
          "ӏ > l; [кĸκ] > k; п > n; [ƅь] > b; в > b; м > m; н > h; "
          "т > t; [шщ] > w; ട > s;"),
       UTRANS_FORWARD, parse_error, status));
   DCHECK(U_SUCCESS(status))
       << "Spoofchecker initalization failed due to an error: "
      << u_errorName(status);
}

Incorrect handling of confusable characters in Omnibox in Google Chrome prior to 65.0.3325.146 allowed a remote attacker to spoof the contents of the Omnibox (URL bar) via a crafted domain name.


IDNSpoofChecker::IDNSpoofChecker() {
  UErrorCode status = U_ZERO_ERROR;
  checker_ = uspoof_open(&status);
  if (U_FAILURE(status)) {
    checker_ = nullptr;
    return;
  }

  uspoof_setRestrictionLevel(checker_, USPOOF_HIGHLY_RESTRICTIVE);

  SetAllowedUnicodeSet(&status);

  int32_t checks = uspoof_getChecks(checker_, &status) | USPOOF_AUX_INFO;
  uspoof_setChecks(checker_, checks, &status);

  deviation_characters_ = icu::UnicodeSet(
      UNICODE_STRING_SIMPLE("[\\u00df\\u03c2\\u200c\\u200d]"), status);
  deviation_characters_.freeze();

  non_ascii_latin_letters_ =
      icu::UnicodeSet(UNICODE_STRING_SIMPLE("[[:Latin:] - [a-zA-Z]]"), status);
  non_ascii_latin_letters_.freeze();

  kana_letters_exceptions_ = icu::UnicodeSet(
      UNICODE_STRING_SIMPLE("[\\u3078-\\u307a\\u30d8-\\u30da\\u30fb-\\u30fe]"),
      status);
  kana_letters_exceptions_.freeze();
  combining_diacritics_exceptions_ =
      icu::UnicodeSet(UNICODE_STRING_SIMPLE("[\\u0300-\\u0339]"), status);
  combining_diacritics_exceptions_.freeze();

  cyrillic_letters_latin_alike_ = icu::UnicodeSet(
      icu::UnicodeString::fromUTF8("[асԁеһіјӏорԛѕԝхуъЬҽпгѵѡ]"), status);
  cyrillic_letters_latin_alike_.freeze();

  cyrillic_letters_ =
      icu::UnicodeSet(UNICODE_STRING_SIMPLE("[[:Cyrl:]]"), status);
  cyrillic_letters_.freeze();

  DCHECK(U_SUCCESS(status));
  lgc_letters_n_ascii_ = icu::UnicodeSet(
      UNICODE_STRING_SIMPLE("[[:Latin:][:Greek:][:Cyrillic:][0-9\\u002e_"
                            "\\u002d][\\u0300-\\u0339]]"),
      status);
  lgc_letters_n_ascii_.freeze();

  UParseError parse_error;
  diacritic_remover_.reset(icu::Transliterator::createFromRules(
      UNICODE_STRING_SIMPLE("DropAcc"),
      icu::UnicodeString::fromUTF8("::NFD; ::[:Nonspacing Mark:] Remove; ::NFC;"
                                   " ł > l; ø > o; đ > d;"),
       UTRANS_FORWARD, parse_error, status));

  //   - {U+00FE (þ), U+03FC (ϼ), U+048F (ҏ)} => p
  //   - {U+0127 (ħ), U+043D (н), U+045B (ћ), U+04A3 (ң), U+04A5 (ҥ),
  //      U+04C8 (ӈ), U+0527 (ԧ), U+0529 (ԩ)} => h
  //   - {U+0138 (ĸ), U+03BA (κ), U+043A (к), U+049B (қ), U+049D (ҝ),
  //      U+049F (ҟ), U+04A1(ҡ), U+04C4 (ӄ), U+051F (ԟ)} => k
  //   - {U+0167 (ŧ), U+0442 (т), U+04AD (ҭ)} => t
  //   - {U+0185 (ƅ), U+044C (ь), U+048D (ҍ), U+0432 (в)} => b
  //   - {U+03C9 (ω), U+0448 (ш), U+0449 (щ)} => w
  //   - {U+043C (м), U+04CE (ӎ)} => m
  //   - U+0491 (ґ) => r
  //   - U+0493 (ғ) => f
  //   - U+04AB (ҫ) => c
  //   - U+04B1 (ұ) => y
  //   - U+03C7 (χ), U+04B3 (ҳ), U+04FD (ӽ), U+04FF (ӿ) => x
  //   - U+04BD (ҽ), U+04BF (ҿ) => e
  //   - U+04CF (ӏ) => l
  //   - U+0503 (ԃ) => d
  //   - U+050D (ԍ) => g
   extra_confusable_mapper_.reset(icu::Transliterator::createFromRules(
       UNICODE_STRING_SIMPLE("ExtraConf"),
      icu::UnicodeString::fromUTF8("[þϼҏ] > p; [ħнћңҥӈԧԩ] > h;"
                                   "[ĸκкқҝҟҡӄԟ] > k; [ŧтҭ] > t;"
                                   "[ƅьҍв] > b;  [ωшщ] > w; [мӎ] > m;"
                                   "п > n; ћ > h; ґ > r; ғ > f; ҫ > c;"
                                   "ұ > y; [χҳӽӿ] > x; [ҽҿ] > e; ӏ > l;"
                                   "ԃ  > d; ԍ > g; ട > s"),
       UTRANS_FORWARD, parse_error, status));
   DCHECK(U_SUCCESS(status))
       << "Spoofchecker initalization failed due to an error: "
      << u_errorName(status);
}


QuicErrorCode QuicStreamSequencerBuffer::OnStreamData(
    QuicStreamOffset starting_offset,
    QuicStringPiece data,
    QuicTime timestamp,
    size_t* const bytes_buffered,
    std::string* error_details) {
  CHECK_EQ(destruction_indicator_, 123456) << "This object has been destructed";
  *bytes_buffered = 0;
  QuicStreamOffset offset = starting_offset;
  size_t size = data.size();
  if (size == 0) {
    *error_details = "Received empty stream frame without FIN.";
    return QUIC_EMPTY_STREAM_FRAME_NO_FIN;
  }

  std::list<Gap>::iterator current_gap = gaps_.begin();
  while (current_gap != gaps_.end() && current_gap->end_offset <= offset) {
     ++current_gap;
   }

  DCHECK(current_gap != gaps_.end());

  if (offset < current_gap->begin_offset &&
      offset + size <= current_gap->begin_offset) {
    QUIC_DVLOG(1) << "Duplicated data at offset: " << offset
                  << " length: " << size;
    return QUIC_NO_ERROR;
  }
  if (offset < current_gap->begin_offset &&
      offset + size > current_gap->begin_offset) {
    string prefix(data.data(), data.length() < 128 ? data.length() : 128);
    *error_details =
        QuicStrCat("Beginning of received data overlaps with buffered data.\n",
                   "New frame range [", offset, ", ", offset + size,
                   ") with first 128 bytes: ", prefix, "\n",
                   "Currently received frames: ", GapsDebugString(), "\n",
                   "Current gaps: ", ReceivedFramesDebugString());
    return QUIC_OVERLAPPING_STREAM_DATA;
  }
  if (offset + size > current_gap->end_offset) {
    string prefix(data.data(), data.length() < 128 ? data.length() : 128);
    *error_details = QuicStrCat(
        "End of received data overlaps with buffered data.\nNew frame range [",
        offset, ", ", offset + size, ") with first 128 bytes: ", prefix, "\n",
        "Currently received frames: ", ReceivedFramesDebugString(), "\n",
        "Current gaps: ", GapsDebugString());
    return QUIC_OVERLAPPING_STREAM_DATA;
   }

  if (offset + size > total_bytes_read_ + max_buffer_capacity_bytes_) {
     *error_details = "Received data beyond available range.";
     return QUIC_INTERNAL_ERROR;
   }

  if (current_gap->begin_offset != starting_offset &&
      current_gap->end_offset != starting_offset + data.length() &&
      gaps_.size() >= kMaxNumGapsAllowed) {
    *error_details = "Too many gaps created for this stream.";
    return QUIC_TOO_MANY_FRAME_GAPS;
  }

  size_t total_written = 0;
  size_t source_remaining = size;
  const char* source = data.data();
  while (source_remaining > 0) {
    const size_t write_block_num = GetBlockIndex(offset);
    const size_t write_block_offset = GetInBlockOffset(offset);
    DCHECK_GT(blocks_count_, write_block_num);

    size_t block_capacity = GetBlockCapacity(write_block_num);
    size_t bytes_avail = block_capacity - write_block_offset;

    if (offset + bytes_avail > total_bytes_read_ + max_buffer_capacity_bytes_) {
      bytes_avail = total_bytes_read_ + max_buffer_capacity_bytes_ - offset;
    }

    if (blocks_ == nullptr) {
      blocks_.reset(new BufferBlock*[blocks_count_]());
      for (size_t i = 0; i < blocks_count_; ++i) {
        blocks_[i] = nullptr;
      }
    }

    if (write_block_num >= blocks_count_) {
      *error_details = QuicStrCat(
          "QuicStreamSequencerBuffer error: OnStreamData() exceed array bounds."
          "write offset = ",
          offset, " write_block_num = ", write_block_num,
          " blocks_count_ = ", blocks_count_);
      return QUIC_STREAM_SEQUENCER_INVALID_STATE;
    }
    if (blocks_ == nullptr) {
      *error_details =
          "QuicStreamSequencerBuffer error: OnStreamData() blocks_ is null";
      return QUIC_STREAM_SEQUENCER_INVALID_STATE;
    }
    if (blocks_[write_block_num] == nullptr) {
      blocks_[write_block_num] = new BufferBlock();
    }

    const size_t bytes_to_copy =
        std::min<size_t>(bytes_avail, source_remaining);
    char* dest = blocks_[write_block_num]->buffer + write_block_offset;
    QUIC_DVLOG(1) << "Write at offset: " << offset
                  << " length: " << bytes_to_copy;

    if (dest == nullptr || source == nullptr) {
      *error_details = QuicStrCat(
          "QuicStreamSequencerBuffer error: OnStreamData()"
          " dest == nullptr: ",
          (dest == nullptr), " source == nullptr: ", (source == nullptr),
          " Writing at offset ", offset, " Gaps: ", GapsDebugString(),
          " Remaining frames: ", ReceivedFramesDebugString(),
          " total_bytes_read_ = ", total_bytes_read_);
      return QUIC_STREAM_SEQUENCER_INVALID_STATE;
    }
    memcpy(dest, source, bytes_to_copy);
    source += bytes_to_copy;
    source_remaining -= bytes_to_copy;
    offset += bytes_to_copy;
    total_written += bytes_to_copy;
  }

  DCHECK_GT(total_written, 0u);
  *bytes_buffered = total_written;
  UpdateGapList(current_gap, starting_offset, total_written);

  frame_arrival_time_map_.insert(
      std::make_pair(starting_offset, FrameInfo(size, timestamp)));
  num_bytes_buffered_ += total_written;
  return QUIC_NO_ERROR;
}

Out-of-bounds Write in the QUIC networking stack in Google Chrome prior to 63.0.3239.84 allowed a remote attacker to gain code execution via a malicious server.


QuicErrorCode QuicStreamSequencerBuffer::OnStreamData(
    QuicStreamOffset starting_offset,
    QuicStringPiece data,
    QuicTime timestamp,
    size_t* const bytes_buffered,
    std::string* error_details) {
  CHECK_EQ(destruction_indicator_, 123456) << "This object has been destructed";
  *bytes_buffered = 0;
  QuicStreamOffset offset = starting_offset;
  size_t size = data.size();
  if (size == 0) {
    *error_details = "Received empty stream frame without FIN.";
    return QUIC_EMPTY_STREAM_FRAME_NO_FIN;
  }

  std::list<Gap>::iterator current_gap = gaps_.begin();
  while (current_gap != gaps_.end() && current_gap->end_offset <= offset) {
     ++current_gap;
   }

  if (current_gap == gaps_.end()) {
    *error_details = "Received stream data outside of maximum range.";
    return QUIC_INTERNAL_ERROR;
  }

  if (offset < current_gap->begin_offset &&
      offset + size <= current_gap->begin_offset) {
    QUIC_DVLOG(1) << "Duplicated data at offset: " << offset
                  << " length: " << size;
    return QUIC_NO_ERROR;
  }
  if (offset < current_gap->begin_offset &&
      offset + size > current_gap->begin_offset) {
    string prefix(data.data(), data.length() < 128 ? data.length() : 128);
    *error_details =
        QuicStrCat("Beginning of received data overlaps with buffered data.\n",
                   "New frame range [", offset, ", ", offset + size,
                   ") with first 128 bytes: ", prefix, "\n",
                   "Currently received frames: ", GapsDebugString(), "\n",
                   "Current gaps: ", ReceivedFramesDebugString());
    return QUIC_OVERLAPPING_STREAM_DATA;
  }
  if (offset + size > current_gap->end_offset) {
    string prefix(data.data(), data.length() < 128 ? data.length() : 128);
    *error_details = QuicStrCat(
        "End of received data overlaps with buffered data.\nNew frame range [",
        offset, ", ", offset + size, ") with first 128 bytes: ", prefix, "\n",
        "Currently received frames: ", ReceivedFramesDebugString(), "\n",
        "Current gaps: ", GapsDebugString());
    return QUIC_OVERLAPPING_STREAM_DATA;
   }

  if (offset + size > total_bytes_read_ + max_buffer_capacity_bytes_ ||
      offset + size < offset) {
     *error_details = "Received data beyond available range.";
     return QUIC_INTERNAL_ERROR;
   }

  if (current_gap->begin_offset != starting_offset &&
      current_gap->end_offset != starting_offset + data.length() &&
      gaps_.size() >= kMaxNumGapsAllowed) {
    *error_details = "Too many gaps created for this stream.";
    return QUIC_TOO_MANY_FRAME_GAPS;
  }

  size_t total_written = 0;
  size_t source_remaining = size;
  const char* source = data.data();
  while (source_remaining > 0) {
    const size_t write_block_num = GetBlockIndex(offset);
    const size_t write_block_offset = GetInBlockOffset(offset);
    DCHECK_GT(blocks_count_, write_block_num);

    size_t block_capacity = GetBlockCapacity(write_block_num);
    size_t bytes_avail = block_capacity - write_block_offset;

    if (offset + bytes_avail > total_bytes_read_ + max_buffer_capacity_bytes_) {
      bytes_avail = total_bytes_read_ + max_buffer_capacity_bytes_ - offset;
    }

    if (blocks_ == nullptr) {
      blocks_.reset(new BufferBlock*[blocks_count_]());
      for (size_t i = 0; i < blocks_count_; ++i) {
        blocks_[i] = nullptr;
      }
    }

    if (write_block_num >= blocks_count_) {
      *error_details = QuicStrCat(
          "QuicStreamSequencerBuffer error: OnStreamData() exceed array bounds."
          "write offset = ",
          offset, " write_block_num = ", write_block_num,
          " blocks_count_ = ", blocks_count_);
      return QUIC_STREAM_SEQUENCER_INVALID_STATE;
    }
    if (blocks_ == nullptr) {
      *error_details =
          "QuicStreamSequencerBuffer error: OnStreamData() blocks_ is null";
      return QUIC_STREAM_SEQUENCER_INVALID_STATE;
    }
    if (blocks_[write_block_num] == nullptr) {
      blocks_[write_block_num] = new BufferBlock();
    }

    const size_t bytes_to_copy =
        std::min<size_t>(bytes_avail, source_remaining);
    char* dest = blocks_[write_block_num]->buffer + write_block_offset;
    QUIC_DVLOG(1) << "Write at offset: " << offset
                  << " length: " << bytes_to_copy;

    if (dest == nullptr || source == nullptr) {
      *error_details = QuicStrCat(
          "QuicStreamSequencerBuffer error: OnStreamData()"
          " dest == nullptr: ",
          (dest == nullptr), " source == nullptr: ", (source == nullptr),
          " Writing at offset ", offset, " Gaps: ", GapsDebugString(),
          " Remaining frames: ", ReceivedFramesDebugString(),
          " total_bytes_read_ = ", total_bytes_read_);
      return QUIC_STREAM_SEQUENCER_INVALID_STATE;
    }
    memcpy(dest, source, bytes_to_copy);
    source += bytes_to_copy;
    source_remaining -= bytes_to_copy;
    offset += bytes_to_copy;
    total_written += bytes_to_copy;
  }

  DCHECK_GT(total_written, 0u);
  *bytes_buffered = total_written;
  UpdateGapList(current_gap, starting_offset, total_written);

  frame_arrival_time_map_.insert(
      std::make_pair(starting_offset, FrameInfo(size, timestamp)));
  num_bytes_buffered_ += total_written;
  return QUIC_NO_ERROR;
}


BlobStorageContext::BlobFlattener::BlobFlattener(
    const BlobDataBuilder& input_builder,
    BlobEntry* output_blob,
    BlobStorageRegistry* registry) {
  const std::string& uuid = input_builder.uuid_;
  std::set<std::string> dependent_blob_uuids;

  size_t num_files_with_unknown_size = 0;
  size_t num_building_dependent_blobs = 0;

  bool found_memory_transport = false;
  bool found_file_transport = false;

  base::CheckedNumeric<uint64_t> checked_total_size = 0;
  base::CheckedNumeric<uint64_t> checked_total_memory_size = 0;
  base::CheckedNumeric<uint64_t> checked_transport_quota_needed = 0;
  base::CheckedNumeric<uint64_t> checked_copy_quota_needed = 0;

  for (scoped_refptr<BlobDataItem> input_item : input_builder.items_) {
    const DataElement& input_element = input_item->data_element();
    DataElement::Type type = input_element.type();
    uint64_t length = input_element.length();

    RecordBlobItemSizeStats(input_element);

    if (IsBytes(type)) {
      DCHECK_NE(0 + DataElement::kUnknownSize, input_element.length());
      found_memory_transport = true;
      if (found_file_transport) {
        status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
        return;
      }
      contains_unpopulated_transport_items |=
          (type == DataElement::TYPE_BYTES_DESCRIPTION);
      checked_transport_quota_needed += length;
      checked_total_size += length;
      scoped_refptr<ShareableBlobDataItem> item = new ShareableBlobDataItem(
          std::move(input_item), ShareableBlobDataItem::QUOTA_NEEDED);
      pending_transport_items.push_back(item);
      transport_items.push_back(item.get());
      output_blob->AppendSharedBlobItem(std::move(item));
      continue;
    }
    if (type == DataElement::TYPE_BLOB) {
      BlobEntry* ref_entry = registry->GetEntry(input_element.blob_uuid());

      if (!ref_entry || input_element.blob_uuid() == uuid) {
        status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
        return;
      }

      if (BlobStatusIsError(ref_entry->status())) {
        status = BlobStatus::ERR_REFERENCED_BLOB_BROKEN;
        return;
      }

      if (ref_entry->total_size() == DataElement::kUnknownSize) {
        status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
        return;
      }

      if (dependent_blob_uuids.find(input_element.blob_uuid()) ==
          dependent_blob_uuids.end()) {
        dependent_blobs.push_back(
            std::make_pair(input_element.blob_uuid(), ref_entry));
        dependent_blob_uuids.insert(input_element.blob_uuid());
        if (BlobStatusIsPending(ref_entry->status())) {
          num_building_dependent_blobs++;
        }
      }

      length = length == DataElement::kUnknownSize ? ref_entry->total_size()
                                                   : input_element.length();
      checked_total_size += length;

      if (input_element.offset() == 0 && length == ref_entry->total_size()) {
        for (const auto& shareable_item : ref_entry->items()) {
          output_blob->AppendSharedBlobItem(shareable_item);
        }
        continue;
       }

      if (input_element.offset() + length > ref_entry->total_size()) {
         status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
         return;
       }

      BlobSlice slice(*ref_entry, input_element.offset(), length);

      if (!slice.copying_memory_size.IsValid() ||
          !slice.total_memory_size.IsValid()) {
        status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
        return;
      }
      checked_total_memory_size += slice.total_memory_size;

      if (slice.first_source_item) {
        copies.push_back(ItemCopyEntry(slice.first_source_item,
                                       slice.first_item_slice_offset,
                                       slice.dest_items.front()));
        pending_copy_items.push_back(slice.dest_items.front());
      }
      if (slice.last_source_item) {
        copies.push_back(
            ItemCopyEntry(slice.last_source_item, 0, slice.dest_items.back()));
        pending_copy_items.push_back(slice.dest_items.back());
      }
      checked_copy_quota_needed += slice.copying_memory_size;

      for (auto& shareable_item : slice.dest_items) {
        output_blob->AppendSharedBlobItem(std::move(shareable_item));
      }
      continue;
    }

    scoped_refptr<ShareableBlobDataItem> item;
    if (BlobDataBuilder::IsFutureFileItem(input_element)) {
      found_file_transport = true;
      if (found_memory_transport) {
        status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
        return;
      }
      contains_unpopulated_transport_items = true;
      item = new ShareableBlobDataItem(std::move(input_item),
                                       ShareableBlobDataItem::QUOTA_NEEDED);
      pending_transport_items.push_back(item);
      transport_items.push_back(item.get());
      checked_transport_quota_needed += length;
    } else {
      item = new ShareableBlobDataItem(
          std::move(input_item),
          ShareableBlobDataItem::POPULATED_WITHOUT_QUOTA);
    }
    if (length == DataElement::kUnknownSize)
      num_files_with_unknown_size++;

    checked_total_size += length;
    output_blob->AppendSharedBlobItem(std::move(item));
  }

  if (num_files_with_unknown_size > 1 && input_builder.items_.size() > 1) {
    status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
    return;
  }
  if (!checked_total_size.IsValid() || !checked_total_memory_size.IsValid() ||
      !checked_transport_quota_needed.IsValid() ||
      !checked_copy_quota_needed.IsValid()) {
    status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
    return;
  }
  total_size = checked_total_size.ValueOrDie();
  total_memory_size = checked_total_memory_size.ValueOrDie();
  transport_quota_needed = checked_transport_quota_needed.ValueOrDie();
  copy_quota_needed = checked_copy_quota_needed.ValueOrDie();
  transport_quota_type = found_file_transport ? TransportQuotaType::FILE
                                              : TransportQuotaType::MEMORY;
  if (transport_quota_needed) {
    status = BlobStatus::PENDING_QUOTA;
  } else {
    status = BlobStatus::PENDING_INTERNALS;
  }
}

Heap buffer overflow in Blob API in Google Chrome prior to 63.0.3239.84 allowed a remote attacker to potentially exploit heap corruption via a crafted HTML page, aka a Blink out-of-bounds read.


BlobStorageContext::BlobFlattener::BlobFlattener(
    const BlobDataBuilder& input_builder,
    BlobEntry* output_blob,
    BlobStorageRegistry* registry) {
  const std::string& uuid = input_builder.uuid_;
  std::set<std::string> dependent_blob_uuids;

  size_t num_files_with_unknown_size = 0;
  size_t num_building_dependent_blobs = 0;

  bool found_memory_transport = false;
  bool found_file_transport = false;

  base::CheckedNumeric<uint64_t> checked_total_size = 0;
  base::CheckedNumeric<uint64_t> checked_total_memory_size = 0;
  base::CheckedNumeric<uint64_t> checked_transport_quota_needed = 0;
  base::CheckedNumeric<uint64_t> checked_copy_quota_needed = 0;

  for (scoped_refptr<BlobDataItem> input_item : input_builder.items_) {
    const DataElement& input_element = input_item->data_element();
    DataElement::Type type = input_element.type();
    uint64_t length = input_element.length();

    RecordBlobItemSizeStats(input_element);

    if (IsBytes(type)) {
      DCHECK_NE(0 + DataElement::kUnknownSize, input_element.length());
      found_memory_transport = true;
      if (found_file_transport) {
        status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
        return;
      }
      contains_unpopulated_transport_items |=
          (type == DataElement::TYPE_BYTES_DESCRIPTION);
      checked_transport_quota_needed += length;
      checked_total_size += length;
      scoped_refptr<ShareableBlobDataItem> item = new ShareableBlobDataItem(
          std::move(input_item), ShareableBlobDataItem::QUOTA_NEEDED);
      pending_transport_items.push_back(item);
      transport_items.push_back(item.get());
      output_blob->AppendSharedBlobItem(std::move(item));
      continue;
    }
    if (type == DataElement::TYPE_BLOB) {
      BlobEntry* ref_entry = registry->GetEntry(input_element.blob_uuid());

      if (!ref_entry || input_element.blob_uuid() == uuid) {
        status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
        return;
      }

      if (BlobStatusIsError(ref_entry->status())) {
        status = BlobStatus::ERR_REFERENCED_BLOB_BROKEN;
        return;
      }

      if (ref_entry->total_size() == DataElement::kUnknownSize) {
        status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
        return;
      }

      if (dependent_blob_uuids.find(input_element.blob_uuid()) ==
          dependent_blob_uuids.end()) {
        dependent_blobs.push_back(
            std::make_pair(input_element.blob_uuid(), ref_entry));
        dependent_blob_uuids.insert(input_element.blob_uuid());
        if (BlobStatusIsPending(ref_entry->status())) {
          num_building_dependent_blobs++;
        }
      }

      length = length == DataElement::kUnknownSize ? ref_entry->total_size()
                                                   : input_element.length();
      checked_total_size += length;

      if (input_element.offset() == 0 && length == ref_entry->total_size()) {
        for (const auto& shareable_item : ref_entry->items()) {
          output_blob->AppendSharedBlobItem(shareable_item);
        }
        continue;
       }

      uint64_t end_byte;
      if (!base::CheckAdd(input_element.offset(), length)
               .AssignIfValid(&end_byte) ||
          end_byte > ref_entry->total_size()) {
         status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
         return;
       }

      BlobSlice slice(*ref_entry, input_element.offset(), length);

      if (!slice.copying_memory_size.IsValid() ||
          !slice.total_memory_size.IsValid()) {
        status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
        return;
      }
      checked_total_memory_size += slice.total_memory_size;

      if (slice.first_source_item) {
        copies.push_back(ItemCopyEntry(slice.first_source_item,
                                       slice.first_item_slice_offset,
                                       slice.dest_items.front()));
        pending_copy_items.push_back(slice.dest_items.front());
      }
      if (slice.last_source_item) {
        copies.push_back(
            ItemCopyEntry(slice.last_source_item, 0, slice.dest_items.back()));
        pending_copy_items.push_back(slice.dest_items.back());
      }
      checked_copy_quota_needed += slice.copying_memory_size;

      for (auto& shareable_item : slice.dest_items) {
        output_blob->AppendSharedBlobItem(std::move(shareable_item));
      }
      continue;
    }

    scoped_refptr<ShareableBlobDataItem> item;
    if (BlobDataBuilder::IsFutureFileItem(input_element)) {
      found_file_transport = true;
      if (found_memory_transport) {
        status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
        return;
      }
      contains_unpopulated_transport_items = true;
      item = new ShareableBlobDataItem(std::move(input_item),
                                       ShareableBlobDataItem::QUOTA_NEEDED);
      pending_transport_items.push_back(item);
      transport_items.push_back(item.get());
      checked_transport_quota_needed += length;
    } else {
      item = new ShareableBlobDataItem(
          std::move(input_item),
          ShareableBlobDataItem::POPULATED_WITHOUT_QUOTA);
    }
    if (length == DataElement::kUnknownSize)
      num_files_with_unknown_size++;

    checked_total_size += length;
    output_blob->AppendSharedBlobItem(std::move(item));
  }

  if (num_files_with_unknown_size > 1 && input_builder.items_.size() > 1) {
    status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
    return;
  }
  if (!checked_total_size.IsValid() || !checked_total_memory_size.IsValid() ||
      !checked_transport_quota_needed.IsValid() ||
      !checked_copy_quota_needed.IsValid()) {
    status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
    return;
  }
  total_size = checked_total_size.ValueOrDie();
  total_memory_size = checked_total_memory_size.ValueOrDie();
  transport_quota_needed = checked_transport_quota_needed.ValueOrDie();
  copy_quota_needed = checked_copy_quota_needed.ValueOrDie();
  transport_quota_type = found_file_transport ? TransportQuotaType::FILE
                                              : TransportQuotaType::MEMORY;
  if (transport_quota_needed) {
    status = BlobStatus::PENDING_QUOTA;
  } else {
    status = BlobStatus::PENDING_INTERNALS;
  }
}


int OmniboxViewViews::OnDrop(const ui::OSExchangeData& data) {
  if (HasTextBeingDragged())
    return ui::DragDropTypes::DRAG_NONE;

  if (data.HasURL(ui::OSExchangeData::CONVERT_FILENAMES)) {
    GURL url;
    base::string16 title;
    if (data.GetURLAndTitle(
            ui::OSExchangeData::CONVERT_FILENAMES, &url, &title)) {
      base::string16 text(
          StripJavascriptSchemas(base::UTF8ToUTF16(url.spec())));
      if (model()->CanPasteAndGo(text)) {
        model()->PasteAndGo(text);
        return ui::DragDropTypes::DRAG_COPY;
      }
    }
   } else if (data.HasString()) {
     base::string16 text;
     if (data.GetString(&text)) {
      base::string16 collapsed_text(base::CollapseWhitespace(text, true));
       if (model()->CanPasteAndGo(collapsed_text))
         model()->PasteAndGo(collapsed_text);
       return ui::DragDropTypes::DRAG_COPY;
    }
  }

  return ui::DragDropTypes::DRAG_NONE;
}

Insufficient policy enforcement in Omnibox in Google Chrome prior to 63.0.3239.84 allowed a socially engineered user to XSS themselves by dragging and dropping a javascript: URL into the URL bar.


int OmniboxViewViews::OnDrop(const ui::OSExchangeData& data) {
  if (HasTextBeingDragged())
    return ui::DragDropTypes::DRAG_NONE;

  if (data.HasURL(ui::OSExchangeData::CONVERT_FILENAMES)) {
    GURL url;
    base::string16 title;
    if (data.GetURLAndTitle(
            ui::OSExchangeData::CONVERT_FILENAMES, &url, &title)) {
      base::string16 text(
          StripJavascriptSchemas(base::UTF8ToUTF16(url.spec())));
      if (model()->CanPasteAndGo(text)) {
        model()->PasteAndGo(text);
        return ui::DragDropTypes::DRAG_COPY;
      }
    }
   } else if (data.HasString()) {
     base::string16 text;
     if (data.GetString(&text)) {
      base::string16 collapsed_text(
          StripJavascriptSchemas(base::CollapseWhitespace(text, true)));
       if (model()->CanPasteAndGo(collapsed_text))
         model()->PasteAndGo(collapsed_text);
       return ui::DragDropTypes::DRAG_COPY;
    }
  }

  return ui::DragDropTypes::DRAG_NONE;
}


void QuicClientPromisedInfo::OnPromiseHeaders(const SpdyHeaderBlock& headers) {
   SpdyHeaderBlock::const_iterator it = headers.find(kHttp2MethodHeader);
  DCHECK(it != headers.end());
   if (!(it->second == "GET" || it->second == "HEAD")) {
     QUIC_DVLOG(1) << "Promise for stream " << id_ << " has invalid method "
                   << it->second;
    Reset(QUIC_INVALID_PROMISE_METHOD);
    return;
  }
  if (!SpdyUtils::UrlIsValid(headers)) {
    QUIC_DVLOG(1) << "Promise for stream " << id_ << " has invalid URL "
                  << url_;
    Reset(QUIC_INVALID_PROMISE_URL);
    return;
  }
  if (!session_->IsAuthorized(SpdyUtils::GetHostNameFromHeaderBlock(headers))) {
    Reset(QUIC_UNAUTHORIZED_PROMISE_URL);
    return;
  }
  request_headers_.reset(new SpdyHeaderBlock(headers.Clone()));
}

A stack buffer overflow in the QUIC networking stack in Google Chrome prior to 62.0.3202.89 allowed a remote attacker to gain code execution via a malicious server.


void QuicClientPromisedInfo::OnPromiseHeaders(const SpdyHeaderBlock& headers) {
   SpdyHeaderBlock::const_iterator it = headers.find(kHttp2MethodHeader);
  if (it == headers.end()) {
    QUIC_DVLOG(1) << "Promise for stream " << id_ << " has no method";
    Reset(QUIC_INVALID_PROMISE_METHOD);
    return;
  }
   if (!(it->second == "GET" || it->second == "HEAD")) {
     QUIC_DVLOG(1) << "Promise for stream " << id_ << " has invalid method "
                   << it->second;
    Reset(QUIC_INVALID_PROMISE_METHOD);
    return;
  }
  if (!SpdyUtils::UrlIsValid(headers)) {
    QUIC_DVLOG(1) << "Promise for stream " << id_ << " has invalid URL "
                  << url_;
    Reset(QUIC_INVALID_PROMISE_URL);
    return;
  }
  if (!session_->IsAuthorized(SpdyUtils::GetHostNameFromHeaderBlock(headers))) {
    Reset(QUIC_UNAUTHORIZED_PROMISE_URL);
    return;
  }
  request_headers_.reset(new SpdyHeaderBlock(headers.Clone()));
}


void ScriptProcessorHandler::Process(size_t frames_to_process) {

  AudioBus* input_bus = Input(0).Bus();
  AudioBus* output_bus = Output(0).Bus();

  unsigned double_buffer_index = this->DoubleBufferIndex();
  bool is_double_buffer_index_good =
      double_buffer_index < 2 && double_buffer_index < input_buffers_.size() &&
      double_buffer_index < output_buffers_.size();
  DCHECK(is_double_buffer_index_good);
  if (!is_double_buffer_index_good)
    return;

  AudioBuffer* input_buffer = input_buffers_[double_buffer_index].Get();
  AudioBuffer* output_buffer = output_buffers_[double_buffer_index].Get();

  unsigned number_of_input_channels = internal_input_bus_->NumberOfChannels();
  bool buffers_are_good =
      output_buffer && BufferSize() == output_buffer->length() &&
      buffer_read_write_index_ + frames_to_process <= BufferSize();

  if (internal_input_bus_->NumberOfChannels())
    buffers_are_good = buffers_are_good && input_buffer &&
                       BufferSize() == input_buffer->length();

  DCHECK(buffers_are_good);
  if (!buffers_are_good)
    return;

  bool is_frames_to_process_good = frames_to_process &&
                                   BufferSize() >= frames_to_process &&
                                   !(BufferSize() % frames_to_process);
  DCHECK(is_frames_to_process_good);
  if (!is_frames_to_process_good)
    return;

  unsigned number_of_output_channels = output_bus->NumberOfChannels();

  bool channels_are_good =
      (number_of_input_channels == number_of_input_channels_) &&
      (number_of_output_channels == number_of_output_channels_);
  DCHECK(channels_are_good);
  if (!channels_are_good)
    return;

  for (unsigned i = 0; i < number_of_input_channels; ++i)
    internal_input_bus_->SetChannelMemory(
        i,
        input_buffer->getChannelData(i).View()->Data() +
            buffer_read_write_index_,
        frames_to_process);

  if (number_of_input_channels)
    internal_input_bus_->CopyFrom(*input_bus);

  for (unsigned i = 0; i < number_of_output_channels; ++i) {
    memcpy(output_bus->Channel(i)->MutableData(),
           output_buffer->getChannelData(i).View()->Data() +
               buffer_read_write_index_,
           sizeof(float) * frames_to_process);
  }

  buffer_read_write_index_ =
      (buffer_read_write_index_ + frames_to_process) % BufferSize();

  if (!buffer_read_write_index_) {
    MutexTryLocker try_locker(process_event_lock_);
    if (!try_locker.Locked()) {
      output_buffer->Zero();
    } else if (Context()->GetExecutionContext()) {
      if (Context()->HasRealtimeConstraint()) {
         TaskRunnerHelper::Get(TaskType::kMediaElementEvent,
                               Context()->GetExecutionContext())
            ->PostTask(BLINK_FROM_HERE,
                       CrossThreadBind(
                           &ScriptProcessorHandler::FireProcessEvent,
                           CrossThreadUnretained(this), double_buffer_index_));
       } else {
        std::unique_ptr<WaitableEvent> waitable_event =
            WTF::MakeUnique<WaitableEvent>();

         TaskRunnerHelper::Get(TaskType::kMediaElementEvent,
                               Context()->GetExecutionContext())
            ->PostTask(BLINK_FROM_HERE,
                       CrossThreadBind(
                           &ScriptProcessorHandler::
                               FireProcessEventForOfflineAudioContext,
                           CrossThreadUnretained(this), double_buffer_index_,
                           CrossThreadUnretained(waitable_event.get())));

        waitable_event->Wait();
      }
    }

    SwapBuffers();
  }
}

A use after free in WebAudio in Blink in Google Chrome prior to 62.0.3202.62 allowed a remote attacker to perform an out of bounds memory read via a crafted HTML page.


void ScriptProcessorHandler::Process(size_t frames_to_process) {

  AudioBus* input_bus = Input(0).Bus();
  AudioBus* output_bus = Output(0).Bus();

  unsigned double_buffer_index = this->DoubleBufferIndex();
  bool is_double_buffer_index_good =
      double_buffer_index < 2 && double_buffer_index < input_buffers_.size() &&
      double_buffer_index < output_buffers_.size();
  DCHECK(is_double_buffer_index_good);
  if (!is_double_buffer_index_good)
    return;

  AudioBuffer* input_buffer = input_buffers_[double_buffer_index].Get();
  AudioBuffer* output_buffer = output_buffers_[double_buffer_index].Get();

  unsigned number_of_input_channels = internal_input_bus_->NumberOfChannels();
  bool buffers_are_good =
      output_buffer && BufferSize() == output_buffer->length() &&
      buffer_read_write_index_ + frames_to_process <= BufferSize();

  if (internal_input_bus_->NumberOfChannels())
    buffers_are_good = buffers_are_good && input_buffer &&
                       BufferSize() == input_buffer->length();

  DCHECK(buffers_are_good);
  if (!buffers_are_good)
    return;

  bool is_frames_to_process_good = frames_to_process &&
                                   BufferSize() >= frames_to_process &&
                                   !(BufferSize() % frames_to_process);
  DCHECK(is_frames_to_process_good);
  if (!is_frames_to_process_good)
    return;

  unsigned number_of_output_channels = output_bus->NumberOfChannels();

  bool channels_are_good =
      (number_of_input_channels == number_of_input_channels_) &&
      (number_of_output_channels == number_of_output_channels_);
  DCHECK(channels_are_good);
  if (!channels_are_good)
    return;

  for (unsigned i = 0; i < number_of_input_channels; ++i)
    internal_input_bus_->SetChannelMemory(
        i,
        input_buffer->getChannelData(i).View()->Data() +
            buffer_read_write_index_,
        frames_to_process);

  if (number_of_input_channels)
    internal_input_bus_->CopyFrom(*input_bus);

  for (unsigned i = 0; i < number_of_output_channels; ++i) {
    memcpy(output_bus->Channel(i)->MutableData(),
           output_buffer->getChannelData(i).View()->Data() +
               buffer_read_write_index_,
           sizeof(float) * frames_to_process);
  }

  buffer_read_write_index_ =
      (buffer_read_write_index_ + frames_to_process) % BufferSize();

  if (!buffer_read_write_index_) {
    MutexTryLocker try_locker(process_event_lock_);
    if (!try_locker.Locked()) {
      output_buffer->Zero();
    } else if (Context()->GetExecutionContext()) {
      if (Context()->HasRealtimeConstraint()) {
         TaskRunnerHelper::Get(TaskType::kMediaElementEvent,
                               Context()->GetExecutionContext())
            ->PostTask(
                BLINK_FROM_HERE,
                CrossThreadBind(&ScriptProcessorHandler::FireProcessEvent,
                                WrapRefPtr(this), double_buffer_index_));
       } else {
        std::unique_ptr<WaitableEvent> waitable_event =
            WTF::MakeUnique<WaitableEvent>();

         TaskRunnerHelper::Get(TaskType::kMediaElementEvent,
                               Context()->GetExecutionContext())
            ->PostTask(
                BLINK_FROM_HERE,
                CrossThreadBind(&ScriptProcessorHandler::
                                    FireProcessEventForOfflineAudioContext,
                                WrapRefPtr(this), double_buffer_index_,
                                CrossThreadUnretained(waitable_event.get())));

        waitable_event->Wait();
      }
    }

    SwapBuffers();
  }
}