提交 f6db3d87 编写于 作者: M Mathias Krause 提交者: Yang Yingliang

drm/vmwgfx: Fix stale file descriptors on failed usercopy

stable inclusion
from linux-4.19.227
commit 0008a0c78fc33a84e2212a7c04e6b21a36ca6f4d
CVE: CVE-2022-22942

--------------------------------

commit a0f90c88 upstream.

A failing usercopy of the fence_rep object will lead to a stale entry in
the file descriptor table as put_unused_fd() won't release it. This
enables userland to refer to a dangling 'file' object through that still
valid file descriptor, leading to all kinds of use-after-free
exploitation scenarios.

Fix this by deferring the call to fd_install() until after the usercopy
has succeeded.

Fixes: c906965d ("drm/vmwgfx: Add export fence to file descriptor support")
Signed-off-by: NMathias Krause <minipli@grsecurity.net>
Signed-off-by: NZack Rusin <zackr@vmware.com>
Signed-off-by: NDave Airlie <airlied@redhat.com>
Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
Reviewed-by: NXiu Jianfeng <xiujianfeng@huawei.com>
Reviewed-by: NJason Yan <yanaijie@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 b2e2d2c0
...@@ -855,15 +855,14 @@ extern int vmw_execbuf_fence_commands(struct drm_file *file_priv, ...@@ -855,15 +855,14 @@ extern int vmw_execbuf_fence_commands(struct drm_file *file_priv,
struct vmw_private *dev_priv, struct vmw_private *dev_priv,
struct vmw_fence_obj **p_fence, struct vmw_fence_obj **p_fence,
uint32_t *p_handle); uint32_t *p_handle);
extern void vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv, extern int vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
struct vmw_fpriv *vmw_fp, struct vmw_fpriv *vmw_fp,
int ret, int ret,
struct drm_vmw_fence_rep __user struct drm_vmw_fence_rep __user
*user_fence_rep, *user_fence_rep,
struct vmw_fence_obj *fence, struct vmw_fence_obj *fence,
uint32_t fence_handle, uint32_t fence_handle,
int32_t out_fence_fd, int32_t out_fence_fd);
struct sync_file *sync_file);
extern int vmw_validate_single_buffer(struct vmw_private *dev_priv, extern int vmw_validate_single_buffer(struct vmw_private *dev_priv,
struct ttm_buffer_object *bo, struct ttm_buffer_object *bo,
bool interruptible, bool interruptible,
......
...@@ -3873,20 +3873,19 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv, ...@@ -3873,20 +3873,19 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv,
* object so we wait for it immediately, and then unreference the * object so we wait for it immediately, and then unreference the
* user-space reference. * user-space reference.
*/ */
void int
vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv, vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
struct vmw_fpriv *vmw_fp, struct vmw_fpriv *vmw_fp,
int ret, int ret,
struct drm_vmw_fence_rep __user *user_fence_rep, struct drm_vmw_fence_rep __user *user_fence_rep,
struct vmw_fence_obj *fence, struct vmw_fence_obj *fence,
uint32_t fence_handle, uint32_t fence_handle,
int32_t out_fence_fd, int32_t out_fence_fd)
struct sync_file *sync_file)
{ {
struct drm_vmw_fence_rep fence_rep; struct drm_vmw_fence_rep fence_rep;
if (user_fence_rep == NULL) if (user_fence_rep == NULL)
return; return 0;
memset(&fence_rep, 0, sizeof(fence_rep)); memset(&fence_rep, 0, sizeof(fence_rep));
...@@ -3914,20 +3913,14 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv, ...@@ -3914,20 +3913,14 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
* and unreference the handle. * and unreference the handle.
*/ */
if (unlikely(ret != 0) && (fence_rep.error == 0)) { if (unlikely(ret != 0) && (fence_rep.error == 0)) {
if (sync_file)
fput(sync_file->file);
if (fence_rep.fd != -1) {
put_unused_fd(fence_rep.fd);
fence_rep.fd = -1;
}
ttm_ref_object_base_unref(vmw_fp->tfile, ttm_ref_object_base_unref(vmw_fp->tfile,
fence_handle, TTM_REF_USAGE); fence_handle, TTM_REF_USAGE);
DRM_ERROR("Fence copy error. Syncing.\n"); DRM_ERROR("Fence copy error. Syncing.\n");
(void) vmw_fence_obj_wait(fence, false, false, (void) vmw_fence_obj_wait(fence, false, false,
VMW_FENCE_WAIT_TIMEOUT); VMW_FENCE_WAIT_TIMEOUT);
} }
return ret ? -EFAULT : 0;
} }
/** /**
...@@ -4287,16 +4280,23 @@ int vmw_execbuf_process(struct drm_file *file_priv, ...@@ -4287,16 +4280,23 @@ int vmw_execbuf_process(struct drm_file *file_priv,
(void) vmw_fence_obj_wait(fence, false, false, (void) vmw_fence_obj_wait(fence, false, false,
VMW_FENCE_WAIT_TIMEOUT); VMW_FENCE_WAIT_TIMEOUT);
}
}
ret = vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
user_fence_rep, fence, handle, out_fence_fd);
if (sync_file) {
if (ret) {
/* usercopy of fence failed, put the file object */
fput(sync_file->file);
put_unused_fd(out_fence_fd);
} else { } else {
/* Link the fence with the FD created earlier */ /* Link the fence with the FD created earlier */
fd_install(out_fence_fd, sync_file->file); fd_install(out_fence_fd, sync_file->file);
} }
} }
vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
user_fence_rep, fence, handle,
out_fence_fd, sync_file);
/* Don't unreference when handing fence out */ /* Don't unreference when handing fence out */
if (unlikely(out_fence != NULL)) { if (unlikely(out_fence != NULL)) {
*out_fence = fence; *out_fence = fence;
...@@ -4315,7 +4315,7 @@ int vmw_execbuf_process(struct drm_file *file_priv, ...@@ -4315,7 +4315,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
*/ */
vmw_resource_list_unreference(sw_context, &resource_list); vmw_resource_list_unreference(sw_context, &resource_list);
return 0; return ret;
out_unlock_binding: out_unlock_binding:
mutex_unlock(&dev_priv->binding_mutex); mutex_unlock(&dev_priv->binding_mutex);
......
...@@ -1169,7 +1169,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data, ...@@ -1169,7 +1169,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
} }
vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence, vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
handle, -1, NULL); handle, -1);
vmw_fence_obj_unreference(&fence); vmw_fence_obj_unreference(&fence);
return 0; return 0;
out_no_create: out_no_create:
......
...@@ -2662,7 +2662,7 @@ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, ...@@ -2662,7 +2662,7 @@ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv,
if (file_priv) if (file_priv)
vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv),
ret, user_fence_rep, fence, ret, user_fence_rep, fence,
handle, -1, NULL); handle, -1);
if (out_fence) if (out_fence)
*out_fence = fence; *out_fence = fence;
else else
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册