Blame SOURCES/tigervnc-be-defensive-about-overflows-in-stream-objects.patch

12537a
From 75e6e0653a48baf474fd45d78b1da53e2f324642 Mon Sep 17 00:00:00 2001
12537a
From: Pierre Ossman <ossman@cendio.se>
12537a
Date: Tue, 24 Sep 2019 09:41:07 +0200
12537a
Subject: [PATCH] Be defensive about overflows in stream objects
12537a
12537a
We use a lot of lengths given to us over the network, so be more
12537a
paranoid about them causing an overflow as otherwise an attacker
12537a
might trick us in to overwriting other memory.
12537a
12537a
This primarily affects the client which often gets lengths from the
12537a
server, but there are also some scenarios where the server might
12537a
theoretically be vulnerable.
12537a
12537a
Issue found by Pavel Cheremushkin from Kaspersky Lab.
12537a
---
12537a
 common/rdr/FdInStream.cxx    |  8 +++++---
12537a
 common/rdr/FdOutStream.cxx   |  7 ++++---
12537a
 common/rdr/FileInStream.cxx  |  8 +++++---
12537a
 common/rdr/HexInStream.cxx   |  8 +++++---
12537a
 common/rdr/HexOutStream.cxx  |  6 ++++--
12537a
 common/rdr/InStream.h        | 24 +++++++++++++-----------
12537a
 common/rdr/MemOutStream.h    |  4 ++++
12537a
 common/rdr/OutStream.h       | 24 +++++++++++++-----------
12537a
 common/rdr/RandomStream.cxx  |  6 ++++--
12537a
 common/rdr/TLSInStream.cxx   | 10 ++++++----
12537a
 common/rdr/TLSOutStream.cxx  |  6 ++++--
12537a
 common/rdr/ZlibInStream.cxx  |  6 ++++--
12537a
 common/rdr/ZlibOutStream.cxx |  6 ++++--
12537a
 13 files changed, 75 insertions(+), 48 deletions(-)
12537a
12537a
diff --git a/common/rdr/FdInStream.cxx b/common/rdr/FdInStream.cxx
12537a
index e99c108..bc944d1 100644
12537a
--- a/common/rdr/FdInStream.cxx
12537a
+++ b/common/rdr/FdInStream.cxx
12537a
@@ -136,7 +136,7 @@ size_t FdInStream::overrun(size_t itemSize, size_t nItems, bool wait)
12537a
   ptr = start;
12537a
 
12537a
   size_t bytes_to_read;
12537a
-  while (end < start + itemSize) {
12537a
+  while ((size_t)(end - start) < itemSize) {
12537a
     bytes_to_read = start + bufSize - end;
12537a
     if (!timing) {
12537a
       // When not timing, we must be careful not to read too much
12537a
@@ -152,8 +152,10 @@ size_t FdInStream::overrun(size_t itemSize, size_t nItems, bool wait)
12537a
     end += n;
12537a
   }
12537a
 
12537a
-  if (itemSize * nItems > (size_t)(end - ptr))
12537a
-    nItems = (end - ptr) / itemSize;
12537a
+  size_t nAvail;
12537a
+  nAvail = (end - ptr) / itemSize;
12537a
+  if (nAvail < nItems)
12537a
+    return nAvail;
12537a
 
12537a
   return nItems;
12537a
 }
12537a
diff --git a/common/rdr/FdOutStream.cxx b/common/rdr/FdOutStream.cxx
12537a
index 0900fd1..9d666e7 100644
12537a
--- a/common/rdr/FdOutStream.cxx
12537a
+++ b/common/rdr/FdOutStream.cxx
12537a
@@ -148,9 +148,10 @@ size_t FdOutStream::overrun(size_t itemSize, size_t nItems)
12537a
     }
12537a
   }
12537a
 
12537a
-  // Can we fit all the items asked for?
12537a
-  if (itemSize * nItems > (size_t)(end - ptr))
12537a
-    nItems = (end - ptr) / itemSize;
12537a
+  size_t nAvail;
12537a
+  nAvail = (end - ptr) / itemSize;
12537a
+  if (nAvail < nItems)
12537a
+    return nAvail;
12537a
 
12537a
   return nItems;
12537a
 }
12537a
diff --git a/common/rdr/FileInStream.cxx b/common/rdr/FileInStream.cxx
12537a
index 56830a0..42eaf11 100644
12537a
--- a/common/rdr/FileInStream.cxx
12537a
+++ b/common/rdr/FileInStream.cxx
12537a
@@ -68,7 +68,7 @@ size_t FileInStream::overrun(size_t itemSize, size_t nItems, bool wait)
12537a
   ptr = b;
