Bug 1732201 - Sandbox woff2 in OTS using RLBox r=bholley

Differential Revision: https://phabricator.services.mozilla.com/D126435
This commit is contained in:
Deian Stefan 2021-11-27 23:30:49 +00:00
Родитель f0ef0360eb
Коммит 1ee9a841d8
24 изменённых файлов: 628 добавлений и 72 удалений

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

@ -96,7 +96,9 @@ gfx/angle/.*
gfx/cairo/.*
gfx/graphite2/.*
gfx/harfbuzz/.*
gfx/ots/.*
gfx/ots/src/.*
gfx/ots/include/.*
gfx/ots/tests/.*
gfx/qcms/.*
gfx/sfntly/.*
gfx/skia/.*
@ -167,7 +169,8 @@ modules/fdlibm/.*
modules/freetype2/.*
modules/libbz2/.*
modules/pdfium/.*
modules/woff2/.*
modules/woff2/include/.*
modules/woff2/src/.*
modules/xz-embedded/.*
modules/zlib/.*
mozglue/misc/decimal/.*

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

@ -217,7 +217,7 @@ endif
ifdef MOZ_USING_WASM_SANDBOXING
security/rlbox/target-objects: config/external/wasm2c_sandbox_compiler/host
security/rlbox/target: security/rlbox/target-objects
dom/media/ogg/target-objects extensions/spellcheck/hunspell/glue/target-objects gfx/thebes/target-objects parser/expat/target-objects parser/htmlparser/target-objects: security/rlbox/target-objects
dom/media/ogg/target-objects extensions/spellcheck/hunspell/glue/target-objects gfx/thebes/target-objects parser/expat/target-objects parser/htmlparser/target-objects gfx/ots/src/target-objects: security/rlbox/target-objects
endif
# Most things are built during compile (target/host), but some things happen during export

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

@ -10,3 +10,4 @@ Additional files: README.mozilla, src/moz.build
Additional patch: ots-visibility.patch (bug 711079).
Additional patch: ots-lz4.patch
Additional patch: ots-rlbox.patch (bug 1732201).

206
gfx/ots/RLBoxWOFF2Host.cpp Normal file
Просмотреть файл

@ -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);
}

58
gfx/ots/RLBoxWOFF2Host.h Normal file
Просмотреть файл

@ -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

37
gfx/ots/RLBoxWOFF2Types.h Normal file
Просмотреть файл

@ -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

56
gfx/ots/ots-rlbox.patch Normal file
Просмотреть файл

