blob: b75a9e85140506af48790e11bf072ab8a655ac70 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/services/ime/ime_sandbox_hook.h"
#include <vector>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "build/buildflag.h"
#include "chromeos/services/ime/constants.h"
#include "chromeos/services/ime/public/cpp/buildflags.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 chromeos {
namespace ime {
namespace {
// Whether IME instance shares a same language data path with each other.
inline constexpr bool CrosImeSharedDataEnabled() {
#if BUILDFLAG(ENABLE_CROS_IME_SHARED_DATA)
return true;
#else
return false;
#endif
}
void AddSharedLibraryAndDepsPath(
std::vector<BrokerFilePermission>* permissions) {
// Where IME decoder shared library and its dependencies will live.
static const char* kReadOnlyLibDirs[] =
#if defined(__x86_64__) || defined(__aarch64__)
{"/usr/lib64", "/lib64"};
#else
{"/usr/lib", "/lib"};
#endif
for (const char* dir : kReadOnlyLibDirs) {
std::string path(dir);
permissions->push_back(
BrokerFilePermission::StatOnlyWithIntermediateDirs(path));
permissions->push_back(BrokerFilePermission::ReadOnlyRecursive(path + "/"));
}
}
void AddBundleFolder(std::vector<BrokerFilePermission>* permissions) {
base::FilePath bundle_dir =
base::FilePath(kBundledInputMethodsDirPath).AsEndingWithSeparator();
permissions->push_back(
BrokerFilePermission::ReadOnlyRecursive(bundle_dir.value()));
}
void AddSharedDataFolderIfEnabled(
std::vector<BrokerFilePermission>* permissions) {
if (!CrosImeSharedDataEnabled())
return;
// Without access to shared home folder, IME servcie will download all
// missing dictionaries to `kUserInputMethodsDirPath` of the current user.
base::FilePath shared_path =
base::FilePath(kSharedInputMethodsDirPath).AsEndingWithSeparator();
if (base::CreateDirectory(shared_path)) {
permissions->push_back(
BrokerFilePermission::ReadWriteCreateRecursive(shared_path.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")};
AddSharedLibraryAndDepsPath(&permissions);
AddBundleFolder(&permissions);
AddUserDataFolder(&permissions);
AddSharedDataFolderIfEnabled(&permissions);
return permissions;
}
} // namespace
bool ImePreSandboxHook(service_manager::SandboxLinux::Options options) {
auto* instance = service_manager::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(),
service_manager::SandboxLinux::PreSandboxHook(),
options);
instance->EngageNamespaceSandboxIfPossible();
return true;
}
} // namespace ime
} // namespace chromeos