|
Takashi Iwai |
b93c2a |
From: Mathias Krause <minipli@grsecurity.net>
|
|
Takashi Iwai |
b93c2a |
Subject: [PATCH] drm/vmwgfx: Fix stale file descriptors on failed usercopy
|
|
Takashi Iwai |
b93c2a |
Patch-mainline: v5.17-rc2
|
|
Takashi Iwai |
b93c2a |
Git-commit: a0f90c8815706981c483a652a6aefca51a5e191c
|
|
Takashi Iwai |
b93c2a |
References: CVE-2022-22942 bsc#1195065
|
|
Takashi Iwai |
b93c2a |
|
|
Takashi Iwai |
b93c2a |
A failing usercopy of the fence_rep object will lead to a stale entry in
|
|
Takashi Iwai |
b93c2a |
the file descriptor table as put_unused_fd() won't release it. This
|
|
Takashi Iwai |
b93c2a |
enables userland to refer to a dangling 'file' object through that still
|
|
Takashi Iwai |
b93c2a |
valid file descriptor, leading to all kinds of use-after-free
|
|
Takashi Iwai |
b93c2a |
exploitation scenarios.
|
|
Takashi Iwai |
b93c2a |
|
|
Takashi Iwai |
b93c2a |
Fix this by deferring the call to fd_install() until after the usercopy
|
|
Takashi Iwai |
b93c2a |
has succeeded.
|
|
Takashi Iwai |
b93c2a |
|
|
Takashi Iwai |
b93c2a |
Cc: Zack Rusin <zackr@vmware.com>
|
|
Takashi Iwai |
b93c2a |
Fixes: c906965dee22 ("drm/vmwgfx: Add export fence to file descriptor support")
|
|
Takashi Iwai |
b93c2a |
[mks: backport to v5.16 and older]
|
|
Takashi Iwai |
b93c2a |
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
|
|
Takashi Iwai |
b93c2a |
Acked-by: Takashi Iwai <tiwai@suse.de>
|
|
Takashi Iwai |
b93c2a |
|
|
Takashi Iwai |
b93c2a |
---
|
|
Takashi Iwai |
b93c2a |
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 5 +---
|
|
Takashi Iwai |
b93c2a |
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 33 ++++++++++++++++----------------
|
|
Takashi Iwai |
b93c2a |
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 2 -
|
|
Takashi Iwai |
b93c2a |
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 2 -
|
|
Takashi Iwai |
b93c2a |
4 files changed, 21 insertions(+), 21 deletions(-)
|
|
Takashi Iwai |
b93c2a |
|
|
Takashi Iwai |
b93c2a |
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
|
|
Takashi Iwai |
b93c2a |
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
|
|
Takashi Iwai |
b93c2a |
@@ -936,15 +936,14 @@ extern int vmw_execbuf_fence_commands(st
|
|
Takashi Iwai |
b93c2a |
struct vmw_private *dev_priv,
|
|
Takashi Iwai |
b93c2a |
struct vmw_fence_obj **p_fence,
|
|
Takashi Iwai |
b93c2a |
uint32_t *p_handle);
|
|
Takashi Iwai |
b93c2a |
-extern void vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
|
|
Takashi Iwai |
b93c2a |
+extern int vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
|
|
Takashi Iwai |
b93c2a |
struct vmw_fpriv *vmw_fp,
|
|
Takashi Iwai |
b93c2a |
int ret,
|
|
Takashi Iwai |
b93c2a |
struct drm_vmw_fence_rep __user
|
|
Takashi Iwai |
b93c2a |
*user_fence_rep,
|
|
Takashi Iwai |
b93c2a |
struct vmw_fence_obj *fence,
|
|
Takashi Iwai |
b93c2a |
uint32_t fence_handle,
|
|
Takashi Iwai |
b93c2a |
- int32_t out_fence_fd,
|
|
Takashi Iwai |
b93c2a |
- struct sync_file *sync_file);
|
|
Takashi Iwai |
b93c2a |
+ int32_t out_fence_fd);
|
|
Takashi Iwai |
b93c2a |
bool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd);
|
|
Takashi Iwai |
b93c2a |
|
|
Takashi Iwai |
b93c2a |
/**
|
|
Takashi Iwai |
b93c2a |
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
|
|
Takashi Iwai |
b93c2a |
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
|
|
Takashi Iwai |
b93c2a |
@@ -3414,17 +3414,17 @@ int vmw_execbuf_fence_commands(struct dr
|
|
Takashi Iwai |
b93c2a |
* Also if copying fails, user-space will be unable to signal the fence object
|
|
Takashi Iwai |
b93c2a |
* so we wait for it immediately, and then unreference the user-space reference.
|
|
Takashi Iwai |
b93c2a |
*/
|
|
Takashi Iwai |
b93c2a |
-void
|
|
Takashi Iwai |
b93c2a |
+int
|
|
Takashi Iwai |
b93c2a |
vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
|
|
Takashi Iwai |
b93c2a |
struct vmw_fpriv *vmw_fp, int ret,
|
|
Takashi Iwai |
b93c2a |
struct drm_vmw_fence_rep __user *user_fence_rep,
|
|
Takashi Iwai |
b93c2a |
struct vmw_fence_obj *fence, uint32_t fence_handle,
|
|
Takashi Iwai |
b93c2a |
- int32_t out_fence_fd, struct sync_file *sync_file)
|
|
Takashi Iwai |
b93c2a |
+ int32_t out_fence_fd)
|
|
Takashi Iwai |
b93c2a |
{
|
|
Takashi Iwai |
b93c2a |
struct drm_vmw_fence_rep fence_rep;
|
|
Takashi Iwai |
b93c2a |
|
|
Takashi Iwai |
b93c2a |
if (user_fence_rep == NULL)
|
|
Takashi Iwai |
b93c2a |
- return;
|
|
Takashi Iwai |
b93c2a |
+ return 0;
|
|
Takashi Iwai |
b93c2a |
|
|
Takashi Iwai |
b93c2a |
memset(&fence_rep, 0, sizeof(fence_rep));
|
|
Takashi Iwai |
b93c2a |
|
|
Takashi Iwai |
b93c2a |
@@ -3452,20 +3452,14 @@ vmw_execbuf_copy_fence_user(struct vmw_p
|
|
Takashi Iwai |
b93c2a |
* handle.
|
|
Takashi Iwai |
b93c2a |
*/
|
|
Takashi Iwai |
b93c2a |
if (unlikely(ret != 0) && (fence_rep.error == 0)) {
|
|
Takashi Iwai |
b93c2a |
- if (sync_file)
|
|
Takashi Iwai |
b93c2a |
- fput(sync_file->file);
|
|
Takashi Iwai |
b93c2a |
-
|
|
Takashi Iwai |
b93c2a |
- if (fence_rep.fd != -1) {
|
|
Takashi Iwai |
b93c2a |
- put_unused_fd(fence_rep.fd);
|
|
Takashi Iwai |
b93c2a |
- fence_rep.fd = -1;
|
|
Takashi Iwai |
b93c2a |
- }
|
|
Takashi Iwai |
b93c2a |
-
|
|
Takashi Iwai |
b93c2a |
ttm_ref_object_base_unref(vmw_fp->tfile, fence_handle,
|
|
Takashi Iwai |
b93c2a |
TTM_REF_USAGE);
|
|
Takashi Iwai |
b93c2a |
VMW_DEBUG_USER("Fence copy error. Syncing.\n");
|
|
Takashi Iwai |
b93c2a |
(void) vmw_fence_obj_wait(fence, false, false,
|
|
Takashi Iwai |
b93c2a |
VMW_FENCE_WAIT_TIMEOUT);
|
|
Takashi Iwai |
b93c2a |
}
|
|
Takashi Iwai |
b93c2a |
+
|
|
Takashi Iwai |
b93c2a |
+ return ret ? -EFAULT : 0;
|
|
Takashi Iwai |
b93c2a |
}
|
|
Takashi Iwai |
b93c2a |
|
|
Takashi Iwai |
b93c2a |
/**
|
|
Takashi Iwai |
b93c2a |
@@ -3807,16 +3801,23 @@ int vmw_execbuf_process(struct drm_file
|
|
Takashi Iwai |
b93c2a |
|
|
Takashi Iwai |
b93c2a |
(void) vmw_fence_obj_wait(fence, false, false,
|
|
Takashi Iwai |
b93c2a |
VMW_FENCE_WAIT_TIMEOUT);
|
|
Takashi Iwai |
b93c2a |
+ }
|
|
Takashi Iwai |
b93c2a |
+ }
|
|
Takashi Iwai |
b93c2a |
+
|
|
Takashi Iwai |
b93c2a |
+ ret = vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
|
|
Takashi Iwai |
b93c2a |
+ user_fence_rep, fence, handle, out_fence_fd);
|
|
Takashi Iwai |
b93c2a |
+
|
|
Takashi Iwai |
b93c2a |
+ if (sync_file) {
|
|
Takashi Iwai |
b93c2a |
+ if (ret) {
|
|
Takashi Iwai |
b93c2a |
+ /* usercopy of fence failed, put the file object */
|
|
Takashi Iwai |
b93c2a |
+ fput(sync_file->file);
|
|
Takashi Iwai |
b93c2a |
+ put_unused_fd(out_fence_fd);
|
|
Takashi Iwai |
b93c2a |
} else {
|
|
Takashi Iwai |
b93c2a |
/* Link the fence with the FD created earlier */
|
|
Takashi Iwai |
b93c2a |
fd_install(out_fence_fd, sync_file->file);
|
|
Takashi Iwai |
b93c2a |
}
|
|
Takashi Iwai |
b93c2a |
}
|
|
Takashi Iwai |
b93c2a |
|
|
Takashi Iwai |
b93c2a |
- vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
|
|
Takashi Iwai |
b93c2a |
- user_fence_rep, fence, handle, out_fence_fd,
|
|
Takashi Iwai |
b93c2a |
- sync_file);
|
|
Takashi Iwai |
b93c2a |
-
|
|
Takashi Iwai |
b93c2a |
/* Don't unreference when handing fence out */
|
|
Takashi Iwai |
b93c2a |
if (unlikely(out_fence != NULL)) {
|
|
Takashi Iwai |
b93c2a |
*out_fence = fence;
|
|
Takashi Iwai |
b93c2a |
@@ -3834,7 +3835,7 @@ int vmw_execbuf_process(struct drm_file
|
|
Takashi Iwai |
b93c2a |
*/
|
|
Takashi Iwai |
b93c2a |
vmw_validation_unref_lists(&val_ctx);
|
|
Takashi Iwai |
b93c2a |
|
|
Takashi Iwai |
b93c2a |
- return 0;
|
|
Takashi Iwai |
b93c2a |
+ return ret;
|
|
Takashi Iwai |
b93c2a |
|
|
Takashi Iwai |
b93c2a |
out_unlock_binding:
|
|
Takashi Iwai |
b93c2a |
mutex_unlock(&dev_priv->binding_mutex);
|
|
Takashi Iwai |
b93c2a |
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
|
|
Takashi Iwai |
b93c2a |
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
|
|
Takashi Iwai |
b93c2a |
@@ -1167,7 +1167,7 @@ int vmw_fence_event_ioctl(struct drm_dev
|
|
Takashi Iwai |
b93c2a |
}
|
|
Takashi Iwai |
b93c2a |
|
|
Takashi Iwai |
b93c2a |
vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
|
|
Takashi Iwai |
b93c2a |
- handle, -1, NULL);
|
|
Takashi Iwai |
b93c2a |
+ handle, -1);
|
|
Takashi Iwai |
b93c2a |
vmw_fence_obj_unreference(&fence);
|
|
Takashi Iwai |
b93c2a |
return 0;
|
|
Takashi Iwai |
b93c2a |
out_no_create:
|
|
Takashi Iwai |
b93c2a |
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
|
|
Takashi Iwai |
b93c2a |
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
|
|
Takashi Iwai |
b93c2a |
@@ -2561,7 +2561,7 @@ void vmw_kms_helper_validation_finish(st
|
|
Takashi Iwai |
b93c2a |
if (file_priv)
|
|
Takashi Iwai |
b93c2a |
vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv),
|
|
Takashi Iwai |
b93c2a |
ret, user_fence_rep, fence,
|
|
Takashi Iwai |
b93c2a |
- handle, -1, NULL);
|
|
Takashi Iwai |
b93c2a |
+ handle, -1);
|
|
Takashi Iwai |
b93c2a |
if (out_fence)
|
|
Takashi Iwai |
b93c2a |
*out_fence = fence;
|
|
Takashi Iwai |
b93c2a |
else
|