12537a
 
12537a
 
12537a
-  while (end < b + itemSize) {
12537a
+  while ((size_t)(end - b) < itemSize) {
12537a
     size_t n = fread((U8 *)end, b + sizeof(b) - end, 1, file);
12537a
     if (n < 1) {
12537a
       if (n < 0 || ferror(file))
12537a
@@ -80,8 +80,10 @@ size_t FileInStream::overrun(size_t itemSize, size_t nItems, bool wait)
12537a
     end += b + sizeof(b) - end;
12537a
   }
12537a
 
12537a
-  if (itemSize * nItems > (size_t)(end - ptr))
12537a
-    nItems = (end - ptr) / itemSize;
12537a
+  size_t nAvail;
12537a
+  nAvail = (end - ptr) / itemSize;
12537a
+  if (nAvail < nItems)
12537a
+    return nAvail;
12537a
 
12537a
   return nItems;
12537a
 }
12537a
diff --git a/common/rdr/HexInStream.cxx b/common/rdr/HexInStream.cxx
12537a
index 8f93988..a6bc92c 100644
12537a
--- a/common/rdr/HexInStream.cxx
12537a
+++ b/common/rdr/HexInStream.cxx
12537a
@@ -91,7 +91,7 @@ size_t HexInStream::overrun(size_t itemSize, size_t nItems, bool wait) {
12537a
   offset += ptr - start;
12537a
   ptr = start;
12537a
 
12537a
-  while (end < ptr + itemSize) {
12537a
+  while ((size_t)(end - ptr) < itemSize) {
12537a
     size_t n = in_stream.check(2, 1, wait);
12537a
     if (n == 0) return 0;
12537a
     const U8* iptr = in_stream.getptr();
12537a
@@ -110,8 +110,10 @@ size_t HexInStream::overrun(size_t itemSize, size_t nItems, bool wait) {
12537a
     end += length;
12537a
   }
12537a
 
12537a
-  if (itemSize * nItems > (size_t)(end - ptr))
12537a
-    nItems = (end - ptr) / itemSize;
12537a
+  size_t nAvail;
12537a
+  nAvail = (end - ptr) / itemSize;
12537a
+  if (nAvail < nItems)
12537a
+    return nAvail;
12537a
 
12537a
   return nItems;
12537a
 }
12537a
diff --git a/common/rdr/HexOutStream.cxx b/common/rdr/HexOutStream.cxx
12537a
index 7232514..eac2eff 100644
12537a
--- a/common/rdr/HexOutStream.cxx
12537a
+++ b/common/rdr/HexOutStream.cxx
12537a
@@ -102,8 +102,10 @@ HexOutStream::overrun(size_t itemSize, size_t nItems) {
12537a
 
12537a
   writeBuffer();
12537a
 
12537a
-  if (itemSize * nItems > (size_t)(end - ptr))
12537a
-    nItems = (end - ptr) / itemSize;
12537a
+  size_t nAvail;
12537a
+  nAvail = (end - ptr) / itemSize;
12537a
+  if (nAvail < nItems)
12537a
+    return nAvail;
12537a
 
12537a
   return nItems;
12537a
 }
12537a
diff --git a/common/rdr/InStream.h b/common/rdr/InStream.h
12537a
index 14ecf09..f71a4d9 100644
12537a
--- a/common/rdr/InStream.h
12537a
+++ b/common/rdr/InStream.h
12537a
@@ -43,12 +43,15 @@ namespace rdr {
12537a
 
12537a
     inline size_t check(size_t itemSize, size_t nItems=1, bool wait=true)
12537a
     {
12537a
-      if (ptr + itemSize * nItems > end) {
12537a
-        if (ptr + itemSize > end)
12537a
-          return overrun(itemSize, nItems, wait);
12537a
+      size_t nAvail;
12537a
+
12537a
+      if (itemSize > (size_t)(end - ptr))
12537a
+        return overrun(itemSize, nItems, wait);
12537a
+
12537a
+      nAvail = (end - ptr) / itemSize;
12537a
+      if (nAvail < nItems)
12537a
+        return nAvail;
12537a
 
12537a
-        nItems = (end - ptr) / itemSize;
12537a
-      }
12537a
       return nItems;
12537a
     }
12537a
 
12537a
@@ -93,13 +96,12 @@ namespace rdr {
12537a
     // readBytes() reads an exact number of bytes.
12537a
 
12537a
     void readBytes(void* data, size_t length) {
12537a
-      U8* dataPtr = (U8*)data;
12537a
-      U8* dataEnd = dataPtr + length;
12537a
-      while (dataPtr < dataEnd) {
12537a
-        size_t n = check(1, dataEnd - dataPtr);
12537a
-        memcpy(dataPtr, ptr, n);
12537a
+      while (length > 0) {
12537a
+        size_t n = check(1, length);
12537a
+        memcpy(data, ptr, n);
12537a
         ptr += n;
12537a
-        dataPtr += n;
12537a
+        data = (U8*)data + n;
12537a
+        length -= n;
12537a
       }
12537a
     }
12537a
 
12537a
diff --git a/common/rdr/MemOutStream.h b/common/rdr/MemOutStream.h
12537a
index 4a815b3..b56bac3 100644
12537a
--- a/common/rdr/MemOutStream.h
12537a
+++ b/common/rdr/MemOutStream.h
12537a
@@ -23,6 +23,7 @@
12537a
 #ifndef __RDR_MEMOUTSTREAM_H__
12537a
 #define __RDR_MEMOUTSTREAM_H__
12537a
 
12537a
+#include <rdr/Exception.h>
12537a
 #include <rdr/OutStream.h>
12537a
 
12537a
 namespace rdr {
12537a
@@ -65,6 +66,9 @@ namespace rdr {
12537a
       if (len < (size_t)(end - start) * 2)
12537a
         len = (end - start) * 2;
12537a
 
12537a
+      if (len < (size_t)(end - start))
12537a
+        throw Exception("Overflow in MemOutStream::overrun()");
12537a
+
12537a
       U8* newStart = new U8[len];
12537a
       memcpy(newStart, start, ptr - start);
12537a
       ptr = newStart + (ptr - start);
12537a
diff --git a/common/rdr/OutStream.h b/common/rdr/OutStream.h
12537a
index 11aafd2..0f60ccc 100644
12537a
--- a/common/rdr/OutStream.h
12537a
+++ b/common/rdr/OutStream.h
12537a
@@ -46,12 +46,15 @@ namespace rdr {
12537a
 
12537a
     inline size_t check(size_t itemSize, size_t nItems=1)
12537a
     {
12537a
-      if (ptr + itemSize * nItems > end) {
12537a
-        if (ptr + itemSize > end)
12537a
-          return overrun(itemSize, nItems);
12537a
+      size_t nAvail;
12537a
+
12537a
+      if (itemSize > (size_t)(end - ptr))
12537a
+        return overrun(itemSize, nItems);
12537a
+
12537a
+      nAvail = (end - ptr) / itemSize;
12537a
+      if (nAvail < nItems)
12537a
+        return nAvail;
12537a
 
12537a
-        nItems = (end - ptr) / itemSize;
12537a
-      }
12537a
       return nItems;
12537a
     }
12537a
 
12537a
@@ -91,13 +94,12 @@ namespace rdr {
12537a
     // writeBytes() writes an exact number of bytes.
12537a
 
12537a
     void writeBytes(const void* data, size_t length) {
12537a
-      const U8* dataPtr = (const U8*)data;
12537a
-      const U8* dataEnd = dataPtr + length;
12537a
-      while (dataPtr < dataEnd) {
12537a
-        size_t n = check(1, dataEnd - dataPtr);
12537a
-        memcpy(ptr, dataPtr, n);
12537a
+      while (length > 0) {
12537a
+        size_t n = check(1, length);
12537a
+        memcpy(ptr, data, n);
12537a
         ptr += n;
12537a
-        dataPtr += n;
12537a
+        data = (U8*)data + n;
12537a
+        length -= n;
12537a
       }
12537a
     }
12537a
 
12537a
diff --git a/common/rdr/RandomStream.cxx b/common/rdr/RandomStream.cxx
12537a
index 7681095..6c64ac5 100644
12537a
--- a/common/rdr/RandomStream.cxx
12537a
+++ b/common/rdr/RandomStream.cxx
12537a
@@ -123,8 +123,10 @@ size_t RandomStream::overrun(size_t itemSize, size_t nItems, bool wait) {
12537a
       *(U8*)end++ = (int) (256.0*rand()/(RAND_MAX+1.0));
12537a
   }
12537a
 
12537a
-  if (itemSize * nItems > (size_t)(end - ptr))
12537a
-    nItems = (end - ptr) / itemSize;
12537a
+  size_t nAvail;
12537a
+  nAvail = (end - ptr) / itemSize;
12537a
+  if (nAvail < nItems)
12537a
+    return nAvail;
12537a
 
12537a
   return nItems;
12537a
 }
12537a
diff --git a/common/rdr/TLSInStream.cxx b/common/rdr/TLSInStream.cxx
12537a
index d0f9426..3e1172f 100644
12537a
--- a/common/rdr/TLSInStream.cxx
12537a
+++ b/common/rdr/TLSInStream.cxx
12537a
@@ -43,7 +43,7 @@ ssize_t TLSInStream::pull(gnutls_transport_ptr_t str, void* data, size_t size)
12537a
       return -1;
12537a
     }
12537a
 
12537a
-    if (in->getend() - in->getptr() < (ptrdiff_t)size)
12537a
+    if ((size_t)(in->getend() - in->getptr()) < size)
12537a
       size = in->getend() - in->getptr();
12537a
   
12537a
     in->readBytes(data, size);
12537a
@@ -92,15 +92,17 @@ size_t TLSInStream::overrun(size_t itemSize, size_t nItems, bool wait)
12537a
   end -= ptr - start;
12537a
   ptr = start;
12537a
 
12537a
-  while (end < start + itemSize) {
12537a
+  while ((size_t)(end - start) < itemSize) {
12537a
     size_t n = readTLS((U8*) end, start + bufSize - end, wait);
12537a
     if (!wait && n == 0)
12537a
       return 0;
12537a
     end += n;
12537a
   }
12537a
 
12537a
-  if (itemSize * nItems > (size_t)(end - ptr))
12537a
-    nItems = (end - ptr) / itemSize;
12537a
+  size_t nAvail;
12537a
+  nAvail = (end - ptr) / itemSize;
12537a
+  if (nAvail < nItems)
12537a
+    return nAvail;
12537a
 
12537a
   return nItems;
12537a
 }
12537a
diff --git a/common/rdr/TLSOutStream.cxx b/common/rdr/TLSOutStream.cxx
12537a
index 30c456f..7d7c3b5 100644
12537a
--- a/common/rdr/TLSOutStream.cxx
12537a
+++ b/common/rdr/TLSOutStream.cxx
12537a
@@ -100,8 +100,10 @@ size_t TLSOutStream::overrun(size_t itemSize, size_t nItems)
12537a
 
12537a
   flush();
12537a
 
12537a
-  if (itemSize * nItems > (size_t)(end - ptr))
12537a
-    nItems = (end - ptr) / itemSize;
12537a
+  size_t nAvail;
12537a
+  nAvail = (end - ptr) / itemSize;
12537a
+  if (nAvail < nItems)
12537a
+    return nAvail;
12537a
 
12537a
   return nItems;
12537a
 }
12537a
diff --git a/common/rdr/ZlibInStream.cxx b/common/rdr/ZlibInStream.cxx
12537a
index e2f971c..9fcfaf6 100644
12537a
--- a/common/rdr/ZlibInStream.cxx
12537a
+++ b/common/rdr/ZlibInStream.cxx
12537a
@@ -113,8 +113,10 @@ size_t ZlibInStream::overrun(size_t itemSize, size_t nItems, bool wait)
12537a
       return 0;
12537a
   }
12537a
 
12537a
-  if (itemSize * nItems > (size_t)(end - ptr))
12537a
-    nItems = (end - ptr) / itemSize;
12537a
+  size_t nAvail;
12537a
+  nAvail = (end - ptr) / itemSize;
12537a
+  if (nAvail < nItems)
12537a
+    return nAvail;
12537a
 
12537a
   return nItems;
12537a
 }
12537a
diff --git a/common/rdr/ZlibOutStream.cxx b/common/rdr/ZlibOutStream.cxx
12537a
index 4e7ffd6..5e158bf 100644
12537a
--- a/common/rdr/ZlibOutStream.cxx
12537a
+++ b/common/rdr/ZlibOutStream.cxx
12537a
@@ -127,8 +127,10 @@ size_t ZlibOutStream::overrun(size_t itemSize, size_t nItems)
12537a
     }
12537a
   }
12537a
 
12537a
-  if (itemSize * nItems > (size_t)(end - ptr))
12537a
-    nItems = (end - ptr) / itemSize;
12537a
+  size_t nAvail;
12537a
+  nAvail = (end - ptr) / itemSize;
12537a
+  if (nAvail < nItems)
12537a
+    return nAvail;
12537a
 
12537a
   return nItems;
12537a
 }