forked from Floorp-Projects/Floorp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug 1732201 - Sandbox woff2 in OTS using RLBox r=bholley
Differential Revision: https://phabricator.services.mozilla.com/D126435
- Loading branch information
Showing
24 changed files
with
628 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
#include "RLBoxWOFF2Host.h" | ||
#include "nsPrintfCString.h" | ||
#include "nsThreadUtils.h" | ||
#include "mozilla/ClearOnShutdown.h" | ||
#include "mozilla/RLBoxUtils.h" | ||
#include "mozilla/ScopeExit.h" | ||
|
||
using namespace rlbox; | ||
using namespace mozilla; | ||
|
||
tainted_woff2<BrotliDecoderResult> RLBoxBrotliDecoderDecompressCallback( | ||
rlbox_sandbox_woff2& aSandbox, tainted_woff2<unsigned long> aEncodedSize, | ||
tainted_woff2<const char*> aEncodedBuffer, | ||
tainted_woff2<unsigned long*> aDecodedSize, | ||
tainted_woff2<char*> aDecodedBuffer) { | ||
if (!aEncodedBuffer || !aDecodedSize || !aDecodedBuffer) { | ||
return BROTLI_DECODER_RESULT_ERROR; | ||
} | ||
|
||
// We don't create temporary buffers for brotli to operate on. Instead we | ||
// pass a pointer to the in (encoded) and out (decoded) buffers. We check | ||
// (specifically, unverified_safe_pointer checks) that the buffers are within | ||
// the sandbox boundary (for the given sizes). | ||
|
||
size_t encodedSize = | ||
aEncodedSize.unverified_safe_because("Any size within sandbox is ok."); | ||
const uint8_t* encodedBuffer = reinterpret_cast<const uint8_t*>( | ||
aEncodedBuffer.unverified_safe_pointer_because( | ||
encodedSize, "Pointer fits within sandbox")); | ||
|
||
size_t decodedSize = | ||
(*aDecodedSize).unverified_safe_because("Any size within sandbox is ok."); | ||
uint8_t* decodedBuffer = | ||
reinterpret_cast<uint8_t*>(aDecodedBuffer.unverified_safe_pointer_because( | ||
decodedSize, "Pointer fits within sandbox")); | ||
|
||
BrotliDecoderResult res = BrotliDecoderDecompress( | ||
encodedSize, encodedBuffer, &decodedSize, decodedBuffer); | ||
|
||
*aDecodedSize = decodedSize; | ||
|
||
return res; | ||
} | ||
|
||
UniquePtr<RLBoxSandboxDataBase> RLBoxWOFF2SandboxPool::CreateSandboxData() { | ||
// Create woff2 sandbox | ||
auto sandbox = MakeUnique<rlbox_sandbox_woff2>(); | ||
|
||
#ifdef MOZ_WASM_SANDBOXING_WOFF2 | ||
bool createOK = sandbox->create_sandbox(/* infallible = */ false); | ||
#else | ||
bool createOK = sandbox->create_sandbox(); | ||
#endif | ||
NS_ENSURE_TRUE(createOK, nullptr); | ||
|
||
UniquePtr<RLBoxWOFF2SandboxData> sbxData = | ||
MakeUnique<RLBoxWOFF2SandboxData>(std::move(sandbox)); | ||
|
||
// Register brotli callback | ||
sbxData->mDecompressCallback = sbxData->Sandbox()->register_callback( | ||
RLBoxBrotliDecoderDecompressCallback); | ||
sbxData->Sandbox()->invoke_sandbox_function(RegisterWOFF2Callback, | ||
sbxData->mDecompressCallback); | ||
|
||
return sbxData; | ||
} | ||
|
||
StaticRefPtr<RLBoxWOFF2SandboxPool> RLBoxWOFF2SandboxPool::sSingleton; | ||
|
||
void RLBoxWOFF2SandboxPool::Initalize(size_t aDelaySeconds) { | ||
AssertIsOnMainThread(); | ||
RLBoxWOFF2SandboxPool::sSingleton = new RLBoxWOFF2SandboxPool(aDelaySeconds); | ||
ClearOnShutdown(&RLBoxWOFF2SandboxPool::sSingleton); | ||
} | ||
|
||
RLBoxWOFF2SandboxData::RLBoxWOFF2SandboxData( | ||
mozilla::UniquePtr<rlbox_sandbox_woff2> aSandbox) | ||
: mSandbox(std::move(aSandbox)) { | ||
MOZ_COUNT_CTOR(RLBoxWOFF2SandboxData); | ||
} | ||
|
||
RLBoxWOFF2SandboxData::~RLBoxWOFF2SandboxData() { | ||
MOZ_ASSERT(mSandbox); | ||
mDecompressCallback.unregister(); | ||
mSandbox->destroy_sandbox(); | ||
MOZ_COUNT_DTOR(RLBoxWOFF2SandboxData); | ||
} | ||
|
||
template <typename T> | ||
using TransferBufferToWOFF2 = | ||
mozilla::RLBoxTransferBufferToSandbox<T, rlbox_woff2_sandbox_type>; | ||
template <typename T> | ||
using WOFF2Alloc = mozilla::RLBoxAllocateInSandbox<T, rlbox_woff2_sandbox_type>; | ||
|
||
bool RLBoxProcessWOFF2(ots::FontFile* aHeader, ots::OTSStream* aOutput, | ||
const uint8_t* aData, size_t aLength, uint32_t aIndex, | ||
ProcessTTCFunc* aProcessTTC, | ||
ProcessTTFFunc* aProcessTTF) { | ||
MOZ_ASSERT(aProcessTTC); | ||
MOZ_ASSERT(aProcessTTF); | ||
|
||
// We index into aData before processing it (very end of this function). Our | ||
// validator ensures that the untrusted size is greater than aLength, so we | ||
// just need to conservatively ensure that aLength is greater than the highest | ||
// index (7). | ||
NS_ENSURE_TRUE(aLength >= 8, false); | ||
|
||
auto sandboxPoolData = RLBoxWOFF2SandboxPool::sSingleton->PopOrCreate(); | ||
NS_ENSURE_TRUE(sandboxPoolData, false); | ||
|
||
const auto* sandboxData = | ||
static_cast<const RLBoxWOFF2SandboxData*>(sandboxPoolData->SandboxData()); | ||
MOZ_ASSERT(sandboxData); | ||
|
||
auto* sandbox = sandboxData->Sandbox(); | ||
|
||
// Transfer aData into the sandbox. | ||
|
||
auto data = TransferBufferToWOFF2<uint8_t>(sandbox, aData, aLength); | ||
NS_ENSURE_TRUE(*data, false); | ||
|
||
// Validator for the decompression size. | ||
// Returns the size and sets validateOK to true if size is valid (and false | ||
// otherwise). | ||
bool validateOK = false; | ||
auto sizeValidator = [aLength, &validateOK](auto size) { | ||
validateOK = false; | ||
if (size < aLength) { | ||
NS_WARNING("Size of decompressed WOFF 2.0 is less than compressed size"); | ||
} else if (size == 0) { | ||
NS_WARNING("Size of decompressed WOFF 2.0 is set to 0"); | ||
} else if (size > OTS_MAX_DECOMPRESSED_FILE_SIZE) { | ||
NS_WARNING( | ||
nsPrintfCString("Size of decompressed WOFF 2.0 font exceeds %gMB", | ||
OTS_MAX_DECOMPRESSED_FILE_SIZE / (1024.0 * 1024.0)) | ||
.get()); | ||
} else { | ||
validateOK = true; | ||
} | ||
return size; | ||
}; | ||
|
||
// Get the (estimated) decompression size and validate it. | ||
|
||
size_t decompressedSize = | ||
sandbox | ||
->invoke_sandbox_function(RLBoxComputeWOFF2FinalSize, *data, aLength) | ||
.copy_and_verify(sizeValidator); | ||
|
||
if (NS_WARN_IF(!validateOK)) { | ||
return false; | ||
} | ||
|
||
// Perform the actual conversion to TTF. | ||
|
||
auto sizep = WOFF2Alloc<size_t>(sandbox); | ||
auto bufp = WOFF2Alloc<uint8_t*>(sandbox); | ||
auto bufOwnerString = | ||
WOFF2Alloc<void*>(sandbox); // pointer to string that owns the bufer | ||
|
||
if (!sandbox | ||
->invoke_sandbox_function(RLBoxConvertWOFF2ToTTF, *data, aLength, | ||
decompressedSize, sizep.get(), | ||
bufOwnerString.get(), bufp.get()) | ||
.unverified_safe_because( | ||
"The ProcessTT* functions validate the decompressed data.")) { | ||
return false; | ||
} | ||
|
||
auto bufCleanup = mozilla::MakeScopeExit([&sandbox, &bufOwnerString] { | ||
// Delete the string created by RLBoxConvertWOFF2ToTTF. | ||
sandbox->invoke_sandbox_function(RLBoxDeleteWOFF2String, | ||
bufOwnerString.get()); | ||
}); | ||
|
||
// Get the actual decompression size and validate it. | ||
// We need to validate the size again. RLBoxConvertWOFF2ToTTF works even if | ||
// the computed size (with RLBoxComputeWOFF2FinalSize) is wrong, so we can't | ||
// trust the decompressedSize to be the same as size sizep. | ||
size_t size = (*sizep.get()).copy_and_verify(sizeValidator); | ||
|
||
if (NS_WARN_IF(!validateOK)) { | ||
return false; | ||
} | ||
|
||
const uint8_t* decompressed = | ||
(*bufp.get()) | ||
.unverified_safe_pointer_because( | ||
size, "Only care that the buffer is within sandbox boundary."); | ||
|
||
// Since ProcessTT* memcpy from the buffer, make sure it's not null. | ||
NS_ENSURE_TRUE(decompressed, false); | ||
|
||
if (aData[4] == 't' && aData[5] == 't' && aData[6] == 'c' && | ||
aData[7] == 'f') { | ||
return aProcessTTC(aHeader, aOutput, decompressed, size, aIndex); | ||
} | ||
ots::Font font(aHeader); | ||
return aProcessTTF(aHeader, &font, aOutput, decompressed, size, 0); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
#ifndef MODULES_WOFF2_RLBOXWOFF2_HOST_H_ | ||
#define MODULES_WOFF2_RLBOXWOFF2_HOST_H_ | ||
|
||
#include "RLBoxWOFF2Types.h" | ||
|
||
// Load general firefox configuration of RLBox | ||
#include "mozilla/rlbox/rlbox_config.h" | ||
|
||
#ifdef MOZ_WASM_SANDBOXING_WOFF2 | ||
// Include the generated header file so that we are able to resolve the symbols | ||
// in the wasm binary | ||
# include "rlbox.wasm.h" | ||
# define RLBOX_USE_STATIC_CALLS() rlbox_wasm2c_sandbox_lookup_symbol | ||
# include "mozilla/rlbox/rlbox_wasm2c_sandbox.hpp" | ||
#else | ||
// Extra configuration for no-op sandbox | ||
# define RLBOX_USE_STATIC_CALLS() rlbox_noop_sandbox_lookup_symbol | ||
# include "mozilla/rlbox/rlbox_noop_sandbox.hpp" | ||
#endif | ||
|
||
#include "mozilla/rlbox/rlbox.hpp" | ||
|
||
#include "woff2/RLBoxWOFF2Sandbox.h" | ||
#include "./src/ots.h" | ||
|
||
class RLBoxWOFF2SandboxData : public mozilla::RLBoxSandboxDataBase { | ||
friend class RLBoxWOFF2SandboxPool; | ||
|
||
public: | ||
RLBoxWOFF2SandboxData(mozilla::UniquePtr<rlbox_sandbox_woff2> aSandbox); | ||
~RLBoxWOFF2SandboxData(); | ||
|
||
rlbox_sandbox_woff2* Sandbox() const { return mSandbox.get(); } | ||
|
||
private: | ||
mozilla::UniquePtr<rlbox_sandbox_woff2> mSandbox; | ||
sandbox_callback_woff2<BrotliDecompressCallback*> mDecompressCallback; | ||
}; | ||
|
||
using ProcessTTCFunc = bool(ots::FontFile* aHeader, ots::OTSStream* aOutput, | ||
const uint8_t* aData, size_t aLength, | ||
uint32_t aIndex); | ||
|
||
using ProcessTTFFunc = bool(ots::FontFile* aHeader, ots::Font* aFont, | ||
ots::OTSStream* aOutput, const uint8_t* aData, | ||
size_t aLength, uint32_t aOffset); | ||
|
||
bool RLBoxProcessWOFF2(ots::FontFile* aHeader, ots::OTSStream* aOutput, | ||
const uint8_t* aData, size_t aLength, uint32_t aIndex, | ||
ProcessTTCFunc* aProcessTTC, | ||
ProcessTTFFunc* aProcessTTF); | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
#ifndef MODULES_WOFF2_RLBOXWOFF2TYPES_H_ | ||
#define MODULES_WOFF2_RLBOXWOFF2TYPES_H_ | ||
|
||
#include <stddef.h> | ||
#include "mozilla/rlbox/rlbox_types.hpp" | ||
#include "woff2/decode.h" | ||
|
||
#ifdef MOZ_WASM_SANDBOXING_WOFF2 | ||
RLBOX_DEFINE_BASE_TYPES_FOR(woff2, wasm2c) | ||
#else | ||
RLBOX_DEFINE_BASE_TYPES_FOR(woff2, noop) | ||
#endif | ||
|
||
#include "mozilla/RLBoxSandboxPool.h" | ||
#include "mozilla/StaticPtr.h" | ||
|
||
class RLBoxWOFF2SandboxPool : public mozilla::RLBoxSandboxPool { | ||
public: | ||
explicit RLBoxWOFF2SandboxPool(size_t aDelaySeconds) | ||
: RLBoxSandboxPool(aDelaySeconds) {} | ||
|
||
static mozilla::StaticRefPtr<RLBoxWOFF2SandboxPool> sSingleton; | ||
static void Initalize(size_t aDelaySeconds = 10); | ||
|
||
protected: | ||
mozilla::UniquePtr<mozilla::RLBoxSandboxDataBase> CreateSandboxData() | ||
override; | ||
~RLBoxWOFF2SandboxPool() = default; | ||
}; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
diff --git a/gfx/ots/src/ots.cc b/gfx/ots/src/ots.cc | ||
--- a/gfx/ots/src/ots.cc | ||
+++ b/gfx/ots/src/ots.cc | ||
@@ -14,7 +14,7 @@ | ||
#include <map> | ||
#include <vector> | ||
|
||
-#include <woff2/decode.h> | ||
+#include "../RLBoxWOFF2Host.h" | ||
|
||
// The OpenType Font File | ||
// http://www.microsoft.com/typography/otspec/otff.htm | ||
@@ -511,39 +511,9 @@ bool ProcessWOFF(ots::FontFile *header, | ||
return ProcessGeneric(header, font, woff_tag, output, data, length, tables, file); | ||
} | ||
|
||
-bool ProcessWOFF2(ots::FontFile *header, | ||
- ots::OTSStream *output, | ||
- const uint8_t *data, | ||
- size_t length, | ||
- uint32_t index) { | ||
- size_t decompressed_size = woff2::ComputeWOFF2FinalSize(data, length); | ||
- | ||
- if (decompressed_size < length) { | ||
- return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 is less than compressed size"); | ||
- } | ||
- | ||
- if (decompressed_size == 0) { | ||
- return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 is set to 0"); | ||
- } | ||
- // decompressed font must be <= OTS_MAX_DECOMPRESSED_FILE_SIZE | ||
- if (decompressed_size > OTS_MAX_DECOMPRESSED_FILE_SIZE) { | ||
- return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 font exceeds %gMB", | ||
- OTS_MAX_DECOMPRESSED_FILE_SIZE / (1024.0 * 1024.0)); | ||
- } | ||
- | ||
- std::string buf(decompressed_size, 0); | ||
- woff2::WOFF2StringOut out(&buf); | ||
- if (!woff2::ConvertWOFF2ToTTF(data, length, &out)) { | ||
- return OTS_FAILURE_MSG_HDR("Failed to convert WOFF 2.0 font to SFNT"); | ||
- } | ||
- const uint8_t *decompressed = reinterpret_cast<const uint8_t*>(buf.data()); | ||
- | ||
- if (data[4] == 't' && data[5] == 't' && data[6] == 'c' && data[7] == 'f') { | ||
- return ProcessTTC(header, output, decompressed, out.Size(), index); | ||
- } else { | ||
- ots::Font font(header); | ||
- return ProcessTTF(header, &font, output, decompressed, out.Size()); | ||
- } | ||
+bool ProcessWOFF2(ots::FontFile* header, ots::OTSStream* output, | ||
+ const uint8_t* data, size_t length, uint32_t index) { | ||
+ return RLBoxProcessWOFF2(header, output, data, length, index, ProcessTTC, ProcessTTF); | ||
} | ||
|
||
ots::TableAction GetTableAction(const ots::FontFile *header, uint32_t tag) { | ||
|
Oops, something went wrong.