Skip to content

Commit 1474b39

Browse files
zackrgregkh
authored andcommitted
drm/vmwgfx: Keep a gem reference to user bos in surfaces
commit 91398b4 upstream. Surfaces can be backed (i.e. stored in) memory objects (mob's) which are created and managed by the userspace as GEM buffers. Surfaces grab only a ttm reference which means that the gem object can be deleted underneath us, especially in cases where prime buffer export is used. Make sure that all userspace surfaces which are backed by gem objects hold a gem reference to make sure they're not deleted before vmw surfaces are done with them, which fixes: ------------[ cut here ]------------ refcount_t: underflow; use-after-free. WARNING: CPU: 2 PID: 2632 at lib/refcount.c:28 refcount_warn_saturate+0xfb/0x150 Modules linked in: overlay vsock_loopback vmw_vsock_virtio_transport_common vmw_vsock_vmci_transport vsock snd_ens1371 snd_ac97_codec ac97_bus snd_pcm gameport> CPU: 2 PID: 2632 Comm: vmw_ref_count Not tainted 6.5.0-rc2-vmwgfx #1 Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020 RIP: 0010:refcount_warn_saturate+0xfb/0x150 Code: eb 9e 0f b6 1d 8b 5b a6 01 80 fb 01 0f 87 ba e4 80 00 83 e3 01 75 89 48 c7 c7 c0 3c f9 a3 c6 05 6f 5b a6 01 01 e8 15 81 98 ff <0f> 0b e9 6f ff ff ff 0f b> RSP: 0018:ffffbdc34344bba0 EFLAGS: 00010286 RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000027 RDX: ffff960475ea1548 RSI: 0000000000000001 RDI: ffff960475ea1540 RBP: ffffbdc34344bba8 R08: 0000000000000003 R09: 65646e75203a745f R10: ffffffffa5b32b20 R11: 72657466612d6573 R12: ffff96037d6a6400 R13: ffff9603484805b0 R14: 000000000000000b R15: ffff9603bed06060 FS: 00007f5fd8520c40(0000) GS:ffff960475e80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f5fda755000 CR3: 000000010d012005 CR4: 00000000003706e0 Call Trace: <TASK> ? show_regs+0x6e/0x80 ? refcount_warn_saturate+0xfb/0x150 ? __warn+0x91/0x150 ? refcount_warn_saturate+0xfb/0x150 ? report_bug+0x19d/0x1b0 ? handle_bug+0x46/0x80 ? exc_invalid_op+0x1d/0x80 ? asm_exc_invalid_op+0x1f/0x30 ? refcount_warn_saturate+0xfb/0x150 drm_gem_object_handle_put_unlocked+0xba/0x110 [drm] drm_gem_object_release_handle+0x6e/0x80 [drm] drm_gem_handle_delete+0x6a/0xc0 [drm] ? __pfx_vmw_bo_unref_ioctl+0x10/0x10 [vmwgfx] vmw_bo_unref_ioctl+0x33/0x40 [vmwgfx] drm_ioctl_kernel+0xbc/0x160 [drm] drm_ioctl+0x2d2/0x580 [drm] ? __pfx_vmw_bo_unref_ioctl+0x10/0x10 [vmwgfx] ? do_vmi_munmap+0xee/0x180 vmw_generic_ioctl+0xbd/0x180 [vmwgfx] vmw_unlocked_ioctl+0x19/0x20 [vmwgfx] __x64_sys_ioctl+0x99/0xd0 do_syscall_64+0x5d/0x90 ? syscall_exit_to_user_mode+0x2a/0x50 ? do_syscall_64+0x6d/0x90 ? handle_mm_fault+0x16e/0x2f0 ? exit_to_user_mode_prepare+0x34/0x170 ? irqentry_exit_to_user_mode+0xd/0x20 ? irqentry_exit+0x3f/0x50 ? exc_page_fault+0x8e/0x190 entry_SYSCALL_64_after_hwframe+0x6e/0xd8 RIP: 0033:0x7f5fda51aaff Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 7> RSP: 002b:00007ffd536a4d30 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 00007ffd536a4de0 RCX: 00007f5fda51aaff RDX: 00007ffd536a4de0 RSI: 0000000040086442 RDI: 0000000000000003 RBP: 0000000040086442 R08: 000055fa603ada50 R09: 0000000000000000 R10: 0000000000000001 R11: 0000000000000246 R12: 00007ffd536a51b8 R13: 0000000000000003 R14: 000055fa5ebb4c80 R15: 00007f5fda90f040 </TASK> ---[ end trace 0000000000000000 ]--- A lot of the analyis on the bug was done by Murray McAllister and Ian Forbes. Reported-by: Murray McAllister <[email protected]> Cc: Ian Forbes <[email protected]> Signed-off-by: Zack Rusin <[email protected]> Fixes: a950b98 ("drm/vmwgfx: Do not drop the reference to the handle too soon") Cc: <[email protected]> # v6.2+ Reviewed-by: Martin Krastev <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 65059dc commit 1474b39

File tree

11 files changed

+68
-49
lines changed

11 files changed

+68
-49
lines changed

drivers/gpu/drm/vmwgfx/vmwgfx_bo.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434

3535
static void vmw_bo_release(struct vmw_bo *vbo)
3636
{
37+
WARN_ON(vbo->tbo.base.funcs &&
38+
kref_read(&vbo->tbo.base.refcount) != 0);
3739
vmw_bo_unmap(vbo);
3840
drm_gem_object_release(&vbo->tbo.base);
3941
}
@@ -497,7 +499,7 @@ static int vmw_user_bo_synccpu_release(struct drm_file *filp,
497499
if (!(flags & drm_vmw_synccpu_allow_cs)) {
498500
atomic_dec(&vmw_bo->cpu_writers);
499501
}
500-
vmw_user_bo_unref(vmw_bo);
502+
vmw_user_bo_unref(&vmw_bo);
501503
}
502504

503505
return ret;
@@ -539,7 +541,7 @@ int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data,
539541
return ret;
540542

541543
ret = vmw_user_bo_synccpu_grab(vbo, arg->flags);
542-
vmw_user_bo_unref(vbo);
544+
vmw_user_bo_unref(&vbo);
543545
if (unlikely(ret != 0)) {
544546
if (ret == -ERESTARTSYS || ret == -EBUSY)
545547
return -EBUSY;
@@ -612,7 +614,6 @@ int vmw_user_bo_lookup(struct drm_file *filp,
612614
}
613615

614616
*out = to_vmw_bo(gobj);
615-
ttm_bo_get(&(*out)->tbo);
616617

617618
return 0;
618619
}

drivers/gpu/drm/vmwgfx/vmwgfx_bo.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,19 @@ static inline struct vmw_bo *vmw_bo_reference(struct vmw_bo *buf)
195195
return buf;
196196
}
197197

