summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael BrĂ¼ning <michael.bruning@qt.io>2020-01-15 16:48:35 +0100
committerMichael BrĂ¼ning <michael.bruning@qt.io>2020-01-16 13:10:15 +0000
commit8417e8352600298a901aeb0360eba25361b2343d (patch)
treec5a839ac489df2b9f954b72d4949776b9a254cfe
parentfd8cf772447ea3567c4301cbd02ecdaeb312cd27 (diff)
downloadqtwebengine-chromium-8417e8352600298a901aeb0360eba25361b2343d.tar.gz
[Backport] Security bug 974375
Manual backport of patch: Implement NativePixmapHandle validation Now ClientNativePixmapDmaBuf and ScenicClientNativePixmapFactory validate layout of the NativePixmapHandle to ensure that the buffer fits the image. Bug: 957314, 974375 Change-Id: Ifc0c0deae2c833e7a74ae96f84a41ae4a0657890 Reviewed-by: Michal Klocek <michal.klocek@qt.io>
-rw-r--r--chromium/gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap.cc3
-rw-r--r--chromium/ui/gfx/client_native_pixmap_factory.h3
-rw-r--r--chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc25
-rw-r--r--chromium/ui/gfx/linux/client_native_pixmap_dmabuf.h3
-rw-r--r--chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc2
-rw-r--r--chromium/ui/ozone/platform/scenic/client_native_pixmap_factory_scenic.cc40
6 files changed, 71 insertions, 5 deletions
diff --git a/chromium/gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap.cc b/chromium/gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap.cc
index 00f86254b99..d581fcff6f8 100644
--- a/chromium/gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap.cc
+++ b/chromium/gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap.cc
@@ -56,7 +56,8 @@ GpuMemoryBufferImplNativePixmap::CreateFromHandle(
std::unique_ptr<gfx::ClientNativePixmap> native_pixmap =
client_native_pixmap_factory->ImportFromHandle(
CloneHandleForIPC(handle.native_pixmap_handle), size, format, usage);
- DCHECK(native_pixmap);
+ if (!native_pixmap)
+ return nullptr;
return base::WrapUnique(new GpuMemoryBufferImplNativePixmap(
handle.id, size, format, std::move(callback), std::move(native_pixmap),
diff --git a/chromium/ui/gfx/client_native_pixmap_factory.h b/chromium/ui/gfx/client_native_pixmap_factory.h
index 566590a8f07..96aede0503c 100644
--- a/chromium/ui/gfx/client_native_pixmap_factory.h
+++ b/chromium/ui/gfx/client_native_pixmap_factory.h
@@ -26,7 +26,8 @@ class GFX_EXPORT ClientNativePixmapFactory {
virtual ~ClientNativePixmapFactory() {}
// Import the native pixmap from |handle| to be used in non-GPU processes.
- // This function takes ownership of any file descriptors in |handle|.
+ // Implementations must verify that the buffer in |handle| fits an image of
+ // the specified |size| and |format|. Otherwise nullptr is returned.
virtual std::unique_ptr<ClientNativePixmap> ImportFromHandle(
gfx::NativePixmapHandle handle,
const gfx::Size& size,
diff --git a/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc b/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc
index aab699da8ea..2c9e6ff9fa8 100644
--- a/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc
+++ b/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc
@@ -22,6 +22,7 @@
#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
+#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/switches.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
@@ -169,11 +170,33 @@ bool ClientNativePixmapDmaBuf::IsConfigurationSupported(
// static
std::unique_ptr<gfx::ClientNativePixmap>
ClientNativePixmapDmaBuf::ImportFromDmabuf(gfx::NativePixmapHandle handle,
- const gfx::Size& size) {
+ const gfx::Size& size,
+ gfx::BufferFormat format) {
std::array<PlaneInfo, kMaxPlanes> plane_info;
+ size_t expected_planes = gfx::NumberOfPlanesForLinearBufferFormat(format);
+ if (expected_planes == 0 || handle.planes.size() != expected_planes) {
+ return nullptr;
+ }
+
const size_t page_size = base::GetPageSize();
for (size_t i = 0; i < handle.planes.size(); ++i) {
+ // Verify that the plane buffer has appropriate size.
+ size_t min_stride = 0;
+ size_t subsample_factor = SubsamplingFactorForBufferFormat(format, i);
+ base::CheckedNumeric<size_t> plane_height =
+ (base::CheckedNumeric<size_t>(size.height()) + subsample_factor - 1) /
+ subsample_factor;
+ if (!gfx::RowSizeForBufferFormatChecked(size.width(), format, i,
+ &min_stride) ||
+ handle.planes[i].stride < min_stride) {
+ return nullptr;
+ }
+ base::CheckedNumeric<size_t> min_size =
+ base::CheckedNumeric<size_t>(handle.planes[i].stride) * plane_height;
+ if (!min_size.IsValid() || handle.planes[i].size < min_size.ValueOrDie())
+ return nullptr;
+
// mmap() fails if the offset argument is not page-aligned.
// Since handle.planes[i].offset is possibly not page-aligned, we
// have to map with an additional offset to be aligned to the page.
diff --git a/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.h b/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.h
index e337c574e28..6c5737cd3d2 100644
--- a/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.h
+++ b/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.h
@@ -27,7 +27,8 @@ class ClientNativePixmapDmaBuf : public gfx::ClientNativePixmap {
static std::unique_ptr<gfx::ClientNativePixmap> ImportFromDmabuf(
gfx::NativePixmapHandle handle,
- const gfx::Size& size);
+ const gfx::Size& size,
+ gfx::BufferFormat format);
~ClientNativePixmapDmaBuf() override;
diff --git a/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc b/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
index 652c23d86f1..201adb1dd3b 100644
--- a/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
+++ b/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
@@ -60,7 +60,7 @@ class ClientNativePixmapFactoryDmabuf : public ClientNativePixmapFactory {
case gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE:
case gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE:
return ClientNativePixmapDmaBuf::ImportFromDmabuf(std::move(handle),
- size);
+ size, format);
case gfx::BufferUsage::GPU_READ:
case gfx::BufferUsage::SCANOUT:
case gfx::BufferUsage::SCANOUT_VDA_WRITE:
diff --git a/chromium/ui/ozone/platform/scenic/client_native_pixmap_factory_scenic.cc b/chromium/ui/ozone/platform/scenic/client_native_pixmap_factory_scenic.cc
index 392670e097f..7df278b7110 100644
--- a/chromium/ui/ozone/platform/scenic/client_native_pixmap_factory_scenic.cc
+++ b/chromium/ui/ozone/platform/scenic/client_native_pixmap_factory_scenic.cc
@@ -10,6 +10,7 @@
#include "base/fuchsia/fuchsia_logging.h"
#include "base/system/sys_info.h"
+#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/client_native_pixmap.h"
#include "ui/gfx/client_native_pixmap_factory.h"
#include "ui/gfx/native_pixmap_handle.h"
@@ -101,8 +102,47 @@ class ScenicClientNativePixmapFactory : public gfx::ClientNativePixmapFactory {
const gfx::Size& size,
gfx::BufferFormat format,
gfx::BufferUsage usage) override {
+ // |planes| may be empty for non-mappable pixmaps. No need to validate the
+ // handle in that case.
if (handle.planes.empty())
+ return std::make_unique<ClientNativePixmapFuchsia>(std::move(handle));
+
+ size_t expected_planes = gfx::NumberOfPlanesForLinearBufferFormat(format);
+ if (handle.planes.size() != expected_planes)
+ return nullptr;
+
+ base::CheckedNumeric<size_t> vmo_size_checked =
+ base::CheckedNumeric<size_t>(handle.planes.back().offset) +
+ handle.planes.back().size;
+ if (!vmo_size_checked.IsValid()) {
return nullptr;
+ }
+ size_t vmo_size = vmo_size_checked.ValueOrDie();
+
+ // Validate plane layout and buffer size.
+ for (size_t i = 0; i < handle.planes.size(); ++i) {
+ size_t min_stride = 0;
+ size_t subsample_factor = SubsamplingFactorForBufferFormat(format, i);
+ base::CheckedNumeric<size_t> plane_height =
+ (base::CheckedNumeric<size_t>(size.height()) + subsample_factor - 1) /
+ subsample_factor;
+ if (!gfx::RowSizeForBufferFormatChecked(size.width(), format, i,
+ &min_stride) ||
+ handle.planes[i].stride < min_stride) {
+ return nullptr;
+ }
+
+ base::CheckedNumeric<size_t> min_size =
+ base::CheckedNumeric<size_t>(handle.planes[i].stride) * plane_height;
+ if (!min_size.IsValid() || handle.planes[i].size < min_size.ValueOrDie())
+ return nullptr;
+
+ base::CheckedNumeric<size_t> end_pos =
+ base::CheckedNumeric<size_t>(handle.planes[i].offset) +
+ handle.planes[i].size;
+ if (!end_pos.IsValid() || end_pos.ValueOrDie() > vmo_size)
+ return nullptr;
+ }
return std::make_unique<ClientNativePixmapFuchsia>(std::move(handle));
}