The UAPI struct drm_qxl_reloc declares src_offset as __u64, but the
internal struct qxl_reloc_info stores it as a signed int.  The
assignment silently truncates the 64-bit value without any bounds check.
A negative or very large truncated offset is then passed to
qxl_bo_physical_address(), which computes:

  slot->high_bits | ((bo->start << PAGE_SHIFT) + offset)

generating a physical address that points outside the source BO.  The
SPICE virtual GPU then interprets this forged address, potentially
reading from arbitrary device memory.

Fix by:
  - Changing src_offset in struct qxl_reloc_info from int to uint32_t
    to prevent sign extension.
  - Validating reloc.src_offset against the source BO size before
    the assignment.

Fixes: f64122c1f6ad ("drm: add qxl driver.")
Cc: [email protected]
Signed-off-by: Aldo Ariel Panzardo <[email protected]>
---
 drivers/gpu/drm/qxl/qxl_ioctl.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c
index 9fba6e26d..6559ba7d8 100644
--- a/drivers/gpu/drm/qxl/qxl_ioctl.c
+++ b/drivers/gpu/drm/qxl/qxl_ioctl.c
@@ -75,7 +75,7 @@ struct qxl_reloc_info {
        struct qxl_bo *dst_bo;
        uint32_t dst_offset;
        struct qxl_bo *src_bo;
-       int src_offset;
+       uint32_t src_offset;
 };
 
 /*
@@ -259,6 +259,10 @@ static int qxl_process_single_command(struct qxl_device 
*qdev,
                                                 &reloc_info[i].src_bo);
                        if (ret)
                                goto out_free_bos;
+                       if (reloc.src_offset >= 
reloc_info[i].src_bo->tbo.base.size) {
+                               ret = -EINVAL;
+                               goto out_free_bos;
+                       }
                        reloc_info[i].src_offset = reloc.src_offset;
                } else {
                        reloc_info[i].src_bo = NULL;
-- 
2.43.0

Reply via email to