198-
static inline void vmw_user_bo_unref(struct vmw_bo *vbo)
198+
static inline struct vmw_bo *vmw_user_bo_ref(struct vmw_bo *vbo)
199199
{
200-
if (vbo) {
201-
ttm_bo_put(&vbo->tbo);
202-
drm_gem_object_put(&vbo->tbo.base);
203-
}
200+
drm_gem_object_get(&vbo->tbo.base);
201+
return vbo;
202+
}
203+
204+
static inline void vmw_user_bo_unref(struct vmw_bo **buf)
205+
{
206+
struct vmw_bo *tmp_buf = *buf;
207+
208+
*buf = NULL;
209+
if (tmp_buf)
210+
drm_gem_object_put(&tmp_buf->tbo.base);
204211
}
205212

206213
static inline struct vmw_bo *to_vmw_bo(struct drm_gem_object *gobj)

drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
432432
* for the new COTable. Initially pin the buffer object to make sure
433433
* we can use tryreserve without failure.
434434
*/
435-
ret = vmw_bo_create(dev_priv, &bo_params, &buf);
435+
ret = vmw_gem_object_create(dev_priv, &bo_params, &buf);
436436
if (ret) {
437437
DRM_ERROR("Failed initializing new cotable MOB.\n");
438438
goto out_done;
@@ -502,7 +502,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
502502

503503
vmw_resource_mob_attach(res);
504504
/* Let go of the old mob. */
505-
vmw_bo_unreference(&old_buf);
505+
vmw_user_bo_unref(&old_buf);
506506
res->id = vcotbl->type;
507507

508508
ret = dma_resv_reserve_fences(bo->base.resv, 1);
@@ -521,7 +521,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
521521
out_wait:
522522
ttm_bo_unpin(bo);
523523
ttm_bo_unreserve(bo);
524-
vmw_bo_unreference(&buf);
524+
vmw_user_bo_unref(&buf);
525525

526526
out_done:
527527
MKS_STAT_TIME_POP(MKSSTAT_KERN_COTABLE_RESIZE);

drivers/gpu/drm/vmwgfx/vmwgfx_drv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,10 @@ static inline bool vmw_resource_mob_attached(const struct vmw_resource *res)
853853
/**
854854
* GEM related functionality - vmwgfx_gem.c
855855
*/
856+
struct vmw_bo_params;
857+
int vmw_gem_object_create(struct vmw_private *vmw,
858+
struct vmw_bo_params *params,
859+
struct vmw_bo **p_vbo);
856860
extern int vmw_gem_object_create_with_handle(struct vmw_private *dev_priv,
857861
struct drm_file *filp,
858862
uint32_t size,

drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,7 +1151,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
11511151
SVGAMobId *id,
11521152
struct vmw_bo **vmw_bo_p)
11531153
{
1154-
struct vmw_bo *vmw_bo;
1154+
struct vmw_bo *vmw_bo, *tmp_bo;
11551155
uint32_t handle = *id;
11561156
struct vmw_relocation *reloc;
11571157
int ret;
@@ -1164,7 +1164,8 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
11641164
}
11651165
vmw_bo_placement_set(vmw_bo, VMW_BO_DOMAIN_MOB, VMW_BO_DOMAIN_MOB);
11661166
ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo);
1167-
vmw_user_bo_unref(vmw_bo);
1167+
tmp_bo = vmw_bo;
1168+
vmw_user_bo_unref(&tmp_bo);
11681169
if (unlikely(ret != 0))
11691170
return ret;
11701171

@@ -1206,7 +1207,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
12061207
SVGAGuestPtr *ptr,
12071208
struct vmw_bo **vmw_bo_p)
12081209
{
1209-
struct vmw_bo *vmw_bo;
1210+
struct vmw_bo *vmw_bo, *tmp_bo;
12101211
uint32_t handle = ptr->gmrId;
12111212
struct vmw_relocation *reloc;
12121213
int ret;
@@ -1220,7 +1221,8 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
12201221
vmw_bo_placement_set(vmw_bo, VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM,
12211222
VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM);
12221223
ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo);
1223-
vmw_user_bo_unref(vmw_bo);
1224+
tmp_bo = vmw_bo;
1225+
vmw_user_bo_unref(&tmp_bo);
12241226
if (unlikely(ret != 0))
12251227
return ret;
12261228

drivers/gpu/drm/vmwgfx/vmwgfx_gem.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,20 @@ static const struct drm_gem_object_funcs vmw_gem_object_funcs = {
111111
.vm_ops = &vmw_vm_ops,
112112
};
113113

114+
int vmw_gem_object_create(struct vmw_private *vmw,
115+
struct vmw_bo_params *params,
116+
struct vmw_bo **p_vbo)
117+
{
118+
int ret = vmw_bo_create(vmw, params, p_vbo);
119+
120+
if (ret != 0)
121+
goto out_no_bo;
122+
123+
(*p_vbo)->tbo.base.funcs = &vmw_gem_object_funcs;
124+
out_no_bo:
125+
return ret;
126+
}
127+
114128
int vmw_gem_object_create_with_handle(struct vmw_private *dev_priv,
115129
struct drm_file *filp,
116130
uint32_t size,
@@ -126,12 +140,10 @@ int vmw_gem_object_create_with_handle(struct vmw_private *dev_priv,
126140
.pin = false
127141
};
128142

129-
ret = vmw_bo_create(dev_priv, &params, p_vbo);
143+
ret = vmw_gem_object_create(dev_priv, &params, p_vbo);
130144
if (ret != 0)
131145
goto out_no_bo;
132146

133-
(*p_vbo)->tbo.base.funcs = &vmw_gem_object_funcs;
134-
135147
ret = drm_gem_handle_create(filp, &(*p_vbo)->tbo.base, handle);
136148
out_no_bo:
137149
return ret;

drivers/gpu/drm/vmwgfx/vmwgfx_kms.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,8 +1471,8 @@ static int vmw_create_bo_proxy(struct drm_device *dev,
14711471
/* Reserve and switch the backing mob. */
14721472
mutex_lock(&res->dev_priv->cmdbuf_mutex);
14731473
(void) vmw_resource_reserve(res, false, true);
1474-
vmw_bo_unreference(&res->guest_memory_bo);
1475-
res->guest_memory_bo = vmw_bo_reference(bo_mob);
1474+
vmw_user_bo_unref(&res->guest_memory_bo);
1475+
res->guest_memory_bo = vmw_user_bo_ref(bo_mob);
14761476
res->guest_memory_offset = 0;
14771477
vmw_resource_unreserve(res, false, false, false, NULL, 0);
14781478
mutex_unlock(&res->dev_priv->cmdbuf_mutex);
@@ -1666,7 +1666,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
16661666
err_out:
16671667
/* vmw_user_lookup_handle takes one ref so does new_fb */
16681668
if (bo)
1669-
vmw_user_bo_unref(bo);
1669+
vmw_user_bo_unref(&bo);
16701670
if (surface)
16711671
vmw_surface_unreference(&surface);
16721672

drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data,
451451

452452
ret = vmw_overlay_update_stream(dev_priv, buf, arg, true);
453453

454-
vmw_user_bo_unref(buf);
454+
vmw_user_bo_unref(&buf);
455455

456456
out_unlock:
457457
mutex_unlock(&overlay->mutex);

drivers/gpu/drm/vmwgfx/vmwgfx_resource.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ static void vmw_resource_release(struct kref *kref)
141141
if (res->coherent)
142142
vmw_bo_dirty_release(res->guest_memory_bo);
143143
ttm_bo_unreserve(bo);
144-
vmw_bo_unreference(&res->guest_memory_bo);
144+
vmw_user_bo_unref(&res->guest_memory_bo);
145145
}
146146

147147
if (likely(res->hw_destroy != NULL)) {
@@ -338,7 +338,7 @@ static int vmw_resource_buf_alloc(struct vmw_resource *res,
338338
return 0;
339339
}
340340

341-
ret = vmw_bo_create(res->dev_priv, &bo_params, &gbo);
341+
ret = vmw_gem_object_create(res->dev_priv, &bo_params, &gbo);
342342
if (unlikely(ret != 0))
343343
goto out_no_bo;
344344

@@ -457,11 +457,11 @@ void vmw_resource_unreserve(struct vmw_resource *res,
457457
vmw_resource_mob_detach(res);
458458
if (res->coherent)
459459
vmw_bo_dirty_release(res->guest_memory_bo);
460-
vmw_bo_unreference(&res->guest_memory_bo);
460+
vmw_user_bo_unref(&res->guest_memory_bo);
461461
}
462462

463463
if (new_guest_memory_bo) {
464-
res->guest_memory_bo = vmw_bo_reference(new_guest_memory_bo);
464+
res->guest_memory_bo = vmw_user_bo_ref(new_guest_memory_bo);
465465

466466
/*
467467
* The validation code should already have added a
@@ -551,7 +551,7 @@ vmw_resource_check_buffer(struct ww_acquire_ctx *ticket,
551551
ttm_bo_put(val_buf->bo);
552552
val_buf->bo = NULL;
553553
if (guest_memory_dirty)
554-
vmw_bo_unreference(&res->guest_memory_bo);
554+
vmw_user_bo_unref(&res->guest_memory_bo);
555555

556556
return ret;
557557
}
@@ -727,7 +727,7 @@ int vmw_resource_validate(struct vmw_resource *res, bool intr,
727727
goto out_no_validate;
728728
else if (!res->func->needs_guest_memory && res->guest_memory_bo) {
729729
WARN_ON_ONCE(vmw_resource_mob_attached(res));
730-
vmw_bo_unreference(&res->guest_memory_bo);
730+
vmw_user_bo_unref(&res->guest_memory_bo);
731731
}
732732

733733
return 0;

drivers/gpu/drm/vmwgfx/vmwgfx_shader.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ static int vmw_gb_shader_init(struct vmw_private *dev_priv,
180180

181181
res->guest_memory_size = size;
182182
if (byte_code) {
183-
res->guest_memory_bo = vmw_bo_reference(byte_code);
183+
res->guest_memory_bo = vmw_user_bo_ref(byte_code);
184184
res->guest_memory_offset = offset;
185185
}
186186
shader->size = size;
@@ -809,7 +809,7 @@ static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,
809809
shader_type, num_input_sig,
810810
num_output_sig, tfile, shader_handle);
811811
out_bad_arg:
812-
vmw_user_bo_unref(buffer);
812+
vmw_user_bo_unref(&buffer);
813813
return ret;
814814
}
815815

0 commit comments

Comments
 (0)