Commit message: None
CVE: CVE-2012-2820
CWE: CWE-20
Vulnerability description: Google Chrome before 20.0.1132.43 does not properly implement SVG filters, which allows remote attackers to cause a denial of service (out-of-bounds read) via unspecified vectors.

Project: Chrome

void NetworkActionPredictor::AddRow(
    const DBCacheKey& key,
    const NetworkActionPredictorDatabase::Row& row) {
  if (!initialized_)
    return;

  DBCacheValue value = { row.number_of_hits, row.number_of_misses };
  db_cache_[key] = value;
  db_id_cache_[key] = row.id;
  content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
      base::Bind(&NetworkActionPredictorDatabase::AddRow, db_, row));
}

Project: Chrome

void NetworkActionPredictor::BeginTransaction() {
  if (!initialized_)
    return;

  content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
      base::Bind(&NetworkActionPredictorDatabase::BeginTransaction, db_));
}

Project: Chrome

double NetworkActionPredictor::CalculateConfidence(
    const string16& user_text,
    const AutocompleteMatch& match,
    bool* is_in_db) const {
  const DBCacheKey key = { user_text, match.destination_url };

  *is_in_db = false;
  if (user_text.length() < kMinimumUserTextLength)
    return 0.0;

  const DBCacheMap::const_iterator iter = db_cache_.find(key);
  if (iter == db_cache_.end())
    return 0.0;

  *is_in_db = true;
  return CalculateConfidenceForDbEntry(iter);
}

Project: Chrome

double NetworkActionPredictor::CalculateConfidenceForDbEntry(
    DBCacheMap::const_iterator iter) const {
  const DBCacheValue& value = iter->second;
  if (value.number_of_hits < kMinimumNumberOfHits)
    return 0.0;

  const double number_of_hits = value.number_of_hits * hit_weight_;
  return number_of_hits / (number_of_hits + value.number_of_misses);
}

Project: Chrome

void NetworkActionPredictor::ClearTransitionalMatches() {
  transitional_matches_.clear();
}

Project: Chrome

void NetworkActionPredictor::CommitTransaction() {
  if (!initialized_)
    return;

  content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
      base::Bind(&NetworkActionPredictorDatabase::CommitTransaction, db_));
}

Project: Chrome

void NetworkActionPredictor::CreateCaches(
    std::vector<NetworkActionPredictorDatabase::Row>* rows) {
  CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  DCHECK(!initialized_);
  DCHECK(db_cache_.empty());
  DCHECK(db_id_cache_.empty());

  for (std::vector<NetworkActionPredictorDatabase::Row>::const_iterator it =
       rows->begin(); it != rows->end(); ++it) {
    const DBCacheKey key = { it->user_text, it->url };
    const DBCacheValue value = { it->number_of_hits, it->number_of_misses };
    db_cache_[key] = value;
    db_id_cache_[key] = it->id;
  }

  HistoryService* history_service =
      profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
  if (!TryDeleteOldEntries(history_service)) {
    notification_registrar_.Add(this, chrome::NOTIFICATION_HISTORY_LOADED,
                                content::Source<Profile>(profile_));
  }
}

Project: Chrome

void NetworkActionPredictor::DeleteAllRows() {
  if (!initialized_)
    return;

  db_cache_.clear();
  db_id_cache_.clear();
  content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
      base::Bind(&NetworkActionPredictorDatabase::DeleteAllRows, db_));
}

Project: Chrome

void NetworkActionPredictor::DeleteOldEntries(history::URLDatabase* url_db) {
  CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  DCHECK(!initialized_);

  std::vector<NetworkActionPredictorDatabase::Row::Id> ids_to_delete;
  DeleteOldIdsFromCaches(url_db, &ids_to_delete);

  content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
      base::Bind(&NetworkActionPredictorDatabase::DeleteRows, db_,
                 ids_to_delete));

  notification_registrar_.Add(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
                              content::Source<Profile>(profile_));
  notification_registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED,
                              content::Source<Profile>(profile_));
  initialized_ = true;
}

Project: Chrome

void NetworkActionPredictor::DeleteOldIdsFromCaches(
    history::URLDatabase* url_db,
    std::vector<NetworkActionPredictorDatabase::Row::Id>* id_list) {
  CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  DCHECK(url_db);
  DCHECK(id_list);
  id_list->clear();
  for (DBCacheMap::iterator it = db_cache_.begin(); it != db_cache_.end();) {
    history::URLRow url_row;

    if ((url_db->GetRowForURL(it->first.url, &url_row) == 0) ||
        ((base::Time::Now() - url_row.last_visit()).InDays() >
         kMaximumDaysToKeepEntry)) {
      const DBIdCacheMap::iterator id_it = db_id_cache_.find(it->first);
      DCHECK(id_it != db_id_cache_.end());
      id_list->push_back(id_it->second);
      db_id_cache_.erase(id_it);
      db_cache_.erase(it++);
    } else {
      ++it;
    }
  }
}

