From: Timo Sirainen Date: Tue, 3 Jun 2025 15:11:09 +0000 (+0300) Subject: lib-compression: Fix potential hangs writing to non-blocking ostreams X-Git-Tag: 2.4.2~670 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8f04ede4b55bc63cc48ae41a544f836ed2d35720;p=thirdparty%2Fdovecot%2Fcore.git lib-compression: Fix potential hangs writing to non-blocking ostreams This especially fixes hangs with IMAP COMPRESS handling in proxies. --- diff --git a/src/lib-compression/ostream-bzlib.c b/src/lib-compression/ostream-bzlib.c index 839fd22138..c7e228b05a 100644 --- a/src/lib-compression/ostream-bzlib.c +++ b/src/lib-compression/ostream-bzlib.c @@ -94,6 +94,11 @@ static int o_stream_zlib_send_outbuf(struct bzlib_ostream *zstream) } if ((size_t)ret != size) { zstream->outbuf_offset += ret; + /* We couldn't send everything to parent stream, but we + accepted all the input already. Set the ostream's flush + pending so when there's more space in the parent stream + we'll continue sending the rest of the data. */ + o_stream_set_flush_pending(&zstream->ostream.ostream, TRUE); return 0; } zstream->outbuf_offset = 0; @@ -301,6 +306,7 @@ static struct ostream *o_stream_create_bz2(struct ostream *output, int level) zstream->zs.next_out = zstream->outbuf; zstream->zs.avail_out = sizeof(zstream->outbuf); + o_stream_init_buffering_flush(&zstream->ostream, output); return o_stream_create(&zstream->ostream, output, o_stream_get_fd(output)); } diff --git a/src/lib-compression/ostream-lz4.c b/src/lib-compression/ostream-lz4.c index 65961603ae..0707e12d43 100644 --- a/src/lib-compression/ostream-lz4.c +++ b/src/lib-compression/ostream-lz4.c @@ -50,6 +50,11 @@ static int o_stream_lz4_send_outbuf(struct lz4_ostream *zstream) } if ((size_t)ret != size) { zstream->outbuf_offset += ret; + /* We couldn't send everything to parent stream, but we + accepted all the input already. Set the ostream's flush + pending so when there's more space in the parent stream + we'll continue sending the rest of the data. */ + o_stream_set_flush_pending(&zstream->ostream.ostream, TRUE); return 0; } zstream->outbuf_offset = 0; @@ -226,6 +231,7 @@ o_stream_create_lz4_auto(struct ostream *output, hdr->max_uncompressed_chunk_size[3] = (OSTREAM_LZ4_CHUNK_SIZE & 0x000000ff); zstream->outbuf_used = sizeof(*hdr); + o_stream_init_buffering_flush(&zstream->ostream, output); return o_stream_create(&zstream->ostream, output, o_stream_get_fd(output)); } diff --git a/src/lib-compression/ostream-zlib.c b/src/lib-compression/ostream-zlib.c index 1367713e68..5cc2215737 100644 --- a/src/lib-compression/ostream-zlib.c +++ b/src/lib-compression/ostream-zlib.c @@ -109,7 +109,11 @@ static int o_stream_zlib_send_gz_header(struct zlib_ostream *zstream) } i_assert((size_t)ret <= zstream->header_bytes_left); zstream->header_bytes_left -= ret; - return zstream->header_bytes_left == 0 ? 1 : 0; + if (zstream->header_bytes_left != 0) { + o_stream_set_flush_pending(&zstream->ostream.ostream, TRUE); + return 0; + } + return 1; } static int o_stream_zlib_lsb_uint32(struct ostream *output, uint32_t num) @@ -159,6 +163,11 @@ static int o_stream_zlib_send_outbuf(struct zlib_ostream *zstream) } if ((size_t)ret != size) { zstream->outbuf_offset += ret; + /* We couldn't send everything to parent stream, but we + accepted all the input already. Set the ostream's flush + pending so when there's more space in the parent stream + we'll continue sending the rest of the data. */ + o_stream_set_flush_pending(&zstream->ostream.ostream, TRUE); return 0; } zstream->outbuf_offset = 0; @@ -414,6 +423,7 @@ o_stream_create_zlib(struct ostream *output, int level, bool gz) zstream->zs.next_out = zstream->outbuf; zstream->zs.avail_out = sizeof(zstream->outbuf); + o_stream_init_buffering_flush(&zstream->ostream, output); return o_stream_create(&zstream->ostream, output, o_stream_get_fd(output)); } diff --git a/src/lib-compression/ostream-zstd.c b/src/lib-compression/ostream-zstd.c index 786765f137..b307fefd60 100644 --- a/src/lib-compression/ostream-zstd.c +++ b/src/lib-compression/ostream-zstd.c @@ -115,8 +115,14 @@ static ssize_t o_stream_zstd_send_outbuf(struct zstd_ostream *zstream) memmove(zstream->outbuf, zstream->outbuf+ret, zstream->output.pos-ret); zstream->output.pos -= ret; } - if (zstream->output.pos > 0) + if (zstream->output.pos > 0) { + /* We couldn't send everything to parent stream, but we + accepted all the input already. Set the ostream's flush + pending so when there's more space in the parent stream + we'll continue sending the rest of the data. */ + o_stream_set_flush_pending(&zstream->ostream.ostream, TRUE); return 0; + } return 1; } @@ -263,6 +269,7 @@ o_stream_create_zstd(struct ostream *output, int level) zstream->output.dst = zstream->outbuf; zstream->output.size = ZSTD_CStreamOutSize(); } + o_stream_init_buffering_flush(&zstream->ostream, output); return o_stream_create(&zstream->ostream, output, o_stream_get_fd(output)); }