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
|
// in-flight chunked command, and then pass the rest along to a second call to
|
||||||
// |HandleCommandsImpl|.
|
// |HandleCommandsImpl|.
|
||||||
size_t chunkSize = std::min(size, mChunkedCommandRemainingSize);
|
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;
|
commands += chunkSize;
|
||||||
mChunkedCommandRemainingSize -= chunkSize;
|
|
||||||
size -= chunkSize;
|
size -= chunkSize;
|
||||||
|
|
||||||
if (mChunkedCommandRemainingSize == 0) {
|
if (mChunkedCommandRemainingSize == 0) {
|
||||||
// Once the chunked command is complete, pass the data to the command handler
|
// Once the chunked command is complete, pass the data to the command handler
|
||||||
// implemenation.
|
// implemenation.
|
||||||
const char* chunkedCommands = mChunkedCommandData.data();
|
auto chunkedCommandData = std::move(mChunkedCommandData);
|
||||||
size_t chunkedSize = mChunkedCommandData.size();
|
if (HandleCommandsImpl(chunkedCommandData.get(), mChunkedCommandPutOffset) ==
|
||||||
if (HandleCommandsImpl(chunkedCommands, chunkedSize) == nullptr) {
|
nullptr) {
|
||||||
// |HandleCommandsImpl| returns nullptr on error. Forward any errors
|
// |HandleCommandsImpl| returns nullptr on error. Forward any errors
|
||||||
// out.
|
// out.
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
mChunkedCommandData.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return HandleCommandsImpl(commands, size);
|
return HandleCommandsImpl(commands, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunkedCommandHandler::BeginChunkedCommandData(const volatile char* commands,
|
ChunkedCommandHandler::ChunkedCommandsResult ChunkedCommandHandler::BeginChunkedCommandData(
|
||||||
size_t commandSize,
|
const volatile char* commands,
|
||||||
size_t initialSize) {
|
size_t commandSize,
|
||||||
ASSERT(mChunkedCommandData.empty());
|
size_t initialSize) {
|
||||||
|
ASSERT(!mChunkedCommandData);
|
||||||
|
|
||||||
// Reserve space for all the command data we're expecting, and append the initial data
|
#if defined(ADDRESS_SANITIZER)
|
||||||
// to the end of the vector.
|
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;
|
mChunkedCommandRemainingSize = commandSize - initialSize;
|
||||||
mChunkedCommandData.reserve(commandSize);
|
|
||||||
mChunkedCommandData.insert(mChunkedCommandData.end(), commands, commands + initialSize);
|
return ChunkedCommandsResult::Consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace dawn_wire
|
} // namespace dawn_wire
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "dawn_wire/WireCmd_autogen.h"
|
#include "dawn_wire/WireCmd_autogen.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <memory>
|
||||||
|
|
||||||
namespace dawn_wire {
|
namespace dawn_wire {
|
||||||
|
|
||||||
|
@ -48,8 +48,7 @@ namespace dawn_wire {
|
||||||
}
|
}
|
||||||
size_t commandSize = static_cast<size_t>(commandSize64);
|
size_t commandSize = static_cast<size_t>(commandSize64);
|
||||||
if (size < commandSize) {
|
if (size < commandSize) {
|
||||||
BeginChunkedCommandData(commands, commandSize, size);
|
return BeginChunkedCommandData(commands, commandSize, size);
|
||||||
return ChunkedCommandsResult::Consumed;
|
|
||||||
}
|
}
|
||||||
return ChunkedCommandsResult::Passthrough;
|
return ChunkedCommandsResult::Passthrough;
|
||||||
}
|
}
|
||||||
|
@ -58,12 +57,13 @@ namespace dawn_wire {
|
||||||
virtual const volatile char* HandleCommandsImpl(const volatile char* commands,
|
virtual const volatile char* HandleCommandsImpl(const volatile char* commands,
|
||||||
size_t size) = 0;
|
size_t size) = 0;
|
||||||
|
|
||||||
void BeginChunkedCommandData(const volatile char* commands,
|
ChunkedCommandsResult BeginChunkedCommandData(const volatile char* commands,
|
||||||
size_t commandSize,
|
size_t commandSize,
|
||||||
size_t initialSize);
|
size_t initialSize);
|
||||||
|
|
||||||
size_t mChunkedCommandRemainingSize = 0;
|
size_t mChunkedCommandRemainingSize = 0;
|
||||||
std::vector<char> mChunkedCommandData;
|
size_t mChunkedCommandPutOffset = 0;
|
||||||
|
std::unique_ptr<char[]> mChunkedCommandData;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dawn_wire
|
} // namespace dawn_wire
|
||||||
|
|
Loading…
Reference in New Issue