Commit message: None
CVE: CVE-2016-5224
CWE: CWE-189
Vulnerability description: A timing attack on denormalized floating point arithmetic in SVG filters in Blink in Google Chrome prior to 55.0.2883.75 for Mac, Windows and Linux, and 55.0.2883.84 for Android allowed a remote attacker to bypass the Same Origin Policy via a crafted HTML page.

Project: Chrome

bool BuildEnvironmentWithApk(std::vector<std::string>* result) {
  DCHECK(result->empty());

  base::FilePath apk_path;
  if (!base::android::GetPathToBaseApk(&apk_path)) {
    return false;
  }

  std::unique_ptr<base::Environment> env(base::Environment::Create());
  static constexpr char kClasspathVar[] = "CLASSPATH";
  std::string classpath;
  env->GetVar(kClasspathVar, &classpath);
  classpath = apk_path.value() + ":" + classpath;

  static constexpr char kLdLibraryPathVar[] = "LD_LIBRARY_PATH";
  std::string library_path;
  env->GetVar(kLdLibraryPathVar, &library_path);
  library_path = apk_path.value() + "!/lib/" CURRENT_ABI ":" + library_path;

  result->push_back("CLASSPATH=" + classpath);
  result->push_back("LD_LIBRARY_PATH=" + library_path);
  for (char** envp = environ; *envp != nullptr; ++envp) {
    if ((strncmp(*envp, kClasspathVar, strlen(kClasspathVar)) == 0 &&
         (*envp)[strlen(kClasspathVar)] == '=') ||
        (strncmp(*envp, kLdLibraryPathVar, strlen(kLdLibraryPathVar)) == 0 &&
         (*envp)[strlen(kLdLibraryPathVar)] == '=')) {
      continue;
    }
    result->push_back(*envp);
  }

  return true;
}

Project: Chrome

void BuildHandlerArgs(CrashReporterClient* crash_reporter_client,
                      base::FilePath* database_path,
                      base::FilePath* metrics_path,
                      std::string* url,
                      std::map<std::string, std::string>* process_annotations,
                      std::vector<std::string>* arguments) {
  crash_reporter_client->GetCrashDumpLocation(database_path);
  crash_reporter_client->GetCrashMetricsLocation(metrics_path);

#if defined(GOOGLE_CHROME_BUILD) && defined(OFFICIAL_BUILD) && \
    !defined(OS_ANDROID)
  *url = "https://clients2.google.com/cr/report";
#else
  *url = std::string();
#endif

  std::string product_name;
  std::string product_version;
  std::string channel;
  crash_reporter_client->GetProductNameAndVersion(&product_name,
                                                  &product_version, &channel);
  (*process_annotations)["prod"] = product_name;
  (*process_annotations)["ver"] = product_version;

#if defined(OS_ANDROID)
  SetBuildInfoAnnotations(process_annotations);
#endif  // OS_ANDROID

#if defined(GOOGLE_CHROME_BUILD)
  const bool allow_empty_channel = true;
#else
  const bool allow_empty_channel = false;
#endif
  if (allow_empty_channel || !channel.empty()) {
    (*process_annotations)["channel"] = channel;
  }

#if defined(OS_ANDROID)
  (*process_annotations)["plat"] = std::string("Android");
#else
  (*process_annotations)["plat"] = std::string("Linux");
#endif

  if (crash_reporter_client->ShouldMonitorCrashHandlerExpensively()) {
    arguments->push_back("--monitor-self");
  }

  arguments->push_back("--monitor-self-annotation=ptype=crashpad-handler");
}

Project: Chrome

  int ConnectToHandler(int signo, base::ScopedFD* connection) {
    int fds[2];
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) {
      return errno;
    }
    base::ScopedFD local_connection(fds[0]);
    base::ScopedFD handlers_socket(fds[1]);

    int optval = 1;
    socklen_t optlen = sizeof(optval);
    setsockopt(handlers_socket.get(), SOL_SOCKET, SO_PASSCRED, &optval, optlen);

    iovec iov[2];
    iov[0].iov_base = &signo;
    iov[0].iov_len = sizeof(signo);
    iov[1].iov_base = &request_dump_;
    iov[1].iov_len = sizeof(request_dump_);

    msghdr msg;
    msg.msg_name = nullptr;
    msg.msg_namelen = 0;
    msg.msg_iov = iov;
    msg.msg_iovlen = base::size(iov);

    char cmsg_buf[CMSG_SPACE(sizeof(int))];
    msg.msg_control = cmsg_buf;
    msg.msg_controllen = sizeof(cmsg_buf);

    cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    *reinterpret_cast<int*>(CMSG_DATA(cmsg)) = handlers_socket.get();

    if (HANDLE_EINTR(sendmsg(server_fd_, &msg, MSG_NOSIGNAL)) < 0) {
      return errno;
    }

    *connection = std::move(local_connection);
    return 0;
  }

