tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }