Commit aa16b2bc authored by Zack McKevitt's avatar Zack McKevitt Committed by Jeff Hugo
Browse files

accel/qaic: Add overflow check to remap_pfn_range during mmap



The call to remap_pfn_range in qaic_gem_object_mmap is susceptible to
(re)mapping beyond the VMA if the BO is too large. This can cause use
after free issues when munmap() unmaps only the VMA region and not the
additional mappings. To prevent this, check the remaining size of the
VMA before remapping and truncate the remapped length if sg->length is
too large.

Reported-by: default avatarLukas Maar <lukas.maar@tugraz.at>
Fixes: ff13be83 ("accel/qaic: Add datapath")
Reviewed-by: default avatarKarol Wachowski <karol.wachowski@linux.intel.com>
Signed-off-by: default avatarZack McKevitt <zachary.mckevitt@oss.qualcomm.com>
Reviewed-by: default avatarJeff Hugo <jeff.hugo@oss.qualcomm.com>
[jhugo: fix braces from checkpatch --strict]
Signed-off-by: default avatarJeff Hugo <jeff.hugo@oss.qualcomm.com>
Link: https://patch.msgid.link/20260430193858.1178641-1-zachary.mckevitt@oss.qualcomm.com
parent 53597dec
Loading
Loading
Loading
Loading
+21 −2
Original line number Diff line number Diff line
@@ -606,8 +606,11 @@ static const struct vm_operations_struct drm_vm_ops = {
static int qaic_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
{
	struct qaic_bo *bo = to_qaic_bo(obj);
	unsigned long remap_start;
	unsigned long offset = 0;
	unsigned long remap_end;
	struct scatterlist *sg;
	unsigned long length;
	int ret = 0;

	if (drm_gem_is_imported(obj))
@@ -615,11 +618,27 @@ static int qaic_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struc

	for (sg = bo->sgt->sgl; sg; sg = sg_next(sg)) {
		if (sg_page(sg)) {
			/* if sg is too large for the VMA, so truncate it to fit */
			if (check_add_overflow(vma->vm_start, offset, &remap_start))
				return -EINVAL;
			if (check_add_overflow(remap_start, sg->length, &remap_end))
				return -EINVAL;

			if (remap_end > vma->vm_end) {
				if (check_sub_overflow(vma->vm_end, remap_start, &length))
					return -EINVAL;
			} else {
				length = sg->length;
			}

			if (length == 0)
				goto out;

			ret = remap_pfn_range(vma, vma->vm_start + offset, page_to_pfn(sg_page(sg)),
					      sg->length, vma->vm_page_prot);
					      length, vma->vm_page_prot);
			if (ret)
				goto out;
			offset += sg->length;
			offset += length;
		}
	}