Commit message: None
CVE: CVE-2018-6089
CWE: CWE-20
Vulnerability description: A lack of CORS checks, after a Service Worker redirected to a cross-origin PDF, in Service Worker in Google Chrome prior to 66.0.3359.117 allowed a remote attacker to leak limited cross-origin data via a crafted HTML page.

Project: Chrome

  ChromeServiceWorkerFetchPPAPIPrivateTest() {}

Project: Chrome

  ChromeServiceWorkerFetchTest() {}

Project: Chrome

  ChromeServiceWorkerTest() {
    EXPECT_TRUE(service_worker_dir_.CreateUniqueTempDir());
    EXPECT_TRUE(base::CreateDirectoryAndGetError(
        service_worker_dir_.GetPath().Append(
            FILE_PATH_LITERAL("scope")), nullptr));
  }

Project: Chrome

  void ExecuteJavaScriptForTests(const std::string& js) {
    base::RunLoop run_loop;
    browser()
        ->tab_strip_model()
        ->GetActiveWebContents()
        ->GetMainFrame()
        ->ExecuteJavaScriptForTests(
            base::ASCIIToUTF16(js),
            base::Bind([](const base::Closure& quit_callback,
                          const base::Value* result) { quit_callback.Run(); },
                       run_loop.QuitClosure()));
    run_loop.Run();
  }

Project: Chrome

  std::string ExecutePNACLUrlLoaderTest(const std::string& mode) {
    std::string result(ExecuteScriptAndExtractString(
        base::StringPrintf("reportOnFetch = false;"
                           "var iframe = document.createElement('iframe');"
                           "iframe.src='%s#%s';"
                           "document.body.appendChild(iframe);",
                           test_page_url_.c_str(), mode.c_str())));
    EXPECT_EQ(base::StringPrintf("OnOpen%s", mode.c_str()), result);
    return ExecuteScriptAndExtractString("reportRequests();");
  }

Project: Chrome

  std::string ExecuteScriptAndExtractString(const std::string& js) {
    std::string result;
    EXPECT_TRUE(content::ExecuteScriptAndExtractString(
        browser()->tab_strip_model()->GetActiveWebContents(), js, &result));
    return result;
  }

Project: Chrome

static void ExpectResultAndRun(T expected,
                               const base::Closure& continuation,
                               T actual) {
  EXPECT_EQ(expected, actual);
  continuation.Run();
}

Project: Chrome

  std::string GetManifestAndIssuedRequests() {
    base::RunLoop run_loop;
    browser()->tab_strip_model()->GetActiveWebContents()->GetManifest(
        base::Bind(&ManifestCallbackAndRun, run_loop.QuitClosure()));
    run_loop.Run();
    return ExecuteScriptAndExtractString(
        "if (issuedRequests.length != 0) reportRequests();"
        "else reportOnFetch = true;");
  }

Project: Chrome

  std::string GetRequestStringForPNACL(const std::string& fragment) const {
    return RequestString(test_page_url_ + fragment, "navigate", "include") +
           RequestString(GetURL("/pnacl_url_loader.nmf"), "same-origin",
                         "same-origin") +
           RequestString(GetURL("/pnacl_url_loader_newlib_pnacl.pexe"),
                         "same-origin", "same-origin");
  }

Project: Chrome

  content::ServiceWorkerContext* GetServiceWorkerContext() {
    return content::BrowserContext::GetDefaultStoragePartition(
               browser()->profile())
        ->GetServiceWorkerContext();
  }

Project: Chrome

  std::string GetURL(const std::string& relative_url) const {
    return embedded_test_server()->GetURL(relative_url).spec();
  }

Project: Chrome

  void InitializeServer() {
    embedded_test_server()->ServeFilesFromDirectory(
        service_worker_dir_.GetPath());
    ASSERT_TRUE(embedded_test_server()->Start());
  }

Project: Chrome

  void InitializeServiceWorkerFetchTestPage() {
    const base::string16 expected_title = base::ASCIIToUTF16("READY");
    content::TitleWatcher title_watcher(
        browser()->tab_strip_model()->GetActiveWebContents(), expected_title);
    ui_test_utils::NavigateToURL(browser(),
                                 embedded_test_server()->GetURL("/test.html"));
    EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
  }

Project: Chrome

  static void ManifestCallbackAndRun(const base::Closure& continuation,
                                     const GURL&,
                                     const content::Manifest&) {
    continuation.Run();
  }

