chromium/chromeos/ash/services/ime/ime_sandbox_hook.cc

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

#include "chromeos/ash/services/ime/ime_sandbox_hook.h"

#include <dlfcn.h>

#include <vector>

#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "chromeos/ash/services/ime/constants.h"
#include "chromeos/ash/services/ime/ime_shared_library_wrapper.h"
#include "sandbox/linux/syscall_broker/broker_command.h"
#include "sandbox/linux/syscall_broker/broker_file_permission.h"

using sandbox::syscall_broker::BrokerFilePermission;
using sandbox::syscall_broker::MakeBrokerCommandSet;

namespace ash {
namespace ime {

namespace {
void AddBundleFolder(std::vector<BrokerFilePermission>* permissions) {
  base::FilePath bundle_dir =
      base::FilePath(kBundledInputMethodsDirPath).AsEndingWithSeparator();
  permissions->push_back(
      BrokerFilePermission::ReadOnlyRecursive(bundle_dir.value()));
}

void AddUserDataFolder(std::vector<BrokerFilePermission>* permissions) {
  // When failed to access user profile folder, decoder still can work, but
  // user dictionary can not be saved.
  base::FilePath user_path =
      base::FilePath(kUserInputMethodsDirPath).AsEndingWithSeparator();
  bool success = base::CreateDirectory(user_path);
  if (!success) {
    LOG(WARNING) << "Unable to create IME folder under user profile folder";
    return;
  }
  // Push this path, otherwise process will crash directly when IME decoder
  // tries to access this folder.
  permissions->push_back(
      BrokerFilePermission::ReadWriteCreateRecursive(user_path.value()));
}

std::vector<BrokerFilePermission> GetImeFilePermissions() {
  // These 2 paths are needed before creating IME service.
  std::vector<BrokerFilePermission> permissions{
      BrokerFilePermission::ReadOnly("/dev/urandom"),
      BrokerFilePermission::ReadOnly("/sys/devices/system/cpu")};

  AddBundleFolder(&permissions);
  AddUserDataFolder(&permissions);
  return permissions;
}

}  // namespace

bool ImePreSandboxHook(sandbox::policy::SandboxLinux::Options options) {
  auto* instance = sandbox::policy::SandboxLinux::GetInstance();
  instance->StartBrokerProcess(MakeBrokerCommandSet({
                                   sandbox::syscall_broker::COMMAND_ACCESS,
                                   sandbox::syscall_broker::COMMAND_OPEN,
                                   sandbox::syscall_broker::COMMAND_MKDIR,
                                   sandbox::syscall_broker::COMMAND_STAT,
                                   sandbox::syscall_broker::COMMAND_STAT64,
                                   sandbox::syscall_broker::COMMAND_RENAME,
                                   sandbox::syscall_broker::COMMAND_UNLINK,
                               }),
                               GetImeFilePermissions(), options);

  // Try to load IME decoder shared library.
  // TODO(crbug.com/40185212): This is not ideal, as it means rule-based
  // input methods will unnecessarily load the IME decoder shared library.
  // Either remove this line, or use a separate sandbox for rule-based.
  ImeSharedLibraryWrapperImpl::GetInstance()->MaybeLoadThenReturnEntryPoints();
  instance->EngageNamespaceSandboxIfPossible();
  return true;
}

}  // namespace ime
}  // namespace ash