mozHunspellRLBoxHost.cpp (7261B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include <limits> 8 9 #include "mozHunspellRLBoxHost.h" 10 #include "mozilla/DebugOnly.h" 11 #include "mozilla/Try.h" 12 #include "nsContentUtils.h" 13 #include "nsILoadInfo.h" 14 #include "nsNetUtil.h" 15 #include "nsUnicharUtils.h" 16 17 #include "hunspell_csutil.hxx" 18 19 using namespace mozilla; 20 21 mozHunspellFileMgrHost::mozHunspellFileMgrHost(const nsCString& aFilename) { 22 nsCOMPtr<nsIChannel> channel; 23 DebugOnly<Result<Ok, nsresult>> result = Open(aFilename, channel, mStream); 24 NS_WARNING_ASSERTION(result.value.isOk(), "Failed to open Hunspell file"); 25 } 26 27 /* static */ 28 Result<Ok, nsresult> mozHunspellFileMgrHost::Open( 29 const nsCString& aPath, nsCOMPtr<nsIChannel>& aChannel, 30 nsCOMPtr<nsIInputStream>& aStream) { 31 nsCOMPtr<nsIURI> uri; 32 MOZ_TRY(NS_NewURI(getter_AddRefs(uri), aPath)); 33 34 MOZ_TRY(NS_NewChannel( 35 getter_AddRefs(aChannel), uri, nsContentUtils::GetSystemPrincipal(), 36 nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT, 37 nsIContentPolicy::TYPE_OTHER)); 38 39 MOZ_TRY(aChannel->Open(getter_AddRefs(aStream))); 40 return Ok(); 41 } 42 43 Result<Ok, nsresult> mozHunspellFileMgrHost::ReadLine(nsACString& aLine) { 44 if (!mStream) { 45 return Err(NS_ERROR_NOT_INITIALIZED); 46 } 47 48 bool ok; 49 MOZ_TRY(NS_ReadLine(mStream.get(), &mLineBuffer, aLine, &ok)); 50 if (!ok) { 51 mStream = nullptr; 52 } 53 54 mLineNum++; 55 return Ok(); 56 } 57 58 /* static */ 59 Result<int64_t, nsresult> mozHunspellFileMgrHost::GetSize( 60 const nsCString& aFilename) { 61 int64_t ret = -1; 62 63 nsCOMPtr<nsIChannel> channel; 64 nsCOMPtr<nsIInputStream> stream; 65 MOZ_TRY(Open(aFilename, channel, stream)); 66 67 channel->GetContentLength(&ret); 68 return ret; 69 } 70 71 bool mozHunspellFileMgrHost::GetLine(nsACString& aResult) { 72 return !ReadLine(aResult).isErr(); 73 } 74 75 /* static */ 76 uint32_t mozHunspellCallbacks::sCurrentFreshId = 0; 77 /* static */ 78 mozilla::StaticRWLock mozHunspellCallbacks::sFileMgrMapLock; 79 /* static */ 80 MOZ_RUNINIT std::map<uint32_t, std::unique_ptr<mozHunspellFileMgrHost>> 81 mozHunspellCallbacks::sFileMgrMap; 82 /* static */ 83 MOZ_RUNINIT std::set<nsCString> mozHunspellCallbacks::sFileMgrAllowList; 84 85 /* static */ 86 void mozHunspellCallbacks::AllowFile(const nsCString& aFilename) { 87 mozilla::StaticAutoWriteLock lock(sFileMgrMapLock); 88 sFileMgrAllowList.insert(aFilename); 89 } 90 91 /* static */ 92 void mozHunspellCallbacks::Clear() { 93 mozilla::StaticAutoWriteLock lock(sFileMgrMapLock); 94 sCurrentFreshId = 0; 95 sFileMgrMap.clear(); 96 sFileMgrAllowList.clear(); 97 } 98 99 /* static */ 100 tainted_hunspell<uint32_t> mozHunspellCallbacks::CreateFilemgr( 101 rlbox_sandbox_hunspell& aSandbox, 102 tainted_hunspell<const char*> t_aFilename) { 103 mozilla::StaticAutoWriteLock lock(sFileMgrMapLock); 104 105 return t_aFilename.copy_and_verify_string( 106 [&](std::unique_ptr<char[]> aFilename) { 107 nsCString cFilename = nsDependentCString(aFilename.get()); 108 109 // Ensure that the filename is in the allowlist 110 auto it = sFileMgrAllowList.find(cFilename); 111 MOZ_RELEASE_ASSERT(it != sFileMgrAllowList.end()); 112 113 // Get new id 114 uint32_t freshId = GetFreshId(); 115 // Save mapping of id to file manager 116 sFileMgrMap[freshId] = std::unique_ptr<mozHunspellFileMgrHost>( 117 new mozHunspellFileMgrHost(cFilename)); 118 119 return freshId; 120 }); 121 } 122 123 /* static */ 124 uint32_t mozHunspellCallbacks::GetFreshId() { 125 // i is uint64_t to prevent overflow during loop increment which would cause 126 // an infinite loop 127 for (uint64_t i = sCurrentFreshId; i < std::numeric_limits<uint32_t>::max(); 128 i++) { 129 auto it = sFileMgrMap.find(i); 130 if (it == sFileMgrMap.end()) { 131 // set sCurrentFreshId to the next (possibly) available id 132 sCurrentFreshId = i + 1; 133 return static_cast<uint32_t>(i); 134 } 135 } 136 137 MOZ_CRASH("Ran out of unique file ids for hunspell dictionaries"); 138 } 139 140 /* static */ 141 mozHunspellFileMgrHost& mozHunspellCallbacks::GetMozHunspellFileMgrHost( 142 tainted_hunspell<uint32_t> t_aFd) { 143 mozilla::StaticAutoReadLock lock(sFileMgrMapLock); 144 uint32_t aFd = t_aFd.copy_and_verify([](uint32_t aFd) { return aFd; }); 145 auto iter = sFileMgrMap.find(aFd); 146 MOZ_RELEASE_ASSERT(iter != sFileMgrMap.end()); 147 return *(iter->second.get()); 148 } 149 150 /* static */ 151 tainted_hunspell<bool> mozHunspellCallbacks::GetLine( 152 rlbox_sandbox_hunspell& aSandbox, tainted_hunspell<uint32_t> t_aFd, 153 tainted_hunspell<char**> t_aLinePtr) { 154 mozHunspellFileMgrHost& inst = 155 mozHunspellCallbacks::GetMozHunspellFileMgrHost(t_aFd); 156 nsAutoCString line; 157 bool ok = inst.GetLine(line); 158 // If the getline fails, return a null which is "graceful" failure 159 if (ok) { 160 // Copy the line into the sandbox. This memory is eventually freed by 161 // hunspell. 162 size_t size = line.Length() + 1; 163 tainted_hunspell<char*> t_line = aSandbox.malloc_in_sandbox<char>(size); 164 165 if (t_line == nullptr) { 166 // If malloc fails, we should go to "graceful" failure path 167 ok = false; 168 } else { 169 rlbox::memcpy(aSandbox, t_line, line.get(), size); 170 } 171 *t_aLinePtr = t_line; 172 } else { 173 *t_aLinePtr = nullptr; 174 } 175 return ok; 176 } 177 178 /* static */ 179 tainted_hunspell<int> mozHunspellCallbacks::GetLineNum( 180 rlbox_sandbox_hunspell& aSandbox, tainted_hunspell<uint32_t> t_aFd) { 181 mozHunspellFileMgrHost& inst = 182 mozHunspellCallbacks::GetMozHunspellFileMgrHost(t_aFd); 183 int num = inst.GetLineNum(); 184 return num; 185 } 186 187 /* static */ 188 void mozHunspellCallbacks::DestructFilemgr(rlbox_sandbox_hunspell& aSandbox, 189 tainted_hunspell<uint32_t> t_aFd) { 190 mozilla::StaticAutoWriteLock lock(sFileMgrMapLock); 191 uint32_t aFd = t_aFd.copy_and_verify([](uint32_t aFd) { return aFd; }); 192 193 auto iter = sFileMgrMap.find(aFd); 194 if (iter != sFileMgrMap.end()) { 195 sFileMgrMap.erase(iter); 196 } 197 } 198 199 // Callbacks for using Firefox's encoding instead of hunspell's 200 201 /* static */ 202 tainted_hunspell<uint32_t> mozHunspellCallbacks::ToUpperCase( 203 rlbox_sandbox_hunspell& aSandbox, tainted_hunspell<uint32_t> t_aChar) { 204 uint32_t aChar = 205 t_aChar.copy_and_verify([](uint32_t aChar) { return aChar; }); 206 return ::ToUpperCase(aChar); 207 } 208 209 /* static */ 210 tainted_hunspell<uint32_t> mozHunspellCallbacks::ToLowerCase( 211 rlbox_sandbox_hunspell& aSandbox, tainted_hunspell<uint32_t> t_aChar) { 212 uint32_t aChar = 213 t_aChar.copy_and_verify([](uint32_t aChar) { return aChar; }); 214 return ::ToLowerCase(aChar); 215 } 216 217 /* static */ tainted_hunspell<struct cs_info*> 218 mozHunspellCallbacks::GetCurrentCS(rlbox_sandbox_hunspell& aSandbox, 219 tainted_hunspell<const char*> t_es) { 220 tainted_hunspell<struct cs_info*> t_ccs = 221 aSandbox.malloc_in_sandbox<struct cs_info>(256); 222 MOZ_RELEASE_ASSERT(t_ccs); 223 return t_es.copy_and_verify_string([&](std::unique_ptr<char[]> es) { 224 struct cs_info* ccs = hunspell_get_current_cs(es.get()); 225 rlbox::memcpy(aSandbox, t_ccs, ccs, sizeof(struct cs_info) * 256); 226 delete[] ccs; 227 return t_ccs; 228 }); 229 }