Skip to content

Commit e4a0e09

Browse files
danvetgregkh
authored andcommitted
drm/atomic: Fix potential use-after-free in nonblocking commits
commit 4e076c7 upstream. 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 <[email protected]> Suggested-by: shanzhulig <[email protected]> Reviewed-by: Maxime Ripard <[email protected]> Cc: Maarten Lankhorst <[email protected]> Cc: Thomas Zimmermann <[email protected]> Cc: David Airlie <[email protected]> Cc: [email protected] Signed-off-by: Daniel Vetter <[email protected]> Signed-off-by: Daniel Vetter <[email protected]> Signed-off-by: Linus Torvalds <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent d34a347 commit e4a0e09

File tree

1 file changed

+10
-1
lines changed

1 file changed

+10
-1
lines changed

drivers/gpu/drm/drm_atomic.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
140140
if (!state->planes)
141141
goto fail;
142142

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);
143149
state->dev = dev;
144150

145151
drm_dbg_atomic(dev, "Allocated atomic state %p\n", state);
@@ -299,7 +305,8 @@ EXPORT_SYMBOL(drm_atomic_state_clear);
299305
void __drm_atomic_state_free(struct kref *ref)
300306
{
301307
struct drm_atomic_state *state = container_of(ref, typeof(*state), ref);
302-
struct drm_mode_config *config = &state->dev->mode_config;
308+
struct drm_device *dev = state->dev;
309+
struct drm_mode_config *config = &dev->mode_config;
303310

304311
drm_atomic_state_clear(state);
305312

@@ -311,6 +318,8 @@ void __drm_atomic_state_free(struct kref *ref)
311318
drm_atomic_state_default_release(state);
312319
kfree(state);
313320
}
321+
322+
drm_dev_put(dev);
314323
}
315324
EXPORT_SYMBOL(__drm_atomic_state_free);
316325

0 commit comments

Comments
 (0)