From 084c4704b830e69937f893f7ec9fb964e8dcd83c Mon Sep 17 00:00:00 2001 From: "shravanrn@gmail.com" Date: Wed, 10 Nov 2021 05:21:55 +0000 Subject: [PATCH] Bug 1740399 - Ensure hunspell fails gracefully on rlbox sandbox OOM r=bholley Differential Revision: https://phabricator.services.mozilla.com/D130827 --- .../hunspell/glue/RLBoxHunspell.cpp | 95 +++++++++++-------- .../spellcheck/hunspell/glue/RLBoxHunspell.h | 17 +++- .../spellcheck/hunspell/glue/mozHunspell.cpp | 2 +- .../hunspell/glue/mozHunspellRLBoxHost.h | 4 +- 4 files changed, 71 insertions(+), 47 deletions(-) diff --git a/extensions/spellcheck/hunspell/glue/RLBoxHunspell.cpp b/extensions/spellcheck/hunspell/glue/RLBoxHunspell.cpp index a6f4fd50177c..9aa7c893a60d 100644 --- a/extensions/spellcheck/hunspell/glue/RLBoxHunspell.cpp +++ b/extensions/spellcheck/hunspell/glue/RLBoxHunspell.cpp @@ -37,11 +37,14 @@ static tainted_hunspell 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 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 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 t_affpath = allocStrInSandbox(mSandbox, affpath); + tainted_hunspell t_affpath = allocStrInSandbox(*mSandbox, affpath); MOZ_RELEASE_ASSERT(t_affpath); - tainted_hunspell t_dpath = allocStrInSandbox(mSandbox, dpath); + tainted_hunspell 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(t_affpath), rlbox::sandbox_const_cast(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 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 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 t_word = allocStrInSandbox(mSandbox, stdWord); + tainted_hunspell 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(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 RLBoxHunspell::suggest(const std::string& stdWord) { MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); // Copy word into the sandbox - tainted_hunspell t_word = allocStrInSandbox(mSandbox, stdWord); + tainted_hunspell t_word = allocStrInSandbox(*mSandbox, stdWord); if (!t_word) { return {}; } // Allocate suggestion list in the sandbox - tainted_hunspell t_slst = mSandbox.malloc_in_sandbox(); + tainted_hunspell t_slst = mSandbox->malloc_in_sandbox(); 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 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(t_word)) .copy_and_verify([](int nr) { @@ -220,15 +231,15 @@ std::vector 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; } diff --git a/extensions/spellcheck/hunspell/glue/RLBoxHunspell.h b/extensions/spellcheck/hunspell/glue/RLBoxHunspell.h index e1ec94fe166e..3d5be203eb02 100644 --- a/extensions/spellcheck/hunspell/glue/RLBoxHunspell.h +++ b/extensions/spellcheck/hunspell/glue/RLBoxHunspell.h @@ -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 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 aSandbox, + const nsAutoCString& affpath, const nsAutoCString& dpath); + + mozilla::UniquePtr mSandbox; sandbox_callback_hunspell mCreateFilemgr; sandbox_callback_hunspell mGetLine; sandbox_callback_hunspell mGetLineNum; diff --git a/extensions/spellcheck/hunspell/glue/mozHunspell.cpp b/extensions/spellcheck/hunspell/glue/mozHunspell.cpp index 2a2e1ac27bc3..e87da74534d7 100644 --- a/extensions/spellcheck/hunspell/glue/mozHunspell.cpp +++ b/extensions/spellcheck/hunspell/glue/mozHunspell.cpp @@ -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 = diff --git a/extensions/spellcheck/hunspell/glue/mozHunspellRLBoxHost.h b/extensions/spellcheck/hunspell/glue/mozHunspellRLBoxHost.h index ca8b5568a678..dfee0e02cc01 100644 --- a/extensions/spellcheck/hunspell/glue/mozHunspellRLBoxHost.h +++ b/extensions/spellcheck/hunspell/glue/mozHunspellRLBoxHost.h @@ -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. */