diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-10-15 12:00:28 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-10-16 12:25:47 +0000 |
commit | 858447a7654404e4c266c147023e1cc30c38b809 (patch) | |
tree | da1f922d731ed7511ca2115b00f0b74031c4c6e5 | |
parent | 6114514c9e767eefd222ae96973e8e3c7d73db0c (diff) | |
download | qtwebengine-chromium-858447a7654404e4c266c147023e1cc30c38b809.tar.gz |
[Backport] Security issue 974354 [2/2]
Fix GpuMemoryBufferImplSharedMemory to validate received handles.
GpuMemoryBufferImplSharedMemory wasn't verifying buffer size of
the buffer it was receiving from another process.
Bug: 974354
Change-Id: I59be4278e3ac57953955153697109c7438d2c428
Commit-Queue: Sergey Ulanov <sergeyu@chromium.org>
Reviewed-by: Michael Spang <spang@chromium.org>
Reviewed-by: Dominick Ng <dominickn@chromium.org>
Cr-Commit-Position: refs/heads/master@{#675463}
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
-rw-r--r-- | chromium/gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.cc | 40 | ||||
-rw-r--r-- | chromium/ui/gfx/buffer_format_util.cc | 102 | ||||
-rw-r--r-- | chromium/ui/gfx/buffer_format_util.h | 5 |
3 files changed, 96 insertions, 51 deletions
diff --git a/chromium/gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.cc b/chromium/gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.cc index 3ea3fa8996a..771cf1cef5e 100644 --- a/chromium/gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.cc +++ b/chromium/gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.cc @@ -105,6 +105,46 @@ GpuMemoryBufferImplSharedMemory::CreateFromHandle( DestructionCallback callback) { DCHECK(handle.region.IsValid()); + size_t minimum_stride = 0; + if (!gfx::RowSizeForBufferFormatChecked(size.width(), format, 0, + &minimum_stride)) { + return nullptr; + } + + size_t min_buffer_size = 0; + + if (gfx::NumberOfPlanesForBufferFormat(format) == 1) { + if (static_cast<size_t>(handle.stride) < minimum_stride) + return nullptr; + + base::CheckedNumeric<size_t> checked_min_buffer_size = + base::MakeCheckedNum(handle.stride) * + (base::MakeCheckedNum(size.height()) - 1) + + minimum_stride; + if (!checked_min_buffer_size.AssignIfValid(&min_buffer_size)) + return nullptr; + } else { + // Custom layout (i.e. non-standard stride) is not allowed for multi-plane + // formats. + if (static_cast<size_t>(handle.stride) != minimum_stride) + return nullptr; + + if (!gfx::BufferSizeForBufferFormatChecked(size, format, + &min_buffer_size)) { + return nullptr; + } + } + + size_t min_buffer_size_with_offset = 0; + if (!base::CheckAdd(handle.offset, min_buffer_size) + .AssignIfValid(&min_buffer_size_with_offset)) { + return nullptr; + } + + if (min_buffer_size_with_offset > handle.region.GetSize()) { + return nullptr; + } + return base::WrapUnique(new GpuMemoryBufferImplSharedMemory( handle.id, size, format, usage, std::move(callback), std::move(handle.region), base::WritableSharedMemoryMapping(), diff --git a/chromium/ui/gfx/buffer_format_util.cc b/chromium/ui/gfx/buffer_format_util.cc index 22326d53e43..0cdc7a2ea69 100644 --- a/chromium/ui/gfx/buffer_format_util.cc +++ b/chromium/ui/gfx/buffer_format_util.cc @@ -25,57 +25,6 @@ static_assert(base::size(kBufferFormats) == (static_cast<int>(BufferFormat::LAST) + 1), "BufferFormat::LAST must be last value of kBufferFormats"); -bool RowSizeForBufferFormatChecked( - size_t width, BufferFormat format, size_t plane, size_t* size_in_bytes) { - base::CheckedNumeric<size_t> checked_size = width; - switch (format) { - case BufferFormat::R_8: - checked_size += 3; - if (!checked_size.IsValid()) - return false; - *size_in_bytes = (checked_size & ~0x3).ValueOrDie(); - return true; - case BufferFormat::R_16: - case BufferFormat::RG_88: - case BufferFormat::BGR_565: - case BufferFormat::RGBA_4444: - case BufferFormat::UYVY_422: - checked_size *= 2; - checked_size += 3; - if (!checked_size.IsValid()) - return false; - *size_in_bytes = (checked_size & ~0x3).ValueOrDie(); - return true; - case BufferFormat::BGRX_8888: - case BufferFormat::BGRX_1010102: - case BufferFormat::RGBX_1010102: - case BufferFormat::RGBX_8888: - case BufferFormat::RGBA_8888: - case BufferFormat::BGRA_8888: - checked_size *= 4; - if (!checked_size.IsValid()) - return false; - *size_in_bytes = checked_size.ValueOrDie(); - return true; - case BufferFormat::RGBA_F16: - checked_size *= 8; - if (!checked_size.IsValid()) - return false; - *size_in_bytes = checked_size.ValueOrDie(); - return true; - case BufferFormat::YVU_420: - DCHECK_EQ(0u, width % 2); - *size_in_bytes = width / SubsamplingFactorForBufferFormat(format, plane); - return true; - case BufferFormat::YUV_420_BIPLANAR: - DCHECK_EQ(width % 2, 0u); - *size_in_bytes = width; - return true; - } - NOTREACHED(); - return false; -} - } // namespace std::vector<BufferFormat> GetBufferFormatsForTesting() { @@ -146,6 +95,57 @@ size_t RowSizeForBufferFormat(size_t width, BufferFormat format, size_t plane) { return row_size; } +bool RowSizeForBufferFormatChecked( + size_t width, BufferFormat format, size_t plane, size_t* size_in_bytes) { + base::CheckedNumeric<size_t> checked_size = width; + switch (format) { + case BufferFormat::R_8: + checked_size += 3; + if (!checked_size.IsValid()) + return false; + *size_in_bytes = (checked_size & ~0x3).ValueOrDie(); + return true; + case BufferFormat::R_16: + case BufferFormat::RG_88: + case BufferFormat::BGR_565: + case BufferFormat::RGBA_4444: + case BufferFormat::UYVY_422: + checked_size *= 2; + checked_size += 3; + if (!checked_size.IsValid()) + return false; + *size_in_bytes = (checked_size & ~0x3).ValueOrDie(); + return true; + case BufferFormat::BGRX_8888: + case BufferFormat::BGRX_1010102: + case BufferFormat::RGBX_1010102: + case BufferFormat::RGBX_8888: + case BufferFormat::RGBA_8888: + case BufferFormat::BGRA_8888: + checked_size *= 4; + if (!checked_size.IsValid()) + return false; + *size_in_bytes = checked_size.ValueOrDie(); + return true; + case BufferFormat::RGBA_F16: + checked_size *= 8; + if (!checked_size.IsValid()) + return false; + *size_in_bytes = checked_size.ValueOrDie(); + return true; + case BufferFormat::YVU_420: + DCHECK_EQ(0u, width % 2); + *size_in_bytes = width / SubsamplingFactorForBufferFormat(format, plane); + return true; + case BufferFormat::YUV_420_BIPLANAR: + DCHECK_EQ(width % 2, 0u); + *size_in_bytes = width; + return true; + } + NOTREACHED(); + return false; +} + size_t BufferSizeForBufferFormat(const Size& size, BufferFormat format) { size_t buffer_size = 0; bool valid = BufferSizeForBufferFormatChecked(size, format, &buffer_size); diff --git a/chromium/ui/gfx/buffer_format_util.h b/chromium/ui/gfx/buffer_format_util.h index 492638811b3..56f4c768e75 100644 --- a/chromium/ui/gfx/buffer_format_util.h +++ b/chromium/ui/gfx/buffer_format_util.h @@ -31,6 +31,11 @@ GFX_EXPORT size_t SubsamplingFactorForBufferFormat(BufferFormat format, GFX_EXPORT size_t RowSizeForBufferFormat(size_t width, BufferFormat format, size_t plane); +GFX_EXPORT bool RowSizeForBufferFormatChecked(size_t width, + BufferFormat format, + size_t plane, + size_t* size_in_bytes) + WARN_UNUSED_RESULT; // Returns the number of bytes used to store all the planes of a given |format|. GFX_EXPORT size_t BufferSizeForBufferFormat(const Size& size, |