Commit 80c7f3d2 authored by Leo Zhang's avatar Leo Zhang Committed by Commit Bot

Add singleton ImeDecoder.

ImeDecoder is used for loading decoder shared library and all
required function pointers before sandbox is engaged. After sandboxing
DecoderEngine will take advantage of these preloaded functions to
decode inputs.

TEST=local betty VM.
BUG=b/161491092

Change-Id: I8ab77da32ad678a996f607be2b3840d7345be4b4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2486825
Commit-Queue: Leo Zhang <googleo@chromium.org>
Reviewed-by: default avatarMatthew Denton <mpdenton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#819214}
parent a505bbf9
...@@ -17,6 +17,21 @@ component("constants") { ...@@ -17,6 +17,21 @@ component("constants") {
] ]
} }
source_set("decoder") {
sources = [
"ime_decoder.cc",
"ime_decoder.h",
]
deps = [
":constants",
"//base",
"//chromeos/constants",
"//chromeos/services/ime/public/cpp:buildflags",
"//chromeos/services/ime/public/cpp/shared_lib:interfaces",
]
}
source_set("lib") { source_set("lib") {
sources = [ sources = [
"decoder/decoder_engine.cc", "decoder/decoder_engine.cc",
...@@ -33,6 +48,7 @@ source_set("lib") { ...@@ -33,6 +48,7 @@ source_set("lib") {
deps = [ deps = [
":constants", ":constants",
":decoder",
"//base", "//base",
"//chromeos/constants", "//chromeos/constants",
"//chromeos/services/ime/public/cpp:buildflags", "//chromeos/services/ime/public/cpp:buildflags",
...@@ -51,6 +67,7 @@ source_set("sandbox_hook") { ...@@ -51,6 +67,7 @@ source_set("sandbox_hook") {
deps = [ deps = [
":constants", ":constants",
":decoder",
"//base", "//base",
"//chromeos/services/ime/public/cpp:buildflags", "//chromeos/services/ime/public/cpp:buildflags",
"//sandbox/linux:sandbox_services", "//sandbox/linux:sandbox_services",
......
...@@ -27,18 +27,6 @@ const base::FilePath::CharType kSharedInputMethodsDirPath[] = ...@@ -27,18 +27,6 @@ const base::FilePath::CharType kSharedInputMethodsDirPath[] =
FILE_PATH_LITERAL("/home/chronos/" IME_DIR_STRING); FILE_PATH_LITERAL("/home/chronos/" IME_DIR_STRING);
const base::FilePath::CharType kLanguageDataDirName[] = const base::FilePath::CharType kLanguageDataDirName[] =
FILE_PATH_LITERAL("google"); FILE_PATH_LITERAL("google");
const char kCrosImeDecoderLib[] = "libimedecoder.so";
bool ImeDecoderInstalled() {
base::FilePath lib_path("/usr");
#if defined(__x86_64__) || defined(__aarch64__)
lib_path = lib_path.Append("lib64");
#else
lib_path = lib_path.Append("lib");
#endif
lib_path = lib_path.Append(kCrosImeDecoderLib);
return base::PathExists(lib_path);
}
#else #else
// IME service does not support third-party IME yet, so the paths below kind // IME service does not support third-party IME yet, so the paths below kind
// of act like a placeholder. In the future, put some well-designed paths here. // of act like a placeholder. In the future, put some well-designed paths here.
...@@ -50,12 +38,6 @@ const base::FilePath::CharType kSharedInputMethodsDirPath[] = ...@@ -50,12 +38,6 @@ const base::FilePath::CharType kSharedInputMethodsDirPath[] =
FILE_PATH_LITERAL("/tmp/" IME_DIR_STRING); FILE_PATH_LITERAL("/tmp/" IME_DIR_STRING);
const base::FilePath::CharType kLanguageDataDirName[] = const base::FilePath::CharType kLanguageDataDirName[] =
FILE_PATH_LITERAL("data"); FILE_PATH_LITERAL("data");
// IME service does not support third-party IME decoder yet.
const char kCrosImeDecoderLib[] = "";
bool ImeDecoderInstalled() {
return false;
}
#endif #endif
const char kGoogleKeyboardDownloadDomain[] = "dl.google.com"; const char kGoogleKeyboardDownloadDomain[] = "dl.google.com";
......
...@@ -44,13 +44,6 @@ extern const base::FilePath::CharType kLanguageDataDirName[]; ...@@ -44,13 +44,6 @@ extern const base::FilePath::CharType kLanguageDataDirName[];
// The domain of Google Keyboard language dictionary download URL. // The domain of Google Keyboard language dictionary download URL.
COMPONENT_EXPORT(CHROMEOS_IME_CONSTANTS) COMPONENT_EXPORT(CHROMEOS_IME_CONSTANTS)
extern const char kGoogleKeyboardDownloadDomain[]; extern const char kGoogleKeyboardDownloadDomain[];
// The name of ChromeOS IME decoder shared Library.
COMPONENT_EXPORT(CHROMEOS_IME_CONSTANTS)
extern const char kCrosImeDecoderLib[];
// Whether IME decoder is installed.
COMPONENT_EXPORT(CHROMEOS_IME_CONSTANTS) bool ImeDecoderInstalled();
} // namespace ime } // namespace ime
} // namespace chromeos } // namespace chromeos
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "chromeos/services/ime/constants.h" #include "chromeos/services/ime/constants.h"
#include "chromeos/services/ime/decoder/proto_conversion.h" #include "chromeos/services/ime/decoder/proto_conversion.h"
#include "chromeos/services/ime/ime_decoder.h"
#include "chromeos/services/ime/public/cpp/buildflags.h" #include "chromeos/services/ime/public/cpp/buildflags.h"
#include "chromeos/services/ime/public/proto/messages.pb.h" #include "chromeos/services/ime/public/proto/messages.pb.h"
...@@ -94,33 +95,15 @@ DecoderEngine::DecoderEngine(ImeCrosPlatform* platform) : platform_(platform) { ...@@ -94,33 +95,15 @@ DecoderEngine::DecoderEngine(ImeCrosPlatform* platform) : platform_(platform) {
DecoderEngine::~DecoderEngine() {} DecoderEngine::~DecoderEngine() {}
bool DecoderEngine::TryLoadDecoder() { bool DecoderEngine::TryLoadDecoder() {
if (!ImeDecoderInstalled()) {
LOG(WARNING) << "IME decoder shared library is not installed.";
return false;
}
if (engine_main_entry_) if (engine_main_entry_)
return true; return true;
// Load the decoder whose DSO has been preloaded before sandbox is engaged. auto* decoder = ImeDecoder::GetInstance();
base::FilePath lib_path(kCrosImeDecoderLib); if (decoder->GetStatus() == ImeDecoder::Status::kSuccess) {
library_ = base::ScopedNativeLibrary(lib_path); engine_main_entry_ = decoder->CreateMainEntry(platform_);
return true;
if (!library_.is_valid()) {
LOG(ERROR) << "Failed to load decoder shared library from: " << lib_path
<< ", error: " << library_.GetError()->ToString();
return false;
} }
return false;
// Prepare the decoder data directory before initialization.
base::FilePath data_dir(platform_->GetImeUserHomeDir());
base::CreateDirectory(data_dir.Append(kLanguageDataDirName));
ImeMainEntryCreateFn createMainEntryFn =
reinterpret_cast<ImeMainEntryCreateFn>(
library_.GetFunctionPointer(IME_MAIN_ENTRY_CREATE_FN_NAME));
engine_main_entry_ = createMainEntryFn(platform_);
return true;
} }
bool DecoderEngine::BindRequest( bool DecoderEngine::BindRequest(
......
// Copyright 2020 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_decoder.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "chromeos/services/ime/constants.h"
namespace chromeos {
namespace ime {
namespace {
const char kCrosImeDecoderLib[] = "libimedecoder.so";
// TODO(b/161491092): Add test image path based on value of
// "CHROMEOS_RELEASE_TRACK" from `base::SysInfo::GetLsbReleaseValue`.
// Returns ImeDecoderLib path based on the run time env.
base::FilePath GetImeDecoderLibPath() {
#if defined(__x86_64__) || defined(__aarch64__)
base::FilePath lib_path("/usr/lib64");
#else
base::FilePath lib_path("/usr/lib");
#endif
lib_path = lib_path.Append(kCrosImeDecoderLib);
return lib_path;
}
} // namespace
ImeDecoder::ImeDecoder() : status_(Status::kUninitialized) {
base::FilePath path = GetImeDecoderLibPath();
if (!base::PathExists(path)) {
LOG(WARNING) << "IME decoder shared library is not installed.";
status_ = Status::kNotInstalled;
return;
}
// Add dlopen flags (RTLD_LAZY | RTLD_NODELETE) later.
base::ScopedNativeLibrary library = base::ScopedNativeLibrary(path);
if (!library.is_valid()) {
LOG(ERROR) << "Failed to load decoder shared library from: " << path
<< ", error: " << library.GetError()->ToString();
status_ = Status::kLoadLibraryFailed;
return;
}
createMainEntry_ = reinterpret_cast<ImeMainEntryCreateFn>(
library.GetFunctionPointer(IME_MAIN_ENTRY_CREATE_FN_NAME));
if (!createMainEntry_) {
status_ = Status::kFunctionMissing;
return;
}
library_ = std::move(library);
status_ = Status::kSuccess;
}
ImeDecoder::~ImeDecoder() = default;
ImeDecoder* ImeDecoder::GetInstance() {
static base::NoDestructor<ImeDecoder> instance;
return instance.get();
}
ImeDecoder::Status ImeDecoder::GetStatus() const {
return status_;
}
ImeEngineMainEntry* ImeDecoder::CreateMainEntry(ImeCrosPlatform* platform) {
DCHECK(status_ == Status::kSuccess);
return createMainEntry_(platform);
}
} // namespace ime
} // namespace chromeos
// Copyright 2020 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.
#ifndef CHROMEOS_SERVICES_IME_IME_DECODER_H_
#define CHROMEOS_SERVICES_IME_IME_DECODER_H_
#include "chromeos/services/ime/public/cpp/shared_lib/interfaces.h"
#include "base/no_destructor.h"
#include "base/optional.h"
#include "base/scoped_native_library.h"
namespace chromeos {
namespace ime {
// A proxy class for the IME decoder.
// ImeDecoder is implemented as a singleton and is initialized before 'ime'
// sandbox is engaged.
class ImeDecoder {
public:
// Status of loading func from IME decoder DSO: either success or error type.
enum class Status {
kSuccess = 0,
kUninitialized = 1,
kNotInstalled = 2,
kLoadLibraryFailed = 3,
kFunctionMissing = 4,
};
// Gets the singleton ImeDecoder.
static ImeDecoder* GetInstance();
// Get status of the IME decoder library initialization.
// Return `Status::kSuccess` if the lib is successfully initialized.
Status GetStatus() const;
// Returns an instance of ImeEngineMainEntry from the IME shared library.
ImeEngineMainEntry* CreateMainEntry(ImeCrosPlatform* platform);
private:
friend class base::NoDestructor<ImeDecoder>;
// Initialize the Ime decoder library.
explicit ImeDecoder();
~ImeDecoder();
Status status_;
// Result of IME decoder DSO initialization.
base::Optional<base::ScopedNativeLibrary> library_;
ImeMainEntryCreateFn createMainEntry_;
DISALLOW_COPY_AND_ASSIGN(ImeDecoder);
};
} // namespace ime
} // namespace chromeos
#endif // CHROMEOS_SERVICES_IME_IME_DECODER_H_
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "build/buildflag.h" #include "build/buildflag.h"
#include "chromeos/services/ime/constants.h" #include "chromeos/services/ime/constants.h"
#include "chromeos/services/ime/ime_decoder.h"
#include "chromeos/services/ime/public/cpp/buildflags.h" #include "chromeos/services/ime/public/cpp/buildflags.h"
#include "sandbox/linux/syscall_broker/broker_command.h" #include "sandbox/linux/syscall_broker/broker_command.h"
#include "sandbox/linux/syscall_broker/broker_file_permission.h" #include "sandbox/linux/syscall_broker/broker_file_permission.h"
...@@ -32,16 +33,6 @@ inline constexpr bool CrosImeSharedDataEnabled() { ...@@ -32,16 +33,6 @@ inline constexpr bool CrosImeSharedDataEnabled() {
#endif #endif
} }
constexpr int dlopen_flag = RTLD_LAZY | RTLD_NODELETE;
void PreloadSharedLibrary() {
if (ImeDecoderInstalled()) {
if (!dlopen(kCrosImeDecoderLib, dlopen_flag))
LOG(ERROR) << "Unable to open " << kCrosImeDecoderLib << " : "
<< dlerror();
}
}
void AddBundleFolder(std::vector<BrokerFilePermission>* permissions) { void AddBundleFolder(std::vector<BrokerFilePermission>* permissions) {
base::FilePath bundle_dir = base::FilePath bundle_dir =
base::FilePath(kBundledInputMethodsDirPath).AsEndingWithSeparator(); base::FilePath(kBundledInputMethodsDirPath).AsEndingWithSeparator();
...@@ -86,7 +77,6 @@ std::vector<BrokerFilePermission> GetImeFilePermissions() { ...@@ -86,7 +77,6 @@ std::vector<BrokerFilePermission> GetImeFilePermissions() {
BrokerFilePermission::ReadOnly("/dev/urandom"), BrokerFilePermission::ReadOnly("/dev/urandom"),
BrokerFilePermission::ReadOnly("/sys/devices/system/cpu")}; BrokerFilePermission::ReadOnly("/sys/devices/system/cpu")};
PreloadSharedLibrary();
AddBundleFolder(&permissions); AddBundleFolder(&permissions);
AddUserDataFolder(&permissions); AddUserDataFolder(&permissions);
AddSharedDataFolderIfEnabled(&permissions); AddSharedDataFolderIfEnabled(&permissions);
...@@ -110,6 +100,8 @@ bool ImePreSandboxHook(sandbox::policy::SandboxLinux::Options options) { ...@@ -110,6 +100,8 @@ bool ImePreSandboxHook(sandbox::policy::SandboxLinux::Options options) {
sandbox::policy::SandboxLinux::PreSandboxHook(), sandbox::policy::SandboxLinux::PreSandboxHook(),
options); options);
// Try to load IME decoder shared library by creating its instance.
ImeDecoder::GetInstance();
instance->EngageNamespaceSandboxIfPossible(); instance->EngageNamespaceSandboxIfPossible();
return true; return true;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment