Skip to content

Commit 924357a

Browse files
minipli-ossshiloong
authored andcommitted
drm/vmwgfx: Fix stale file descriptors on failed usercopy
ANBZ: torvalds#420 commit a0f90c8 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: c906965 ("drm/vmwgfx: Add export fence to file descriptor support") Signed-off-by: Mathias Krause <[email protected]> Signed-off-by: Zack Rusin <[email protected]> Signed-off-by: Dave Airlie <[email protected]> Signed-off-by: Linus Torvalds <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> Fixes: CVE-2022-22942 Signed-off-by: Shile Zhang <[email protected]> Acked-by: Joseph Qi <[email protected]>
1 parent fcabf7b commit 924357a

File tree

4 files changed

+21
-22
lines changed

4 files changed

+21
-22
lines changed

drivers/gpu/drm/vmwgfx/vmwgfx_drv.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -855,15 +855,14 @@ extern int vmw_execbuf_fence_commands(struct drm_file *file_priv,
855855
struct vmw_private *dev_priv,
856856
struct vmw_fence_obj **p_fence,
857857
uint32_t *p_handle);
858-
extern void vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
858+
extern int vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
859859
struct vmw_fpriv *vmw_fp,
860860
int ret,
861861
struct drm_vmw_fence_rep __user
862862
*user_fence_rep,
863863
struct vmw_fence_obj *fence,
864864
uint32_t fence_handle,
865-
int32_t out_fence_fd,
866-
struct sync_file *sync_file);
865+
int32_t out_fence_fd);
867866
extern int vmw_validate_single_buffer(struct vmw_private *dev_priv,
868867
struct ttm_buffer_object *bo,
869868
bool interruptible,

drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3873,20 +3873,19 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv,
38733873
* object so we wait for it immediately, and then unreference the
38743874
* user-space reference.
38753875
*/
3876-
void
3876+
int
38773877
vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
38783878
struct vmw_fpriv *vmw_fp,
38793879
int ret,
38803880
struct drm_vmw_fence_rep __user *user_fence_rep,
38813881
struct vmw_fence_obj *fence,
38823882
uint32_t fence_handle,
3883-
int32_t out_fence_fd,
3884-
struct sync_file *sync_file)
3883+
int32_t out_fence_fd)
38853884
{
38863885
struct drm_vmw_fence_rep fence_rep;
38873886

38883887
if (user_fence_rep == NULL)
3889-
return;
3888+
return 0;
38903889

38913890
memset(&fence_rep, 0, sizeof(fence_rep));
38923891

@@ -3914,20 +3913,14 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
39143913
* and unreference the handle.
39153914
*/
39163915
if (unlikely(ret != 0) && (fence_rep.error == 0)) {
3917-
if (sync_file)
3918-
fput(sync_file->file);
3919-
3920-
if (fence_rep.fd != -1) {
3921-
put_unused_fd(fence_rep.fd);
3922-
fence_rep.fd = -1;
3923-
}
3924-
39253916
ttm_ref_object_base_unref(vmw_fp->tfile,
39263917
fence_handle, TTM_REF_USAGE);
39273918
DRM_ERROR("Fence copy error. Syncing.\n");
39283919
(void) vmw_fence_obj_wait(fence, false, false,
39293920
VMW_FENCE_WAIT_TIMEOUT);
39303921
}
3922+
3923+
return ret ? -EFAULT : 0;
39313924
}
39323925

39333926
/**
@@ -4287,16 +4280,23 @@ int vmw_execbuf_process(struct drm_file *file_priv,
42874280

42884281
(void) vmw_fence_obj_wait(fence, false, false,
42894282
VMW_FENCE_WAIT_TIMEOUT);
4283+
}
4284+
}
4285+
4286+
ret = vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
4287+
user_fence_rep, fence, handle, out_fence_fd);
4288+
4289+
if (sync_file) {
4290+
if (ret) {
4291+
/* usercopy of fence failed, put the file object */
4292+
fput(sync_file->file);
4293+
put_unused_fd(out_fence_fd);
42904294
} else {
42914295
/* Link the fence with the FD created earlier */
42924296
fd_install(out_fence_fd, sync_file->file);
42934297
}
42944298
}
42954299

4296-
vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
4297-
user_fence_rep, fence, handle,
4298-
out_fence_fd, sync_file);
4299-
43004300
/* Don't unreference when handing fence out */
43014301
if (unlikely(out_fence != NULL)) {
43024302
*out_fence = fence;
@@ -4315,7 +4315,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
43154315
*/
43164316
vmw_resource_list_unreference(sw_context, &resource_list);
43174317

4318-
return 0;
4318+
return ret;
43194319

43204320
out_unlock_binding:
43214321
mutex_unlock(&dev_priv->binding_mutex);

drivers/gpu/drm/vmwgfx/vmwgfx_fence.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1169,7 +1169,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
11691169
}
11701170

11711171
vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
1172-
handle, -1, NULL);
1172+
handle, -1);
11731173
vmw_fence_obj_unreference(&fence);
11741174
return 0;
11751175
out_no_create:

drivers/gpu/drm/vmwgfx/vmwgfx_kms.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2662,7 +2662,7 @@ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv,
26622662
if (file_priv)
26632663
vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv),
26642664
ret, user_fence_rep, fence,
2665-
handle, -1, NULL);
2665+
handle, -1);
26662666
if (out_fence)
26672667
*out_fence = fence;
26682668
else

0 commit comments

Comments
 (0)