From: Desmond Cheong Zhi Xi desmondcheongzx@gmail.com
stable inclusion from stable-v5.10.44 commit 491d52e0078860b33b6c14f0a7ac74ca1b603bd6 bugzilla: https://bugzilla.openeuler.org/show_bug.cgi?id=390 CVE: NA
-------------------------------------------------
commit b436acd1cf7fac0ba987abd22955d98025c80c2b upstream.
There is a time-of-check-to-time-of-use error in drm_getunique() due to retrieving file_priv->master prior to locking the device's master mutex.
An example can be seen in the crash report of the use-after-free error found by Syzbot: https://syzkaller.appspot.com/bug?id=148d2f1dfac64af52ffd27b661981a540724f80...
In the report, the master pointer was used after being freed. This is because another process had acquired the device's master mutex in drm_setmaster_ioctl(), then overwrote fpriv->master in drm_new_set_master(). The old value of fpriv->master was subsequently freed before the mutex was unlocked.
To fix this, we lock the device's master mutex before retrieving the pointer from from fpriv->master. This patch passes the Syzbot reproducer test.
Reported-by: syzbot+c3a706cec1ea99e1c693@syzkaller.appspotmail.com Signed-off-by: Desmond Cheong Zhi Xi desmondcheongzx@gmail.com Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter daniel.vetter@ffwll.ch Link: https://patchwork.freedesktop.org/patch/msgid/20210608110436.239583-1-desmon... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Cwj 161434832@qq.com --- drivers/gpu/drm/drm_ioctl.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 789ee65ac1f5..ae647be4a49f 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -118,17 +118,18 @@ int drm_getunique(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_unique *u = data; - struct drm_master *master = file_priv->master; + struct drm_master *master;
- mutex_lock(&master->dev->master_mutex); + mutex_lock(&dev->master_mutex); + master = file_priv->master; if (u->unique_len >= master->unique_len) { if (copy_to_user(u->unique, master->unique, master->unique_len)) { - mutex_unlock(&master->dev->master_mutex); + mutex_unlock(&dev->master_mutex); return -EFAULT; } } u->unique_len = master->unique_len; - mutex_unlock(&master->dev->master_mutex); + mutex_unlock(&dev->master_mutex);
return 0; }