From: Daniel Vetter <daniel.vetter@xxxxxxxx> commit 4b848f20eda5974020f043ca14bacf7a7e634fc8 upstream. There's two references floating around here (for the object reference, not the handle_count reference, that's a different thing): - The temporary reference held by vgem_gem_create, acquired by creating the object and released by calling drm_gem_object_put_unlocked. - The reference held by the object handle, created by drm_gem_handle_create. This one generally outlives the function, except if a 2nd thread races with a GEM_CLOSE ioctl call. So usually everything is correct, except in that race case, where the access to gem_object->size could be looking at freed data already. Which again isn't a real problem (userspace shot its feet off already with the race, we could return garbage), but maybe someone can exploit this as an information leak. Cc: Dan Carpenter <dan.carpenter@xxxxxxxxxx> Cc: Hillf Danton <hdanton@xxxxxxxx> Reported-by: syzbot+0dc4444774d419e916c8@xxxxxxxxxxxxxxxxxxxxxxxxx Cc: stable@xxxxxxxxxxxxxxx Cc: Emil Velikov <emil.velikov@xxxxxxxxxxxxx> Cc: Daniel Vetter <daniel.vetter@xxxxxxxx> Cc: Sean Paul <seanpaul@xxxxxxxxxxxx> Cc: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> Cc: Eric Anholt <eric@xxxxxxxxxx> Cc: Sam Ravnborg <sam@xxxxxxxxxxxx> Cc: Rob Clark <robdclark@xxxxxxxxxxxx> Reviewed-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> Signed-off-by: Daniel Vetter <daniel.vetter@xxxxxxxxx> Link: https://patchwork.freedesktop.org/patch/msgid/20200202132133.1891846-1-daniel.vetter@xxxxxxxx [OP: backport to 4.19: adjusted DRM_DEBUG() -> DRM_DEBUG_DRIVER()] Signed-off-by: Ovidiu Panait <ovidiu.panait@xxxxxxxxxxxxx> --- This is the fix for CVE-2022-1419. The testcase from [1] adjusted to run in a while(1); loop generates the following KASAN trace currently: root@intel-x86-64:~# ./poc [ 37.663495] ================================================================== [ 37.664441] BUG: KASAN: use-after-free in vgem_gem_dumb_create+0x22c/0x240 [ 37.665266] Read of size 8 at addr ffff88810b27b380 by task poc/5993 [ 37.666047] [ 37.666257] CPU: 1 PID: 5993 Comm: poc Not tainted 4.19.241 #7 [ 37.666937] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014 [ 37.668034] Call Trace: [ 37.668360] dump_stack+0x188/0x1ff [ 37.668804] ? vgem_gem_dumb_create+0x22c/0x240 [ 37.669376] print_address_description.cold+0x7c/0x212 [ 37.670004] ? vgem_gem_dumb_create+0x22c/0x240 [ 37.670553] kasan_report.cold+0x88/0x2af [ 37.671059] vgem_gem_dumb_create+0x22c/0x240 [ 37.671602] drm_mode_create_dumb+0x27e/0x310 [ 37.672153] drm_ioctl_kernel+0x1f1/0x2a0 [ 37.672647] ? drm_mode_create_dumb+0x310/0x310 [ 37.673199] ? drm_setversion+0x880/0x880 [ 37.673695] ? __might_fault+0x192/0x1d0 [ 37.674173] drm_ioctl+0x4e4/0x9a0 [ 37.674631] ? drm_mode_create_dumb+0x310/0x310 [ 37.675199] ? drm_version+0x3d0/0x3d0 [ 37.675659] ? pud_val+0xf0/0xf0 [ 37.676084] ? find_held_lock+0x2d/0x110 [ 37.676557] ? __fget+0x341/0x500 [ 37.676975] ? drm_version+0x3d0/0x3d0 [ 37.677443] do_vfs_ioctl+0xcdb/0x12e0 [ 37.677907] ? check_preemption_disabled+0x41/0x280 [ 37.678508] ? ioctl_preallocate+0x200/0x200 [ 37.679021] ? __fget+0x368/0x500 [ 37.679420] ? ksys_dup3+0x3c0/0x3c0 [ 37.679859] ? syscall_trace_enter+0x3b8/0xd50 [ 37.680387] ? syscall_get_arguments.part.0+0x10/0x10 [ 37.680980] ksys_ioctl+0x9b/0xc0 [ 37.681375] __x64_sys_ioctl+0x6f/0xb0 [ 37.681826] do_syscall_64+0xf0/0x180 [ 37.682275] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 37.682876] RIP: 0033:0x7fb3d3c0ac87 With the fix applied, the testcase is OK. [1] https://www.openwall.com/lists/oss-security/2022/04/21/1 drivers/gpu/drm/vgem/vgem_drv.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c index 1c1a435d354b..56ed771032c2 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.c +++ b/drivers/gpu/drm/vgem/vgem_drv.c @@ -189,9 +189,10 @@ static struct drm_gem_object *vgem_gem_create(struct drm_device *dev, return ERR_CAST(obj); ret = drm_gem_handle_create(file, &obj->base, handle); - drm_gem_object_put_unlocked(&obj->base); - if (ret) + if (ret) { + drm_gem_object_put_unlocked(&obj->base); return ERR_PTR(ret); + } return &obj->base; } @@ -214,7 +215,9 @@ static int vgem_gem_dumb_create(struct drm_file *file, struct drm_device *dev, args->size = gem_object->size; args->pitch = pitch; - DRM_DEBUG_DRIVER("Created object of size %lld\n", size); + drm_gem_object_put_unlocked(gem_object); + + DRM_DEBUG_DRIVER("Created object of size %llu\n", args->size); return 0; } -- 2.36.0