Project: Chrome

bool ConnectToHandler(CrashReporterClient* client, base::ScopedFD* connection) {
  int fds[2];
  if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) {
    PLOG(ERROR) << "socketpair";
    return false;
  }
  base::ScopedFD local_connection(fds[0]);
  base::ScopedFD handlers_socket(fds[1]);

  if (!HandlerStarter::Get()->StartHandlerForClient(client,
                                                    handlers_socket.get())) {
    return false;
  }

  *connection = std::move(local_connection);
  return true;
}

Project: Chrome

void DumpWithoutCrashing() {
  if (g_is_browser) {
    CRASHPAD_SIMULATE_CRASH();
  } else {
    siginfo_t siginfo;
    siginfo.si_signo = crashpad::Signals::kSimulatedSigno;
    siginfo.si_errno = 0;
    siginfo.si_code = 0;

    ucontext_t context;
    crashpad::CaptureContext(&context);

    crashpad::SandboxedHandler::Get()->HandleCrashNonFatal(siginfo.si_signo,
                                                           &siginfo, &context);
  }
}

Project: Chrome

bool DumpWithoutCrashingForClient(CrashReporterClient* client) {
  base::ScopedFD connection;
  if (!ConnectToHandler(client, &connection)) {
    return false;
  }

  siginfo_t siginfo;
  siginfo.si_signo = crashpad::Signals::kSimulatedSigno;
  siginfo.si_errno = 0;
  siginfo.si_code = 0;

  ucontext_t context;
  crashpad::CaptureContext(&context);

  crashpad::SanitizationInformation sanitization;
  crashpad::SetSanitizationInfo(client, &sanitization);

  crashpad::ExceptionInformation exception;
  crashpad::SetExceptionInformation(&siginfo, &context, &exception);

  crashpad::ClientInformation info;
  crashpad::SetClientInformation(&exception, &sanitization, &info);

  crashpad::ExceptionHandlerClient handler_client(connection.get());
  return handler_client.RequestCrashDump(info) == 0;
}

Project: Chrome

  static SandboxedHandler* Get() {
    static SandboxedHandler* instance = new SandboxedHandler();
    return instance;
  }

Project: Chrome

  static HandlerStarter* Get() {
    static HandlerStarter* instance = new HandlerStarter();
    return instance;
  }

Project: Chrome

bool GetHandlerPath(base::FilePath* exe_dir, base::FilePath* handler_path) {
#if defined(OS_ANDROID)
  if (!base::PathService::Get(base::DIR_MODULE, exe_dir)) {
    return false;
  }
  *handler_path = exe_dir->Append("libcrashpad_handler.so");
#else
  if (!base::PathService::Get(base::DIR_EXE, exe_dir)) {
    return false;
  }
  *handler_path = exe_dir->Append("crashpad_handler");
#endif
  return true;
}

Project: Chrome

  void HandleCrashNonFatal(int signo, siginfo_t* siginfo, void* context) {
    base::ScopedFD connection;
    if (ConnectToHandler(signo, &connection) == 0) {
      ExceptionInformation exception_information;
      SetExceptionInformation(siginfo, static_cast<ucontext_t*>(context),
                              &exception_information);

      ClientInformation info;
      SetClientInformation(&exception_information, &sanitization_, &info);

      ExceptionHandlerClient handler_client(connection.get());
      handler_client.SetCanSetPtracer(false);
      handler_client.RequestCrashDump(info);
    }
  }

Project: Chrome

  bool Initialize(bool dump_at_crash) {
    request_dump_ = dump_at_crash ? 1 : 0;

    SetSanitizationInfo(crash_reporter::GetCrashReporterClient(),
                        &sanitization_);
    server_fd_ = base::GlobalDescriptors::GetInstance()->Get(
        service_manager::kCrashDumpSignal);

    return Signals::InstallCrashHandlers(HandleCrash, 0, &old_actions_);
  }

Project: Chrome

  base::FilePath Initialize(bool dump_at_crash) {
    base::FilePath database_path;
    base::FilePath metrics_path;
    std::string url;
    std::map<std::string, std::string> process_annotations;
    std::vector<std::string> arguments;
    BuildHandlerArgs(GetCrashReporterClient(), &database_path, &metrics_path,
                     &url, &process_annotations, &arguments);

    base::FilePath exe_dir;
    base::FilePath handler_path;
    if (!GetHandlerPath(&exe_dir, &handler_path)) {
      return database_path;
    }

    if (crashpad::SetSanitizationInfo(GetCrashReporterClient(),
                                      &browser_sanitization_info_)) {
      arguments.push_back(base::StringPrintf("--sanitization-information=%p",
                                             &browser_sanitization_info_));
    }

#if defined(OS_ANDROID)
    if (!base::PathExists(handler_path)) {
      use_java_handler_ = true;
    }

    if (!dump_at_crash) {
      return database_path;
    }

    if (use_java_handler_) {
      std::vector<std::string> env;
      if (!BuildEnvironmentWithApk(&env)) {
        return database_path;
      }

      bool result = GetCrashpadClient().StartJavaHandlerAtCrash(
          kCrashpadJavaMain, &env, database_path, metrics_path, url,
          process_annotations, arguments);
      DCHECK(result);
      return database_path;
    }
#endif

    if (!SetLdLibraryPath(exe_dir)) {
      return database_path;
    }

    bool result = GetCrashpadClient().StartHandlerAtCrash(
        handler_path, database_path, metrics_path, url, process_annotations,
        arguments);
    DCHECK(result);
    return database_path;
  }

Project: Chrome

base::FilePath PlatformCrashpadInitialization(
    bool initial_client,
    bool browser_process,
    bool embedded_handler,
    const std::string& user_data_dir,
    const base::FilePath& exe_path,
    const std::vector<std::string>& initial_arguments) {
  DCHECK_EQ(initial_client, browser_process);
  DCHECK(initial_arguments.empty());

  DCHECK(!embedded_handler);
  DCHECK(exe_path.empty());

  g_is_browser = browser_process;

  bool dump_at_crash = true;
#if defined(OS_ANDROID)
  base::android::SetJavaExceptionCallback(SetJavaExceptionInfo);

  unsigned int dump_percentage =
      GetCrashReporterClient()->GetCrashDumpPercentageForWebView();
  if (dump_percentage < 100 && rand() % 100 >= dump_percentage) {
    dump_at_crash = false;
  }
#endif  // OS_ANDROID

  if (browser_process) {
    HandlerStarter* starter = HandlerStarter::Get();
    return starter->Initialize(dump_at_crash);
  }

  crashpad::SandboxedHandler* handler = crashpad::SandboxedHandler::Get();
  bool result = handler->Initialize(dump_at_crash);
  DCHECK(result);

  return base::FilePath();
}

Project: Chrome

void SetClientInformation(ExceptionInformation* exception,
                          SanitizationInformation* sanitization,
                          ClientInformation* info) {
  info->exception_information_address =
      FromPointerCast<decltype(info->exception_information_address)>(exception);

  info->sanitization_information_address =
      FromPointerCast<decltype(info->sanitization_information_address)>(
          sanitization);
}

Project: Chrome

void SetJavaExceptionInfo(const char* info_string) {
  static crashpad::StringAnnotation<5 * 4096> exception_info("exception_info");
  if (info_string) {
    exception_info.Set(info_string);
  } else {
    exception_info.Clear();
  }
}

Project: Chrome

bool SetLdLibraryPath(const base::FilePath& lib_path) {
#if defined(OS_ANDROID) && defined(COMPONENT_BUILD)
  std::string library_path(lib_path.value());

  static constexpr char kLibraryPathVar[] = "LD_LIBRARY_PATH";
  std::unique_ptr<base::Environment> env(base::Environment::Create());
  std::string old_path;
  if (env->GetVar(kLibraryPathVar, &old_path)) {
    library_path.push_back(':');
    library_path.append(old_path);
  }

  if (!env->SetVar(kLibraryPathVar, library_path)) {
    return false;
  }
#endif

  return true;
}

Project: Chrome

  bool StartHandlerForClient(CrashReporterClient* client, int fd) {
    base::FilePath database_path;
    base::FilePath metrics_path;
    std::string url;
    std::map<std::string, std::string> process_annotations;
    std::vector<std::string> arguments;
    BuildHandlerArgs(client, &database_path, &metrics_path, &url,
                     &process_annotations, &arguments);

#if defined(OS_ANDROID)
    std::string browser_ptype;
    if (GetCrashReporterClient()->GetBrowserProcessType(&browser_ptype)) {
      process_annotations["ptype"] = browser_ptype;
    }
#endif  // defined(OS_ANDROID)

    base::FilePath exe_dir;
    base::FilePath handler_path;
    if (!GetHandlerPath(&exe_dir, &handler_path)) {
      return false;
    }

#if defined(OS_ANDROID)
    if (use_java_handler_) {
      std::vector<std::string> env;
      if (!BuildEnvironmentWithApk(&env)) {
        return false;
      }

      bool result = GetCrashpadClient().StartJavaHandlerForClient(
          kCrashpadJavaMain, &env, database_path, metrics_path, url,
          process_annotations, arguments, fd);
      return result;
    }
#endif

    if (!SetLdLibraryPath(exe_dir)) {
      return false;
    }

    return GetCrashpadClient().StartHandlerForClient(
        handler_path, database_path, metrics_path, url, process_annotations,
        arguments, fd);
  }

Project: Chrome

bool StartHandlerForClient(int fd) {
  return HandlerStarter::Get()->StartHandlerForClient(GetCrashReporterClient(),
                                                      fd);
}