1

I am creating a client server application in Qt.

I serialize and deserialize some structures using my own algorithm, however in order to deserialize them, I need to load the QByteArray that contains the object into memory. In order to prevent some sort of hacker attacks that would cause the server go OOM, I set a fixed limit for a maximum size of the array that shouldn't, in normal situation be ever exceeded, so that if some "hacker" attempted to send for example array that contains 200GB of data, the server rejects it, instead of reading the data until it dies OOM.

Now the problem is that I implemented compression to the network protocol in order to speed it up. So I don't really know the size of uncompressed data, until I run qUncompress on the byte array I received from client. I am not sure if it's technically possible, but I think that someone in theory, could craft data that are so easy to compress that even if compressed version has few kb, uncompressed version could have gigabytes.

Is it possible? If so, is there any way to prevent this? For example run qUncompress in a way that it doesn't allow inflating over some specific size?

Petr
  • 13,747
  • 20
  • 89
  • 144

2 Answers2

0

There is no way to do it with qUncompress, since it's a very simple API. However, there is a nice libary for Qt called Quazip. It gives you complete control over the compression and would allow you to e.g. abort once the decompression reaches the limit.

Felix
  • 6,885
  • 1
  • 29
  • 54
0

Maximum memory which qUncompress can allocate is 2147483632 bytes. It's a little more than 2GB. If the size of uncompressed data exceeds this limit, qUncompress return empty QByteArray.

Theoretical limit of compression factor for the deflate method is 1032:1. Gygabyte of zeroes can be compressed to 1 megabyte. It is impossible to compress gigabytes to few kb.

If you need more control over memory allocation, use zlib directly.

.pro file
LIBS += -lz
------------
#include "zlib.h"
...
QByteArray compressed = qCompress("Hello, World!");
//a four byte header contain the expected length (in bytes) of the uncompressed data
unsigned long len = (compressed[0] << 24) | (compressed[1] << 16) | (compressed[2] <<  8) | (compressed[3]);
unsigned char *buffer = new unsigned char[len + 1];

int result = ::uncompress(buffer, &len, (const unsigned char*)compressed.constData() + 4, compressed.length() - 4);

QByteArray uncompressed;
if (result == Z_OK)
    uncompressed = QByteArray((char*)buffer, len);

delete[] buffer;

qDebug() <<  uncompressed;
Meefte
  • 6,469
  • 1
  • 39
  • 42
  • Is this factor related to Qt only? Because it's technically possible to create zip file which expands to exa bytes: https://stackoverflow.com/questions/1459673/how-does-one-make-a-zip-bomb – Petr Nov 20 '15 at 08:11
  • 45kilo inflates to 1.30exa in that case – Petr Nov 20 '15 at 08:12
  • I am wondering, if that line of code `unsigned long len = (compressed[0] << 24) | (compressed[1] << 16) | (compressed[2] << 8) | (compressed[3]);` works on data compressed with qCompress, what do I need zlib for? You already provided code that gets me the size of uncompressed data, which is exactly what I asked for. – Petr Nov 20 '15 at 08:14
  • @Petr Qt uses deflate algorithm, but not zip. `qUncompress` can exceeds the expected size. – Meefte Nov 20 '15 at 08:46