Commit 5e28b7b94408 introduced a logical error by failing to replace the newly generated IDR pointer to old id's pointer at the correct location within the "change handle" logic; this resulted in the issue reported by syzbot [1]. Specifically, the new IDR object pointer is intended to replace the original id's pointer during the normal execution flow. Additionally, an unnecessary conditional check for the ret exit path has been removed. [1] !RB_EMPTY_ROOT(&prime_fpriv->dmabufs) WARNING: drivers/gpu/drm/drm_prime.c:224 at drm_prime_destroy_file_private+0x48/0x60 drivers/gpu/drm/drm_prime.c:224, CPU#0: syz.0.17/5833 Call Trace: drm_file_free.part.0+0x7e6/0xcc0 drivers/gpu/drm/drm_file.c:269 drm_file_free drivers/gpu/drm/drm_file.c:237 [inline] drm_close_helper.isra.0+0x186/0x200 drivers/gpu/drm/drm_file.c:290 drm_release+0x1ab/0x360 drivers/gpu/drm/drm_file.c:438
Unified · Split
| @@ -1067,17 +1067,12 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data, · 1066 unmodified lines | ||
| 1067 | 1067 | |
| 1068 | 1068 | spin_unlock(&file_priv->table_lock); |
| 1069 | 1069 | |
| 1070 | − if (ret < 0) | |
| 1071 | − goto out_unlock; | |
| 1072 | − | |
| 1073 | 1070 | if (obj->dma_buf) { |
| 1074 | 1071 | ret = drm_prime_add_buf_handle(&file_priv->prime, obj->dma_buf, |
| 1075 | 1072 | handle); |
| 1076 | 1073 | if (ret < 0) { |
| 1077 | 1074 | spin_lock(&file_priv->table_lock); |
| 1078 | 1075 | idr_remove(&file_priv->object_idr, handle); |
| 1079 | − idrobj = idr_replace(&file_priv->object_idr, obj, handle); | |
| 1080 | − WARN_ON(idrobj != NULL); | |
| 1081 | 1076 | spin_unlock(&file_priv->table_lock); |
| 1082 | 1077 | goto out_unlock; |
| 1083 | 1078 | } |
| @@ -1089,7 +1084,9 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data, · 5 unmodified lines | ||
| 1089 | 1084 | |
| 1090 | 1085 | spin_lock(&file_priv->table_lock); |
| 1091 | 1086 | idr_remove(&file_priv->object_idr, args->handle); |
| 1087 | + idrobj = idr_replace(&file_priv->object_idr, obj, handle); | |
| 1092 | 1088 | spin_unlock(&file_priv->table_lock); |
| 1089 | + WARN_ON(idrobj != NULL); | |
| 1093 | 1090 | |
| 1094 | 1091 | out_unlock: |
| 1095 | 1092 | mutex_unlock(&file_priv->prime.lock); |