Commit message: None
CVE: CVE-2015-1299
Vulnerability description: Use-after-free vulnerability in the shared-timer implementation in Blink, as used in Google Chrome before 45.0.2454.85, allows remote attackers to cause a denial of service or possibly have unspecified other impact by leveraging erroneous timer firing, related to ThreadTimers.cpp and Timer.cpp.

Project: Chrome

scoped_ptr<gfx::GpuMemoryBuffer> RenderThreadImpl::AllocateGpuMemoryBuffer(
    size_t width,
    size_t height,
    unsigned internalformat,
    unsigned usage) {
  TRACE_EVENT0("renderer", "RenderThreadImpl::AllocateGpuMemoryBuffer");

  DCHECK(allocate_gpu_memory_buffer_thread_checker_.CalledOnValidThread());

  if (!GpuMemoryBufferImpl::IsFormatValid(internalformat))
    return scoped_ptr<gfx::GpuMemoryBuffer>();

  gfx::GpuMemoryBufferHandle handle;
  bool success;
  IPC::Message* message = new ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer(
      width, height, internalformat, usage, &handle);

  if (base::MessageLoop::current() == message_loop())
    success = ChildThread::Send(message);
  else
    success = sync_message_filter()->Send(message);

  if (!success)
    return scoped_ptr<gfx::GpuMemoryBuffer>();

  scoped_ptr<GpuMemoryBufferImpl> buffer(GpuMemoryBufferImpl::CreateFromHandle(
      handle,
      gfx::Size(width, height),
      internalformat,
      base::Bind(&DeletedGpuMemoryBuffer,
                 make_scoped_refptr(thread_safe_sender()),
                 handle.type,
                 handle.global_id)));
  if (!buffer) {
    thread_safe_sender()->Send(new ChildProcessHostMsg_DeletedGpuMemoryBuffer(
        handle.type, handle.global_id));
    return scoped_ptr<gfx::GpuMemoryBuffer>();
  }

  return buffer.PassAs<gfx::GpuMemoryBuffer>();
}

Project: Chrome

RenderThreadImpl::CreateOffscreenContext3d() {
  blink::WebGraphicsContext3D::Attributes attributes(GetOffscreenAttribs());
  bool lose_context_when_out_of_memory = true;

  scoped_refptr<GpuChannelHost> gpu_channel_host(EstablishGpuChannelSync(
      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE));
  return make_scoped_ptr(
      WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
          gpu_channel_host.get(),
          attributes,
          lose_context_when_out_of_memory,
          GURL("chrome://gpu/RenderThreadImpl::CreateOffscreenContext3d"),
          WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits(),
          NULL));
}

Project: Chrome

void DeletedGpuMemoryBuffer(ThreadSafeSender* sender,
                            gfx::GpuMemoryBufferType type,
                            const gfx::GpuMemoryBufferId& id) {
  TRACE_EVENT0("renderer", "RenderThreadImpl::DeletedGpuMemoryBuffer");
  sender->Send(new ChildProcessHostMsg_DeletedGpuMemoryBuffer(type, id));
}

Project: Chrome

RenderThreadImpl::GetMediaThreadTaskRunner() {
  DCHECK(message_loop() == base::MessageLoop::current());
  if (!media_thread_) {
    media_thread_.reset(new base::Thread("Media"));
    media_thread_->Start();

#if defined(OS_ANDROID)
    renderer_demuxer_ = new RendererDemuxerAndroid();
    AddFilter(renderer_demuxer_.get());
#endif
  }
  return media_thread_->message_loop_proxy();
}

Project: Chrome

blink::WebGraphicsContext3D::Attributes GetOffscreenAttribs() {
  blink::WebGraphicsContext3D::Attributes attributes;
  attributes.shareResources = true;
  attributes.depth = false;
  attributes.stencil = false;
  attributes.antialias = false;
  attributes.noAutomaticFlushes = true;
  return attributes;
}

Project: Chrome

