amdxdna_drm_gem_mmap() can be called after drm_dev_unplug() during device
removal. In that case, the mmap path may access amdxdna_client after it
has been freed, leading to a use-after-free.

Guard the mmap path with drm_dev_enter()/drm_dev_exit() and return an
error if the device is already unplugged.

Fixes: 91f4da826c08 ("accel/amdxdna: Add command doorbell and wait support")
Signed-off-by: Lizhi Hou <[email protected]>
---
 drivers/accel/amdxdna/amdxdna_pci_drv.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c 
b/drivers/accel/amdxdna/amdxdna_pci_drv.c
index a22c986f1b33..c18ddad9f645 100644
--- a/drivers/accel/amdxdna/amdxdna_pci_drv.c
+++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c
@@ -253,15 +253,24 @@ static int amdxdna_drm_gem_mmap(struct file *filp, struct 
vm_area_struct *vma)
 {
        struct drm_file *drm_filp = filp->private_data;
        struct amdxdna_client *client = drm_filp->driver_priv;
-       struct amdxdna_dev *xdna = client->xdna;
+       struct amdxdna_dev *xdna;
+       int ret, idx;
 
        if (likely(vma->vm_pgoff >= DRM_FILE_PAGE_OFFSET_START))
                return drm_gem_mmap(filp, vma);
 
-       if (!xdna->dev_info->ops->mmap)
-               return -EOPNOTSUPP;
+       if (!drm_dev_enter(drm_filp->minor->dev, &idx))
+               return -ENODEV;
 
-       return xdna->dev_info->ops->mmap(client, vma);
+       xdna = client->xdna;
+       if (xdna->dev_info->ops->mmap)
+               ret = xdna->dev_info->ops->mmap(client, vma);
+       else
+               ret = -EOPNOTSUPP;
+
+       drm_dev_exit(idx);
+
+       return ret;
 }
 
 static const struct drm_ioctl_desc amdxdna_drm_ioctls[] = {
-- 
2.34.1

Reply via email to