From: Tuo Li islituo@gmail.com
stable inclusion from stable-v5.10.197 commit 5475b8bea1489403a4e6c2d102fcb5dde310acb3 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I917IV
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
[ Upstream commit 2e63972a2de14482d0eae1a03a73e379f1c3f44c ]
The variable crtc->state->event is often protected by the lock crtc->dev->event_lock when is accessed. However, it is accessed as a condition of an if statement in exynos_drm_crtc_atomic_disable() without holding the lock:
if (crtc->state->event && !crtc->state->active)
However, if crtc->state->event is changed to NULL by another thread right after the conditions of the if statement is checked to be true, a null-pointer dereference can occur in drm_crtc_send_vblank_event():
e->pipe = pipe;
To fix this possible null-pointer dereference caused by data race, the spin lock coverage is extended to protect the if statement as well as the function call to drm_crtc_send_vblank_event().
Reported-by: BassCheck bass@buaa.edu.cn Link: https://sites.google.com/view/basscheck/home Signed-off-by: Tuo Li islituo@gmail.com Reviewed-by: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org Added relevant link. Signed-off-by: Inki Dae inki.dae@samsung.com Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: Wang Hai wanghai38@huawei.com --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 1c03485676ef..de9fadccf22e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -39,13 +39,12 @@ static void exynos_drm_crtc_atomic_disable(struct drm_crtc *crtc, if (exynos_crtc->ops->atomic_disable) exynos_crtc->ops->atomic_disable(exynos_crtc);
+ spin_lock_irq(&crtc->dev->event_lock); if (crtc->state->event && !crtc->state->active) { - spin_lock_irq(&crtc->dev->event_lock); drm_crtc_send_vblank_event(crtc, crtc->state->event); - spin_unlock_irq(&crtc->dev->event_lock); - crtc->state->event = NULL; } + spin_unlock_irq(&crtc->dev->event_lock); }
static int exynos_crtc_atomic_check(struct drm_crtc *crtc,