void RenderThreadImpl::IdleHandler() {
  bool run_in_foreground_tab = (widget_count_ > hidden_widget_count_) &&
                               GetContentClient()->renderer()->
                                   RunIdleHandlerWhenWidgetsHidden();
  if (run_in_foreground_tab) {
    IdleHandlerInForegroundTab();
    return;
  }

  base::allocator::ReleaseFreeMemory();

  bool continue_timer = !webkit_shared_timer_suspended_;

  if (blink::mainThreadIsolate() &&
      !blink::mainThreadIsolate()->IdleNotification(1000)) {
    continue_timer = true;
  }
  if (!base::DiscardableMemory::ReduceMemoryUsage()) {
    continue_timer = true;
  }

  if (continue_timer) {
    ScheduleIdleHandler(
        std::max(kLongIdleHandlerDelayMs,
                 idle_notification_delay_in_ms_ +
                 1000000 / (idle_notification_delay_in_ms_ + 2000)));

  } else {
    idle_timer_.Stop();
  }

  FOR_EACH_OBSERVER(RenderProcessObserver, observers_, IdleNotification());
}

Project: Chrome

void RenderThreadImpl::IdleHandlerInForegroundTab() {
  int64 new_delay_ms = idle_notification_delay_in_ms_ +
                       1000000 / (idle_notification_delay_in_ms_ + 2000);
  if (new_delay_ms >= kLongIdleHandlerDelayMs)
    new_delay_ms = kShortIdleHandlerDelayMs;

  if (idle_notifications_to_skip_ > 0) {
    idle_notifications_to_skip_--;
  } else  {
    int cpu_usage = 0;
    Send(new ViewHostMsg_GetCPUUsage(&cpu_usage));
    int idle_hint = static_cast<int>(new_delay_ms / 10);
    if (cpu_usage < kIdleCPUUsageThresholdInPercents) {
      base::allocator::ReleaseFreeMemory();

      bool finished_idle_work = true;
      if (blink::mainThreadIsolate() &&
          !blink::mainThreadIsolate()->IdleNotification(idle_hint)) {
        finished_idle_work = false;
      }
      if (!base::DiscardableMemory::ReduceMemoryUsage())
        finished_idle_work = false;

      if (finished_idle_work)
        new_delay_ms = kLongIdleHandlerDelayMs;
    }
  }
  ScheduleIdleHandler(new_delay_ms);
}

Project: Chrome

