mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
drm-misc-fixes for v7.2-rc4:
- Fix UAF in host1x, amdxdna. - Handle invalid firmware log in ivpu. - Fix error handling in panthor. - Handle NULL pages and backup handles in ttm_pool_backup() correctly. - Reject more invalid amdxdna command submissions. - Improve unmap and error handling on gpusvm. - Fix virtio deadlock and invalid gem detach. - Fix wrong read in ivpu. - Always synchronize for CPU in begin_cpu_udmabuf. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAmpZtq8ACgkQ/lWMcqZw E8PLWRAAo9O26HSkkkIHK+eTqURIUFvRdJTEsRWkm/dJJQxeQsngyquCrAWR6Djm BZmQS+Kk8hLPvvbv7+d8jMYC7Eft2ebufBq1SSndVuzzwQVnptdw6W+SFr+awCf6 d9Km4TlVtCANTBez3BeisYoguMDq2UK1WZDSm93NRJQe1t4nDvUJ8yyW2jVpquo6 UdUokuHZ+d8ZeXyFa3JGXe2JDE9kwiFA9C0nPCYTGem75cJ/7QneiMV6WquMQyXQ 4dYXBiqbm4lWZfi8scZSdDK9CLuscO04Tw1W+V9yDl+r/szXrEy6e9WIFfZI92sD x3vV/X/6/EsCaHMyxcmmgHcP0zxpsXKYvz1BuDsPj37vqNmSZG8yQvHbANR5XleD jBOTks6Zzx6PLHaSGJX3UpdDIRwX5xHoopJi6Qj/Ohau9Jwr0BHGHsJmXby7lw66 Pflt2fcQdmGjzvTCpDr1bKQlfr5d7aQqR8rFP0g3RD59BSaYmNejjv1zz991KX0h rY7SUY2TyONHQQzJQ7qIj7aU2G6CQxLX9KTiV6/qrkg0rTyIaGXpYcSsYjhnzNX1 tN97Ln5LIniKaPBhD5i7Zv24rTBN4Oey8EyM6ZTb45bvCR3uyeY7Mc+/5lpCqiRy BlalKZLe7aEPNiHqNpFtXgbcJShbTQP+EDpsq7k2JbwIqvsBcaE= =LuJL -----END PGP SIGNATURE----- Merge tag 'drm-misc-fixes-2026-07-17' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-fixes drm-misc-fixes for v7.2-rc4: - Fix UAF in host1x, amdxdna. - Handle invalid firmware log in ivpu. - Fix error handling in panthor. - Handle NULL pages and backup handles in ttm_pool_backup() correctly. - Reject more invalid amdxdna command submissions. - Improve unmap and error handling on gpusvm. - Fix virtio deadlock and invalid gem detach. - Fix wrong read in ivpu. - Always synchronize for CPU in begin_cpu_udmabuf. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patch.msgid.link/7f10281e-88f5-4be5-8b42-367e7ce7c547@linux.intel.com
This commit is contained in:
commit
4f7b10f3a4
|
|
@ -577,6 +577,7 @@ void amdxdna_sched_job_cleanup(struct amdxdna_sched_job *job)
|
|||
amdxdna_arg_bos_put(job);
|
||||
amdxdna_gem_put_obj(job->cmd_bo);
|
||||
dma_fence_put(job->fence);
|
||||
mmdrop(job->mm);
|
||||
}
|
||||
|
||||
int amdxdna_cmd_submit(struct amdxdna_client *client,
|
||||
|
|
@ -590,6 +591,10 @@ int amdxdna_cmd_submit(struct amdxdna_client *client,
|
|||
int ret, idx;
|
||||
|
||||
XDNA_DBG(xdna, "Command BO hdl %d, Arg BO count %d", cmd_bo_hdl, arg_bo_cnt);
|
||||
|
||||
if (!xdna->dev_info->ops->cmd_submit)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
job = kzalloc_flex(*job, bos, arg_bo_cnt);
|
||||
if (!job)
|
||||
return -ENOMEM;
|
||||
|
|
@ -603,6 +608,16 @@ int amdxdna_cmd_submit(struct amdxdna_client *client,
|
|||
ret = -EINVAL;
|
||||
goto free_job;
|
||||
}
|
||||
} else if (!drv_cmd) {
|
||||
/*
|
||||
* Only internal driver commands (drv_cmd != NULL) may omit a
|
||||
* command BO. A user command submission with the invalid handle
|
||||
* would leave job->cmd_bo NULL and later fault when the scheduler
|
||||
* dereferences it in amdxdna_cmd_set_state().
|
||||
*/
|
||||
XDNA_DBG(xdna, "Command BO handle required for user submission");
|
||||
ret = -EINVAL;
|
||||
goto free_job;
|
||||
}
|
||||
|
||||
ret = amdxdna_arg_bos_lookup(client, job, arg_bo_hdls, arg_bo_cnt);
|
||||
|
|
@ -628,6 +643,7 @@ int amdxdna_cmd_submit(struct amdxdna_client *client,
|
|||
|
||||
job->hwctx = hwctx;
|
||||
job->mm = current->mm;
|
||||
mmgrab(job->mm);
|
||||
|
||||
job->fence = amdxdna_fence_create(hwctx);
|
||||
if (!job->fence) {
|
||||
|
|
@ -662,6 +678,8 @@ int amdxdna_cmd_submit(struct amdxdna_client *client,
|
|||
cmd_put:
|
||||
amdxdna_gem_put_obj(job->cmd_bo);
|
||||
free_job:
|
||||
if (job->mm)
|
||||
mmdrop(job->mm);
|
||||
kfree(job);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@ static int fw_log_from_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *off
|
|||
ivpu_dbg(vdev, FW_BOOT, "Invalid header size 0x%x\n", log->header_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (log->size < log->header_size) {
|
||||
ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((char *)log + log->size > (char *)ivpu_bo_vaddr(bo) + ivpu_bo_size(bo)) {
|
||||
ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size);
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -927,7 +927,7 @@ static void diagnose_failure_mtl(struct ivpu_device *vdev)
|
|||
|
||||
static void diagnose_failure_lnl(struct ivpu_device *vdev)
|
||||
{
|
||||
u32 reg = REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) & BTRS_LNL_IRQ_MASK;
|
||||
u32 reg = REGB_RD32(VPU_HW_BTRS_LNL_INTERRUPT_STAT) & BTRS_LNL_IRQ_MASK;
|
||||
|
||||
if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, ATS_ERR, reg)) {
|
||||
ivpu_err(vdev, "ATS_ERR_LOG1 0x%08x ATS_ERR_LOG2 0x%08x\n",
|
||||
|
|
|
|||
|
|
@ -224,21 +224,22 @@ static int begin_cpu_udmabuf(struct dma_buf *buf,
|
|||
{
|
||||
struct udmabuf *ubuf = buf->priv;
|
||||
struct device *dev = ubuf->device->this_device;
|
||||
int ret = 0;
|
||||
|
||||
if (!ubuf->sg) {
|
||||
ubuf->sg = get_sg_table(dev, buf, direction);
|
||||
if (IS_ERR(ubuf->sg)) {
|
||||
int ret;
|
||||
|
||||
ret = PTR_ERR(ubuf->sg);
|
||||
ubuf->sg = NULL;
|
||||
return ret;
|
||||
} else {
|
||||
ubuf->sg_dir = direction;
|
||||
}
|
||||
} else {
|
||||
dma_sync_sgtable_for_cpu(dev, ubuf->sg, direction);
|
||||
}
|
||||
|
||||
return ret;
|
||||
dma_sync_sgtable_for_cpu(dev, ubuf->sg, direction);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int end_cpu_udmabuf(struct dma_buf *buf,
|
||||
|
|
|
|||
|
|
@ -1146,20 +1146,35 @@ static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
|
|||
};
|
||||
bool use_iova = dma_use_iova(&svm_pages->state);
|
||||
|
||||
if (use_iova)
|
||||
dma_iova_destroy(dev, &svm_pages->state,
|
||||
svm_pages->state_offset,
|
||||
svm_pages->dma_addr[0].dir, 0);
|
||||
/*
|
||||
* IOVA is reserved for the whole range but only the linked
|
||||
* system pages (state_offset bytes) need unlinking; free the
|
||||
* entire reservation to avoid leaking the device-page part.
|
||||
* On the error path state_offset is 0, so just free it.
|
||||
*/
|
||||
if (use_iova) {
|
||||
if (svm_pages->state_offset)
|
||||
dma_iova_unlink(dev, &svm_pages->state, 0,
|
||||
svm_pages->state_offset,
|
||||
svm_pages->dma_addr[0].dir, 0);
|
||||
dma_iova_free(dev, &svm_pages->state);
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < npages; j++) {
|
||||
struct drm_pagemap_addr *addr = &svm_pages->dma_addr[j];
|
||||
|
||||
if (!use_iova && addr->proto == DRM_INTERCONNECT_SYSTEM)
|
||||
dma_unmap_page(dev,
|
||||
addr->addr,
|
||||
PAGE_SIZE << addr->order,
|
||||
addr->dir);
|
||||
else if (dpagemap && dpagemap->ops->device_unmap)
|
||||
if (addr->proto == DRM_INTERCONNECT_SYSTEM) {
|
||||
/*
|
||||
* Linked IOVA pages were already torn down by
|
||||
* the dma_iova_unlink()/dma_iova_free() above;
|
||||
* only the non-IOVA mappings need unmap here.
|
||||
*/
|
||||
if (!use_iova)
|
||||
dma_unmap_page(dev,
|
||||
addr->addr,
|
||||
PAGE_SIZE << addr->order,
|
||||
addr->dir);
|
||||
} else if (dpagemap && dpagemap->ops->device_unmap)
|
||||
dpagemap->ops->device_unmap(dpagemap,
|
||||
dev, addr);
|
||||
i += 1 << addr->order;
|
||||
|
|
@ -1486,7 +1501,7 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
|
|||
/* Unlock and restart mapping to allocate memory. */
|
||||
drm_gpusvm_notifier_unlock(gpusvm);
|
||||
svm_pages->dma_addr =
|
||||
kvmalloc_objs(*svm_pages->dma_addr, npages);
|
||||
kvzalloc_objs(*svm_pages->dma_addr, npages);
|
||||
if (!svm_pages->dma_addr) {
|
||||
err = -ENOMEM;
|
||||
goto err_free;
|
||||
|
|
@ -1529,6 +1544,16 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
|
|||
err = -EAGAIN;
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the dpagemap as soon as the first
|
||||
* device page is mapped so the err_unmap path
|
||||
* can device_unmap() the device mappings that
|
||||
* have already been created.
|
||||
*/
|
||||
drm_pagemap_get(dpagemap);
|
||||
drm_pagemap_put(svm_pages->dpagemap);
|
||||
svm_pages->dpagemap = dpagemap;
|
||||
}
|
||||
svm_pages->dma_addr[j] =
|
||||
dpagemap->ops->device_map(dpagemap,
|
||||
|
|
@ -1596,12 +1621,8 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
|
|||
goto err_unmap;
|
||||
}
|
||||
|
||||
if (pagemap) {
|
||||
if (pagemap)
|
||||
flags.has_devmem_pages = true;
|
||||
drm_pagemap_get(dpagemap);
|
||||
drm_pagemap_put(svm_pages->dpagemap);
|
||||
svm_pages->dpagemap = dpagemap;
|
||||
}
|
||||
|
||||
/* WRITE_ONCE pairs with READ_ONCE for opportunistic checks */
|
||||
WRITE_ONCE(svm_pages->flags.__flags, flags.__flags);
|
||||
|
|
|
|||
|
|
@ -182,7 +182,10 @@ int panthor_device_init(struct panthor_device *ptdev)
|
|||
return ret;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
drmm_mutex_init(&ptdev->base, &ptdev->gems.lock);
|
||||
ret = drmm_mutex_init(&ptdev->base, &ptdev->gems.lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
INIT_LIST_HEAD(&ptdev->gems.node);
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -829,6 +829,7 @@ static int panthor_fw_load(struct panthor_device *ptdev)
|
|||
}
|
||||
|
||||
if (hdr.size > iter.size) {
|
||||
ret = -EINVAL;
|
||||
drm_err(&ptdev->base, "Firmware image is truncated\n");
|
||||
goto out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1051,9 +1051,31 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt,
|
|||
return -EBUSY;
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
/* Anything returned to the system needs to be cached. */
|
||||
if (tt->caching != ttm_cached)
|
||||
set_pages_array_wb(tt->pages, tt->num_pages);
|
||||
/* Anything returned to the system needs to be cached. Walk allocations
|
||||
* skipping NULL pages and issue set_pages_array_wb() per contiguous run.
|
||||
*/
|
||||
if (tt->caching != ttm_cached) {
|
||||
pgoff_t run_start = 0, run_count = 0;
|
||||
|
||||
for (i = 0; i < tt->num_pages; i += num_pages) {
|
||||
page = tt->pages[i];
|
||||
if (unlikely(!page || ttm_backup_page_ptr_is_handle(page))) {
|
||||
if (run_count) {
|
||||
set_pages_array_wb(&tt->pages[run_start],
|
||||
run_count);
|
||||
run_count = 0;
|
||||
}
|
||||
num_pages = 1;
|
||||
continue;
|
||||
}
|
||||
num_pages = 1UL << ttm_pool_page_order(pool, page);
|
||||
if (!run_count)
|
||||
run_start = i;
|
||||
run_count += num_pages;
|
||||
}
|
||||
if (run_count)
|
||||
set_pages_array_wb(&tt->pages[run_start], run_count);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tt->dma_address || flags->purge) {
|
||||
|
|
@ -1061,7 +1083,7 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt,
|
|||
unsigned int order;
|
||||
|
||||
page = tt->pages[i];
|
||||
if (unlikely(!page)) {
|
||||
if (unlikely(!page || ttm_backup_page_ptr_is_handle(page))) {
|
||||
num_pages = 1;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1104,6 +1126,10 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt,
|
|||
if (unlikely(!page))
|
||||
continue;
|
||||
|
||||
/* Already-handled entry from a previous attempt. */
|
||||
if (unlikely(ttm_backup_page_ptr_is_handle(page)))
|
||||
continue;
|
||||
|
||||
ttm_pool_split_for_swap(pool, page);
|
||||
|
||||
shandle = ttm_backup_backup_page(backup, page, flags->writeback, i,
|
||||
|
|
|
|||
|
|
@ -139,13 +139,15 @@ void virtio_gpu_gem_object_close(struct drm_gem_object *obj,
|
|||
if (!vgdev->has_virgl_3d)
|
||||
return;
|
||||
|
||||
objs = virtio_gpu_array_alloc(1);
|
||||
if (!objs)
|
||||
return;
|
||||
virtio_gpu_array_add_obj(objs, obj);
|
||||
if (vfpriv->context_created) {
|
||||
objs = virtio_gpu_array_alloc(1);
|
||||
if (!objs)
|
||||
return;
|
||||
virtio_gpu_array_add_obj(objs, obj);
|
||||
|
||||
virtio_gpu_cmd_context_detach_resource(vgdev, vfpriv->ctx_id,
|
||||
objs);
|
||||
virtio_gpu_cmd_context_detach_resource(vgdev, vfpriv->ctx_id,
|
||||
objs);
|
||||
}
|
||||
virtio_gpu_notify(vgdev);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,10 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work)
|
|||
virtio_gpu_cmd_get_edids(vgdev);
|
||||
virtio_gpu_cmd_get_display_info(vgdev);
|
||||
virtio_gpu_notify(vgdev);
|
||||
drm_helper_hpd_irq_event(vgdev->ddev);
|
||||
wait_event_timeout(vgdev->resp_wq,
|
||||
!vgdev->display_info_pending,
|
||||
5 * HZ);
|
||||
drm_kms_helper_hotplug_event(vgdev->ddev);
|
||||
}
|
||||
events_clear |= VIRTIO_GPU_EVENT_DISPLAY;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -840,9 +840,6 @@ static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev,
|
|||
vgdev->display_info_pending = false;
|
||||
spin_unlock(&vgdev->display_info_lock);
|
||||
wake_up(&vgdev->resp_wq);
|
||||
|
||||
if (!drm_helper_hpd_irq_event(vgdev->ddev))
|
||||
drm_kms_helper_hotplug_event(vgdev->ddev);
|
||||
}
|
||||
|
||||
static void virtio_gpu_cmd_get_capset_info_cb(struct virtio_gpu_device *vgdev,
|
||||
|
|
|
|||
|
|
@ -1012,10 +1012,10 @@ void host1x_bo_clear_cached_mappings(struct host1x_bo *bo)
|
|||
if (WARN_ON(!cache))
|
||||
continue;
|
||||
|
||||
mutex_lock(&mapping->cache->lock);
|
||||
mutex_lock(&cache->lock);
|
||||
WARN_ON(kref_read(&mapping->ref) != 1);
|
||||
__host1x_bo_unpin(&mapping->ref);
|
||||
mutex_unlock(&mapping->cache->lock);
|
||||
mutex_unlock(&cache->lock);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(host1x_bo_clear_cached_mappings);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user