Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 79a3137

Browse files
committed
Add warning about vulnerabilities of using compression
1 parent 1e8c9ae commit 79a3137

File tree

4 files changed

+100
-32
lines changed

4 files changed

+100
-32
lines changed

doc/src/sgml/protocol.sgml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -275,12 +275,13 @@
275275
<term>CompressionAck</term>
276276
<listitem>
277277
<para>
278-
Server acknowledge using compression for client-server communication protocol.
278+
Server acknowledges using compression for client-server communication protocol.
279279
Compression can be requested by client by including "compression" option in connection string.
280-
Client sends to the server list of compression algorithms, supported by client library.
281-
If server supports one of this algorithms, then it acknowledges use of this algorithm and then all libpq messages send both from client to server and
280+
Client sends to the server list of compression algorithms, supported by client library
281+
(compression algorithm is identified by one letter: <literal>'f'</literal> - Facebook zstd, <literal>'z'</literal> - zlib,...).
282+
If server supports one of this algorithms, then it acknowledges use of this algorithm and all subsequent libpq messages send both from client to server and
282283
visa versa will be compressed. If server is not supporting any of the suggested algorithms, then it replies with 'n' (no compression)
283-
message and it is up to the client whether to continue work without compression or report error.
284+
algorithm identifier and it is up to the client whether to continue work without compression or report error.
284285
</para>
285286
</listitem>
286287
</varlistentry>
@@ -3460,7 +3461,7 @@ CompressionAck (B)
34603461
</term>
34613462
<listitem>
34623463
<para>
3463-
Used compression algorithm. Right now the following streaming compression algorithms are supported: 'f' - Facebook zstd, 'z' - zlib, 'n' - no compresion.
3464+
Used compression algorithm. Right now the following streaming compression algorithms are supported: 'f' - Facebook zstd, 'z' - zlib, 'n' - no compression.
34643465
</para>
34653466
</listitem>
34663467
</varlistentry>
@@ -5895,8 +5896,9 @@ StartupMessage (F)
58955896
<listitem>
58965897
<para>
58975898
Request compression of libpq traffic. Value is list of compression algorithms supported by client:
5898-
<literal>'f'</literal> - Facebook zstd, <literal>'z'</literal> - zlib, <literal>'n'</literal> - no compresion.
5899-
By default compression is disabled.
5899+
<literal>'f'</literal> - Facebook zstd, <literal>'z'</literal> - zlib, <literal>'n'</literal> - no compression.
5900+
By default compression is disabled. Please notice that using compression together with SSL may add extra vulnerabilities:
5901+
<ulink url="https://en.wikipedia.org/wiki/CRIME">CRIME</ulink>.
59005902
</para>
59015903
</listitem>
59025904
</varlistentry>

src/backend/libpq/pqcomm.c

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -199,16 +199,22 @@ WaitEventSet *FeBeWaitSet;
199199
int
200200
pq_configure(Port* port)
201201
{
202-
char server_compression_algorithms[ZPQ_MAX_ALGORITHMS];
203202
char* client_compression_algorithms = port->compression_algorithms;
204-
char compression_algorithm = ZPQ_NO_COMPRESSION;
205-
char compression[6] = {'z',0,0,0,5,0}; /* message length = 5 */
206-
int rc;
207-
208-
zpq_get_supported_algorithms(server_compression_algorithms);
209-
203+
/*
204+
* If client request compression, it sends list of supported compression algorithms.
205+
* Each compression algorirthm is idetified by one letter ('f' - Facebook zsts, 'z' - xlib)
206+
*/
210207
if (client_compression_algorithms)
211208
{
209+
char server_compression_algorithms[ZPQ_MAX_ALGORITHMS];
210+
char compression_algorithm = ZPQ_NO_COMPRESSION;
211+
char compression[6] = {'z',0,0,0,5,0}; /* message length = 5 */
212+
int rc;
213+
214+
/* Get list of compression algorithms, supported by server */
215+
zpq_get_supported_algorithms(server_compression_algorithms);
216+
217+
/* Intersect lists */
212218
while (*client_compression_algorithms != '\0')
213219
{
214220
if (strchr(server_compression_algorithms, *client_compression_algorithms))
@@ -218,19 +224,19 @@ pq_configure(Port* port)
218224
}
219225
client_compression_algorithms += 1;
220226
}
221-
}
222227

