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