Project: Chrome

  void NavigateToPageAndWaitForReadyTitle(const std::string path) {
    const base::string16 expected_title1 = base::ASCIIToUTF16("READY");
    content::TitleWatcher title_watcher1(
        browser()->tab_strip_model()->GetActiveWebContents(), expected_title1);
    ui_test_utils::NavigateToURL(browser(),
                                 embedded_test_server()->GetURL(path));
    EXPECT_EQ(expected_title1, title_watcher1.WaitAndGetTitle());
  }

Project: Chrome

  std::string RequestString(const std::string& url,
                            const std::string& mode,
                            const std::string& credentials) const {
    return base::StringPrintf("url:%s, mode:%s, credentials:%s\n", url.c_str(),
                              mode.c_str(), credentials.c_str());
  }

Project: Chrome

  void WriteFile(const base::FilePath::StringType& filename,
                 base::StringPiece contents) {
    base::ScopedAllowBlockingForTesting allow_blocking;
    EXPECT_EQ(base::checked_cast<int>(contents.size()),
              base::WriteFile(service_worker_dir_.GetPath().Append(filename),
                              contents.data(), contents.size()));
  }

Project: Chrome

  void WriteServiceWorkerFetchTestFiles() {
    WriteFile(FILE_PATH_LITERAL("sw.js"),
              "this.onactivate = function(event) {"
              "  event.waitUntil(self.clients.claim());"
              "};"
              "this.onfetch = function(event) {"
              "  event.respondWith("
              "      self.clients.matchAll().then(function(clients) {"
              "          clients.forEach(function(client) {"
              "              client.postMessage("
              "                'url:' + event.request.url + ', ' +"
              "                'mode:' + event.request.mode + ', ' +"
              "                'credentials:' + event.request.credentials"
              "              );"
              "            });"
              "          return fetch(event.request);"
              "        }));"
              "};");
    WriteFile(FILE_PATH_LITERAL("test.html"),
              "<script>"
              "navigator.serviceWorker.register('./sw.js', {scope: './'})"
              "  .then(function(reg) {"
              "      reg.addEventListener('updatefound', function() {"
              "          var worker = reg.installing;"
              "          worker.addEventListener('statechange', function() {"
              "              if (worker.state == 'activated')"
              "                document.title = 'READY';"
              "            });"
              "        });"
              "    });"
              "var reportOnFetch = true;"
              "var issuedRequests = [];"
              "function reportRequests() {"
              "  var str = '';"
              "  issuedRequests.forEach(function(data) {"
              "      str += data + '\\n';"
              "    });"
              "  window.domAutomationController.send(str);"
              "}"
              "navigator.serviceWorker.addEventListener("
              "    'message',"
              "    function(event) {"
              "      issuedRequests.push(event.data);"
              "      if (reportOnFetch) {"
              "        reportRequests();"
              "      }"
              "    }, false);"
              "</script>");
  }

Project: Chrome

content::WebContents* AddTab(Browser* browser, const GURL& url) {
  int starting_tab_count = browser->tab_strip_model()->count();
  ui_test_utils::NavigateToURLWithDisposition(
      browser, url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
  int tab_count = browser->tab_strip_model()->count();
  EXPECT_EQ(starting_tab_count + 1, tab_count);
  return browser->tab_strip_model()->GetActiveWebContents();
}

Project: Chrome

void DoNothingWithBool(bool b) {}

Project: Chrome

  std::string ExtractInnerText(content::WebContents* contents) {
    std::string inner_text;
    if (!content::ExecuteScriptAndExtractString(
            contents,
            "window.domAutomationController.send(document.body.innerText)",
            &inner_text)) {
      ADD_FAILURE() << "Failed to get inner text for "
                    << contents->GetVisibleURL();
    }
    return inner_text;
  }

Project: Chrome

  PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
      int64_t service_worker_registration_id,
      const GURL& origin) {
    PushMessagingAppIdentifier app_identifier =
        PushMessagingAppIdentifier::FindByServiceWorker(
            profile(), origin, service_worker_registration_id);

    EXPECT_FALSE(app_identifier.is_null());
    return app_identifier;
  }

