]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
accel/ivpu: Validate scatter-gather size against buffer size
authorKarol Wachowski <karol.wachowski@linux.intel.com>
Mon, 15 Dec 2025 07:09:33 +0000 (08:09 +0100)
committerKarol Wachowski <karol.wachowski@linux.intel.com>
Tue, 16 Dec 2025 07:10:19 +0000 (08:10 +0100)
Validate scatter-gather table size matches buffer object size before
mapping. Break mapping early if the table exceeds buffer size to
prevent overwriting existing mappings. Also validate the table is
not smaller than buffer size to avoid unmapped regions that trigger
MMU translation faults.

Log error and fail mapping operation on size mismatch to prevent
data corruption from mismatched host memory locations and NPU
addresses. Unmap any partially mapped buffer on failure.

Reviewed-by: Lizhi Hou <lizhi.hou@amd.com>
Signed-off-by: Karol Wachowski <karol.wachowski@linux.intel.com>
Link: https://patch.msgid.link/20251215070933.520377-1-karol.wachowski@linux.intel.com
drivers/accel/ivpu/ivpu_gem.c
drivers/accel/ivpu/ivpu_mmu_context.c
drivers/accel/ivpu/ivpu_mmu_context.h

index ece68f570b7eadcbcae2ecfd0eb876a888977407..98b9ce26962b12a73bdd15c3c410d4d2993a5f1f 100644 (file)
@@ -95,7 +95,7 @@ int __must_check ivpu_bo_bind(struct ivpu_bo *bo)
 
        if (!bo->mmu_mapped) {
                drm_WARN_ON(&vdev->drm, !bo->ctx);
-               ret = ivpu_mmu_context_map_sgt(vdev, bo->ctx, bo->vpu_addr, sgt,
+               ret = ivpu_mmu_context_map_sgt(vdev, bo->ctx, bo->vpu_addr, sgt, ivpu_bo_size(bo),
                                               ivpu_bo_is_snooped(bo), ivpu_bo_is_read_only(bo));
                if (ret) {
                        ivpu_err(vdev, "Failed to map BO in MMU: %d\n", ret);
index 87ad593ef47d306ba737b9a61174602b1fa054d1..c4014c83e7271a7e89c37f4d916379f69933b98c 100644 (file)
@@ -429,11 +429,12 @@ static void ivpu_mmu_context_unmap_pages(struct ivpu_mmu_context *ctx, u64 vpu_a
 }
 
 int
-ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
-                        u64 vpu_addr, struct sg_table *sgt, bool llc_coherent, bool read_only)
+ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u64 vpu_addr,
+                        struct sg_table *sgt, size_t bo_size, bool llc_coherent, bool read_only)
 {
        size_t start_vpu_addr = vpu_addr;
        struct scatterlist *sg;
+       size_t sgt_size = 0;
        int ret;
        u64 prot;
        u64 i;
@@ -462,12 +463,25 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
                ivpu_dbg(vdev, MMU_MAP, "Map ctx: %u dma_addr: 0x%llx vpu_addr: 0x%llx size: %lu\n",
                         ctx->id, dma_addr, vpu_addr, size);
 
+               if (sgt_size + size > bo_size) {
+                       ivpu_err(vdev, "Scatter-gather table size exceeds buffer object size\n");
+                       ret = -EINVAL;
+                       goto err_unmap_pages;
+               }
+
                ret = ivpu_mmu_context_map_pages(vdev, ctx, vpu_addr, dma_addr, size, prot);
                if (ret) {
                        ivpu_err(vdev, "Failed to map context pages\n");
                        goto err_unmap_pages;
                }
                vpu_addr += size;
+               sgt_size += size;
+       }
+
+       if (sgt_size < bo_size) {
+               ivpu_err(vdev, "Scatter-gather table size too small to cover buffer object size\n");
+               ret = -EINVAL;
+               goto err_unmap_pages;
        }
 
        if (!ctx->is_cd_valid) {
@@ -493,7 +507,7 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
        return 0;
 
 err_unmap_pages:
-       ivpu_mmu_context_unmap_pages(ctx, start_vpu_addr, vpu_addr - start_vpu_addr);
+       ivpu_mmu_context_unmap_pages(ctx, start_vpu_addr, sgt_size);
        mutex_unlock(&ctx->lock);
        return ret;
 }
index 663a11a9db1110b52c5bad2bcd282db8782ef877..cc02e7bab04e67c9abe8126867c6f62c7b666520 100644 (file)
@@ -41,8 +41,9 @@ int ivpu_mmu_context_insert_node(struct ivpu_mmu_context *ctx, const struct ivpu
                                 u64 size, struct drm_mm_node *node);
 void ivpu_mmu_context_remove_node(struct ivpu_mmu_context *ctx, struct drm_mm_node *node);
 
-int ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
-                            u64 vpu_addr, struct sg_table *sgt, bool llc_coherent, bool read_only);
+int
+ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u64 vpu_addr,
+                        struct sg_table *sgt, size_t bo_size, bool llc_coherent, bool read_only);
 void ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
                                u64 vpu_addr, struct sg_table *sgt);
 int ivpu_mmu_context_set_pages_ro(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,