mirror of
https://github.com/kasmtech/KasmVNC.git
synced 2024-11-25 01:24:04 +01:00
Be defensive about overflows in stream objects
We use a lot of lengths given to us over the network, so be more paranoid about them causing an overflow as otherwise an attacker might trick us in to overwriting other memory. This primarily affects the client which often gets lengths from the server, but there are also some scenarios where the server might theoretically be vulnerable. Issue found by Pavel Cheremushkin from Kaspersky Lab.
This commit is contained in:
parent
259f1055cb
commit
ae6cbd19e9
@ -136,7 +136,7 @@ size_t FdInStream::overrun(size_t itemSize, size_t nItems, bool wait)
|
|||||||
ptr = start;
|
ptr = start;
|
||||||
|
|
||||||
size_t bytes_to_read;
|
size_t bytes_to_read;
|
||||||
while (end < start + itemSize) {
|
while ((size_t)(end - start) < itemSize) {
|
||||||
bytes_to_read = start + bufSize - end;
|
bytes_to_read = start + bufSize - end;
|
||||||
if (!timing) {
|
if (!timing) {
|
||||||
// When not timing, we must be careful not to read too much
|
// When not timing, we must be careful not to read too much
|
||||||
@ -152,8 +152,10 @@ size_t FdInStream::overrun(size_t itemSize, size_t nItems, bool wait)
|
|||||||
end += n;
|
end += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemSize * nItems > (size_t)(end - ptr))
|
size_t nAvail;
|
||||||
nItems = (end - ptr) / itemSize;
|
nAvail = (end - ptr) / itemSize;
|
||||||
|
if (nAvail < nItems)
|
||||||
|
return nAvail;
|
||||||
|
|
||||||
return nItems;
|
return nItems;
|
||||||
}
|
}
|
||||||
|
@ -149,9 +149,10 @@ size_t FdOutStream::overrun(size_t itemSize, size_t nItems)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can we fit all the items asked for?
|
size_t nAvail;
|
||||||
if (itemSize * nItems > (size_t)(end - ptr))
|
nAvail = (end - ptr) / itemSize;
|
||||||
nItems = (end - ptr) / itemSize;
|
if (nAvail < nItems)
|
||||||
|
return nAvail;
|
||||||
|
|
||||||
return nItems;
|
return nItems;
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ size_t FileInStream::overrun(size_t itemSize, size_t nItems, bool wait)
|
|||||||
ptr = b;
|
ptr = b;
|
||||||
|
|
||||||
|
|
||||||
while (end < b + itemSize) {
|
while ((size_t)(end - b) < itemSize) {
|
||||||
size_t n = fread((U8 *)end, b + sizeof(b) - end, 1, file);
|
size_t n = fread((U8 *)end, b + sizeof(b) - end, 1, file);
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
if (ferror(file))
|
if (ferror(file))
|
||||||
@ -80,8 +80,10 @@ size_t FileInStream::overrun(size_t itemSize, size_t nItems, bool wait)
|
|||||||
end += b + sizeof(b) - end;
|
end += b + sizeof(b) - end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemSize * nItems > (size_t)(end - ptr))
|
size_t nAvail;
|
||||||
nItems = (end - ptr) / itemSize;
|
nAvail = (end - ptr) / itemSize;
|
||||||
|
if (nAvail < nItems)
|
||||||
|
return nAvail;
|
||||||
|
|
||||||
return nItems;
|
return nItems;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ size_t HexInStream::overrun(size_t itemSize, size_t nItems, bool wait) {
|
|||||||
offset += ptr - start;
|
offset += ptr - start;
|
||||||
ptr = start;
|
ptr = start;
|
||||||
|
|
||||||
while (end < ptr + itemSize) {
|
while ((size_t)(end - ptr) < itemSize) {
|
||||||
size_t n = in_stream.check(2, 1, wait);
|
size_t n = in_stream.check(2, 1, wait);
|
||||||
if (n == 0) return 0;
|
if (n == 0) return 0;
|
||||||
const U8* iptr = in_stream.getptr();
|
const U8* iptr = in_stream.getptr();
|
||||||
@ -110,8 +110,10 @@ size_t HexInStream::overrun(size_t itemSize, size_t nItems, bool wait) {
|
|||||||
end += length;
|
end += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemSize * nItems > (size_t)(end - ptr))
|
size_t nAvail;
|
||||||
nItems = (end - ptr) / itemSize;
|
nAvail = (end - ptr) / itemSize;
|
||||||
|
if (nAvail < nItems)
|
||||||
|
return nAvail;
|
||||||
|
|
||||||
return nItems;
|
return nItems;
|
||||||
}
|
}
|
||||||
|
@ -102,8 +102,10 @@ HexOutStream::overrun(size_t itemSize, size_t nItems) {
|
|||||||
|
|
||||||
writeBuffer();
|
writeBuffer();
|
||||||
|
|
||||||
if (itemSize * nItems > (size_t)(end - ptr))
|
size_t nAvail;
|
||||||
nItems = (end - ptr) / itemSize;
|
nAvail = (end - ptr) / itemSize;
|
||||||
|
if (nAvail < nItems)
|
||||||
|
return nAvail;
|
||||||
|
|
||||||
return nItems;
|
return nItems;
|
||||||
}
|
}
|
||||||
|
@ -43,12 +43,15 @@ namespace rdr {
|
|||||||
|
|
||||||
inline size_t check(size_t itemSize, size_t nItems=1, bool wait=true)
|
inline size_t check(size_t itemSize, size_t nItems=1, bool wait=true)
|
||||||
{
|
{
|
||||||
if (ptr + itemSize * nItems > end) {
|
size_t nAvail;
|
||||||
if (ptr + itemSize > end)
|
|
||||||
|
if (itemSize > (size_t)(end - ptr))
|
||||||
return overrun(itemSize, nItems, wait);
|
return overrun(itemSize, nItems, wait);
|
||||||
|
|
||||||
nItems = (end - ptr) / itemSize;
|
nAvail = (end - ptr) / itemSize;
|
||||||
}
|
if (nAvail < nItems)
|
||||||
|
return nAvail;
|
||||||
|
|
||||||
return nItems;
|
return nItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,13 +96,12 @@ namespace rdr {
|
|||||||
// readBytes() reads an exact number of bytes.
|
// readBytes() reads an exact number of bytes.
|
||||||
|
|
||||||
void readBytes(void* data, size_t length) {
|
void readBytes(void* data, size_t length) {
|
||||||
U8* dataPtr = (U8*)data;
|
while (length > 0) {
|
||||||
U8* dataEnd = dataPtr + length;
|
size_t n = check(1, length);
|
||||||
while (dataPtr < dataEnd) {
|
memcpy(data, ptr, n);
|
||||||
size_t n = check(1, dataEnd - dataPtr);
|
|
||||||
memcpy(dataPtr, ptr, n);
|
|
||||||
ptr += n;
|
ptr += n;
|
||||||
dataPtr += n;
|
data = (U8*)data + n;
|
||||||
|
length -= n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#ifndef __RDR_MEMOUTSTREAM_H__
|
#ifndef __RDR_MEMOUTSTREAM_H__
|
||||||
#define __RDR_MEMOUTSTREAM_H__
|
#define __RDR_MEMOUTSTREAM_H__
|
||||||
|
|
||||||
|
#include <rdr/Exception.h>
|
||||||
#include <rdr/OutStream.h>
|
#include <rdr/OutStream.h>
|
||||||
|
|
||||||
namespace rdr {
|
namespace rdr {
|
||||||
@ -65,6 +66,9 @@ namespace rdr {
|
|||||||
if (len < (size_t)(end - start) * 2)
|
if (len < (size_t)(end - start) * 2)
|
||||||
len = (end - start) * 2;
|
len = (end - start) * 2;
|
||||||
|
|
||||||
|
if (len < (size_t)(end - start))
|
||||||
|
throw Exception("Overflow in MemOutStream::overrun()");
|
||||||
|
|
||||||
U8* newStart = new U8[len];
|
U8* newStart = new U8[len];
|
||||||
memcpy(newStart, start, ptr - start);
|
memcpy(newStart, start, ptr - start);
|
||||||
ptr = newStart + (ptr - start);
|
ptr = newStart + (ptr - start);
|
||||||
|
@ -46,12 +46,15 @@ namespace rdr {
|
|||||||
|
|
||||||
inline size_t check(size_t itemSize, size_t nItems=1)
|
inline size_t check(size_t itemSize, size_t nItems=1)
|
||||||
{
|
{
|
||||||
if (ptr + itemSize * nItems > end) {
|
size_t nAvail;
|
||||||
if (ptr + itemSize > end)
|
|
||||||
|
if (itemSize > (size_t)(end - ptr))
|
||||||
return overrun(itemSize, nItems);
|
return overrun(itemSize, nItems);
|
||||||
|
|
||||||
nItems = (end - ptr) / itemSize;
|
nAvail = (end - ptr) / itemSize;
|
||||||
}
|
if (nAvail < nItems)
|
||||||
|
return nAvail;
|
||||||
|
|
||||||
return nItems;
|
return nItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,13 +94,12 @@ namespace rdr {
|
|||||||
// writeBytes() writes an exact number of bytes.
|
// writeBytes() writes an exact number of bytes.
|
||||||
|
|
||||||
void writeBytes(const void* data, size_t length) {
|
void writeBytes(const void* data, size_t length) {
|
||||||
const U8* dataPtr = (const U8*)data;
|
while (length > 0) {
|
||||||
const U8* dataEnd = dataPtr + length;
|
size_t n = check(1, length);
|
||||||
while (dataPtr < dataEnd) {
|
memcpy(ptr, data, n);
|
||||||
size_t n = check(1, dataEnd - dataPtr);
|
|
||||||
memcpy(ptr, dataPtr, n);
|
|
||||||
ptr += n;
|
ptr += n;
|
||||||
dataPtr += n;
|
data = (U8*)data + n;
|
||||||
|
length -= n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,8 +123,10 @@ size_t RandomStream::overrun(size_t itemSize, size_t nItems, bool wait) {
|
|||||||
*(U8*)end++ = (int) (256.0*rand()/(RAND_MAX+1.0));
|
*(U8*)end++ = (int) (256.0*rand()/(RAND_MAX+1.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemSize * nItems > (size_t)(end - ptr))
|
size_t nAvail;
|
||||||
nItems = (end - ptr) / itemSize;
|
nAvail = (end - ptr) / itemSize;
|
||||||
|
if (nAvail < nItems)
|
||||||
|
return nAvail;
|
||||||
|
|
||||||
return nItems;
|
return nItems;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ ssize_t TLSInStream::pull(gnutls_transport_ptr_t str, void* data, size_t size)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in->getend() - in->getptr() < (ptrdiff_t)size)
|
if ((size_t)(in->getend() - in->getptr()) < size)
|
||||||
size = in->getend() - in->getptr();
|
size = in->getend() - in->getptr();
|
||||||
|
|
||||||
in->readBytes(data, size);
|
in->readBytes(data, size);
|
||||||
@ -92,15 +92,17 @@ size_t TLSInStream::overrun(size_t itemSize, size_t nItems, bool wait)
|
|||||||
end -= ptr - start;
|
end -= ptr - start;
|
||||||
ptr = start;
|
ptr = start;
|
||||||
|
|
||||||
while (end < start + itemSize) {
|
while ((size_t)(end - start) < itemSize) {
|
||||||
size_t n = readTLS((U8*) end, start + bufSize - end, wait);
|
size_t n = readTLS((U8*) end, start + bufSize - end, wait);
|
||||||
if (!wait && n == 0)
|
if (!wait && n == 0)
|
||||||
return 0;
|
return 0;
|
||||||
end += n;
|
end += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemSize * nItems > (size_t)(end - ptr))
|
size_t nAvail;
|
||||||
nItems = (end - ptr) / itemSize;
|
nAvail = (end - ptr) / itemSize;
|
||||||
|
if (nAvail < nItems)
|
||||||
|
return nAvail;
|
||||||
|
|
||||||
return nItems;
|
return nItems;
|
||||||
}
|
}
|
||||||
|
@ -100,8 +100,10 @@ size_t TLSOutStream::overrun(size_t itemSize, size_t nItems)
|
|||||||
|
|
||||||
flush();
|
flush();
|
||||||
|
|
||||||
if (itemSize * nItems > (size_t)(end - ptr))
|
size_t nAvail;
|
||||||
nItems = (end - ptr) / itemSize;
|
nAvail = (end - ptr) / itemSize;
|
||||||
|
if (nAvail < nItems)
|
||||||
|
return nAvail;
|
||||||
|
|
||||||
return nItems;
|
return nItems;
|
||||||
}
|
}
|
||||||
|
@ -113,8 +113,10 @@ size_t ZlibInStream::overrun(size_t itemSize, size_t nItems, bool wait)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemSize * nItems > (size_t)(end - ptr))
|
size_t nAvail;
|
||||||
nItems = (end - ptr) / itemSize;
|
nAvail = (end - ptr) / itemSize;
|
||||||
|
if (nAvail < nItems)
|
||||||
|
return nAvail;
|
||||||
|
|
||||||
return nItems;
|
return nItems;
|
||||||
}
|
}
|
||||||
|
@ -127,8 +127,10 @@ size_t ZlibOutStream::overrun(size_t itemSize, size_t nItems)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemSize * nItems > (size_t)(end - ptr))
|
size_t nAvail;
|
||||||
nItems = (end - ptr) / itemSize;
|
nAvail = (end - ptr) / itemSize;
|
||||||
|
if (nAvail < nItems)
|
||||||
|
return nAvail;
|
||||||
|
|
||||||
return nItems;
|
return nItems;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user