Project: Chrome

  size_t GetWorkerRefCount(const GURL& origin) {
    content::ServiceWorkerContext* sw_context =
        content::BrowserContext::GetDefaultStoragePartition(
            browser()->profile())
            ->GetServiceWorkerContext();
    base::RunLoop run_loop;
    size_t ref_count = 0;
    auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
                            size_t external_request_count) {
      *ref_count = external_request_count;
      run_loop->Quit();
    };
    sw_context->CountExternalRequestsForTest(
        origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
    run_loop.Run();
    return ref_count;
  }

Project: Chrome

  void GrantNotificationPermissionForTest(const GURL& url) {
    GURL origin = url.GetOrigin();
    DesktopNotificationProfileUtil::GrantPermission(profile(), origin);
    ASSERT_EQ(CONTENT_SETTING_ALLOW,
              PermissionManager::Get(profile())
                  ->GetPermissionStatus(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                        origin, origin)
                  .content_setting);
  }

Project: Chrome

  content::WebContents* Navigate(const GURL& url) {
    ui_test_utils::NavigateToURLWithDisposition(
        browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
        ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    content::WebContents* web_contents =
        browser()->tab_strip_model()->GetActiveWebContents();
    content::WaitForLoadStop(web_contents);
    return web_contents;
  }

Project: Chrome

  content::PageType NavigateAndGetPageType(const GURL& url) {
    return Navigate(url)->GetController().GetActiveEntry()->GetPageType();
  }

Project: Chrome

  ServiceWorkerBackgroundSyncTest() {}

Project: Chrome

  ServiceWorkerLazyBackgroundTest()
      : ServiceWorkerTest(
            version_info::Channel::UNKNOWN) {}

Project: Chrome

  ServiceWorkerPushMessagingTest()
      : gcm_driver_(nullptr), push_service_(nullptr) {}

Project: Chrome

  const Extension* StartTestFromBackgroundPage(const char* script_name,
                                               std::string* error_or_null) {
    const Extension* extension =
        LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
    CHECK(extension);
    ExtensionHost* background_host =
        process_manager()->GetBackgroundHostForExtension(extension->id());
    CHECK(background_host);
    std::string error;
    CHECK(content::ExecuteScriptAndExtractString(
        background_host->host_contents(),
        base::StringPrintf("test.registerServiceWorker('%s')", script_name),
        &error));
    if (error_or_null)
      *error_or_null = error;
    else if (!error.empty())
      ADD_FAILURE() << "Got unexpected error " << error;
    return extension;
  }

Project: Chrome

  void WaitForLoadStop() {
    if (load_stop_observed_)
      return;
    message_loop_runner_ = new content::MessageLoopRunner;
    message_loop_runner_->Run();
  }

Project: Chrome

  explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
      : content::WebContentsObserver(web_contents),
        load_stop_observed_(false) {}

Project: Chrome

  instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
    return gcm_driver_;
  }

Project: Chrome

  ProcessManager* process_manager() { return ProcessManager::Get(profile()); }

Project: Chrome

  static v8::Local<v8::Object> Create(
      v8::Isolate* isolate,
      base::WeakPtr<MimeHandlerViewContainer> container) {
    ScriptableObject* scriptable_object =
        new ScriptableObject(isolate, container);
    return gin::CreateHandle(isolate, scriptable_object)
        .ToV8()
        .As<v8::Object>();
  }

Project: Chrome

void MimeHandlerViewContainer::DidFinishLoading(double /* unused */) {
  DCHECK(is_embedded_);
  CreateMimeHandlerViewGuestIfNecessary();
}

Project: Chrome

void MimeHandlerViewContainer::DidReceiveData(const char* data,
                                              int data_length) {
  view_id_ += std::string(data, data_length);
}

Project: Chrome

void MimeHandlerViewContainer::DidResizeElement(const gfx::Size& new_size) {
  element_size_ = new_size;

  CreateMimeHandlerViewGuestIfNecessary();

  if (!guest_created_)
    return;

  render_frame()->Send(new ExtensionsGuestViewHostMsg_ResizeGuest(
      render_frame()->GetRoutingID(), element_instance_id(), new_size));
}

Project: Chrome

MimeHandlerViewContainer::FromRenderFrame(content::RenderFrame* render_frame) {
  auto it = g_mime_handler_view_container_map.Get().find(render_frame);
  if (it == g_mime_handler_view_container_map.Get().end())
    return std::vector<MimeHandlerViewContainer*>();

  return std::vector<MimeHandlerViewContainer*>(it->second.begin(),
                                                it->second.end());
}

Project: Chrome

