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:
parent
8d69298d9b
commit
bc6a700bf5
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue