X11: Fix segfault when _glfw.x11.display is higher than 1024

FD_SETSIZE is hardcoded to 1024 in glibc. See the bugs section of the select call for more info.
In some cases, it is possible for _glfw.x11.display to be larger than FD_SETSIZE, causing a segfault or buffer overflow.
Replacing select() with poll() seems to be the recommended solution:
- https://www.man7.org/linux/man-pages/man2/select.2.html#BUGS
- https://access.redhat.com/solutions/488623
- https://stackoverflow.com/questions/7976388/increasing-limit-of-fd-setsize-and-select/7977082#7977082
This commit is contained in:
illustris 2022-01-04 08:10:05 +05:30
parent df8d7bc892
commit 57ab8acc0e

View File

@ -41,6 +41,10 @@
#include <errno.h> #include <errno.h>
#include <assert.h> #include <assert.h>
#if defined(__linux__)
#include <poll.h>
#endif
// Action for EWMH client messages // Action for EWMH client messages
#define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_REMOVE 0
#define _NET_WM_STATE_ADD 1 #define _NET_WM_STATE_ADD 1
@ -63,31 +67,47 @@
// //
static GLFWbool waitForEvent(double* timeout) static GLFWbool waitForEvent(double* timeout)
{ {
fd_set fds;
const int fd = ConnectionNumber(_glfw.x11.display); const int fd = ConnectionNumber(_glfw.x11.display);
int count = fd + 1;
int count;
#if defined(__linux__) #if defined(__linux__)
if (_glfw.linjs.inotify > fd) struct pollfd pfd[2];
count = _glfw.linjs.inotify + 1; #else
fd_set fds;
count = fd + 1;
#endif #endif
for (;;) for (;;)
{ {
#if defined(__linux__)
pfd[0].fd = fd;
pfd[0].events = POLLIN;
if (_glfw.linjs.inotify > 0)
{
count = 2;
pfd[1].fd = _glfw.linjs.inotify;
pfd[1].events = POLLIN;
}
else
count = 1;
#else
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(fd, &fds); FD_SET(fd, &fds);
#if defined(__linux__)
if (_glfw.linjs.inotify > 0)
FD_SET(_glfw.linjs.inotify, &fds);
#endif #endif
if (timeout) if (timeout)
{ {
const long seconds = (long) *timeout; const long seconds = (long) *timeout;
const long microseconds = (long) ((*timeout - seconds) * 1e6); const long microseconds = (long) ((*timeout - seconds) * 1e6);
struct timeval tv = { seconds, microseconds };
const uint64_t base = _glfwPlatformGetTimerValue(); const uint64_t base = _glfwPlatformGetTimerValue();
#if defined(__linux__)
int timeout_ms = (seconds * 1000) + (microseconds / 1000);
const int result = poll(pfd, count, timeout_ms);
#else
struct timeval tv = { seconds, microseconds };
const int result = select(count, &fds, NULL, NULL, &tv); const int result = select(count, &fds, NULL, NULL, &tv);
#endif
const int error = errno; const int error = errno;
*timeout -= (_glfwPlatformGetTimerValue() - base) / *timeout -= (_glfwPlatformGetTimerValue() - base) /
@ -98,7 +118,11 @@ static GLFWbool waitForEvent(double* timeout)
if ((result == -1 && error == EINTR) || *timeout <= 0.0) if ((result == -1 && error == EINTR) || *timeout <= 0.0)
return GLFW_FALSE; return GLFW_FALSE;
} }
#if defined(__linux__)
else if (poll(pfd, count, 0) != -1 || errno != EINTR)
#else
else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR) else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR)
#endif
return GLFW_TRUE; return GLFW_TRUE;
} }
} }