Bug 1639563 - sanitize WR fonts. r=jrmuizel

Differential Revision: https://phabricator.services.mozilla.com/D76360
This commit is contained in:
Lee Salzman 2020-05-22 15:48:55 +00:00
Родитель 96e684e365
Коммит e97b3d4035
7 изменённых файлов: 143 добавлений и 17 удалений

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

@ -244,10 +244,10 @@ struct TableRecord {
CFDataRef data;
};
static int maxPow2LessThan(int a) {
static int maxPow2LessThanEqual(int a) {
int x = 1;
int shift = 0;
while ((x << (shift + 1)) < a) {
while ((x << (shift + 1)) <= a) {
shift++;
}
return shift;
@ -332,10 +332,10 @@ bool UnscaledFontMac::GetFontFileData(FontFileDataOutput aDataCallback,
buf.writeElement(CFSwapInt32HostToBig(0x00010000));
}
buf.writeElement(CFSwapInt16HostToBig(count));
buf.writeElement(CFSwapInt16HostToBig((1 << maxPow2LessThan(count)) * 16));
buf.writeElement(CFSwapInt16HostToBig(maxPow2LessThan(count)));
buf.writeElement(
CFSwapInt16HostToBig(count * 16 - ((1 << maxPow2LessThan(count)) * 16)));
int maxPow2Count = maxPow2LessThanEqual(count);
buf.writeElement(CFSwapInt16HostToBig((1 << maxPow2Count) * 16));
buf.writeElement(CFSwapInt16HostToBig(maxPow2Count));
buf.writeElement(CFSwapInt16HostToBig((count - (1 << maxPow2Count)) * 16));
// write table record entries
for (CFIndex i = 0; i < count; i++) {

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

@ -230,12 +230,12 @@ bool ShmSegmentsReader::Read(const layers::OffsetRange& aRange,
size_t initialLength = aInto.Length();
size_t srcCursor = aRange.start();
int remainingBytesToCopy = aRange.length();
size_t remainingBytesToCopy = aRange.length();
while (remainingBytesToCopy > 0) {
const size_t shm_idx = srcCursor / mChunkSize;
const size_t ptrOffset = srcCursor % mChunkSize;
const size_t copyRange =
std::min<int>(remainingBytesToCopy, mChunkSize - ptrOffset);
std::min(remainingBytesToCopy, mChunkSize - ptrOffset);
uint8_t* srcPtr =
RefCountedShm::GetBytes(mSmallAllocs[shm_idx]) + ptrOffset;
@ -248,6 +248,50 @@ bool ShmSegmentsReader::Read(const layers::OffsetRange& aRange,
return aInto.Length() - initialLength == aRange.length();
}
Maybe<Range<uint8_t>> ShmSegmentsReader::GetReadPointerLarge(
const layers::OffsetRange& aRange) {
// source = zero is for small allocs.
MOZ_RELEASE_ASSERT(aRange.source() != 0);
if (aRange.source() > mLargeAllocs.Length()) {
return Nothing();
}
size_t id = aRange.source() - 1;
const ipc::Shmem& shm = mLargeAllocs[id];
if (shm.Size<uint8_t>() < aRange.length()) {
return Nothing();
}
uint8_t* srcPtr = shm.get<uint8_t>();
return Some(Range<uint8_t>(srcPtr, aRange.length()));
}
Maybe<Range<uint8_t>> ShmSegmentsReader::GetReadPointer(
const layers::OffsetRange& aRange) {
if (aRange.length() == 0) {
return Some(Range<uint8_t>());
}
if (aRange.source() != 0) {
return GetReadPointerLarge(aRange);
}
if (mChunkSize == 0 ||
aRange.start() + aRange.length() > mChunkSize * mSmallAllocs.Length()) {
return Nothing();
}
size_t srcCursor = aRange.start();
size_t remainingBytesToCopy = aRange.length();
const size_t shm_idx = srcCursor / mChunkSize;
const size_t ptrOffset = srcCursor % mChunkSize;
// Return nothing if we can't return a pointer to the full range
if (mChunkSize - ptrOffset < remainingBytesToCopy) {
return Nothing();
}
uint8_t* srcPtr = RefCountedShm::GetBytes(mSmallAllocs[shm_idx]) + ptrOffset;
return Some(Range<uint8_t>(srcPtr, remainingBytesToCopy));
}
IpcResourceUpdateQueue::IpcResourceUpdateQueue(
layers::WebRenderBridgeChild* aAllocator, size_t aChunkSize)
: mWriter(aAllocator, aChunkSize) {}

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

@ -71,9 +71,34 @@ class ShmSegmentsReader {
bool Read(const layers::OffsetRange& aRange, wr::Vec<uint8_t>& aInto);
// Get a read pointer, if possible, directly into the shm. If the range has
// been broken up into multiple chunks that can't be represented by a single
// range, nothing will be returned to indicate failure.
Maybe<Range<uint8_t>> GetReadPointer(const layers::OffsetRange& aRange);
// Get a read pointer, if possible, directly into the shm. Otherwise, copy
// it into the Vec and return a pointer to that contiguous memory instead.
// If all fails, return nothing.
Maybe<Range<uint8_t>> GetReadPointerOrCopy(const layers::OffsetRange& aRange,
wr::Vec<uint8_t>& aInto) {
if (Maybe<Range<uint8_t>> ptr = GetReadPointer(aRange)) {
return ptr;
} else {
size_t initialLength = aInto.Length();
if (Read(aRange, aInto)) {
return Some(Range<uint8_t>(aInto.Data() + initialLength,
aInto.Length() - initialLength));
} else {
return Nothing();
}
}
}
protected:
bool ReadLarge(const layers::OffsetRange& aRange, wr::Vec<uint8_t>& aInto);
Maybe<Range<uint8_t>> GetReadPointerLarge(const layers::OffsetRange& aRange);
const nsTArray<layers::RefCountedShmem>& mSmallAllocs;
const nsTArray<mozilla::ipc::Shmem>& mLargeAllocs;
size_t mChunkSize;
@ -87,9 +112,8 @@ class IpcResourceUpdateQueue {
// we use here. The RefCountedShmem type used to allocate the chunks keeps a
// 16 bytes header in the buffer which we account for here as well. So we pick
// 64k - 2 * 4k - 16 = 57328 bytes as the default alloc size.
explicit IpcResourceUpdateQueue(
layers::WebRenderBridgeChild* aAllocator,
size_t aChunkSize = 57328);
explicit IpcResourceUpdateQueue(layers::WebRenderBridgeChild* aAllocator,
size_t aChunkSize = 57328);
IpcResourceUpdateQueue(IpcResourceUpdateQueue&& aOther) noexcept;
IpcResourceUpdateQueue& operator=(IpcResourceUpdateQueue&& aOther) noexcept;

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

@ -8,7 +8,7 @@
#include "CompositableHost.h"
#include "gfxEnv.h"
#include "gfxEnv.h"
#include "gfxOTSUtils.h"
#include "GeckoProfiler.h"
#include "GLContext.h"
#include "GLContextProvider.h"
@ -430,6 +430,48 @@ void WebRenderBridgeParent::Destroy() {
ClearResources();
}
struct WROTSAlloc {
wr::Vec<uint8_t> mVec;
void* Grow(void* aPtr, size_t aLength) {
if (aLength > mVec.Length()) {
mVec.Reserve(aLength - mVec.Length());
}
return mVec.inner.data;
}
wr::Vec<uint8_t> ShrinkToFit(void* aPtr, size_t aLength) {
wr::Vec<uint8_t> result(std::move(mVec));
result.inner.length = aLength;
return result;
}
void Free(void* aPtr) {}
};
static bool ReadRawFont(const OpAddRawFont& aOp, wr::ShmSegmentsReader& aReader,
wr::TransactionBuilder& aUpdates) {
wr::Vec<uint8_t> sourceBytes;
Maybe<Range<uint8_t>> ptr =
aReader.GetReadPointerOrCopy(aOp.bytes(), sourceBytes);
if (ptr.isNothing()) {
return false;
}
Range<uint8_t>& source = ptr.ref();
// Attempt to sanitize the font before passing it along for updating
size_t lengthHint = gfxOTSContext::GuessSanitizedFontSize(
source.begin().get(), source.length());
if (!lengthHint) {
return false;
}
gfxOTSExpandingMemoryStream<WROTSAlloc> output(lengthHint);
gfxOTSContext otsContext;
if (!otsContext.Process(&output, source.begin().get(), source.length())) {
return false;
}
wr::Vec<uint8_t> bytes = output.forget();
aUpdates.AddRawFont(aOp.key(), bytes, aOp.fontIndex());
return true;
}
bool WebRenderBridgeParent::UpdateResources(
const nsTArray<OpUpdateResource>& aResourceUpdates,
const nsTArray<RefCountedShmem>& aSmallShmems,
@ -529,12 +571,9 @@ bool WebRenderBridgeParent::UpdateResources(
break;
}
case OpUpdateResource::TOpAddRawFont: {
const auto& op = cmd.get_OpAddRawFont();
wr::Vec<uint8_t> bytes;
if (!reader.Read(op.bytes(), bytes)) {
if (!ReadRawFont(cmd.get_OpAddRawFont(), reader, aUpdates)) {
return false;
}
aUpdates.AddRawFont(op.key(), bytes, op.fontIndex());
break;
}
case OpUpdateResource::TOpAddFontDescriptor: {

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

@ -27,7 +27,8 @@ class gfxOTSExpandingMemoryStream : public ots::OTSStream {
// limit output/expansion to 256MB by default
enum { DEFAULT_LIMIT = 256 * 1024 * 1024 };
gfxOTSExpandingMemoryStream(size_t initial, size_t limit = DEFAULT_LIMIT)
explicit gfxOTSExpandingMemoryStream(size_t initial,
size_t limit = DEFAULT_LIMIT)
: mLength(initial), mLimit(limit), mOff(0) {
mPtr = mAlloc.Grow(nullptr, mLength);
}

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

@ -652,12 +652,18 @@ struct Vec<uint8_t> final {
inner.length = 0;
}
uint8_t* Data() { return inner.data; }
size_t Length() { return inner.length; }
Range<uint8_t> GetRange() { return Range<uint8_t>(Data(), Length()); }
void PushBytes(Range<uint8_t> aBytes) {
wr_vec_u8_push_bytes(&inner, RangeToByteSlice(aBytes));
}
void Reserve(size_t aLength) { wr_vec_u8_reserve(&inner, aLength); }
~Vec() {
if (inner.data) {
wr_vec_u8_free(inner);

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

@ -269,11 +269,18 @@ impl WrVecU8 {
w
}
fn reserve(&mut self, len: usize) {
let mut vec = self.flush_into_vec();
vec.reserve(len);
*self = Self::from_vec(vec);
}
fn push_bytes(&mut self, bytes: &[u8]) {
let mut vec = self.flush_into_vec();
vec.extend_from_slice(bytes);
*self = Self::from_vec(vec);
}
}
#[no_mangle]
@ -281,6 +288,11 @@ pub extern "C" fn wr_vec_u8_push_bytes(v: &mut WrVecU8, bytes: ByteSlice) {
v.push_bytes(bytes.as_slice());
}
#[no_mangle]
pub extern "C" fn wr_vec_u8_reserve(v: &mut WrVecU8, len: usize) {
v.reserve(len);
}
#[no_mangle]
pub extern "C" fn wr_vec_u8_free(v: WrVecU8) {
v.to_vec();