void RenderThreadImpl::Init() {
  TRACE_EVENT_BEGIN_ETW("RenderThreadImpl::Init", 0, "");

  base::debug::TraceLog::GetInstance()->SetThreadSortIndex(
      base::PlatformThread::CurrentId(),
      kTraceEventRendererMainThreadSortIndex);

#if defined(OS_MACOSX) || defined(OS_ANDROID)
  blink::WebView::setUseExternalPopupMenus(true);
#endif

  lazy_tls.Pointer()->Set(this);

  ChildProcess::current()->set_main_thread(this);

  suspend_webkit_shared_timer_ = true;
  notify_webkit_of_modal_loop_ = true;
  webkit_shared_timer_suspended_ = false;
  widget_count_ = 0;
  hidden_widget_count_ = 0;
  idle_notification_delay_in_ms_ = kInitialIdleHandlerDelayMs;
  idle_notifications_to_skip_ = 0;
  layout_test_mode_ = false;

  appcache_dispatcher_.reset(
      new AppCacheDispatcher(Get(), new AppCacheFrontendImpl()));
  dom_storage_dispatcher_.reset(new DomStorageDispatcher());
  main_thread_indexed_db_dispatcher_.reset(new IndexedDBDispatcher(
      thread_safe_sender()));
  embedded_worker_dispatcher_.reset(new EmbeddedWorkerDispatcher());

  media_stream_center_ = NULL;

  db_message_filter_ = new DBMessageFilter();
  AddFilter(db_message_filter_.get());

  vc_manager_.reset(new VideoCaptureImplManager());
  AddFilter(vc_manager_->video_capture_message_filter());

#if defined(ENABLE_WEBRTC)
  peer_connection_tracker_.reset(new PeerConnectionTracker());
  AddObserver(peer_connection_tracker_.get());

  p2p_socket_dispatcher_ =
      new P2PSocketDispatcher(GetIOMessageLoopProxy().get());
  AddFilter(p2p_socket_dispatcher_.get());

  webrtc_identity_service_.reset(new WebRTCIdentityService());

  aec_dump_message_filter_ =
      new AecDumpMessageFilter(GetIOMessageLoopProxy(),
                               message_loop()->message_loop_proxy());
  AddFilter(aec_dump_message_filter_.get());

  peer_connection_factory_.reset(new PeerConnectionDependencyFactory(
      p2p_socket_dispatcher_.get()));
#endif  // defined(ENABLE_WEBRTC)

  audio_input_message_filter_ =
      new AudioInputMessageFilter(GetIOMessageLoopProxy());
  AddFilter(audio_input_message_filter_.get());

  audio_message_filter_ = new AudioMessageFilter(GetIOMessageLoopProxy());
  AddFilter(audio_message_filter_.get());

  midi_message_filter_ = new MidiMessageFilter(GetIOMessageLoopProxy());
  AddFilter(midi_message_filter_.get());

  AddFilter((new IndexedDBMessageFilter(thread_safe_sender()))->GetFilter());

  AddFilter((new EmbeddedWorkerContextMessageFilter())->GetFilter());

  GetContentClient()->renderer()->RenderThreadStarted();

  InitSkiaEventTracer();

  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
  if (command_line.HasSwitch(cc::switches::kEnableGpuBenchmarking))
      RegisterExtension(GpuBenchmarkingExtension::Get());

  is_impl_side_painting_enabled_ =
      command_line.HasSwitch(switches::kEnableImplSidePainting);
  cc_blink::WebLayerImpl::SetImplSidePaintingEnabled(
      is_impl_side_painting_enabled_);

  is_zero_copy_enabled_ = command_line.HasSwitch(switches::kEnableZeroCopy) &&
                          !command_line.HasSwitch(switches::kDisableZeroCopy);

  is_one_copy_enabled_ = command_line.HasSwitch(switches::kEnableOneCopy);

  if (command_line.HasSwitch(switches::kDisableLCDText)) {
    is_lcd_text_enabled_ = false;
  } else if (command_line.HasSwitch(switches::kEnableLCDText)) {
    is_lcd_text_enabled_ = true;
  } else {
#if defined(OS_ANDROID)
    is_lcd_text_enabled_ = false;
#else
    is_lcd_text_enabled_ = true;
#endif
  }

  is_gpu_rasterization_enabled_ =
      command_line.HasSwitch(switches::kEnableGpuRasterization);
  is_gpu_rasterization_forced_ =
      command_line.HasSwitch(switches::kForceGpuRasterization);

  if (command_line.HasSwitch(switches::kDisableDistanceFieldText)) {
    is_distance_field_text_enabled_ = false;
  } else if (command_line.HasSwitch(switches::kEnableDistanceFieldText)) {
    is_distance_field_text_enabled_ = true;
  } else {
    is_distance_field_text_enabled_ = false;
  }

  base::FilePath media_path;
  PathService::Get(DIR_MEDIA_LIBS, &media_path);
  if (!media_path.empty())
    media::InitializeMediaLibrary(media_path);

  memory_pressure_listener_.reset(new base::MemoryPressureListener(
      base::Bind(&RenderThreadImpl::OnMemoryPressure, base::Unretained(this))));

  std::vector<base::DiscardableMemoryType> supported_types;
  base::DiscardableMemory::GetSupportedTypes(&supported_types);
  DCHECK(!supported_types.empty());

  base::DiscardableMemoryType type = supported_types[0];

  if (command_line.HasSwitch(switches::kUseDiscardableMemory)) {
    std::string requested_type_name = command_line.GetSwitchValueASCII(
        switches::kUseDiscardableMemory);
    base::DiscardableMemoryType requested_type =
        base::DiscardableMemory::GetNamedType(requested_type_name);
    if (std::find(supported_types.begin(),
                  supported_types.end(),
                  requested_type) != supported_types.end()) {
      type = requested_type;
    } else {
      LOG(ERROR) << "Requested discardable memory type is not supported.";
    }
  }

  base::DiscardableMemory::SetPreferredType(type);

  allocate_gpu_memory_buffer_thread_checker_.DetachFromThread();

  if (is_impl_side_painting_enabled_) {
    int num_raster_threads = 0;
    std::string string_value =
        command_line.GetSwitchValueASCII(switches::kNumRasterThreads);
    bool parsed_num_raster_threads =
        base::StringToInt(string_value, &num_raster_threads);
    DCHECK(parsed_num_raster_threads) << string_value;
    DCHECK_GT(num_raster_threads, 0);
    cc::RasterWorkerPool::SetNumRasterThreads(num_raster_threads);
  }

  service_registry()->AddService<RenderFrameSetup>(
      base::Bind(CreateRenderFrameSetup));

  TRACE_EVENT_END_ETW("RenderThreadImpl::Init", 0, "");
}

