dawn_wire: Protect against large allocations in ChunkedCommandHandler

Use std::nothrow on the allocation to catch failed allocations. Enforce
a max allocation limit a bit lower than ASAN's max 2GB allocation.

Bug: chromium:1145204
Change-Id: I91f2ddd5b58da6c39d4ab8bc447f7d9b7af8615f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/32340
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
Austin Eng 2020-11-13 01:49:12 +00:00 committed by Commit Bot service account
parent 8d69298d9b
commit bc6a700bf5
2 changed files with 38 additions and 21 deletions

View File

@ -28,39 +28,56 @@ namespace dawn_wire {
// in-flight chunked command, and then pass the rest along to a second call to
// |HandleCommandsImpl|.
size_t chunkSize = std::min(size, mChunkedCommandRemainingSize);
mChunkedCommandData.insert(mChunkedCommandData.end(), commands, commands + chunkSize);
memcpy(mChunkedCommandData.get() + mChunkedCommandPutOffset,
const_cast<const char*>(commands), chunkSize);
mChunkedCommandPutOffset += chunkSize;
mChunkedCommandRemainingSize -= chunkSize;
commands += chunkSize;
mChunkedCommandRemainingSize -= chunkSize;
size -= chunkSize;
if (mChunkedCommandRemainingSize == 0) {
// Once the chunked command is complete, pass the data to the command handler
// implemenation.
const char* chunkedCommands = mChunkedCommandData.data();
size_t chunkedSize = mChunkedCommandData.size();
if (HandleCommandsImpl(chunkedCommands, chunkedSize) == nullptr) {
auto chunkedCommandData = std::move(mChunkedCommandData);
if (HandleCommandsImpl(chunkedCommandData.get(), mChunkedCommandPutOffset) ==
nullptr) {
// |HandleCommandsImpl| returns nullptr on error. Forward any errors
// out.
return nullptr;
}
mChunkedCommandData.clear();
}
}
return HandleCommandsImpl(commands, size);
}
void ChunkedCommandHandler::BeginChunkedCommandData(const volatile char* commands,
size_t commandSize,
size_t initialSize) {
ASSERT(mChunkedCommandData.empty());
ChunkedCommandHandler::ChunkedCommandsResult ChunkedCommandHandler::BeginChunkedCommandData(
const volatile char* commands,
size_t commandSize,
size_t initialSize) {
ASSERT(!mChunkedCommandData);
// Reserve space for all the command data we're expecting, and append the initial data
// to the end of the vector.
#if defined(ADDRESS_SANITIZER)
if (commandSize >= 0x70000000) {
// std::nothrow isn't implemented on ASAN and it has a 2GB allocation limit.
// Catch large allocations and error out so fuzzers make progress.
return ChunkedCommandsResult::Error;
}
#endif
// Reserve space for all the command data we're expecting, and copy the initial data
// to the start of the memory.
mChunkedCommandData.reset(new (std::nothrow) char[commandSize]);
if (!mChunkedCommandData) {
return ChunkedCommandsResult::Error;
}
memcpy(mChunkedCommandData.get(), const_cast<const char*>(commands), initialSize);
mChunkedCommandPutOffset = initialSize;
mChunkedCommandRemainingSize = commandSize - initialSize;
mChunkedCommandData.reserve(commandSize);
mChunkedCommandData.insert(mChunkedCommandData.end(), commands, commands + initialSize);
return ChunkedCommandsResult::Consumed;
}
} // namespace dawn_wire

View File

@ -20,7 +20,7 @@
#include "dawn_wire/WireCmd_autogen.h"
#include <cstdint>
#include <vector>
#include <memory>
namespace dawn_wire {
@ -48,8 +48,7 @@ namespace dawn_wire {
}
size_t commandSize = static_cast<size_t>(commandSize64);
if (size < commandSize) {
BeginChunkedCommandData(commands, commandSize, size);
return ChunkedCommandsResult::Consumed;
return BeginChunkedCommandData(commands, commandSize, size);
}
return ChunkedCommandsResult::Passthrough;
}
@ -58,12 +57,13 @@ namespace dawn_wire {
virtual const volatile char* HandleCommandsImpl(const volatile char* commands,
size_t size) = 0;
void BeginChunkedCommandData(const volatile char* commands,
size_t commandSize,
size_t initialSize);
ChunkedCommandsResult BeginChunkedCommandData(const volatile char* commands,
size_t commandSize,
size_t initialSize);
size_t mChunkedCommandRemainingSize = 0;
std::vector<char> mChunkedCommandData;
size_t mChunkedCommandPutOffset = 0;
std::unique_ptr<char[]> mChunkedCommandData;
};
} // namespace dawn_wire