@ -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) {

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

@ -7,6 +7,11 @@
EXPORTS += [
'../include/opentype-sanitiser.h',
'../include/ots-memory-stream.h',
'../RLBoxWOFF2Types.h',
]
UNIFIED_SOURCES += [
'../RLBoxWOFF2Host.cpp'
]
UNIFIED_SOURCES += [
@ -71,5 +76,6 @@ USE_LIBS += [
]
LOCAL_INCLUDES += [
'!/security/rlbox',
'/modules/woff2/src',
]

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

@ -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) {

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

@ -36,3 +36,6 @@ patch -p3 < ots-visibility.patch
echo "Applying ots-lz4.patch..."
patch -p3 < ots-lz4.patch
echo "Applying ots-rlbox.patch..."
patch -p3 < ots-rlbox.patch

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

@ -19,6 +19,7 @@ UNIFIED_SOURCES += [
include("/ipc/chromium/chromium-config.mozbuild")
LOCAL_INCLUDES += [
"!/security/rlbox",
"../base",
"../forms",
"../generic",

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

@ -129,6 +129,7 @@
#include "mozilla/intl/nsComplexBreaker.h"
#include "nsRLBoxExpatDriver.h"
#include "RLBoxWOFF2Types.h"
using namespace mozilla;
using namespace mozilla::net;
@ -298,6 +299,8 @@ nsresult nsLayoutStatics::Initialize() {
RLBoxExpatSandboxPool::Initialize();
RLBoxWOFF2SandboxPool::Initalize();
return NS_OK;
}

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

@ -12,3 +12,5 @@ The in-tree copy is updated by running
from within the modules/woff2 directory.
Current version: [commit 1bccf208bca986e53a647dfe4811322adb06ecf8].
Additional patch: woff2-rlbox.patch (bug 1732201).

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

@ -0,0 +1,66 @@
/* -*- 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 <woff2/decode.h>
#include <cassert>
#include "RLBoxWOFF2Sandbox.h"
bool RLBoxConvertWOFF2ToTTF(const uint8_t* aData, size_t aLength,
size_t aDecompressedSize, size_t* aResultSize,
void** aResultOwningStr, uint8_t** aResultData) {
std::unique_ptr<std::string> buf =
std::make_unique<std::string>(aDecompressedSize, 0);
woff2::WOFF2StringOut out(buf.get());
if (!woff2::ConvertWOFF2ToTTF(aData, aLength, &out)) {
return false;
}
*aResultSize = out.Size();
// Return the string and its underlying C string. We need both to make sure we
// can free the string (which we do with RLBoxDeleteWOFF2String).
*aResultData = reinterpret_cast<uint8_t*>(buf->data());
*aResultOwningStr = static_cast<void*>(buf.release());
return true;
}
void RLBoxDeleteWOFF2String(void** aStr) {
std::string* buf = static_cast<std::string*>(*aStr);
delete buf;
}
size_t RLBoxComputeWOFF2FinalSize(const uint8_t* aData, size_t aLength) {
return woff2::ComputeWOFF2FinalSize(aData, aLength);
}
BrotliDecompressCallback* sRLBoxBrotliDecompressCallback = nullptr;
void RegisterWOFF2Callback(BrotliDecompressCallback* aCallback) {
#ifdef MOZ_IN_WASM_SANDBOX
// When Woff2 is wasmboxed, we need to register a callback for brotli
// decompression. The easiest way to store this is in a static variable. This
// is thread-safe because each (potentially-concurrent) woff2 instance gets
// its own sandbox with its own copy of the statics.
//
// When the sandbox is disabled (replaced with the noop sandbox), setting the
// callback is actually racey. However, we don't actually need a callback in
// that case, and can just invoke brotli directly.
sRLBoxBrotliDecompressCallback = aCallback;
#endif
}
BrotliDecoderResult RLBoxBrotliDecoderDecompress(size_t aEncodedSize,
const uint8_t* aEncodedBuffer,
size_t* aDecodedSize,
uint8_t* aDecodedBuffer) {
#ifdef MOZ_IN_WASM_SANDBOX
assert(sRLBoxBrotliDecompressCallback);
return sRLBoxBrotliDecompressCallback(
aEncodedSize, reinterpret_cast<const char*>(aEncodedBuffer), aDecodedSize,
reinterpret_cast<char*>(aDecodedBuffer));
#else
return BrotliDecoderDecompress(aEncodedSize, aEncodedBuffer, aDecodedSize,
aDecodedBuffer);
#endif
}

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

@ -0,0 +1,42 @@
/* -*- 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_RLBOX_WOFF2_SANDBOX_H_
#define MODULES_WOFF2_RLBOX_WOFF2_SANDBOX_H_
#include <brotli/decode.h>
extern "C" {
// Since RLBox doesn't support C++ APIs, we expose C wrappers for the WOFF2.
size_t RLBoxComputeWOFF2FinalSize(const uint8_t* aData, size_t aLength);
bool RLBoxConvertWOFF2ToTTF(const uint8_t* aData, size_t aLength,
size_t aDecompressedSize, size_t* aResultSize,
void** aResultOwningStr, uint8_t** aResultData);
// RLBoxDeleteWOFF2String is used to delete the C++ string allocated by
// RLBoxConvertWOFF2ToTTF.
void RLBoxDeleteWOFF2String(void** aStr);
// Type of brotli decoder function. Because RLBox doesn't (yet) cleanly support
// {size,uint8}_t types for callbacks, we're using unsigned long instead of
// size_t and char instead of uint8_t.
typedef BrotliDecoderResult(BrotliDecompressCallback)(
unsigned long aEncodedSize, const char* aEncodedBuffer,
unsigned long* aDecodedSize, char* aDecodedBuffer);
// Callback to the unsandboxed Brotli.
extern BrotliDecompressCallback* sRLBoxBrotliDecompressCallback;
void RegisterWOFF2Callback(BrotliDecompressCallback* aCallback);
BrotliDecoderResult RLBoxBrotliDecoderDecompress(size_t aEncodedSize,
const uint8_t* aEncodedBuffer,
size_t* aDecodedSize,
uint8_t* aDecodedBuffer);
};
#endif

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

@ -4,24 +4,24 @@
# 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("sources.mozbuild")
with Files('**'):
BUG_COMPONENT = ('Core', 'Graphics: Text')
UNIFIED_SOURCES += [
'src/table_tags.cc',
'src/variable_length.cc',
'src/woff2_common.cc',
'src/woff2_dec.cc',
'src/woff2_out.cc',
]
UNIFIED_SOURCES += woff2_sources
EXPORTS.woff2 += [
'include/woff2/decode.h',
'include/woff2/encode.h',
'include/woff2/output.h',
'RLBoxWOFF2Sandbox.h',
]
# We allow warnings for third-party code that can be updated from upstream.
AllowCompilerWarnings()
Library('woff2')
REQUIRES_UNIFIED_BUILD = True

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

@ -0,0 +1,14 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
woff2_sources = [
'RLBoxWOFF2Sandbox.cpp',
'src/table_tags.cc',
'src/variable_length.cc',
'src/woff2_common.cc',
'src/woff2_dec.cc',
'src/woff2_out.cc',
]

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

@ -19,7 +19,6 @@
#include <memory>
#include <utility>
#include <brotli/decode.h>
#include "./buffer.h"
#include "./port.h"
#include "./round.h"
@ -28,6 +27,8 @@
#include "./variable_length.h"
#include "./woff2_common.h"
#include "../RLBoxWOFF2Sandbox.h"
namespace woff2 {
namespace {
@ -758,7 +759,7 @@ bool ReconstructTransformedHmtx(const uint8_t* transformed_buf,
bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size,
const uint8_t* src_buf, size_t src_size) {
size_t uncompressed_size = dst_size;
BrotliDecoderResult result = BrotliDecoderDecompress(
BrotliDecoderResult result = RLBoxBrotliDecoderDecompress(
src_size, src_buf, &uncompressed_size, dst_buf);
if (PREDICT_FALSE(result != BROTLI_DECODER_RESULT_SUCCESS ||
uncompressed_size != dst_size)) {

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

@ -22,3 +22,6 @@ echo "###"
echo "### Updated woff2 to $COMMIT."
echo "### Remember to verify and commit the changes to source control!"
echo "###"
echo "Applying woff2-rlbox.patch..."
patch -p3 < woff2-rlbox.patch

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

@ -0,0 +1,29 @@
diff --git a/modules/woff2/src/woff2_dec.cc b/modules/woff2/src/woff2_dec.cc
--- a/modules/woff2/src/woff2_dec.cc
+++ b/modules/woff2/src/woff2_dec.cc
@@ -19,7 +19,6 @@
#include <memory>
#include <utility>
-#include <brotli/decode.h>
#include "./buffer.h"
#include "./port.h"
#include "./round.h"
@@ -28,6 +27,8 @@
#include "./variable_length.h"
#include "./woff2_common.h"
+#include "../RLBoxWOFF2Sandbox.h"
+
namespace woff2 {
namespace {
@@ -758,7 +759,7 @@ bool ReconstructTransformedHmtx(const uint8_t* transformed_buf,
bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size,
const uint8_t* src_buf, size_t src_size) {
size_t uncompressed_size = dst_size;
- BrotliDecoderResult result = BrotliDecoderDecompress(
+ BrotliDecoderResult result = RLBoxBrotliDecoderDecompress(
src_size, src_buf, &uncompressed_size, dst_buf);
if (PREDICT_FALSE(result != BROTLI_DECODER_RESULT_SUCCESS ||
uncompressed_size != dst_size)) {

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

@ -36,6 +36,7 @@
#include "nsThreadUtils.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/RLBoxUtils.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Logging.h"
@ -106,34 +107,12 @@ static const XML_Char* unverified_xml_string(uintptr_t ptr) {
}
/* The TransferBuffer class is used to copy (or directly expose in the
* noop-sandbox case) buffers into the sandbox that are automatically freed
* when the TransferBuffer is out of scope. NOTE: The sandbox lifetime must
* outlive all of its TransferBuffers.
* noop-sandbox case) buffers into the expat sandbox (and automatically
* when out of scope).
*/
template <typename T>
class MOZ_STACK_CLASS TransferBuffer {
public:
TransferBuffer() = delete;
TransferBuffer(rlbox_sandbox_expat* aSandbox, const T* aBuf,
const size_t aLen)
: mSandbox(aSandbox), mCopied(false), mBuf(nullptr) {
if (aBuf) {
mBuf = rlbox::copy_memory_or_grant_access(
*mSandbox, aBuf, aLen * sizeof(T), false, mCopied);
}
};
~TransferBuffer() {
if (mCopied) {
mSandbox->free_in_sandbox(mBuf);
}
};
tainted_expat<const T*> operator*() const { return mBuf; };
private:
rlbox_sandbox_expat* mSandbox;
bool mCopied;
tainted_expat<const T*> mBuf;
};
using TransferBuffer =
mozilla::RLBoxTransferBufferToSandbox<T, rlbox_expat_sandbox_type>;
/*************************** END RLBOX HELPERS ******************************/

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

@ -75,3 +75,8 @@ if CONFIG["MOZ_WASM_SANDBOXING_EXPAT"]:
for k, v in expat_defines:
WASM_DEFINES[k] = v
LOCAL_INCLUDES += ["/parser/expat/lib/"]
if CONFIG["MOZ_WASM_SANDBOXING_WOFF2"]:
include("/modules/woff2/sources.mozbuild")
WASM_SOURCES += ["/modules/woff2/" + s for s in woff2_sources]
LOCAL_INCLUDES += ["/modules/woff2/include"]

70
xpcom/base/RLBoxUtils.h Normal file
Просмотреть файл

@ -0,0 +1,70 @@
/* -*- 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 SECURITY_RLBOX_UTILS_H_
#define SECURITY_RLBOX_UTILS_H_
#include "mozilla/rlbox/rlbox_types.hpp"
namespace mozilla {
/* The RLBoxTransferBufferToSandbox class is used to copy (or directly expose in
* the noop-sandbox case) buffers into the sandbox that are automatically freed
* when the RLBoxTransferBufferToSandbox is out of scope. NOTE: The sandbox
* lifetime must outlive all of its RLBoxTransferBufferToSandbox.
*/
template <typename T, typename S>
class MOZ_STACK_CLASS RLBoxTransferBufferToSandbox {
public:
RLBoxTransferBufferToSandbox() = delete;
RLBoxTransferBufferToSandbox(rlbox::rlbox_sandbox<S>* aSandbox, const T* aBuf,
const size_t aLen)
: mSandbox(aSandbox), mCopied(false), mBuf(nullptr) {
if (aBuf) {
mBuf = rlbox::copy_memory_or_grant_access(
*mSandbox, aBuf, aLen * sizeof(T), false, mCopied);
}
};
~RLBoxTransferBufferToSandbox() {
if (mCopied) {
mSandbox->free_in_sandbox(mBuf);
}
};
rlbox::tainted<const T*, S> operator*() const { return mBuf; };
private:
rlbox::rlbox_sandbox<S>* mSandbox;
bool mCopied;
rlbox::tainted<const T*, S> mBuf;
};
/* The RLBoxAllocateInSandbox class is used to allocate data int sandbox that is
* automatically freed when the RLBoxAllocateInSandbox is out of scope. NOTE:
* The sandbox lifetime must outlive all of its RLBoxAllocateInSandbox'ations.
*/
template <typename T, typename S>
class MOZ_STACK_CLASS RLBoxAllocateInSandbox {
public:
RLBoxAllocateInSandbox() = delete;
explicit RLBoxAllocateInSandbox(rlbox::rlbox_sandbox<S>* aSandbox)
: mSandbox(aSandbox) {
mPtr = mSandbox->template malloc_in_sandbox<T>();
};
~RLBoxAllocateInSandbox() {
if (mPtr) {
mSandbox->free_in_sandbox(mPtr);
}
};
rlbox::tainted<T*, S> get() const { return mPtr; };
private:
rlbox::rlbox_sandbox<S>* mSandbox;
rlbox::tainted<T*, S> mPtr;
};
} // namespace mozilla
#endif

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

@ -131,6 +131,7 @@ EXPORTS.mozilla += [
"NSPRLogModulesParser.h",
"OwningNonNull.h",
"RLBoxSandboxPool.h",
"RLBoxUtils.h",
"ShutdownPhase.h",
"SizeOfState.h",
"StaticLocalPtr.h",