910e62b5创建于 1月15日历史提交
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "services/test/echo/echo_service.h"

#include <optional>
#include <string>

#include "base/check.h"
#include "base/debug/stack_trace.h"
#include "base/immediate_crash.h"
#include "base/memory/shared_memory_mapping.h"
#include "build/build_config.h"
#include "build/chromecast_buildflags.h"
#include "components/os_crypt/sync/os_crypt.h"

#if BUILDFLAG(IS_WIN)
#include <windows.h>

#include <winevt.h>

#include "base/native_library.h"
#endif

#include <string>

namespace echo {

EchoService::EchoService(mojo::PendingReceiver<mojom::EchoService> receiver)
    : receiver_(this, std::move(receiver)) {}

EchoService::~EchoService() = default;

void EchoService::EchoString(const std::string& input,
                             EchoStringCallback callback) {
  std::move(callback).Run(input);
}

void EchoService::EchoStringToSharedMemory(
    const std::string& input,
    base::UnsafeSharedMemoryRegion region) {
  base::WritableSharedMemoryMapping mapping = region.Map();
  base::span(mapping).copy_prefix_from(base::as_byte_span(input));
}

void EchoService::Quit() {
  receiver_.reset();
}

void EchoService::Crash() {
#if BUILDFLAG(IS_WIN)
  // Avoid symbolizing a stack we won't use.
  base::debug::DisableInProcessStackDumpingForTesting();
#endif
  base::ImmediateCrash();
}

#if BUILDFLAG(IS_WIN)
void EchoService::DelayLoad() {
  // This causes wevtapi.dll to be delay loaded. It should not work from inside
  // a sandboxed process.
  EVT_HANDLE handle = ::EvtCreateRenderContext(0, nullptr, 0);
  ::EvtClose(handle);
}

void EchoService::LoadNativeLibrary(const ::base::FilePath& library,
                                    bool call_sec32_delayload,
                                    LoadNativeLibraryCallback callback) {
  // This attempts to load a library inside the sandbox - it should fail unless
  // the library was in `ServiceProcessHostOptions::WithPreloadedLibraries()`.
  base::NativeLibraryLoadError error;
  // We leak the module as preloading already leaked it.
  HMODULE hmod = base::LoadNativeLibrary(library, &error);
  if (!hmod) {
    std::move(callback).Run(LoadStatus::kFailedLoadLibrary, error.code);
    return;
  }

  // Calls an exported function that calls a delayloaded function that should
  // be loaded in the utility (as secur32.dll is imported by chrome.dll).
  if (call_sec32_delayload) {
    BOOL(WINAPI * fn)() = nullptr;
    fn = reinterpret_cast<decltype(fn)>(
        GetProcAddress(hmod, "FnCallsDelayloadFn"));
    if (!fn) {
      std::move(callback).Run(LoadStatus::kFailedGetProcAddress,
                              GetLastError());
      return;
    }
    BOOL ret = fn();
    if (!ret) {
      std::move(callback).Run(LoadStatus::kFailedCallingDelayLoad,
                              GetLastError());
      return;
    }
  }
  std::move(callback).Run(LoadStatus::kSuccess, ERROR_SUCCESS);
}
#endif  // BUILDFLAG(IS_WIN)

void EchoService::DecryptEncrypt(os_crypt_async::Encryptor encryptor,
                                 const std::vector<uint8_t>& input,
                                 DecryptEncryptCallback callback) {
// OSCrypt sync services are not available because they are not initialized in
// a child process, except on POSIX platforms where encryption is always
// available.
#if !(BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE) &&         \
          !(BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CASTOS)) || \
      BUILDFLAG(IS_FUCHSIA))
  CHECK(!OSCrypt::IsEncryptionAvailable());
#else
  CHECK(OSCrypt::IsEncryptionAvailable());
#endif  // !(BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE) &&
        // !(BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CASTOS)) ||
        // BUILDFLAG(IS_FUCHSIA))

  CHECK(encryptor.IsDecryptionAvailable());
  // Take the input, which was encrypted in the caller process, and decrypt it.
  const auto plaintext = encryptor.DecryptData(input);
  if (!plaintext.has_value()) {
    std::move(callback).Run(std::nullopt);
    return;
  }

  CHECK(encryptor.IsEncryptionAvailable());
  // Encrypt it again using the key inside this process, and return the
  // encrypted ciphertext to the caller.
  std::move(callback).Run(encryptor.EncryptString(*plaintext));
}

}  // namespace echo