From b3e70318931691ad61eea88c460c21e140a14120 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Tue, 9 Mar 2021 10:09:21 +0200 Subject: [PATCH] platforms/drm: Fix potential stack corruption If the file descriptor of the DRM device is greater than FD_SETSIZE, the stack will be corrupted. However, it is highly unlikely that we ever hit this case because DRM devices are opened at startup of kwin, so the file descriptors should small. In order to prevent the potential stack corruption, this change replaces the usage of select() with poll(). Unlike select(), the api of poll() is much more sensible. Back 20 or so years ago the main argument against poll() was that it's not implemented by all platforms. But, nowadays, it's supported on all major platforms. --- src/plugins/platforms/drm/drm_gpu.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/plugins/platforms/drm/drm_gpu.cpp b/src/plugins/platforms/drm/drm_gpu.cpp index 4563db74d4..47cdf4303c 100644 --- a/src/plugins/platforms/drm/drm_gpu.cpp +++ b/src/plugins/platforms/drm/drm_gpu.cpp @@ -25,6 +25,7 @@ // system #include #include +#include #include // drm #include @@ -339,21 +340,21 @@ void DrmGpu::waitIdle() if (idle) { break; } - fd_set set; - FD_ZERO(&set); - FD_SET(m_fd, &set); - timeval timeout; - timeout.tv_sec = 30; - timeout.tv_usec = 0; - const int descriptorCount = select(m_fd + 1, &set, nullptr, nullptr, &timeout); - if (descriptorCount < 0) { - qCWarning(KWIN_DRM) << "select() in DrmGpu::waitIdle failed:" << strerror(errno); - break; - } else if (FD_ISSET(m_fd, &set)) { - dispatchEvents(); - } else { + pollfd pfds[1]; + pfds[0].fd = m_fd; + pfds[0].events = POLLIN; + + const int ready = poll(pfds, 1, 30000); + if (ready < 0) { + if (errno != EINTR) { + qCWarning(KWIN_DRM) << Q_FUNC_INFO << "poll() failed:" << strerror(errno); + break; + } + } else if (ready == 0) { qCWarning(KWIN_DRM) << "No drm events for gpu" << m_devNode << "within last 30 seconds"; break; + } else { + dispatchEvents(); } }; m_socketNotifier->setEnabled(true);