Add a BufferConsumer primitive for wire [de]serialization

BufferConsumer wraps a buffer pointer and size and exposes a
limited number of operations to get data while decrementing
the remaining available size. This makes it so that code
reading or writing into a buffer cannot easily consume more
bytes than available.

This CL guards against serialization overflows using
BufferConsumer, and it implements GetPtrFromBuffer
(for deserialization) on top of BufferConsumer. A future patch
will make the rest of the deserialization code use BufferConsumer.

Bug: dawn:680
Change-Id: Ic2bd6e7039e83ce70307c2ff47aaca9891c16d91
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/41780
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Stephen White <senorblanco@chromium.org>
This commit is contained in:
Austin Eng
2021-02-17 22:14:56 +00:00
committed by Commit Bot service account
parent eb71aaf689
commit 1b31dc0bb2
9 changed files with 236 additions and 84 deletions

View File

@@ -63,6 +63,7 @@ dawn_component("dawn_wire") {
"ChunkedCommandHandler.h",
"ChunkedCommandSerializer.cpp",
"ChunkedCommandSerializer.h",
"Wire.cpp",
"WireClient.cpp",
"WireDeserializeAllocator.cpp",
"WireDeserializeAllocator.h",

View File

@@ -35,6 +35,7 @@ target_sources(dawn_wire PRIVATE
"ChunkedCommandHandler.h"
"ChunkedCommandSerializer.cpp"
"ChunkedCommandSerializer.h"
"Wire.cpp"
"WireClient.cpp"
"WireDeserializeAllocator.cpp"
"WireDeserializeAllocator.h"

View File

@@ -32,7 +32,7 @@ namespace dawn_wire {
template <typename Cmd>
void SerializeCommand(const Cmd& cmd) {
SerializeCommand(cmd, 0, [](char*) {});
SerializeCommand(cmd, 0, [](SerializeBuffer*) { return true; });
}
template <typename Cmd, typename ExtraSizeSerializeFn>
@@ -41,15 +41,15 @@ namespace dawn_wire {
ExtraSizeSerializeFn&& SerializeExtraSize) {
SerializeCommandImpl(
cmd,
[](const Cmd& cmd, size_t requiredSize, char* allocatedBuffer) {
cmd.Serialize(requiredSize, allocatedBuffer);
[](const Cmd& cmd, size_t requiredSize, SerializeBuffer* serializeBuffer) {
return cmd.Serialize(requiredSize, serializeBuffer);
},
extraSize, std::forward<ExtraSizeSerializeFn>(SerializeExtraSize));
}
template <typename Cmd>
void SerializeCommand(const Cmd& cmd, const ObjectIdProvider& objectIdProvider) {
SerializeCommand(cmd, objectIdProvider, 0, [](char*) {});
SerializeCommand(cmd, objectIdProvider, 0, [](SerializeBuffer*) { return true; });
}
template <typename Cmd, typename ExtraSizeSerializeFn>
@@ -59,8 +59,9 @@ namespace dawn_wire {
ExtraSizeSerializeFn&& SerializeExtraSize) {
SerializeCommandImpl(
cmd,
[&objectIdProvider](const Cmd& cmd, size_t requiredSize, char* allocatedBuffer) {
cmd.Serialize(requiredSize, allocatedBuffer, objectIdProvider);
[&objectIdProvider](const Cmd& cmd, size_t requiredSize,
SerializeBuffer* serializeBuffer) {
return cmd.Serialize(requiredSize, serializeBuffer, objectIdProvider);
},
extraSize, std::forward<ExtraSizeSerializeFn>(SerializeExtraSize));
}
@@ -77,8 +78,13 @@ namespace dawn_wire {
if (requiredSize <= mMaxAllocationSize) {
char* allocatedBuffer = static_cast<char*>(mSerializer->GetCmdSpace(requiredSize));
if (allocatedBuffer != nullptr) {
SerializeCmd(cmd, requiredSize, allocatedBuffer);
SerializeExtraSize(allocatedBuffer + commandSize);
SerializeBuffer serializeBuffer(allocatedBuffer, requiredSize);
bool success = true;
success &= SerializeCmd(cmd, requiredSize, &serializeBuffer);
success &= SerializeExtraSize(&serializeBuffer);
if (DAWN_UNLIKELY(!success)) {
mSerializer->OnSerializeError();
}
}
return;
}
@@ -87,8 +93,14 @@ namespace dawn_wire {
if (!cmdSpace) {
return;
}
SerializeCmd(cmd, requiredSize, cmdSpace.get());
SerializeExtraSize(cmdSpace.get() + commandSize);
SerializeBuffer serializeBuffer(cmdSpace.get(), requiredSize);
bool success = true;
success &= SerializeCmd(cmd, requiredSize, &serializeBuffer);
success &= SerializeExtraSize(&serializeBuffer);
if (DAWN_UNLIKELY(!success)) {
mSerializer->OnSerializeError();
return;
}
SerializeChunkedCommand(cmdSpace.get(), requiredSize);
}

26
src/dawn_wire/Wire.cpp Normal file
View File

@@ -0,0 +1,26 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/Wire.h"
namespace dawn_wire {
CommandSerializer::~CommandSerializer() = default;
void CommandSerializer::OnSerializeError() {
}
CommandHandler::~CommandHandler() = default;
} // namespace dawn_wire

View File

@@ -14,6 +14,7 @@
#include "dawn_wire/client/Buffer.h"
#include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/client/Client.h"
#include "dawn_wire/client/Device.h"
@@ -73,19 +74,24 @@ namespace dawn_wire { namespace client {
cmd.handleCreateInfoLength = writeHandleCreateInfoLength;
cmd.handleCreateInfo = nullptr;
wireClient->SerializeCommand(cmd, writeHandleCreateInfoLength, [&](char* cmdSpace) {
if (descriptor->mappedAtCreation) {
// Serialize the WriteHandle into the space after the command.
writeHandle->SerializeCreate(cmdSpace);
wireClient->SerializeCommand(
cmd, writeHandleCreateInfoLength, [&](SerializeBuffer* serializeBuffer) {
if (descriptor->mappedAtCreation) {
if (serializeBuffer->AvailableSize() != writeHandleCreateInfoLength) {
return false;
}
// Serialize the WriteHandle into the space after the command.
writeHandle->SerializeCreate(serializeBuffer->Buffer());
// Set the buffer state for the mapping at creation. The buffer now owns the write
// handle..
buffer->mWriteHandle = std::move(writeHandle);
buffer->mMappedData = writeData;
buffer->mMapOffset = 0;
buffer->mMapSize = buffer->mSize;
}
});
// Set the buffer state for the mapping at creation. The buffer now owns the
// write handle..
buffer->mWriteHandle = std::move(writeHandle);
buffer->mMappedData = writeData;
buffer->mMapOffset = 0;
buffer->mMapSize = buffer->mSize;
}
return true;
});
return ToAPI(buffer);
}
@@ -199,15 +205,25 @@ namespace dawn_wire { namespace client {
// Step 3a. Fill the handle create info in the command.
if (isReadMode) {
cmd.handleCreateInfoLength = request.readHandle->SerializeCreateSize();
client->SerializeCommand(cmd, cmd.handleCreateInfoLength, [&](char* cmdSpace) {
request.readHandle->SerializeCreate(cmdSpace);
});
client->SerializeCommand(
cmd, cmd.handleCreateInfoLength, [&](SerializeBuffer* serializeBuffer) {
bool success = serializeBuffer->AvailableSize() == cmd.handleCreateInfoLength;
if (success) {
request.readHandle->SerializeCreate(serializeBuffer->Buffer());
}
return success;
});
} else {
ASSERT(isWriteMode);
cmd.handleCreateInfoLength = request.writeHandle->SerializeCreateSize();
client->SerializeCommand(cmd, cmd.handleCreateInfoLength, [&](char* cmdSpace) {
request.writeHandle->SerializeCreate(cmdSpace);
});
client->SerializeCommand(
cmd, cmd.handleCreateInfoLength, [&](SerializeBuffer* serializeBuffer) {
bool success = serializeBuffer->AvailableSize() == cmd.handleCreateInfoLength;
if (success) {
request.writeHandle->SerializeCreate(serializeBuffer->Buffer());
}
return success;
});
}
// Step 4. Register this request so that we can retrieve it from its serial when the server
@@ -334,11 +350,16 @@ namespace dawn_wire { namespace client {
cmd.writeFlushInfoLength = writeFlushInfoLength;
cmd.writeFlushInfo = nullptr;
client->SerializeCommand(cmd, writeFlushInfoLength, [&](char* cmdSpace) {
// Serialize flush metadata into the space after the command.
// This closes the handle for writing.
mWriteHandle->SerializeFlush(cmdSpace);
});
client->SerializeCommand(
cmd, writeFlushInfoLength, [&](SerializeBuffer* serializeBuffer) {
bool success = serializeBuffer->AvailableSize() == writeFlushInfoLength;
if (success) {
// Serialize flush metadata into the space after the command.
// This closes the handle for writing.
mWriteHandle->SerializeFlush(serializeBuffer->Buffer());
}
return success;
});
mWriteHandle = nullptr;
} else if (mReadHandle) {

View File

@@ -13,6 +13,7 @@
// limitations under the License.
#include "common/Assert.h"
#include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/server/Server.h"
#include <memory>
@@ -242,11 +243,15 @@ namespace dawn_wire { namespace server {
data->readHandle->SerializeInitialDataSize(readData, data->size);
}
SerializeCommand(cmd, cmd.readInitialDataInfoLength, [&](char* cmdSpace) {
SerializeCommand(cmd, cmd.readInitialDataInfoLength, [&](SerializeBuffer* serializeBuffer) {
if (isSuccess) {
if (isRead) {
if (serializeBuffer->AvailableSize() != cmd.readInitialDataInfoLength) {
return false;
}
// Serialize the initialization message into the space after the command.
data->readHandle->SerializeInitialData(readData, data->size, cmdSpace);
data->readHandle->SerializeInitialData(readData, data->size,
serializeBuffer->Buffer());
// The in-flight map request returned successfully.
// Move the ReadHandle so it is owned by the buffer.
bufferData->readHandle = std::move(data->readHandle);
@@ -261,6 +266,7 @@ namespace dawn_wire { namespace server {
data->size);
}
}
return true;
});
}

View File

@@ -25,7 +25,7 @@ namespace dawn_wire {
class DAWN_WIRE_EXPORT CommandSerializer {
public:
virtual ~CommandSerializer() = default;
virtual ~CommandSerializer();
// Get space for serializing commands.
// GetCmdSpace will never be called with a value larger than
@@ -34,11 +34,12 @@ namespace dawn_wire {
virtual void* GetCmdSpace(size_t size) = 0;
virtual bool Flush() = 0;
virtual size_t GetMaximumAllocationSize() const = 0;
virtual void OnSerializeError();
};
class DAWN_WIRE_EXPORT CommandHandler {
public:
virtual ~CommandHandler() = default;
virtual ~CommandHandler();
virtual const volatile char* HandleCommands(const volatile char* commands, size_t size) = 0;
};