Bug 1740399 - Ensure hunspell fails gracefully on rlbox sandbox OOM r=bholley

Differential Revision: https://phabricator.services.mozilla.com/D130827
This commit is contained in:
shravanrn@gmail.com 2021-11-10 05:21:55 +00:00
Родитель dc8d909659
Коммит 084c4704b8
4 изменённых файлов: 71 добавлений и 47 удалений

Просмотреть файл

@ -37,11 +37,14 @@ static tainted_hunspell<char*> allocStrInSandbox(
return t_str;
}
RLBoxHunspell::RLBoxHunspell(const nsAutoCString& affpath,
const nsAutoCString& dpath)
: mHandle(nullptr) {
/* static */
RLBoxHunspell* RLBoxHunspell::Create(const nsAutoCString& affpath,
const nsAutoCString& dpath) {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
mozilla::UniquePtr<rlbox_sandbox_hunspell, RLBoxDeleter> sandbox(
new rlbox_sandbox_hunspell());
#if defined(MOZ_WASM_SANDBOXING_HUNSPELL) && !defined(HAVE_64BIT_BUILD)
// By default, the rlbox sandbox size is smaller on 32-bit builds than the max
// 4GB We may need to ask for a larger sandbox size for hunspell to spellcheck
@ -65,16 +68,20 @@ RLBoxHunspell::RLBoxHunspell(const nsAutoCString& affpath,
// If we expect a higher memory usage, override the defaults
// else stick with the defaults for the sandbox
if (expectedMaxMemory > defaultMaxSizeForSandbox) {
mSandbox.create_sandbox(true /* abort on creation failure */,
expectedMaxMemory);
} else {
mSandbox.create_sandbox();
}
const uint64_t selectedMaxMemory =
std::max(expectedMaxMemory, defaultMaxSizeForSandbox);
bool success = sandbox->create_sandbox(/* shouldAbortOnFailure = */ false,
selectedMaxMemory);
#elif defined(MOZ_WASM_SANDBOXING_HUNSPELL)
bool success = sandbox->create_sandbox(/* shouldAbortOnFailure = */ false);
#else
mSandbox.create_sandbox();
sandbox->create_sandbox();
const bool success = true;
#endif
NS_ENSURE_TRUE(success, nullptr);
// Add the aff and dict files to allow list
if (!affpath.IsEmpty()) {
mozHunspellCallbacks::AllowFile(affpath);
@ -83,46 +90,53 @@ RLBoxHunspell::RLBoxHunspell(const nsAutoCString& affpath,
mozHunspellCallbacks::AllowFile(dpath);
}
return new RLBoxHunspell(std::move(sandbox), affpath, dpath);
}
RLBoxHunspell::RLBoxHunspell(
mozilla::UniquePtr<rlbox_sandbox_hunspell, RLBoxDeleter> aSandbox,
const nsAutoCString& affpath, const nsAutoCString& dpath)
: mSandbox(std::move(aSandbox)), mHandle(nullptr) {
// Register callbacks
mCreateFilemgr =
mSandbox.register_callback(mozHunspellCallbacks::CreateFilemgr);
mGetLine = mSandbox.register_callback(mozHunspellCallbacks::GetLine);
mGetLineNum = mSandbox.register_callback(mozHunspellCallbacks::GetLineNum);
mSandbox->register_callback(mozHunspellCallbacks::CreateFilemgr);
mGetLine = mSandbox->register_callback(mozHunspellCallbacks::GetLine);
mGetLineNum = mSandbox->register_callback(mozHunspellCallbacks::GetLineNum);
mDestructFilemgr =
mSandbox.register_callback(mozHunspellCallbacks::DestructFilemgr);
mSandbox->register_callback(mozHunspellCallbacks::DestructFilemgr);
mHunspellToUpperCase =
mSandbox.register_callback(mozHunspellCallbacks::ToUpperCase);
mSandbox->register_callback(mozHunspellCallbacks::ToUpperCase);
mHunspellToLowerCase =
mSandbox.register_callback(mozHunspellCallbacks::ToLowerCase);
mSandbox->register_callback(mozHunspellCallbacks::ToLowerCase);
mHunspellGetCurrentCS =
mSandbox.register_callback(mozHunspellCallbacks::GetCurrentCS);
mSandbox->register_callback(mozHunspellCallbacks::GetCurrentCS);
mSandbox.invoke_sandbox_function(RegisterHunspellCallbacks, mCreateFilemgr,
mGetLine, mGetLineNum, mDestructFilemgr,
mHunspellToUpperCase, mHunspellToLowerCase,
mHunspellGetCurrentCS);
mSandbox->invoke_sandbox_function(RegisterHunspellCallbacks, mCreateFilemgr,
mGetLine, mGetLineNum, mDestructFilemgr,
mHunspellToUpperCase, mHunspellToLowerCase,
mHunspellGetCurrentCS);
// Copy the affpath and dpath into the sandbox
// These allocations should definitely succeed as these are first allocations
// inside the sandbox.
tainted_hunspell<char*> t_affpath = allocStrInSandbox(mSandbox, affpath);
tainted_hunspell<char*> t_affpath = allocStrInSandbox(*mSandbox, affpath);
MOZ_RELEASE_ASSERT(t_affpath);
tainted_hunspell<char*> t_dpath = allocStrInSandbox(mSandbox, dpath);
tainted_hunspell<char*> t_dpath = allocStrInSandbox(*mSandbox, dpath);
MOZ_RELEASE_ASSERT(t_dpath);
// Create handle
mHandle = mSandbox.invoke_sandbox_function(
mHandle = mSandbox->invoke_sandbox_function(
Hunspell_create, rlbox::sandbox_const_cast<const char*>(t_affpath),
rlbox::sandbox_const_cast<const char*>(t_dpath));
MOZ_RELEASE_ASSERT(mHandle);
mSandbox.free_in_sandbox(t_dpath);
mSandbox.free_in_sandbox(t_affpath);
mSandbox->free_in_sandbox(t_dpath);
mSandbox->free_in_sandbox(t_affpath);
// Get dictionary encoding
tainted_hunspell<char*> t_enc =
mSandbox.invoke_sandbox_function(Hunspell_get_dic_encoding, mHandle);
mSandbox->invoke_sandbox_function(Hunspell_get_dic_encoding, mHandle);
t_enc.copy_and_verify_string([&](std::unique_ptr<char[]> enc) {
size_t len = std::strlen(enc.get());
mDicEncoding = std::string(enc.get(), len);
@ -132,7 +146,7 @@ RLBoxHunspell::RLBoxHunspell(const nsAutoCString& affpath,
RLBoxHunspell::~RLBoxHunspell() {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
// Call hunspell's destroy which frees mHandle
mSandbox.invoke_sandbox_function(Hunspell_destroy, mHandle);
mSandbox->invoke_sandbox_function(Hunspell_destroy, mHandle);
mHandle = nullptr;
// Unregister callbacks
@ -146,15 +160,12 @@ RLBoxHunspell::~RLBoxHunspell() {
// Clear any callback data and allow list
mozHunspellCallbacks::Clear();
// Dstroy sandbox
mSandbox.destroy_sandbox();
}
int RLBoxHunspell::spell(const std::string& stdWord) {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
// Copy word into the sandbox
tainted_hunspell<char*> t_word = allocStrInSandbox(mSandbox, stdWord);
tainted_hunspell<char*> t_word = allocStrInSandbox(*mSandbox, stdWord);
if (!t_word) {
// Ran out of memory in the hunspell sandbox
// Fail gracefully assuming the word is spelt correctly
@ -164,11 +175,11 @@ int RLBoxHunspell::spell(const std::string& stdWord) {
// Check word
int good = mSandbox
.invoke_sandbox_function(
->invoke_sandbox_function(
Hunspell_spell, mHandle,
rlbox::sandbox_const_cast<const char*>(t_word))
.copy_and_verify([](int good) { return good; });
mSandbox.free_in_sandbox(t_word);
mSandbox->free_in_sandbox(t_word);
return good;
}
@ -181,16 +192,16 @@ const std::string& RLBoxHunspell::get_dict_encoding() const {
std::vector<std::string> RLBoxHunspell::suggest(const std::string& stdWord) {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
// Copy word into the sandbox
tainted_hunspell<char*> t_word = allocStrInSandbox(mSandbox, stdWord);
tainted_hunspell<char*> t_word = allocStrInSandbox(*mSandbox, stdWord);
if (!t_word) {
return {};
}
// Allocate suggestion list in the sandbox
tainted_hunspell<char***> t_slst = mSandbox.malloc_in_sandbox<char**>();
tainted_hunspell<char***> t_slst = mSandbox->malloc_in_sandbox<char**>();
if (!t_slst) {
// Free the earlier allocation
mSandbox.free_in_sandbox(t_word);
mSandbox->free_in_sandbox(t_word);
return {};
}
@ -198,7 +209,7 @@ std::vector<std::string> RLBoxHunspell::suggest(const std::string& stdWord) {
// Get suggestions
int nr = mSandbox
.invoke_sandbox_function(
->invoke_sandbox_function(
Hunspell_suggest, mHandle, t_slst,
rlbox::sandbox_const_cast<const char*>(t_word))
.copy_and_verify([](int nr) {
@ -220,15 +231,15 @@ std::vector<std::string> RLBoxHunspell::suggest(const std::string& stdWord) {
t_sug.copy_and_verify_string(
[&](std::string sug) { suggestions.push_back(std::move(sug)); });
// free the suggestion string allocated by the sandboxed hunspell
mSandbox.free_in_sandbox(t_sug);
mSandbox->free_in_sandbox(t_sug);
}
}
// free the suggestion list allocated by the sandboxed hunspell
mSandbox.free_in_sandbox(t_slst_ref);
mSandbox->free_in_sandbox(t_slst_ref);
}
mSandbox.free_in_sandbox(t_word);
mSandbox.free_in_sandbox(t_slst);
mSandbox->free_in_sandbox(t_word);
mSandbox->free_in_sandbox(t_slst);
return suggestions;
}

Просмотреть файл

@ -29,7 +29,9 @@
class RLBoxHunspell {
public:
RLBoxHunspell(const nsAutoCString& affpath, const nsAutoCString& dpath);
static RLBoxHunspell* Create(const nsAutoCString& affpath,
const nsAutoCString& dpath);
~RLBoxHunspell();
int spell(const std::string& stdWord);
@ -38,7 +40,18 @@ class RLBoxHunspell {
std::vector<std::string> suggest(const std::string& word);
private:
rlbox_sandbox_hunspell mSandbox;
struct RLBoxDeleter {
void operator()(rlbox_sandbox_hunspell* sandbox) {
sandbox->destroy_sandbox();
delete sandbox;
}
};
RLBoxHunspell(
mozilla::UniquePtr<rlbox_sandbox_hunspell, RLBoxDeleter> aSandbox,
const nsAutoCString& affpath, const nsAutoCString& dpath);
mozilla::UniquePtr<rlbox_sandbox_hunspell, RLBoxDeleter> mSandbox;
sandbox_callback_hunspell<hunspell_create_filemgr_t*> mCreateFilemgr;
sandbox_callback_hunspell<hunspell_get_line_t*> mGetLine;
sandbox_callback_hunspell<hunspell_get_line_num_t*> mGetLineNum;

Просмотреть файл

@ -188,7 +188,7 @@ mozHunspell::SetDictionary(const nsACString& aDictionary) {
mDictionary = dict;
mAffixFileName = affFileName;
mHunspell = new RLBoxHunspell(affFileName, dictFileName);
mHunspell = RLBoxHunspell::Create(affFileName, dictFileName);
if (!mHunspell) return NS_ERROR_OUT_OF_MEMORY;
auto encoding =

Просмотреть файл

@ -78,8 +78,8 @@ class mozHunspellCallbacks {
* Add filename to allow list.
*/
static void AllowFile(const nsCString& aFilename);
friend RLBoxHunspell::RLBoxHunspell(const nsAutoCString& affpath,
const nsAutoCString& dpath);
friend RLBoxHunspell* RLBoxHunspell::Create(const nsAutoCString& affpath,
const nsAutoCString& dpath);
/**
* Clear allow list and map of hunspell file managers.
*/