Project: Chrome

bool RenderThreadImpl::OnControlMessageReceived(const IPC::Message& msg) {
  ObserverListBase<RenderProcessObserver>::Iterator it(observers_);
  RenderProcessObserver* observer;
  while ((observer = it.GetNext()) != NULL) {
    if (observer->OnControlMessageReceived(msg))
      return true;
  }

  if (appcache_dispatcher_->OnMessageReceived(msg) ||
      dom_storage_dispatcher_->OnMessageReceived(msg) ||
      embedded_worker_dispatcher_->OnMessageReceived(msg)) {
    return true;
  }

  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(RenderThreadImpl, msg)
    IPC_MESSAGE_HANDLER(FrameMsg_NewFrame, OnCreateNewFrame)
    IPC_MESSAGE_HANDLER(FrameMsg_NewFrameProxy, OnCreateNewFrameProxy)
    IPC_MESSAGE_HANDLER(ViewMsg_SetZoomLevelForCurrentURL,
                        OnSetZoomLevelForCurrentURL)
    IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView)
    IPC_MESSAGE_HANDLER(ViewMsg_NetworkTypeChanged, OnNetworkTypeChanged)
    IPC_MESSAGE_HANDLER(ViewMsg_TempCrashWithData, OnTempCrashWithData)
    IPC_MESSAGE_HANDLER(WorkerProcessMsg_CreateWorker, OnCreateNewSharedWorker)
    IPC_MESSAGE_HANDLER(ViewMsg_TimezoneChange, OnUpdateTimezone)
#if defined(OS_ANDROID)
    IPC_MESSAGE_HANDLER(ViewMsg_SetWebKitSharedTimersSuspended,
                        OnSetWebKitSharedTimersSuspended)
#endif
#if defined(OS_MACOSX)
    IPC_MESSAGE_HANDLER(ViewMsg_UpdateScrollbarTheme, OnUpdateScrollbarTheme)
#endif
#if defined(ENABLE_PLUGINS)
    IPC_MESSAGE_HANDLER(ViewMsg_PurgePluginListCache, OnPurgePluginListCache)
#endif
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

Project: Chrome

void RenderThreadImpl::OnCreateNewFrame(int routing_id, int parent_routing_id) {
  RenderFrameImpl::CreateFrame(routing_id, parent_routing_id);
}

Project: Chrome

void RenderThreadImpl::OnCreateNewFrameProxy(int routing_id,
                                             int parent_routing_id,
                                             int render_view_routing_id) {
  RenderFrameProxy::CreateFrameProxy(
      routing_id, parent_routing_id, render_view_routing_id);
}

Project: Chrome

void RenderThreadImpl::OnCreateNewView(const ViewMsg_New_Params& params) {
  EnsureWebKitInitialized();
  RenderViewImpl::Create(params.opener_route_id,
                         params.window_was_created_with_opener,
                         params.renderer_preferences,
                         params.web_preferences,
                         params.view_id,
                         params.main_frame_routing_id,
                         params.surface_id,
                         params.session_storage_namespace_id,
                         params.frame_name,
                         false,
                         params.swapped_out,
                         params.proxy_routing_id,
                         params.hidden,
                         params.never_visible,
                         params.next_page_id,
                         params.screen_info);
}

Project: Chrome

void RenderThreadImpl::OnMemoryPressure(
    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
  base::allocator::ReleaseFreeMemory();

  if (webkit_platform_support_ && blink::mainThreadIsolate()) {
    blink::mainThreadIsolate()->LowMemoryNotification();
  }

  if (memory_pressure_level ==
      base::MemoryPressureListener::MEMORY_PRESSURE_CRITICAL) {
    if (webkit_platform_support_) {
      blink::WebImageCache::clear();
    }

    size_t font_cache_limit = SkGraphics::SetFontCacheLimit(0);
    SkGraphics::SetFontCacheLimit(font_cache_limit);
  }
}

Project: Chrome

RenderThreadImpl::RenderThreadImpl()
    : ChildThread(Options(ShouldUseMojoChannel())) {
  Init();
}

Project: Chrome

