This fixes stack smashing I've seen in Okteta.

The problem is that fd_set by default uses limit (FD_SETSIZE) of 1024,
unless FD_SETSIZE is set before including the <sys/select.h> header.
The Qt4 source code contains some checks, but backtrace from GDB tells
they're not enough. Instead of spending time on looking what's missed,
I've just replaced select(2) with poll(2). Given that code actually
shrunk, and I see no crashes anymore, I think it should go in.

I suppose this could be a security issue, as you could somehow trigger
stack smashing, but I can't see anything harder than local DoS for now.
But this could be different for some Qt-based apps. There are more
select(2) calls which I'm willing to tweak before, though. This patch
just fixes a problem I faced.

Remember that Qt4 is EOL, so we don't have to bother about pushing
those patches upstream. On the other side, Qt5 wants same treatment.
Not sure that all platforms Qt5 runs on support poll(2) correctly,
though.

So, okay for this patch going in for now?
--
WBR,
  Vadim Zhukov


Index: Makefile
===================================================================
RCS file: /cvs/ports/x11/qt4/Makefile,v
retrieving revision 1.131
diff -u -p -r1.131 Makefile
--- Makefile    6 Jan 2016 17:17:32 -0000       1.131
+++ Makefile    30 Jan 2016 19:46:21 -0000
@@ -24,7 +24,7 @@ PKGNAME-main =                qt4-${PKGVERSION}
 PKGNAME-debug =                qt4-debug-${PKGVERSION}
 FULLPKGNAME-html =     qt4-html-${PKGVERSION}
 FULLPKGPATH-html =     ${BASE_PKGPATH},-html
-REVISION-main =                3
+REVISION-main =                4
 
 # XXX qmake include parser is bogus
 DPB_PROPERTIES =       parallel        nojunk
Index: patches/patch-src_network_socket_qnativesocketengine_unix_cpp
===================================================================
RCS file: patches/patch-src_network_socket_qnativesocketengine_unix_cpp
diff -N patches/patch-src_network_socket_qnativesocketengine_unix_cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_network_socket_qnativesocketengine_unix_cpp       30 Jan 
2016 19:46:21 -0000
@@ -0,0 +1,78 @@
+$OpenBSD$
+Fix for cases of >1024 open files.
+--- src/network/socket/qnativesocketengine_unix.cpp.orig       Sat Jan 30 
09:34:38 2016
++++ src/network/socket/qnativesocketengine_unix.cpp    Sat Jan 30 19:19:51 2016
+@@ -50,6 +50,7 @@
+ #include <time.h>
+ #include <errno.h>
+ #include <fcntl.h>
++#include <poll.h>
+ #ifndef QT_NO_IPV6IFNAME
+ #include <net/if.h>
+ #endif
+@@ -1068,48 +1069,31 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *da
+ 
+ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) 
const
+ {
+-    fd_set fds;
+-    FD_ZERO(&fds);
+-    FD_SET(socketDescriptor, &fds);
++    struct pollfd pd;
+ 
+-    struct timeval tv;
+-    tv.tv_sec = timeout / 1000;
+-    tv.tv_usec = (timeout % 1000) * 1000;
+-
+-    int retval;
+-    if (selectForRead)
+-        retval = qt_safe_select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 
? 0 : &tv);
+-    else
+-        retval = qt_safe_select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 
? 0 : &tv);
+-
+-    return retval;
++    memset(&pd, 0, sizeof(struct pollfd));
++    pd.fd = socketDescriptor;
++    pd.events = selectForRead ? POLLIN : POLLHUP;
++    return poll(&pd, 1, timeout); 
+ }
+ 
+ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, 
bool checkWrite,
+                        bool *selectForRead, bool *selectForWrite) const
+ {
+-    fd_set fdread;
+-    FD_ZERO(&fdread);
+-    if (checkRead)
+-        FD_SET(socketDescriptor, &fdread);
+-
+-    fd_set fdwrite;
+-    FD_ZERO(&fdwrite);
+-    if (checkWrite)
+-        FD_SET(socketDescriptor, &fdwrite);
+-
+-    struct timeval tv;
+-    tv.tv_sec = timeout / 1000;
+-    tv.tv_usec = (timeout % 1000) * 1000;
+-
++    struct pollfd pd;
+     int ret;
+-    ret = qt_safe_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout 
< 0 ? 0 : &tv);
+ 
+-    if (ret <= 0)
+-        return ret;
+-    *selectForRead = FD_ISSET(socketDescriptor, &fdread);
+-    *selectForWrite = FD_ISSET(socketDescriptor, &fdwrite);
+-
++    memset(&pd, 0, sizeof(struct pollfd));
++    pd.fd = socketDescriptor;
++    if (checkRead)
++        pd.events |= POLLIN;
++    if (checkWrite)
++        pd.events |= POLLOUT;
++    ret = poll(&pd, 1, timeout); 
++    if (ret > 0) {
++        *selectForRead = ((pd.events & POLLIN) == POLLIN);
++        *selectForWrite = ((pd.events & POLLOUT) == POLLOUT);
++    }
+     return ret;
+ }
+ 

Reply via email to