Commit message: None
CVE: CVE-2018-6159
CWE: CWE-200
Vulnerability description: Insufficient policy enforcement in ServiceWorker in Google Chrome prior to 68.0.3440.75 allowed a remote attacker to obtain potentially sensitive information from process memory via a crafted HTML page.

Project: Chrome

void Performance::ActivateObserver(PerformanceObserver& observer) {
  if (active_observers_.IsEmpty())
    deliver_observations_timer_.StartOneShot(TimeDelta(), FROM_HERE);

  active_observers_.insert(&observer);
}

Project: Chrome

void Performance::AddFirstContentfulPaintTiming(TimeTicks start_time) {
  AddPaintTiming(PerformancePaintTiming::PaintType::kFirstContentfulPaint,
                 start_time);
}

Project: Chrome

void Performance::AddFirstPaintTiming(TimeTicks start_time) {
  AddPaintTiming(PerformancePaintTiming::PaintType::kFirstPaint, start_time);
}

Project: Chrome

void Performance::AddLongTaskTiming(
    TimeTicks start_time,
    TimeTicks end_time,
    const String& name,
    const String& frame_src,
    const String& frame_id,
    const String& frame_name,
    const SubTaskAttribution::EntriesVector& sub_task_attributions) {
  if (!HasObserverFor(PerformanceEntry::kLongTask))
    return;

  for (auto&& it : sub_task_attributions) {
    it->setHighResStartTime(
        MonotonicTimeToDOMHighResTimeStamp(it->startTime()));
    it->setHighResDuration(
        ConvertTimeDeltaToDOMHighResTimeStamp(it->duration()));
  }
  PerformanceEntry* entry = PerformanceLongTaskTiming::Create(
      MonotonicTimeToDOMHighResTimeStamp(start_time),
      MonotonicTimeToDOMHighResTimeStamp(end_time), name, frame_src, frame_id,
      frame_name, sub_task_attributions);
  NotifyObserversOfEntry(*entry);
}

Project: Chrome

void Performance::AddPaintTiming(PerformancePaintTiming::PaintType type,
                                 TimeTicks start_time) {
  if (!RuntimeEnabledFeatures::PerformancePaintTimingEnabled())
    return;

  PerformanceEntry* entry = new PerformancePaintTiming(
      type, MonotonicTimeToDOMHighResTimeStamp(start_time));
  if (type == PerformancePaintTiming::PaintType::kFirstPaint)
    first_paint_timing_ = entry;
  else if (type == PerformancePaintTiming::PaintType::kFirstContentfulPaint)
    first_contentful_paint_timing_ = entry;
  NotifyObserversOfEntry(*entry);
}

Project: Chrome

void Performance::AddResourceTimingBuffer(PerformanceEntry& entry) {
  resource_timing_buffer_.push_back(&entry);

  if (IsResourceTimingBufferFull())
    DispatchEvent(Event::Create(EventTypeNames::resourcetimingbufferfull));
}

Project: Chrome

bool Performance::AllowsTimingRedirect(
    const Vector<ResourceResponse>& redirect_chain,
    const ResourceResponse& final_response,
    const SecurityOrigin& initiator_security_origin,
    ExecutionContext* context) {
  if (!PassesTimingAllowCheck(final_response, initiator_security_origin,
                              AtomicString(), context))
    return false;

  for (const ResourceResponse& response : redirect_chain) {
    if (!PassesTimingAllowCheck(response, initiator_security_origin,
                                AtomicString(), context))
      return false;
  }

  return true;
}

Project: Chrome

void Performance::BuildJSONValue(V8ObjectBuilder& builder) const {
  builder.AddNumber("timeOrigin", timeOrigin());
}

Project: Chrome

double Performance::ClampTimeResolution(double time_seconds) {
  DEFINE_THREAD_SAFE_STATIC_LOCAL(TimeClamper, clamper, ());
  return clamper.ClampTimeResolution(time_seconds);
}

Project: Chrome

void Performance::DeliverObservationsTimerFired(TimerBase*) {
  decltype(active_observers_) observers;
  active_observers_.Swap(observers);
  for (const auto& observer : observers) {
    if (observer->ShouldBeSuspended())
      suspended_observers_.insert(observer);
    else
      observer->Deliver();
  }
}