RenderThreadImpl::RenderThreadImpl(
    scoped_ptr<base::MessageLoop> main_message_loop)
    : ChildThread(Options(ShouldUseMojoChannel())),
      main_message_loop_(main_message_loop.Pass()) {
  Init();
}

Project: Chrome

void RenderThreadImpl::SampleGamepads(blink::WebGamepads* data) {
  webkit_platform_support_->sampleGamepads(*data);
}

Project: Chrome

RenderThreadImpl::SharedMainThreadContextProvider() {
  DCHECK(IsMainThread());
  if (!shared_main_thread_contexts_.get() ||
      shared_main_thread_contexts_->DestroyedOnMainThread()) {
    shared_main_thread_contexts_ = NULL;
#if defined(OS_ANDROID)
    if (SynchronousCompositorFactory* factory =
            SynchronousCompositorFactory::GetInstance()) {
      shared_main_thread_contexts_ = factory->CreateOffscreenContextProvider(
          GetOffscreenAttribs(), "Offscreen-MainThread");
    }
#endif
    if (!shared_main_thread_contexts_.get()) {
      shared_main_thread_contexts_ = ContextProviderCommandBuffer::Create(
          CreateOffscreenContext3d(), "Offscreen-MainThread");
    }
    if (shared_main_thread_contexts_.get() &&
        !shared_main_thread_contexts_->BindToCurrentThread())
      shared_main_thread_contexts_ = NULL;
  }
  return shared_main_thread_contexts_;
}

Project: Chrome

bool ShouldUseMojoChannel() {
  return CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kEnableRendererMojoChannel);
}

Project: Chrome

void RenderThreadImpl::Shutdown() {
  FOR_EACH_OBSERVER(
      RenderProcessObserver, observers_, OnRenderProcessShutdown());

  ChildThread::Shutdown();

  if (memory_observer_) {
    message_loop()->RemoveTaskObserver(memory_observer_.get());
    memory_observer_.reset();
  }

  if (webkit_platform_support_) {
    WebView::willEnterModalLoop();
    webkit_platform_support_->web_database_observer_impl()->
        WaitForAllDatabasesToClose();
    WebView::didExitModalLoop();
  }

  if (devtools_agent_message_filter_.get()) {
    RemoveFilter(devtools_agent_message_filter_.get());
    devtools_agent_message_filter_ = NULL;
  }

  RemoveFilter(audio_input_message_filter_.get());
  audio_input_message_filter_ = NULL;

#if defined(ENABLE_WEBRTC)
  RTCPeerConnectionHandler::DestructAllHandlers();

  peer_connection_factory_.reset();
#endif
  RemoveFilter(vc_manager_->video_capture_message_filter());
  vc_manager_.reset();

  RemoveFilter(db_message_filter_.get());
  db_message_filter_ = NULL;

  if (file_thread_)
    file_thread_->Stop();

  if (compositor_output_surface_filter_.get()) {
    RemoveFilter(compositor_output_surface_filter_.get());
    compositor_output_surface_filter_ = NULL;
  }

  media_thread_.reset();

  RemoveFilter(audio_message_filter_.get());
  audio_message_filter_ = NULL;

  compositor_thread_.reset();
  input_handler_manager_.reset();
  if (input_event_filter_.get()) {
    RemoveFilter(input_event_filter_.get());
    input_event_filter_ = NULL;
  }

  embedded_worker_dispatcher_.reset();

  main_thread_indexed_db_dispatcher_.reset();

  main_thread_compositor_task_runner_ = NULL;

  main_message_loop_.reset();
  if (webkit_platform_support_)
    blink::shutdown();

  lazy_tls.Pointer()->Set(NULL);

#if defined(OS_WIN)
  NPChannelBase::CleanupChannels();
#endif
}

Project: Chrome

void RenderThreadImpl::WidgetHidden() {
  DCHECK_LT(hidden_widget_count_, widget_count_);
  hidden_widget_count_++;

  if (widget_count_ && hidden_widget_count_ == widget_count_) {
    base::internal::DiscardableMemoryEmulated::
        ReduceMemoryUsageUntilWithinLimit(
            kEmulatedDiscardableMemoryBytesToKeepWhenWidgetsHidden);

    if (GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden())
      ScheduleIdleHandler(kInitialIdleHandlerDelayMs);
  }
}