Buffer: fix overflows in SetSubData and mapping validation

Also adds tests for overflows.

BUG=chromium:914240

Change-Id: Ibb4f86c04ffab1f1d834b8a439ba542a5291441f
Reviewed-on: https://dawn-review.googlesource.com/c/3320
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Corentin Wallez 2018-12-17 17:08:41 +00:00 committed by Commit Bot service account
parent 0d95887dbc
commit 6322010014
2 changed files with 58 additions and 7 deletions

View File

@ -166,8 +166,12 @@ namespace dawn_native {
}
MaybeError BufferBase::ValidateSetSubData(uint32_t start, uint32_t count) const {
// TODO(cwallez@chromium.org): check for overflows.
if (start + count > GetSize()) {
if (count > GetSize()) {
return DAWN_VALIDATION_ERROR("Buffer subdata with too much data");
}
// Note that no overflow can happen because we already checked for GetSize() >= count
if (start > GetSize() - count) {
return DAWN_VALIDATION_ERROR("Buffer subdata out of range");
}
@ -181,9 +185,13 @@ namespace dawn_native {
MaybeError BufferBase::ValidateMap(uint32_t start,
uint32_t size,
dawn::BufferUsageBit requiredUsage) const {
// TODO(cwallez@chromium.org): check for overflows.
if (start + size > GetSize()) {
return DAWN_VALIDATION_ERROR("Buffer map read out of range");
if (size > GetSize()) {
return DAWN_VALIDATION_ERROR("Buffer mapping with too big a region");
}
// Note that no overflow can happen because we already checked for GetSize() >= size
if (start > GetSize() - size) {
return DAWN_VALIDATION_ERROR("Buffer mapping out of range");
}
if (mIsMapped) {

View File

@ -187,6 +187,36 @@ TEST_F(BufferValidationTest, MapWriteOutOfRange) {
ASSERT_DEVICE_ERROR(buf.MapWriteAsync(0, 5, ToMockBufferMapWriteCallback, userdata));
}
// Test map reading out of range causes an error, with an overflow
TEST_F(BufferValidationTest, MapReadOutOfRangeOverflow) {
dawn::Buffer buf = CreateMapReadBuffer(4);
dawn::CallbackUserdata userdata = 40599;
EXPECT_CALL(*mockBufferMapReadCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR, nullptr, userdata))
.Times(1);
// An offset that when added to "2" would overflow to be zero and pass validation without
// overflow checks.
uint32_t offset = uint32_t(int32_t(0) - int32_t(2));
ASSERT_DEVICE_ERROR(buf.MapReadAsync(offset, 2, ToMockBufferMapReadCallback, userdata));
}
// Test map writing out of range causes an error, with an overflow
TEST_F(BufferValidationTest, MapWriteOutOfRangeOverflow) {
dawn::Buffer buf = CreateMapWriteBuffer(4);
dawn::CallbackUserdata userdata = 40599;
EXPECT_CALL(*mockBufferMapWriteCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR, nullptr, userdata))
.Times(1);
// An offset that when added to "2" would overflow to be zero and pass validation without
// overflow checks.
uint32_t offset = uint32_t(int32_t(0) - int32_t(2));
ASSERT_DEVICE_ERROR(buf.MapWriteAsync(offset, 5, ToMockBufferMapWriteCallback, userdata));
}
// Test map reading a buffer with wrong current usage
TEST_F(BufferValidationTest, MapReadWrongUsage) {
dawn::BufferDescriptor descriptor;
@ -437,8 +467,21 @@ TEST_F(BufferValidationTest, SetSubDataSuccess) {
TEST_F(BufferValidationTest, SetSubDataOutOfBounds) {
dawn::Buffer buf = CreateSetSubDataBuffer(1);
uint8_t foo = 0;
ASSERT_DEVICE_ERROR(buf.SetSubData(0, 2, &foo));
uint8_t foo[2] = {0, 0};
ASSERT_DEVICE_ERROR(buf.SetSubData(0, 2, foo));
}
// Test error case for SetSubData out of bounds with an overflow
TEST_F(BufferValidationTest, SetSubDataOutOfBoundsOverflow) {
dawn::Buffer buf = CreateSetSubDataBuffer(1000);
uint8_t foo[2] = {0, 0};
// An offset that when added to "2" would overflow to be zero and pass validation without
// overflow checks.
uint32_t offset = uint32_t(int32_t(0) - int32_t(2));
ASSERT_DEVICE_ERROR(buf.SetSubData(offset, 2, foo));
}
// Test error case for SetSubData with the wrong usage