Project: Chrome

void Performance::GenerateAndAddResourceTiming(
    const ResourceTimingInfo& info,
    const AtomicString& initiator_type) {
  if (IsResourceTimingBufferFull() &&
      !HasObserverFor(PerformanceEntry::kResource))
    return;

  ExecutionContext* context = GetExecutionContext();
  const SecurityOrigin* security_origin = GetSecurityOrigin(context);
  if (!security_origin)
    return;
  AddResourceTiming(
      GenerateResourceTiming(*security_origin, info, *context),
      !initiator_type.IsNull() ? initiator_type : info.InitiatorType());
}

Project: Chrome

WebResourceTimingInfo Performance::GenerateResourceTiming(
    const SecurityOrigin& destination_origin,
    const ResourceTimingInfo& info,
    ExecutionContext& context_for_use_counter) {
  const ResourceResponse& final_response = info.FinalResponse();
  WebResourceTimingInfo result;
  result.name = info.InitialURL().GetString();
  result.start_time = info.InitialTime();
  result.alpn_negotiated_protocol = final_response.AlpnNegotiatedProtocol();
  result.connection_info = final_response.ConnectionInfoString();
  result.timing = final_response.GetResourceLoadTiming();
  result.finish_time = info.LoadFinishTime();

  result.allow_timing_details = PassesTimingAllowCheck(
      final_response, destination_origin, info.OriginalTimingAllowOrigin(),
      &context_for_use_counter);

  const Vector<ResourceResponse>& redirect_chain = info.RedirectChain();
  if (!redirect_chain.IsEmpty()) {
    result.allow_redirect_details =
        AllowsTimingRedirect(redirect_chain, final_response, destination_origin,
                             &context_for_use_counter);

    if (ResourceLoadTiming* last_chained_timing =
            redirect_chain.back().GetResourceLoadTiming()) {
      result.last_redirect_end_time =
          TimeTicksInSeconds(last_chained_timing->ReceiveHeadersEnd());
    } else {
      result.allow_redirect_details = false;
      result.last_redirect_end_time = 0.0;
    }
    if (!result.allow_redirect_details) {
      if (ResourceLoadTiming* final_timing =
              final_response.GetResourceLoadTiming()) {
        result.start_time = TimeTicksInSeconds(final_timing->RequestTime());
      }
    }
  } else {
    result.allow_redirect_details = false;
    result.last_redirect_end_time = 0.0;
  }

  result.transfer_size = info.TransferSize();
  result.encoded_body_size = final_response.EncodedBodyLength();
  result.decoded_body_size = final_response.DecodedBodyLength();
  result.did_reuse_connection = final_response.ConnectionReused();
  result.allow_negative_values = info.NegativeAllowed();

  if (result.allow_timing_details) {
    result.server_timing = PerformanceServerTiming::ParseServerTiming(info);
  }
  if (!result.server_timing.empty()) {
    UseCounter::Count(&context_for_use_counter,
                      WebFeature::kPerformanceServerTiming);
  }

  return result;
}

Project: Chrome

const SecurityOrigin* GetSecurityOrigin(ExecutionContext* context) {
  if (context)
    return context->GetSecurityOrigin();
  return nullptr;
}

Project: Chrome

DOMHighResTimeStamp GetUnixAtZeroMonotonic() {
  DEFINE_THREAD_SAFE_STATIC_LOCAL(
      DOMHighResTimeStamp, unix_at_zero_monotonic,
      {ConvertSecondsToDOMHighResTimeStamp(CurrentTime() -
                                           CurrentTimeTicksInSeconds())});
  return unix_at_zero_monotonic;
}

Project: Chrome

bool Performance::HasObserverFor(
    PerformanceEntry::EntryType filter_type) const {
  return observer_filter_options_ & filter_type;
}

Project: Chrome

const AtomicString& Performance::InterfaceName() const {
  return EventTargetNames::Performance;
}

Project: Chrome

bool IsNavigationTimingType(
    Performance::PerformanceMeasurePassedInParameterType type) {
  return type != Performance::kObjectObject && type != Performance::kOther;
}

Project: Chrome

bool Performance::IsResourceTimingBufferFull() {
  return resource_timing_buffer_.size() >= resource_timing_buffer_size_;
}

Project: Chrome

DOMHighResTimeStamp Performance::MonotonicTimeToDOMHighResTimeStamp(
    TimeTicks time_origin,
    TimeTicks monotonic_time,
    bool allow_negative_value) {
  if (monotonic_time.is_null() || time_origin.is_null())
    return 0.0;

  double clamped_time_in_seconds =
      ClampTimeResolution(TimeTicksInSeconds(monotonic_time)) -
      ClampTimeResolution(TimeTicksInSeconds(time_origin));
  if (clamped_time_in_seconds < 0 && !allow_negative_value)
    return 0.0;
  return ConvertSecondsToDOMHighResTimeStamp(clamped_time_in_seconds);
}

Project: Chrome

DOMHighResTimeStamp Performance::MonotonicTimeToDOMHighResTimeStamp(
    TimeTicks monotonic_time) const {
  return MonotonicTimeToDOMHighResTimeStamp(time_origin_, monotonic_time,
                                            false /* allow_negative_value */);
}

Project: Chrome

void Performance::NotifyNavigationTimingToObservers() {
  if (!navigation_timing_)
    navigation_timing_ = CreateNavigationTimingInstance();
  if (navigation_timing_)
    NotifyObserversOfEntry(*navigation_timing_);
}

Project: Chrome

Performance::Performance(
    TimeTicks time_origin,
    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
    : frame_timing_buffer_size_(kDefaultFrameTimingBufferSize),
      resource_timing_buffer_size_(kDefaultResourceTimingBufferSize),
      user_timing_(nullptr),
      time_origin_(time_origin),
      observer_filter_options_(PerformanceEntry::kInvalid),
      deliver_observations_timer_(std::move(task_runner),
                                  this,
                                  &Performance::DeliverObservationsTimerFired) {
}

Project: Chrome

void Performance::RegisterPerformanceObserver(PerformanceObserver& observer) {
  observer_filter_options_ |= observer.FilterOptions();
  observers_.insert(&observer);
  UpdateLongTaskInstrumentation();
}

Project: Chrome

void Performance::ResumeSuspendedObservers() {
  if (suspended_observers_.IsEmpty())
    return;

  PerformanceObserverVector suspended;
  CopyToVector(suspended_observers_, suspended);
  for (size_t i = 0; i < suspended.size(); ++i) {
    if (!suspended[i]->ShouldBeSuspended()) {
      suspended_observers_.erase(suspended[i]);
      ActivateObserver(*suspended[i]);
    }
  }
}

Project: Chrome

void Performance::Trace(blink::Visitor* visitor) {
  visitor->Trace(frame_timing_buffer_);
  visitor->Trace(resource_timing_buffer_);
  visitor->Trace(navigation_timing_);
  visitor->Trace(user_timing_);
  visitor->Trace(first_paint_timing_);
  visitor->Trace(first_contentful_paint_timing_);
  visitor->Trace(observers_);
  visitor->Trace(active_observers_);
  visitor->Trace(suspended_observers_);
  EventTargetWithInlineData::Trace(visitor);
}

Project: Chrome

void Performance::TraceWrappers(ScriptWrappableVisitor* visitor) const {
  for (const auto& observer : observers_)
    visitor->TraceWrappers(observer);
  EventTargetWithInlineData::TraceWrappers(visitor);
}

Project: Chrome

void Performance::UnregisterPerformanceObserver(
    PerformanceObserver& old_observer) {
  observers_.erase(&old_observer);
  UpdatePerformanceObserverFilterOptions();
  UpdateLongTaskInstrumentation();
}

Project: Chrome

void Performance::UpdatePerformanceObserverFilterOptions() {
  observer_filter_options_ = PerformanceEntry::kInvalid;
  for (const auto& observer : observers_) {
    observer_filter_options_ |= observer->FilterOptions();
  }
  UpdateLongTaskInstrumentation();
}

Project: Chrome

void Performance::clearMarks(const String& mark_name) {
  if (!user_timing_)
    user_timing_ = UserTiming::Create(*this);
  user_timing_->ClearMarks(mark_name);
}

Project: Chrome

void Performance::clearMeasures(const String& measure_name) {
  if (!user_timing_)
    user_timing_ = UserTiming::Create(*this);
  user_timing_->ClearMeasures(measure_name);
}

Project: Chrome

void Performance::clearResourceTimings() {
  resource_timing_buffer_.clear();
}

Project: Chrome

PerformanceEntryVector Performance::getEntriesByName(const String& name,
                                                     const String& entry_type) {
  PerformanceEntryVector entries;
  PerformanceEntry::EntryType type =
      PerformanceEntry::ToEntryTypeEnum(entry_type);

  if (!entry_type.IsNull() && type == PerformanceEntry::kInvalid)
    return entries;

  if (entry_type.IsNull() || type == PerformanceEntry::kResource) {
    for (const auto& resource : resource_timing_buffer_) {
      if (resource->name() == name)
        entries.push_back(resource);
    }
  }

  if (entry_type.IsNull() || type == PerformanceEntry::kNavigation) {
    if (!navigation_timing_)
      navigation_timing_ = CreateNavigationTimingInstance();
    if (navigation_timing_ && navigation_timing_->name() == name)
      entries.push_back(navigation_timing_);
  }

  if (entry_type.IsNull() || type == PerformanceEntry::kComposite ||
      type == PerformanceEntry::kRender) {
    for (const auto& frame : frame_timing_buffer_) {
      if (frame->name() == name &&
          (entry_type.IsNull() || entry_type == frame->entryType()))
        entries.push_back(frame);
    }
  }

  if (user_timing_) {
    if (entry_type.IsNull() || type == PerformanceEntry::kMark)
      entries.AppendVector(user_timing_->GetMarks(name));
    if (entry_type.IsNull() || type == PerformanceEntry::kMeasure)
      entries.AppendVector(user_timing_->GetMeasures(name));
  }

  if (entry_type.IsNull() || type == PerformanceEntry::kPaint) {
    if (first_paint_timing_ && first_paint_timing_->name() == name)
      entries.push_back(first_paint_timing_);
    if (first_contentful_paint_timing_ &&
        first_contentful_paint_timing_->name() == name)
      entries.push_back(first_contentful_paint_timing_);
  }

  std::sort(entries.begin(), entries.end(),
            PerformanceEntry::StartTimeCompareLessThan);
  return entries;
}

Project: Chrome

PerformanceEntryVector Performance::getEntriesByType(const String& entry_type) {
  PerformanceEntryVector entries;
  PerformanceEntry::EntryType type =
      PerformanceEntry::ToEntryTypeEnum(entry_type);

  switch (type) {
    case PerformanceEntry::kResource:
      for (const auto& resource : resource_timing_buffer_)
        entries.push_back(resource);
      break;
    case PerformanceEntry::kNavigation:
      if (!navigation_timing_)
        navigation_timing_ = CreateNavigationTimingInstance();
      if (navigation_timing_)
        entries.push_back(navigation_timing_);
      break;
    case PerformanceEntry::kComposite:
    case PerformanceEntry::kRender:
      for (const auto& frame : frame_timing_buffer_) {
        if (type == frame->EntryTypeEnum()) {
          entries.push_back(frame);
        }
      }
      break;
    case PerformanceEntry::kMark:
      if (user_timing_)
        entries.AppendVector(user_timing_->GetMarks());
      break;
    case PerformanceEntry::kMeasure:
      if (user_timing_)
        entries.AppendVector(user_timing_->GetMeasures());
      break;
    case PerformanceEntry::kPaint:
      UseCounter::Count(GetExecutionContext(),
                        WebFeature::kPaintTimingRequested);
      if (first_paint_timing_)
        entries.push_back(first_paint_timing_);
      if (first_contentful_paint_timing_)
        entries.push_back(first_contentful_paint_timing_);
      break;
    case PerformanceEntry::kLongTask:
      break;
    case PerformanceEntry::kTaskAttribution:
      break;
    case PerformanceEntry::kInvalid:
      break;
  }

  std::sort(entries.begin(), entries.end(),
            PerformanceEntry::StartTimeCompareLessThan);
  return entries;
}

Project: Chrome

void Performance::mark(ScriptState* script_state,
                       const String& mark_name,
                       ExceptionState& exception_state) {
  DoubleOrPerformanceMarkOptions startOrOptions;
  this->mark(script_state, mark_name, startOrOptions, exception_state);
}

Project: Chrome

void Performance::mark(
    ScriptState* script_state,
    const String& mark_name,
    DoubleOrPerformanceMarkOptions& start_time_or_mark_options,
    ExceptionState& exception_state) {
  if (!RuntimeEnabledFeatures::CustomUserTimingEnabled()) {
    DCHECK(start_time_or_mark_options.IsNull());
  }

  if (!user_timing_)
    user_timing_ = UserTiming::Create(*this);

  DOMHighResTimeStamp start = 0.0;
  if (start_time_or_mark_options.IsDouble()) {
    start = start_time_or_mark_options.GetAsDouble();
  } else if (start_time_or_mark_options.IsPerformanceMarkOptions() &&
             start_time_or_mark_options.GetAsPerformanceMarkOptions()
                 .hasStartTime()) {
    start =
        start_time_or_mark_options.GetAsPerformanceMarkOptions().startTime();
  } else {
    start = now();
  }

  ScriptValue detail = ScriptValue::CreateNull(script_state);
  if (start_time_or_mark_options.IsPerformanceMarkOptions()) {
    detail = start_time_or_mark_options.GetAsPerformanceMarkOptions().detail();
  }

  if (PerformanceEntry* entry = user_timing_->Mark(
          script_state, mark_name, start, detail, exception_state))
    NotifyObserversOfEntry(*entry);
}

Project: Chrome

void Performance::measure(const String& measure_name,
                          const String& start_mark,
                          const String& end_mark,
                          ExceptionState& exception_state) {
  UMA_HISTOGRAM_ENUMERATION(
      "Performance.PerformanceMeasurePassedInParameter.StartMark",
      ToPerformanceMeasurePassedInParameterType(start_mark),
      kPerformanceMeasurePassedInParameterCount);
  UMA_HISTOGRAM_ENUMERATION(
      "Performance.PerformanceMeasurePassedInParameter.EndMark",
      ToPerformanceMeasurePassedInParameterType(end_mark),
      kPerformanceMeasurePassedInParameterCount);

  ExecutionContext* execution_context = GetExecutionContext();
  if (execution_context) {
    PerformanceMeasurePassedInParameterType start_type =
        ToPerformanceMeasurePassedInParameterType(start_mark);
    PerformanceMeasurePassedInParameterType end_type =
        ToPerformanceMeasurePassedInParameterType(end_mark);

    if (start_type == kObjectObject) {
      UseCounter::Count(execution_context,
                        WebFeature::kPerformanceMeasurePassedInObject);
    }

    if (IsNavigationTimingType(start_type) ||
        IsNavigationTimingType(end_type)) {
      UseCounter::Count(
          execution_context,
          WebFeature::kPerformanceMeasurePassedInNavigationTiming);
    }
  }

  if (!user_timing_)
    user_timing_ = UserTiming::Create(*this);
  if (PerformanceEntry* entry = user_timing_->Measure(
          measure_name, start_mark, end_mark, exception_state))
    NotifyObserversOfEntry(*entry);
}

Project: Chrome

MemoryInfo* Performance::memory() const {
  return nullptr;
}

Project: Chrome

DOMHighResTimeStamp Performance::now() const {
  return MonotonicTimeToDOMHighResTimeStamp(CurrentTimeTicks());
}

Project: Chrome

void Performance::setResourceTimingBufferSize(unsigned size) {
  resource_timing_buffer_size_ = size;
  if (IsResourceTimingBufferFull())
    DispatchEvent(Event::Create(EventTypeNames::resourcetimingbufferfull));
}

Project: Chrome

PerformanceTiming* Performance::timing() const {
  return nullptr;
}