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>
diff --git a/src/dawn_wire/BUILD.gn b/src/dawn_wire/BUILD.gn
index 04340b0..4b21299 100644
--- a/src/dawn_wire/BUILD.gn
+++ b/src/dawn_wire/BUILD.gn
@@ -63,6 +63,7 @@
"ChunkedCommandHandler.h",
"ChunkedCommandSerializer.cpp",
"ChunkedCommandSerializer.h",
+ "Wire.cpp",
"WireClient.cpp",
"WireDeserializeAllocator.cpp",
"WireDeserializeAllocator.h",
diff --git a/src/dawn_wire/CMakeLists.txt b/src/dawn_wire/CMakeLists.txt
index 2776bb4..d6d430f 100644
--- a/src/dawn_wire/CMakeLists.txt
+++ b/src/dawn_wire/CMakeLists.txt
@@ -35,6 +35,7 @@
"ChunkedCommandHandler.h"
"ChunkedCommandSerializer.cpp"
"ChunkedCommandSerializer.h"
+ "Wire.cpp"
"WireClient.cpp"
"WireDeserializeAllocator.cpp"
"WireDeserializeAllocator.h"
diff --git a/src/dawn_wire/ChunkedCommandSerializer.h b/src/dawn_wire/ChunkedCommandSerializer.h
index 1f21dcd..e62cb99 100644
--- a/src/dawn_wire/ChunkedCommandSerializer.h
+++ b/src/dawn_wire/ChunkedCommandSerializer.h
@@ -32,7 +32,7 @@
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 @@
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 @@
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 @@
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 @@
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);
}
diff --git a/src/dawn_wire/Wire.cpp b/src/dawn_wire/Wire.cpp
new file mode 100644
index 0000000..89e5ac1
--- /dev/null
+++ b/src/dawn_wire/Wire.cpp
@@ -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
diff --git a/src/dawn_wire/client/Buffer.cpp b/src/dawn_wire/client/Buffer.cpp
index da3691c..4f45984 100644
--- a/src/dawn_wire/client/Buffer.cpp
+++ b/src/dawn_wire/client/Buffer.cpp
@@ -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 @@
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 @@
// 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 @@
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) {
diff --git a/src/dawn_wire/server/ServerBuffer.cpp b/src/dawn_wire/server/ServerBuffer.cpp
index 7cc5c9b..c279845 100644
--- a/src/dawn_wire/server/ServerBuffer.cpp
+++ b/src/dawn_wire/server/ServerBuffer.cpp
@@ -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 @@
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 @@
data->size);
}
}
+ return true;
});
}
diff --git a/src/include/dawn_wire/Wire.h b/src/include/dawn_wire/Wire.h
index bb46701..590a6cc 100644
--- a/src/include/dawn_wire/Wire.h
+++ b/src/include/dawn_wire/Wire.h
@@ -25,7 +25,7 @@
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 @@
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;
};