void MimeHandlerViewContainer::OnGuestAttached(int /* unused */,
                                               int guest_proxy_routing_id) {
  guest_proxy_routing_id_ = guest_proxy_routing_id;
}

Project: Chrome

bool MimeHandlerViewContainer::OnMessage(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(MimeHandlerViewContainer, message)
  IPC_MESSAGE_HANDLER(ExtensionsGuestViewMsg_CreateMimeHandlerViewGuestACK,
                      OnCreateMimeHandlerViewGuestACK)
  IPC_MESSAGE_HANDLER(
      ExtensionsGuestViewMsg_MimeHandlerViewGuestOnLoadCompleted,
      OnMimeHandlerViewGuestOnLoadCompleted)
  IPC_MESSAGE_HANDLER(GuestViewMsg_GuestAttached, OnGuestAttached)
  IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

Project: Chrome

void MimeHandlerViewContainer::OnMimeHandlerViewGuestOnLoadCompleted(
    int /* unused */) {
  if (!render_frame())
    return;

  guest_loaded_ = true;
  if (pending_messages_.empty())
    return;

  blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
  if (!frame)
    return;

  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  v8::HandleScope handle_scope(isolate);
  v8::Context::Scope context_scope(frame->MainWorldScriptContext());
  for (const auto& pending_message : pending_messages_)
    PostJavaScriptMessage(isolate,
                          v8::Local<v8::Value>::New(isolate, pending_message));

  pending_messages_.clear();
}

Project: Chrome

void MimeHandlerViewContainer::OnRenderFrameDestroyed() {
  g_mime_handler_view_container_map.Get().erase(render_frame());
}

Project: Chrome

void MimeHandlerViewContainer::PluginDidFinishLoading() {
  DCHECK(!is_embedded_);
  CreateMimeHandlerViewGuestIfNecessary();
}

Project: Chrome

void MimeHandlerViewContainer::PluginDidReceiveData(const char* data,
                                                    int data_length) {
  view_id_ += std::string(data, data_length);
}

Project: Chrome

void MimeHandlerViewContainer::PostJavaScriptMessage(
    v8::Isolate* isolate,
    v8::Local<v8::Value> message) {
  if (!guest_loaded_) {
    pending_messages_.push_back(v8::Global<v8::Value>(isolate, message));
    return;
  }

  content::RenderView* guest_proxy_render_view =
      content::RenderView::FromRoutingID(guest_proxy_routing_id_);
  if (!guest_proxy_render_view)
    return;
  blink::WebFrame* guest_proxy_frame =
      guest_proxy_render_view->GetWebView()->MainFrame();
  if (!guest_proxy_frame)
    return;

  v8::Context::Scope context_scope(
      render_frame()->GetWebFrame()->MainWorldScriptContext());

  v8::Local<v8::Object> guest_proxy_window = guest_proxy_frame->GlobalProxy();
  gin::Dictionary window_object(isolate, guest_proxy_window);
  v8::Local<v8::Function> post_message;
  if (!window_object.Get(std::string(kPostMessageName), &post_message))
    return;

  v8::Local<v8::Value> args[] = {
      message,
      gin::StringToV8(isolate, "*")};
  render_frame()->GetWebFrame()->CallFunctionEvenIfScriptDisabled(
      post_message.As<v8::Function>(), guest_proxy_window, arraysize(args),
      args);
}

Project: Chrome

  ScriptableObject(v8::Isolate* isolate,
                   base::WeakPtr<MimeHandlerViewContainer> container)
    : gin::NamedPropertyInterceptor(isolate, this),
      container_(container) {}

Project: Chrome

v8::Local<v8::Object> MimeHandlerViewContainer::V8ScriptableObject(
    v8::Isolate* isolate) {
  if (scriptable_object_.IsEmpty()) {
    v8::Local<v8::Object> object =
        ScriptableObject::Create(isolate, weak_factory_.GetWeakPtr());
    scriptable_object_.Reset(isolate, object);
  }
  return v8::Local<v8::Object>::New(isolate, scriptable_object_);
}

Project: Chrome

MimeHandlerViewContainer::~MimeHandlerViewContainer() {
  if (loader_) {
    DCHECK(is_embedded_);
    loader_->Cancel();
  }

  if (render_frame()) {
    g_mime_handler_view_container_map.Get()[render_frame()].erase(this);
    if (g_mime_handler_view_container_map.Get()[render_frame()].empty())
      g_mime_handler_view_container_map.Get().erase(render_frame());
  }
}