chromium/remoting/base/breakpad_server.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <memory>
#include <string>
#include <utility>

#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "base/win/access_control_list.h"
#include "base/win/security_descriptor.h"
#include "base/win/sid.h"
#include "remoting/base/breakpad.h"
#include "remoting/base/breakpad_utils.h"
#include "remoting/base/logging.h"
#include "remoting/base/version.h"
#include "third_party/breakpad/breakpad/src/client/windows/crash_generation/crash_generation_server.h"

namespace remoting {

namespace {

using base::win::SecurityDescriptor;
using base::win::Sid;
using base::win::SecurityAccessMode::kGrant;
using base::win::WellKnownSid::kLocalSystem;

// Passed as a flag in the named pipe DACL entry to indicate no inheritance.
constexpr bool kNoInheritance = false;

class BreakpadServer {
 public:
  BreakpadServer();

  BreakpadServer(const BreakpadServer&) = delete;
  BreakpadServer& operator=(const BreakpadServer&) = delete;

  ~BreakpadServer();

  static BreakpadServer& GetInstance();

  void set_client_connected_time(base::Time client_connected_time) {
    client_connected_time_ = client_connected_time;
  }
  base::Time get_client_connected_time() { return client_connected_time_; }

 private:
  base::Time client_connected_time_;
  std::unique_ptr<google_breakpad::CrashGenerationServer> crash_server_;
};

void OnClientConnectedCallback(void* context,
                               const google_breakpad::ClientInfo* client_info) {
  HOST_LOG << "OOP Crash client connected";
  BreakpadServer::GetInstance().set_client_connected_time(
      base::Time::NowFromSystemTime());
}

void OnClientDumpRequestCallback(void* context,
                                 const google_breakpad::ClientInfo* client_info,
                                 const std::wstring* file_path) {
  if (!file_path) {
    LOG(ERROR) << "OnClientDumpRequestCallback called with invalid file_path";
    return;
  }
  base::FilePath dump_file(*file_path);
  if (!GetMinidumpDirectoryPath().IsParent(dump_file)) {
    LOG(ERROR) << "Minidump written to an unexpected location: " << dump_file;
    return;
  }

  base::Value::Dict metadata;
  // Use the crash server version since we update all host components in the
  // same package and we've seen problems trying to use the metadata provided
  // by the client process, see crbug.com/350725178.
  metadata.Set(kBreakpadProductVersionKey, REMOTING_VERSION_STRING);

  // We only have one OOP client so we can use the value of the 'last connected'
  // client to determine an approximate uptime for that process.
  auto process_start_time =
      BreakpadServer::GetInstance().get_client_connected_time();
  auto process_uptime = base::Time::NowFromSystemTime() - process_start_time;
  metadata.Set(kBreakpadProcessUptimeKey,
               base::NumberToString(process_uptime.InMilliseconds()));

  WriteMetadataForMinidump(dump_file, std::move(metadata));
}

BreakpadServer::BreakpadServer() {
  base::win::SecurityDescriptor sd;
  sd.set_owner(Sid(kLocalSystem));
  sd.set_group(Sid(kLocalSystem));

  // Configure the named pipe to prevent non-SYSTEM access unless a handle is
  // created by the server and provided over IPC or STDIO.
  if (!sd.SetDaclEntry(kLocalSystem, kGrant, FILE_ALL_ACCESS, kNoInheritance)) {
    LOG(ERROR) << "Failed to set named pipe security attributes, skipping "
               << "out-of-process crash handler initialization.";
    return;
  }

  SECURITY_DESCRIPTOR security_descriptor;
  sd.ToAbsolute(security_descriptor);

  SECURITY_ATTRIBUTES security_attributes = {0};
  security_attributes.nLength = sizeof(security_attributes);
  security_attributes.lpSecurityDescriptor = &security_descriptor;
  security_attributes.bInheritHandle = false;

  crash_server_ = std::make_unique<google_breakpad::CrashGenerationServer>(
      kCrashServerPipeName, &security_attributes,
      /*connect_callback=*/OnClientConnectedCallback,
      /*connect_context=*/nullptr,
      /*dump_callback=*/OnClientDumpRequestCallback,
      /*dump_context=*/nullptr,
      /*exit_callback=*/nullptr,
      /*exit_context=*/nullptr,
      /*upload_request_callback=*/nullptr,
      /*upload_context=*/nullptr,
      /*generate_dumps=*/true, &GetMinidumpDirectoryPath().value());
  crash_server_->Start();
}

BreakpadServer::~BreakpadServer() = default;

// static
BreakpadServer& BreakpadServer::GetInstance() {
  static base::NoDestructor<BreakpadServer> instance;
  return *instance;
}

}  // namespace

void InitializeOopCrashServer() {
  // Touch the object to make sure it is initialized.
  BreakpadServer::GetInstance();
}

}  // namespace remoting