summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-10-15 12:00:28 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-10-16 12:25:47 +0000
commit858447a7654404e4c266c147023e1cc30c38b809 (patch)
treeda1f922d731ed7511ca2115b00f0b74031c4c6e5
parent6114514c9e767eefd222ae96973e8e3c7d73db0c (diff)
downloadqtwebengine-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.cc40
-rw-r--r--chromium/ui/gfx/buffer_format_util.cc102
-rw-r--r--chromium/ui/gfx/buffer_format_util.h5
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,