| From cbd75e97a525e3819c02dc18bc2d67aa544c9e45 Mon Sep 17 00:00:00 2001 |
| From: Thomas Hellstrom <thellstrom@vmware.com> |
| Date: Tue, 15 Apr 2014 18:25:48 +0200 |
| Subject: drm/vmwgfx: Make sure user-space can't DMA across buffer object boundaries v2 |
| |
| From: Thomas Hellstrom <thellstrom@vmware.com> |
| |
| commit cbd75e97a525e3819c02dc18bc2d67aa544c9e45 upstream. |
| |
| We already check that the buffer object we're accessing is registered with |
| the file. Now also make sure that we can't DMA across buffer object boundaries. |
| |
| v2: Code commenting update. |
| |
| Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> |
| Reviewed-by: Jakob Bornecrantz <jakob@vmware.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 22 ++++++++++++++++++++++ |
| 1 file changed, 22 insertions(+) |
| |
| --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c |
| +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c |
| @@ -1214,14 +1214,36 @@ static int vmw_cmd_dma(struct vmw_privat |
| SVGA3dCmdSurfaceDMA dma; |
| } *cmd; |
| int ret; |
| + SVGA3dCmdSurfaceDMASuffix *suffix; |
| + uint32_t bo_size; |
| |
| cmd = container_of(header, struct vmw_dma_cmd, header); |
| + suffix = (SVGA3dCmdSurfaceDMASuffix *)((unsigned long) &cmd->dma + |
| + header->size - sizeof(*suffix)); |
| + |
| + /* Make sure device and verifier stays in sync. */ |
| + if (unlikely(suffix->suffixSize != sizeof(*suffix))) { |
| + DRM_ERROR("Invalid DMA suffix size.\n"); |
| + return -EINVAL; |
| + } |
| + |
| ret = vmw_translate_guest_ptr(dev_priv, sw_context, |
| &cmd->dma.guest.ptr, |
| &vmw_bo); |
| if (unlikely(ret != 0)) |
| return ret; |
| |
| + /* Make sure DMA doesn't cross BO boundaries. */ |
| + bo_size = vmw_bo->base.num_pages * PAGE_SIZE; |
| + if (unlikely(cmd->dma.guest.ptr.offset > bo_size)) { |
| + DRM_ERROR("Invalid DMA offset.\n"); |
| + return -EINVAL; |
| + } |
| + |
| + bo_size -= cmd->dma.guest.ptr.offset; |
| + if (unlikely(suffix->maximumOffset > bo_size)) |
| + suffix->maximumOffset = bo_size; |
| + |
| ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, |
| user_surface_converter, &cmd->dma.host.sid, |
| NULL); |