Project: Chrome

void NetworkActionPredictor::DeleteRowsWithURLs(const std::set<GURL>& urls) {
  if (!initialized_)
    return;

  std::vector<NetworkActionPredictorDatabase::Row::Id> id_list;

  for (DBCacheMap::iterator it = db_cache_.begin(); it != db_cache_.end();) {
    if (urls.find(it->first.url) != urls.end()) {
      const DBIdCacheMap::iterator id_it = db_id_cache_.find(it->first);
      DCHECK(id_it != db_id_cache_.end());
      id_list.push_back(id_it->second);
      db_id_cache_.erase(id_it);
      db_cache_.erase(it++);
    } else {
      ++it;
    }
  }

  content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
      base::Bind(&NetworkActionPredictorDatabase::DeleteRows, db_, id_list));
}

Project: Chrome

bool NetworkActionPredictor::IsPreconnectable(const AutocompleteMatch& match) {
  switch (match.type) {
    case AutocompleteMatch::SEARCH_WHAT_YOU_TYPED:
    case AutocompleteMatch::SEARCH_HISTORY:
    case AutocompleteMatch::SEARCH_SUGGEST:
    case AutocompleteMatch::SEARCH_OTHER_ENGINE:
      return true;

    default:
      return false;
  }
}

Project: Chrome

NetworkActionPredictor::NetworkActionPredictor(Profile* profile)
    : profile_(profile),
      db_(new NetworkActionPredictorDatabase(profile)),
      initialized_(false) {
  content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
      base::Bind(&NetworkActionPredictorDatabase::Initialize, db_));

  HistoryService* history_service =
      profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
  if (history_service)
    history_service->InMemoryDatabase();

  std::vector<NetworkActionPredictorDatabase::Row>* rows =
      new std::vector<NetworkActionPredictorDatabase::Row>();
  content::BrowserThread::PostTaskAndReply(
      content::BrowserThread::DB, FROM_HERE,
      base::Bind(&NetworkActionPredictorDatabase::GetAllRows, db_, rows),
      base::Bind(&NetworkActionPredictor::CreateCaches, AsWeakPtr(),
                 base::Owned(rows)));

}

Project: Chrome

void NetworkActionPredictor::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  switch (type) {
    case chrome::NOTIFICATION_HISTORY_URLS_DELETED: {
      DCHECK(initialized_);
      const content::Details<const history::URLsDeletedDetails>
          urls_deleted_details =
              content::Details<const history::URLsDeletedDetails>(details);
      if (urls_deleted_details->all_history)
        DeleteAllRows();
      else
        DeleteRowsWithURLs(urls_deleted_details->urls);
      break;
    }

    case chrome::NOTIFICATION_OMNIBOX_OPENED_URL: {
      DCHECK(initialized_);

      OnOmniboxOpenedUrl(*content::Details<AutocompleteLog>(details).ptr());
      break;
    }

    case chrome::NOTIFICATION_HISTORY_LOADED: {
      DCHECK(!initialized_);
      TryDeleteOldEntries(content::Details<HistoryService>(details).ptr());

      notification_registrar_.Remove(this,
                                     chrome::NOTIFICATION_HISTORY_LOADED,
                                     content::Source<Profile>(profile_));
      break;
    }

    default:
      NOTREACHED() << "Unexpected notification observed.";
      break;
  }
}

Project: Chrome

