summaryrefslogtreecommitdiffstats
path: root/libvncserver
diff options
context:
space:
mode:
authorChristian Beier <dontmind@freeshell.org>2019-01-06 19:16:02 +0100
committerGitHub <noreply@github.com>2019-01-06 19:16:02 +0100
commitffa449ad01d803acdace6d178ef198d9abdcc16f (patch)
tree73a3e1433fbe1ae4f184d0a47949ccc844fcb300 /libvncserver
parentcd197f6daea0f750a76e8e9d5a5b78cfd24ebeb3 (diff)
parent00bae113d54014bafcf20c9f4c8c296e3e91bde5 (diff)
downloadlibtdevnc-ffa449ad01d803acdace6d178ef198d9abdcc16f.tar.gz
libtdevnc-ffa449ad01d803acdace6d178ef198d9abdcc16f.zip
Merge pull request #238 from tetrane/pr-fix-use-after-free
Fix use-after-free and concurrent access segmentation fault
Diffstat (limited to 'libvncserver')
-rw-r--r--libvncserver/main.c50
-rw-r--r--libvncserver/rfbserver.c5
2 files changed, 46 insertions, 9 deletions
diff --git a/libvncserver/main.c b/libvncserver/main.c
index 05b4b13..17bef7e 100644
--- a/libvncserver/main.c
+++ b/libvncserver/main.c
@@ -33,6 +33,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
+#include <fcntl.h>
#endif
#include <signal.h>
@@ -533,6 +534,7 @@ clientInput(void *data)
FD_ZERO(&rfds);
FD_SET(cl->sock, &rfds);
+ FD_SET(cl->pipe_notify_client_thread[0], &rfds);
FD_ZERO(&efds);
FD_SET(cl->sock, &efds);
@@ -541,9 +543,13 @@ clientInput(void *data)
if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1))
FD_SET(cl->sock, &wfds);
+ int nfds = cl->pipe_notify_client_thread[0] > cl->sock ? cl->pipe_notify_client_thread[0] : cl->sock;
+
tv.tv_sec = 60; /* 1 minute */
tv.tv_usec = 0;
- n = select(cl->sock + 1, &rfds, &wfds, &efds, &tv);
+
+ n = select(nfds + 1, &rfds, &wfds, &efds, &tv);
+
if (n < 0) {
rfbLogPerror("ReadExact: select");
break;
@@ -558,6 +564,13 @@ clientInput(void *data)
if (FD_ISSET(cl->sock, &wfds))
rfbSendFileTransferChunk(cl);
+ if (FD_ISSET(cl->pipe_notify_client_thread[0], &rfds))
+ {
+ // Reset the pipe
+ char buf;
+ while (read(cl->pipe_notify_client_thread[0], &buf, sizeof(buf)) == sizeof(buf));
+ }
+
if (FD_ISSET(cl->sock, &rfds) || FD_ISSET(cl->sock, &efds))
{
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
@@ -628,8 +641,15 @@ rfbStartOnHoldClient(rfbClientPtr cl)
{
cl->onHold = FALSE;
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
- if(cl->screen->backgroundLoop)
- pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl);
+ if(cl->screen->backgroundLoop) {
+ if (pipe(cl->pipe_notify_client_thread) == -1) {
+ cl->pipe_notify_client_thread[0] = -1;
+ cl->pipe_notify_client_thread[1] = -1;
+ }
+ fcntl(cl->pipe_notify_client_thread[0], F_SETFL, O_NONBLOCK);
+
+ pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl);
+ }
#endif
}
@@ -1081,15 +1101,27 @@ void rfbInitServer(rfbScreenInfoPtr screen)
void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) {
if(disconnectClients) {
- rfbClientPtr cl;
rfbClientIteratorPtr iter = rfbGetClientIterator(screen);
- while( (cl = rfbClientIteratorNext(iter)) ) {
- if (cl->sock > -1) {
- /* we don't care about maxfd here, because the server goes away */
- rfbCloseClient(cl);
- rfbClientConnectionGone(cl);
+ rfbClientPtr nextCl, currentCl = rfbClientIteratorNext(iter);
+
+ while(currentCl) {
+ nextCl = rfbClientIteratorNext(iter);
+ if (currentCl->sock > -1) {
+ /* we don't care about maxfd here, because the server goes away */
+ rfbCloseClient(currentCl);
}
+
+#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+ // Notify the thread and join it
+ write(currentCl->pipe_notify_client_thread[1], "\x00", 1);
+ pthread_join(currentCl->client_thread, NULL);
+#else
+ rfbClientConnectionGone(currentCl);
+#endif
+
+ currentCl = nextCl;
}
+
rfbReleaseClientIterator(iter);
}
diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c
index e210a32..7af8490 100644
--- a/libvncserver/rfbserver.c
+++ b/libvncserver/rfbserver.c
@@ -619,6 +619,11 @@ rfbClientConnectionGone(rfbClientPtr cl)
UNLOCK(cl->sendMutex);
TINI_MUTEX(cl->sendMutex);
+#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+ close(cl->pipe_notify_client_thread[0]);
+ close(cl->pipe_notify_client_thread[1]);
+#endif
+
rfbPrintStats(cl);
rfbResetStats(cl);