223-
compression[5] = compression_algorithm;
224-
/* Switch on compression at client side */
225-
socket_set_nonblocking(false);
226-
while ((rc = secure_write(MyProcPort, compression, sizeof(compression))) < 0
227-
&& errno == EINTR);
228-
if ((size_t)rc != sizeof(compression))
229-
return -1;
230-
231-
/* initialize compression */
232-
if (zpq_set_algorithm(compression_algorithm))
233-
PqStream = zpq_create((zpq_tx_func)secure_write, (zpq_rx_func)secure_read, MyProcPort);
228+
compression[5] = compression_algorithm;
229+
/* Send 'z' message to the client with selectde comression algorithm ('n' if match is ont found) */
230+
socket_set_nonblocking(false);
231+
while ((rc = secure_write(MyProcPort, compression, sizeof(compression))) < 0
232+
&& errno == EINTR);
233+
if ((size_t)rc != sizeof(compression))
234+
return -1;
235+
236+
/* initialize compression */
237+
if (zpq_set_algorithm(compression_algorithm))
238+
PqStream = zpq_create((zpq_tx_func)secure_write, (zpq_rx_func)secure_read, MyProcPort);
239+
}
234240
return 0;
235241
}
236242

@@ -983,6 +989,7 @@ socket_set_nonblocking(bool nonblocking)
983989
/* --------------------------------
984990
* pq_recvbuf - load some bytes into the input buffer
985991
*
992+
* nowait parameter toggles non-blocking mode.
986993
* returns number of read bytes, EOF if trouble
987994
* --------------------------------
988995
*/
@@ -1012,6 +1019,7 @@ pq_recvbuf(bool nowait)
10121019
for (;;)
10131020
{
10141021
size_t processed = 0;
1022+
/* If srteaming compression is enabled then use correpondent comression read function. */
10151023
r = PqStream
10161024
? zpq_read(PqStream, PqRecvBuffer + PqRecvLength,
10171025
PQ_RECV_BUFFER_SIZE - PqRecvLength, &processed)

src/common/zpq_stream.c

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,48 @@
33
#include "c.h"
44
#include "pg_config.h"
55

6-
static int zpq_algorithm_impl;
7-
6+
/*
7+
* Functions implementing streaming compression algorithm
8+
*/
89
typedef struct
910
{
11+
/*
12+
* Returns letter identifying compression algorithm.
13+
*/
1014
char (*name)(void);
15+
16+
/*
17+
* Create compression stream with using rx/tx function for fetching/sending compressed data
18+
*/
1119
ZpqStream* (*create)(zpq_tx_func tx_func, zpq_rx_func rx_func, void *arg);
20+
21+
/*
22+
* Read up to "size" raw (decompressed) bytes.
23+
* Returns number of decompressed bytes or error code. In the last case amount of decompressed bytes is stored in *processed.
24+
* Error code is either ZPQ_DECOMPRESS_ERROR either error code returned by the rx function.
25+
*/
1226
ssize_t (*read)(ZpqStream *zs, void *buf, size_t size, size_t *processed);
27+
28+
/*
29+
* Write up to "size" raw (decompressed) bytes.
30+
* Returns number of written raw bytes or error code returned by tx function.
31+
* In the last case amount of written raw bytes is stored in *processed.
32+
*/
1333
ssize_t (*write)(ZpqStream *zs, void const *buf, size_t size, size_t *processed);
34+
35+
/*
36+
* Free stream created by create function.
37+
*/
1438
void (*free)(ZpqStream *zs);
39+
40+
/*
41+
* Get error message.
42+
*/
1543
char const* (*error)(ZpqStream *zs);
44+
45+
/*
46+
* Returns amount of data in internal compression buffer.
47+
*/
1648
size_t (*buffered)(ZpqStream *zs);
1749
} ZpqAlgorithm;
1850

@@ -31,8 +63,8 @@ typedef struct ZstdStream
3163
ZSTD_DStream* rx_stream;
3264
ZSTD_outBuffer tx;
3365
ZSTD_inBuffer rx;
34-
size_t tx_not_flushed; /* Amount of datas in internal zstd buffer */
35-
size_t tx_buffered; /* Data which is consumed by zpq_read but not yet sent */
66+
size_t tx_not_flushed; /* Amount of data in internal zstd buffer */
67+
size_t tx_buffered; /* Data which is consumed by ztd_read but not yet sent */
3668
zpq_tx_func tx_func;
3769
zpq_rx_func rx_func;
3870
void* arg;
@@ -367,7 +399,10 @@ zlib_name(void)
367399

368400
#endif
369401

370-
static ZpqAlgorithm const zpq_algorithms[] =
402+
/*
403+
* Array with all supported compression algorithms.
404+
*/
405+
static ZpqAlgorithm const zpq_algorithms[] =
371406
{
372407
#if HAVE_LIBZSTD
373408
{zstd_name, zstd_create, zstd_read, zstd_write, zstd_free, zstd_error, zstd_buffered},
@@ -378,6 +413,12 @@ static ZpqAlgorithm const zpq_algorithms[] =
378413
{NULL}
379414
};
380415

416+
/*
417+
* Index of used compression algorithm in zpq_algorithms array.
418+
*/
419+
static int zpq_algorithm_impl;
420+
421+
381422
ZpqStream*
382423
zpq_create(zpq_tx_func tx_func, zpq_rx_func rx_func, void *arg)
383424
{
@@ -415,6 +456,11 @@ zpq_buffered(ZpqStream *zs)
415456
return zpq_algorithms[zpq_algorithm_impl].buffered(zs);
416457
}
417458

459+
/*
460+
* Get list of the supported algorithms.
461+
* Each algorithm is identified by one letter: 'f' - Facebook zstd, 'z' - zlib.
462+
* Algorithm identifies are appended to the provided buffer and terminated by '\0'.
463+
*/
418464
void
419465
zpq_get_supported_algorithms(char algorithms[ZPQ_MAX_ALGORITHMS])
420466
{
@@ -428,7 +474,11 @@ zpq_get_supported_algorithms(char algorithms[ZPQ_MAX_ALGORITHMS])
428474
algorithms[i] = '\0';
429475
}
430476

431-
477+
/*
478+
* Choose current algorithm implementation.
479+
* Returns true if algorithm identifier is located in the list of the supported algorithms,
480+
* false otherwise
481+
*/
432482
bool
433483
zpq_set_algorithm(char name)
434484
{

src/interfaces/libpq/fe-protocol3.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2135,6 +2135,10 @@ pqBuildStartupPacket3(PGconn *conn, int *packetlen,
21352135
return startpacket;
21362136
}
21372137

2138+
/*
2139+
* Parse boolean value. This code is copied from backend/utils/atd/bool.c
2140+
* because it is not available at frontend.
2141+
*/
21382142
static bool
21392143
parse_bool(const char *value, bool *result)
21402144
{
@@ -2257,6 +2261,10 @@ build_startup_packet(const PGconn *conn, char *packet,
22572261
if (conn->compression && conn->compression[0])
22582262
{
22592263
bool enabled;
2264+
/*
2265+
* If compressoin is enabled, then send to the server list of compression algorithms
2266+
* supported by client
2267+
*/
22602268
if (parse_bool(conn->compression, &enabled))
22612269
{
22622270
char compression_algorithms[ZPQ_MAX_ALGORITHMS];

0 commit comments

Comments
 (0)