Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/atomic: Fix potential use-after-free in nonblocking commits

This requires a bit of background. Properly done a modeset driver's
unload/remove sequence should be

drm_dev_unplug();
drm_atomic_helper_shutdown();
drm_dev_put();

The trouble is that the drm_dev_unplugged() checks are by design racy,
they do not synchronize against all outstanding ioctl. This is because
those ioctl could block forever (both for modeset and for driver
specific ioctls), leading to deadlocks in hotunplug. Instead the code
sections that touch the hardware need to be annotated with
drm_dev_enter/exit, to avoid accessing hardware resources after the
unload/remove has finished.

To avoid use-after-free issues all the involved userspace visible
objects are supposed to hold a reference on the underlying drm_device,
like drm_file does.

The issue now is that we missed one, the atomic modeset ioctl can be run
in a nonblocking fashion, and in that case it cannot rely on the implied
drm_device reference provided by the ioctl calling context. This can
result in a use-after-free if an nonblocking atomic commit is carefully
raced against a driver unload.

Fix this by unconditionally grabbing a drm_device reference for any
drm_atomic_state structures. Strictly speaking this isn't required for
blocking commits and TEST_ONLY calls, but it's the simpler approach.

Thanks to shanzhulig for the initial idea of grabbing an unconditional
reference, I just added comments, a condensed commit message and fixed a
minor potential issue in where exactly we drop the final reference.

Reported-by: shanzhulig <shanzhulig@gmail.com>
Suggested-by: shanzhulig <shanzhulig@gmail.com>
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: David Airlie <airlied@gmail.com>
Cc: stable@kernel.org
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Daniel Vetter and committed by
Linus Torvalds
4e076c73 f7e3a1ba

+10 -1
+10 -1
drivers/gpu/drm/drm_atomic.c
··· 140 140 if (!state->planes) 141 141 goto fail; 142 142 143 + /* 144 + * Because drm_atomic_state can be committed asynchronously we need our 145 + * own reference and cannot rely on the on implied by drm_file in the 146 + * ioctl call. 147 + */ 148 + drm_dev_get(dev); 143 149 state->dev = dev; 144 150 145 151 drm_dbg_atomic(dev, "Allocated atomic state %p\n", state); ··· 305 299 void __drm_atomic_state_free(struct kref *ref) 306 300 { 307 301 struct drm_atomic_state *state = container_of(ref, typeof(*state), ref); 308 - struct drm_mode_config *config = &state->dev->mode_config; 302 + struct drm_device *dev = state->dev; 303 + struct drm_mode_config *config = &dev->mode_config; 309 304 310 305 drm_atomic_state_clear(state); 311 306 ··· 318 311 drm_atomic_state_default_release(state); 319 312 kfree(state); 320 313 } 314 + 315 + drm_dev_put(dev); 321 316 } 322 317 EXPORT_SYMBOL(__drm_atomic_state_free); 323 318