void NetworkActionPredictor::OnOmniboxOpenedUrl(const AutocompleteLog& log) {
  if (log.text.length() < kMinimumUserTextLength)
    return;

  const AutocompleteMatch& match = log.result.match_at(log.selected_index);

  UMA_HISTOGRAM_BOOLEAN(
      StringPrintf("Prerender.OmniboxNavigationsCouldPrerender_%.1f",
                   get_hit_weight()).c_str(),
      prerender::IsOmniboxEnabled(profile_));

  const GURL& opened_url = match.destination_url;

  prerender::PrerenderManager* prerender_manager =
      prerender::PrerenderManagerFactory::GetForProfile(profile_);
  if (prerender_manager && !prerender_manager->IsPrerendering(opened_url))
    prerender_manager->CancelOmniboxPrerenders();

  const string16 lower_user_text(base::i18n::ToLower(log.text));

  BeginTransaction();
  for (std::vector<TransitionalMatch>::const_iterator it =
       transitional_matches_.begin(); it != transitional_matches_.end();
       ++it) {
    if (!StartsWith(lower_user_text, it->user_text, true))
      continue;

    for (std::vector<GURL>::const_iterator url_it = it->urls.begin();
         url_it != it->urls.end(); ++url_it) {
      DCHECK(it->user_text.length() >= kMinimumUserTextLength);
      const DBCacheKey key = { it->user_text, *url_it };
      const bool is_hit = (*url_it == opened_url);

      NetworkActionPredictorDatabase::Row row;
      row.user_text = key.user_text;
      row.url = key.url;

      DBCacheMap::iterator it = db_cache_.find(key);
      if (it == db_cache_.end()) {
        row.id = guid::GenerateGUID();
        row.number_of_hits = is_hit ? 1 : 0;
        row.number_of_misses = is_hit ? 0 : 1;

        AddRow(key, row);
      } else {
        DCHECK(db_id_cache_.find(key) != db_id_cache_.end());
        row.id = db_id_cache_.find(key)->second;
        row.number_of_hits = it->second.number_of_hits + (is_hit ? 1 : 0);
        row.number_of_misses = it->second.number_of_misses + (is_hit ? 0 : 1);

        UpdateRow(it, row);
      }
    }
  }
  CommitTransaction();

  ClearTransitionalMatches();

  for (std::vector<std::pair<GURL, double> >::const_iterator it =
       tracked_urls_.begin(); it != tracked_urls_.end();
       ++it) {
    if (opened_url == it->first) {
      UMA_HISTOGRAM_COUNTS_100("NetworkActionPredictor.AccurateCount",
                               it->second * 100);
    }
  }
  tracked_urls_.clear();
}

Project: Chrome

NetworkActionPredictor::Action NetworkActionPredictor::RecommendAction(
    const string16& user_text,
    const AutocompleteMatch& match) const {
  bool is_in_db = false;
  const double confidence = CalculateConfidence(user_text, match, &is_in_db);
  DCHECK(confidence >= 0.0 && confidence <= 1.0);

  UMA_HISTOGRAM_BOOLEAN("NetworkActionPredictor.MatchIsInDb", is_in_db);

  if (is_in_db) {
    tracked_urls_.push_back(std::make_pair(match.destination_url, confidence));
    UMA_HISTOGRAM_COUNTS_100("NetworkActionPredictor.Confidence",
                             confidence * 100);
  }

  Action action = ACTION_NONE;
  for (int i = 0; i < LAST_PREDICT_ACTION; ++i) {
    if (confidence >= kConfidenceCutoff[i]) {
      action = static_cast<Action>(i);
      break;
    }
  }

  if (action == ACTION_PRERENDER && !prerender::IsOmniboxEnabled(profile_))
    action = ACTION_PRECONNECT;

  return action;
}

Project: Chrome

void NetworkActionPredictor::RegisterTransitionalMatches(
    const string16& user_text,
    const AutocompleteResult& result) {
  if (user_text.length() < kMinimumUserTextLength)
    return;
  const string16 lower_user_text(base::i18n::ToLower(user_text));

  std::vector<TransitionalMatch>::iterator match_it =
      std::find(transitional_matches_.begin(), transitional_matches_.end(),
                lower_user_text);

  if (match_it == transitional_matches_.end()) {
    TransitionalMatch transitional_match;
    transitional_match.user_text = lower_user_text;
    match_it = transitional_matches_.insert(transitional_matches_.end(),
                                            transitional_match);
  }

  for (AutocompleteResult::const_iterator it = result.begin();
       it != result.end(); ++it) {
    if (std::find(match_it->urls.begin(), match_it->urls.end(),
                  it->destination_url) == match_it->urls.end()) {
      match_it->urls.push_back(it->destination_url);
    }
  }
}

Project: Chrome

void NetworkActionPredictor::Shutdown() {
  db_->OnPredictorDestroyed();
}

Project: Chrome

NetworkActionPredictor::TransitionalMatch::TransitionalMatch() {
}

Project: Chrome

bool NetworkActionPredictor::TryDeleteOldEntries(HistoryService* service) {
  if (!service)
    return false;

  history::URLDatabase* url_db = service->InMemoryDatabase();
  if (!url_db)
    return false;

  DeleteOldEntries(url_db);
  return true;
}

Project: Chrome

void NetworkActionPredictor::UpdateRow(
    DBCacheMap::iterator it,
    const NetworkActionPredictorDatabase::Row& row) {
  if (!initialized_)
    return;

  DCHECK(it != db_cache_.end());
  it->second.number_of_hits = row.number_of_hits;
  it->second.number_of_misses = row.number_of_misses;
  content::BrowserThread::PostTask(content::BrowserThread::DB, FROM_HERE,
      base::Bind(&NetworkActionPredictorDatabase::UpdateRow, db_, row));
}

Project: Chrome

NetworkActionPredictor::TransitionalMatch::~TransitionalMatch() {
}