Package: release.debian.org
Severity: normal
User: release.debian....@packages.debian.org
Usertags: unblock

I prepared an upload to fix grave bug #762745, cherry-picking patches from
upstream to fix multiple vulnerabilities. I also took the chance to include
fixes for #766257 and #758754. Please tell me whether I should drop these
instead.

The problem with this (tentative) upload is related to this commit, needed to
fix CVE-2014-6055:
https://github.com/newsoft/libvncserver/commit/06ccdf016154fde8eccb5355613ba04c59127b2e

It seems there's an API/ABI break, also reported in RedHat, as per
https://bugzilla.redhat.com/show_bug.cgi?id=1144293#c2, which could be
problematic at this point. What would be the recommended way to proceed from
here?



-- System Information:
Debian Release: jessie/sid
  APT prefers testing-updates
  APT policy: (500, 'testing-updates'), (500, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 3.16-3-amd64 (SMP w/8 CPU cores)
diff --git a/debian/changelog b/debian/changelog
index 4cb521d..77de074 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,19 @@
+libvncserver (0.9.9+dfsg-7) UNRELEASED; urgency=medium
+
+  * debian/patches/CVE-2014.patch:
+    - Fix multiple vulnerabilities (Closes: #762745).
+      - CVE-2014-6051 Integer overflow in MallocFrameBuffer() on client side.
+      - CVE-2014-6052 Lack of malloc() return value checking on client side.
+      - CVE-2014-6053 Server crash on a very large ClientCutText message.
+      - CVE-2014-6054 Server crash when scaling factor is set to zero.
+      - CVE-2014-6055 Multiple stack overflows in File Transfer feature.
+  * debian/patches/novnc.patch:
+    - Set opcode correctly for binary frames (Closes: #766257).
+  * debian/control:
+    - Use uppercase VNC in short descriptions (Closes: #758754).
+
+ -- Luca Falavigna <dktrkr...@debian.org>  Fri, 21 Nov 2014 20:51:50 +0100
+
 libvncserver (0.9.9+dfsg-6) unstable; urgency=medium
 
   [ Luca Falavigna ]
diff --git a/debian/control b/debian/control
index 9e188be..17ebbe6 100644
--- a/debian/control
+++ b/debian/control
@@ -22,7 +22,7 @@ Depends: ${shlibs:Depends},
 Breaks: libvncserver0 (<< 0.9.9+dfsg-3)
 Replaces: libvncserver0 (<< 0.9.9+dfsg-3)
 Multi-Arch: same
-Description: API to write one's own vnc server - client library
+Description: API to write one's own VNC server - client library
  LibVNCServer makes writing a VNC server (or more correctly, a program
  exporting a framebuffer via the Remote Frame Buffer protocol) easy. It hides
  the programmer from the tedious task of managing clients and compression.
@@ -35,7 +35,7 @@ Pre-Depends: ${misc:Pre-Depends}
 Depends: ${shlibs:Depends},
          ${misc:Depends}
 Multi-Arch: same
-Description: API to write one's own vnc server
+Description: API to write one's own VNC server
  LibVNCServer makes writing a VNC server (or more correctly, a program
  exporting a framebuffer via the Remote Frame Buffer protocol) easy. It hides
  the programmer from the tedious task of managing clients and compression.
@@ -53,7 +53,7 @@ Depends: ${misc:Depends},
          zlib1g-dev,
          libvncserver-config
 Multi-Arch: same
-Description: API to write one's own vnc server - development files
+Description: API to write one's own VNC server - development files
  LibVNCServer makes writing a VNC server (or more correctly, a program
  exporting a framebuffer via the Remote Frame Buffer protocol) easy. It hides
  the programmer from the tedious task of managing clients and compression.
@@ -68,7 +68,7 @@ Depends: ${misc:Depends},
          libvncclient0 (= ${binary:Version}),
          libvncserver0 (= ${binary:Version})
 Multi-Arch: foreign
-Description: API to write one's own vnc server - library utility
+Description: API to write one's own VNC server - library utility
  LibVNCServer makes writing a VNC server (or more correctly, a program
  exporting a framebuffer via the Remote Frame Buffer protocol) easy. It hides
  the programmer from the tedious task of managing clients and compression.
diff --git a/debian/patches/CVE-2014.patch b/debian/patches/CVE-2014.patch
new file mode 100644
index 0000000..3931854
--- /dev/null
+++ b/debian/patches/CVE-2014.patch
@@ -0,0 +1,293 @@
+Description: Fix CVE-2014-6051 CVE-2014-6052 CVE-2014-6053
+ CVE-2014-6054 CVE-2014-6055
+Author: Nicolas Ruff <nr...@google.com>
+
+Index: libvncserver/libvncclient/rfbproto.c
+===================================================================
+--- libvncserver.orig/libvncclient/rfbproto.c	2014-11-21 20:35:19.488146693 +0100
++++ libvncserver/libvncclient/rfbproto.c	2014-11-21 20:45:30.973828663 +0100
+@@ -1807,7 +1807,8 @@
+ 	client->updateRect.x = client->updateRect.y = 0;
+ 	client->updateRect.w = client->width;
+ 	client->updateRect.h = client->height;
+-	client->MallocFrameBuffer(client);
++  if (!client->MallocFrameBuffer(client))
++    return FALSE;
+ 	SendFramebufferUpdateRequest(client, 0, 0, rect.r.w, rect.r.h, FALSE);
+ 	rfbClientLog("Got new framebuffer size: %dx%d\n", rect.r.w, rect.r.h);
+ 	continue;
+@@ -2276,7 +2277,9 @@
+     client->updateRect.x = client->updateRect.y = 0;
+     client->updateRect.w = client->width;
+     client->updateRect.h = client->height;
+-    client->MallocFrameBuffer(client);
++    if (!client->MallocFrameBuffer(client))
++      return FALSE;
++
+     SendFramebufferUpdateRequest(client, 0, 0, client->width, client->height, FALSE);
+     rfbClientLog("Got new framebuffer size: %dx%d\n", client->width, client->height);
+     break;
+Index: libvncserver/libvncclient/vncviewer.c
+===================================================================
+--- libvncserver.orig/libvncclient/vncviewer.c	2014-11-21 20:35:19.488146693 +0100
++++ libvncserver/libvncclient/vncviewer.c	2014-11-21 20:45:30.973828663 +0100
+@@ -82,9 +82,27 @@
+ #endif
+ }
+ static rfbBool MallocFrameBuffer(rfbClient* client) {
++uint64_t allocSize;
++
+   if(client->frameBuffer)
+     free(client->frameBuffer);
+-  client->frameBuffer=malloc(client->width*client->height*client->format.bitsPerPixel/8);
++
++  /* SECURITY: promote 'width' into uint64_t so that the multiplication does not overflow
++     'width' and 'height' are 16-bit integers per RFB protocol design
++     SIZE_MAX is the maximum value that can fit into size_t
++  */
++  allocSize = (uint64_t)client->width * client->height * client->format.bitsPerPixel/8;
++
++  if (allocSize >= SIZE_MAX) {
++    rfbClientErr("CRITICAL: cannot allocate frameBuffer, requested size is too large\n");
++    return FALSE;
++  }
++
++  client->frameBuffer=malloc( (size_t)allocSize );
++
++  if (client->frameBuffer == NULL)
++    rfbClientErr("CRITICAL: frameBuffer allocation failed, requested size too large or not enough memory?\n");
++
+   return client->frameBuffer?TRUE:FALSE;
+ }
+ 
+@@ -225,7 +243,8 @@
+ 
+   client->width=client->si.framebufferWidth;
+   client->height=client->si.framebufferHeight;
+-  client->MallocFrameBuffer(client);
++  if (!client->MallocFrameBuffer(client))
++    return FALSE;
+ 
+   if (!SetFormatAndEncodings(client))
+     return FALSE;
+Index: libvncserver/libvncserver/rfbserver.c
+===================================================================
+--- libvncserver.orig/libvncserver/rfbserver.c	2014-11-21 20:35:19.488146693 +0100
++++ libvncserver/libvncserver/rfbserver.c	2014-11-21 20:45:59.494260310 +0100
+@@ -1237,21 +1237,35 @@
+ #define RFB_FILE_ATTRIBUTE_TEMPORARY  0x100
+ #define RFB_FILE_ATTRIBUTE_COMPRESSED 0x800
+ 
+-rfbBool rfbFilenameTranslate2UNIX(rfbClientPtr cl, char *path, char *unixPath)
++rfbBool rfbFilenameTranslate2UNIX(rfbClientPtr cl, /* in */ char *path, /* out */ char *unixPath, size_t unixPathMaxLen )
+ {
+     int x;
+     char *home=NULL;
+ 
+     FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
+ 
++    /*
++     * Do not use strncpy() - truncating the file name would probably have undesirable side effects
++     * Instead check if destination buffer is big enough
++     */
++
++    if (strlen(path) >= unixPathMaxLen)
++      return FALSE;
++
+     /* C: */
+     if (path[0]=='C' && path[1]==':')
++    {
+       strcpy(unixPath, &path[2]);
++    }
+     else
+     {
+       home = getenv("HOME");
+       if (home!=NULL)
+       {
++        /* Re-check buffer size */
++        if ((strlen(path) + strlen(home) + 1) >= unixPathMaxLen)
++          return FALSE;
++
+         strcpy(unixPath, home);
+         strcat(unixPath,"/");
+         strcat(unixPath, path);
+@@ -1289,7 +1303,8 @@
+     FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
+ 
+     /* Client thinks we are Winblows */
+-    rfbFilenameTranslate2UNIX(cl, buffer, path);
++    if (!rfbFilenameTranslate2UNIX(cl, buffer, path, sizeof(path)))
++      return FALSE;
+ 
+     if (DB) rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent: \"%s\"->\"%s\"\n",buffer, path);
+ 
+@@ -1566,7 +1581,9 @@
+         /* add some space to the end of the buffer as we will be adding a timespec to it */
+         if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
+         /* The client requests a File */
+-        rfbFilenameTranslate2UNIX(cl, buffer, filename1);
++        if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
++          goto fail;
++
+         cl->fileTransfer.fd=open(filename1, O_RDONLY, 0744);
+ 
+         /*
+@@ -1660,16 +1677,17 @@
+         */
+         if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
+ 
+-        /* Parse the FileTime */
++        /* Parse the FileTime
++         * TODO: FileTime is actually never used afterwards
++         */
+         p = strrchr(buffer, ',');
+         if (p!=NULL) {
+             *p = '\0';
+-            strcpy(szFileTime, p+1);
++            strncpy(szFileTime, p+1, sizeof(szFileTime));
++            szFileTime[sizeof(szFileTime)-1] = '\x00'; /* ensure NULL terminating byte is present, even if copy overflowed */
+         } else
+             szFileTime[0]=0;
+ 
+-
+-
+         /* Need to read in sizeHtmp */
+         if ((n = rfbReadExact(cl, (char *)&sizeHtmp, 4)) <= 0) {
+             if (n != 0)
+@@ -1681,7 +1699,8 @@
+         }
+         sizeHtmp = Swap32IfLE(sizeHtmp);
+         
+-        rfbFilenameTranslate2UNIX(cl, buffer, filename1);
++        if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
++          goto fail;
+ 
+         /* If the file exists... We can send a rfbFileChecksums back to the client before we send an rfbFileAcceptHeader */
+         /* TODO: Delta Transfer */
+@@ -1810,7 +1829,9 @@
+         if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
+         switch (contentParam) {
+         case rfbCDirCreate:  /* Client requests the creation of a directory */
+-            rfbFilenameTranslate2UNIX(cl, buffer, filename1);
++            if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
++              goto fail;
++
+             retval = mkdir(filename1, 0755);
+             if (DB) rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCDirCreate(\"%s\"->\"%s\") %s\n", buffer, filename1, (retval==-1?"Failed":"Success"));
+             /*
+@@ -1819,7 +1840,9 @@
+             if (buffer!=NULL) free(buffer);
+             return retval;
+         case rfbCFileDelete: /* Client requests the deletion of a file */
+-            rfbFilenameTranslate2UNIX(cl, buffer, filename1);
++            if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
++              goto fail;
++
+             if (stat(filename1,&statbuf)==0)
+             {
+                 if (S_ISDIR(statbuf.st_mode))
+@@ -1837,8 +1860,12 @@
+             {
+                 /* Split into 2 filenames ('*' is a seperator) */
+                 *p = '\0';
+-                rfbFilenameTranslate2UNIX(cl, buffer, filename1);
+-                rfbFilenameTranslate2UNIX(cl, p+1,    filename2);
++                if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
++                  goto fail;
++
++                if (!rfbFilenameTranslate2UNIX(cl, p+1,    filename2, sizeof(filename2)))
++                  goto fail;
++
+                 retval = rename(filename1,filename2);
+                 if (DB) rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCFileRename(\"%s\"->\"%s\" -->> \"%s\"->\"%s\") %s\n", buffer, filename1, p+1, filename2, (retval==-1?"Failed":"Success"));
+                 /*
+@@ -1858,6 +1885,10 @@
+     /* NOTE: don't forget to free(buffer) if you return early! */
+     if (buffer!=NULL) free(buffer);
+     return TRUE;
++
++fail:
++    if (buffer!=NULL) free(buffer);
++    return FALSE;
+ }
+ 
+ /*
+@@ -2457,6 +2488,11 @@
+ 	msg.cct.length = Swap32IfLE(msg.cct.length);
+ 
+ 	str = (char *)malloc(msg.cct.length);
++	if (str == NULL) {
++		rfbLogPerror("rfbProcessClientNormalMessage: not enough memory");
++		rfbCloseClient(cl);
++		return;
++	}
+ 
+ 	if ((n = rfbReadExact(cl, str, msg.cct.length)) <= 0) {
+ 	    if (n != 0)
+@@ -2498,6 +2534,20 @@
+           rfbCloseClient(cl);
+           return;
+       }
++
++      if (msg.ssc.scale == 0) {
++          rfbLogPerror("rfbProcessClientNormalMessage: will not accept a scale factor of zero");
++          rfbCloseClient(cl);
++          return;
++      }
++
++
++      if (msg.ssc.scale == 0) {
++          rfbLogPerror("rfbProcessClientNormalMessage: will not accept a scale factor of zero");
++          rfbCloseClient(cl);
++          return;
++      }
++
+       rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetScaleMsg, sz_rfbSetScaleMsg);
+       rfbLog("rfbSetScale(%d)\n", msg.ssc.scale);
+       rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale);
+Index: libvncserver/libvncserver/scale.c
+===================================================================
+--- libvncserver.orig/libvncserver/scale.c	2014-11-21 20:35:19.492147116 +0100
++++ libvncserver/libvncserver/scale.c	2014-11-21 20:46:34.088646966 +0100
+@@ -66,6 +66,10 @@
+         (double) ((int) (x)) : (double) ((int) (x) + 1) )
+ #define FLOOR(x) ( (double) ((int) (x)) )
+ 
++static inline int pad4(int value) {
++    int remainder = value & 3;
++    return value + (remainder == 0 ? 0 : 4 - remainder);
++}
+ 
+ int ScaleX(rfbScreenInfoPtr from, rfbScreenInfoPtr to, int x)
+ {
+@@ -281,14 +285,29 @@
+     ptr = malloc(sizeof(rfbScreenInfo));
+     if (ptr!=NULL)
+     {
++        int allocSize;
++
+         /* copy *everything* (we don't use most of it, but just in case) */
+         memcpy(ptr, cl->screen, sizeof(rfbScreenInfo));
++
++        /* SECURITY: make sure that no integer overflow will occur afterwards.
++         * Note: this is defensive coding, as the check should have already been
++         * performed during initial, non-scaled screen setup.
++         */
++        allocSize = pad4(width * (ptr->bitsPerPixel/8)); /* per protocol, width<2**16 and bpp<256 */
++        if ((height == 0) || (allocSize >= (SIZE_MAX / height)))
++        {
++          free(ptr);
++          return NULL; /* malloc() will allocate an incorrect buffer size - early abort */
++        }
++
++        /* Resume copy everything */
+         ptr->width = width;
+         ptr->height = height;
+         ptr->paddedWidthInBytes = (ptr->bitsPerPixel/8)*ptr->width;
+ 
+         /* Need to by multiples of 4 for Sparc systems */
+-        ptr->paddedWidthInBytes += (ptr->paddedWidthInBytes % 4);
++        ptr->paddedWidthInBytes = pad4(ptr->paddedWidthInBytes);
+ 
+         /* Reset the reference count to 0! */
+         ptr->scaledScreenRefCount = 0;
diff --git a/debian/patches/novnc.patch b/debian/patches/novnc.patch
new file mode 100644
index 0000000..c81b742
--- /dev/null
+++ b/debian/patches/novnc.patch
@@ -0,0 +1,15 @@
+Description: Set opcode correctly for binary frames
+Author: Joel Martin <git...@martintribe.org>
+
+Index: libvncserver/libvncserver/websockets.c
+===================================================================
+--- libvncserver.orig/libvncserver/websockets.c	2014-11-21 20:35:19.492147116 +0100
++++ libvncserver/libvncserver/websockets.c	2014-11-21 20:49:23.374940701 +0100
+@@ -783,6 +783,7 @@
+ 	/* calculate the resulting size */
+ 	blen = B64LEN(len);
+     } else {
++	opcode = WS_OPCODE_BINARY_FRAME;
+ 	blen = len;
+     }
+ 
diff --git a/debian/patches/series b/debian/patches/series
index 158e82e..48391d2 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -5,3 +5,5 @@ multiarch.patch
 listenSock.patch
 ppc64el.patch
 pkgconfig.patch
+CVE-2014.patch
+novnc.patch

Reply via email to