|
|
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 |
}
|