Skip to content

Commit 5905f0f

Browse files
committed
Merge r1619448, r1619486, r1895552, r1894152, r1914800 from trunk:
leave a hint while scrolling through inflate() calls mod_deflate: - fix signed/unsigned (int/size_t) comparisons, - add consume_buffer() to factorize code used multiple times, - cleanup passed brigade (don't rely on next output filters to do it). * modules/filters/mod_deflate.c (deflate_in_filter): Handle FLUSH in the input brigade even if done inflating (ctx->done is true), but don't try to flush the inflate stream in that case. (Caught by Coverity) * modules/filters/mod_deflate.c (deflate_out_filter): Catch apr_bucket_read() errors. mod_deflate: remove filter after seeing EOS Github: closes #423 Submitted by: covener, ylavic, jorton, Eric Norris <enorris etsy.com> Reviewed by: jorton, gbechis, ylavic git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1916557 13f79535-47bb-0310-9956-ffa450edef68
1 parent 9ab08c3 commit 5905f0f

File tree

2 files changed

+99
-118
lines changed

2 files changed

+99
-118
lines changed

changes-entries/deflate-cleanups.txt

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*) mod_deflate: Fixes and better logging for handling various
2+
error and edge cases. [Eric Covener, Yann Ylavic, Joe Orton,
3+
Eric Norris <enorris etsy.com>]
4+

modules/filters/mod_deflate.c

+95-118
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ typedef struct deflate_filter_config_t
6666
int windowSize;
6767
int memlevel;
6868
int compressionlevel;
69-
apr_size_t bufferSize;
69+
int bufferSize;
7070
const char *note_ratio_name;
7171
const char *note_input_name;
7272
const char *note_output_name;
@@ -254,7 +254,7 @@ static const char *deflate_set_buffer_size(cmd_parms *cmd, void *dummy,
254254
return "DeflateBufferSize should be positive";
255255
}
256256

257-
c->bufferSize = (apr_size_t)n;
257+
c->bufferSize = n;
258258

259259
return NULL;
260260
}
@@ -416,35 +416,40 @@ typedef struct deflate_ctx_t
416416
/* Do update ctx->crc, see comment in flush_libz_buffer */
417417
#define UPDATE_CRC 1
418418

419+
static void consume_buffer(deflate_ctx *ctx, deflate_filter_config *c,
420+
int len, int crc, apr_bucket_brigade *bb)
421+
{
422+
apr_bucket *b;
423+
424+
/*
425+
* Do we need to update ctx->crc? Usually this is the case for
426+
* inflate action where we need to do a crc on the output, whereas
427+
* in the deflate case we need to do a crc on the input
428+
*/
429+
if (crc) {
430+
ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
431+
}
432+
433+
b = apr_bucket_heap_create((char *)ctx->buffer, len, NULL,
434+
bb->bucket_alloc);
435+
APR_BRIGADE_INSERT_TAIL(bb, b);
436+
437+
ctx->stream.next_out = ctx->buffer;
438+
ctx->stream.avail_out = c->bufferSize;
439+
}
440+
419441
static int flush_libz_buffer(deflate_ctx *ctx, deflate_filter_config *c,
420-
struct apr_bucket_alloc_t *bucket_alloc,
421442
int (*libz_func)(z_streamp, int), int flush,
422443
int crc)
423444
{
424445
int zRC = Z_OK;
425446
int done = 0;
426-
unsigned int deflate_len;
427-
apr_bucket *b;
447+
int deflate_len;
428448

429449
for (;;) {
430450
deflate_len = c->bufferSize - ctx->stream.avail_out;
431-
432-
if (deflate_len != 0) {
433-
/*
434-
* Do we need to update ctx->crc? Usually this is the case for
435-
* inflate action where we need to do a crc on the output, whereas
436-
* in the deflate case we need to do a crc on the input
437-
*/
438-
if (crc) {
439-
ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer,
440-
deflate_len);
441-
}
442-
b = apr_bucket_heap_create((char *)ctx->buffer,
443-
deflate_len, NULL,
444-
bucket_alloc);
445-
APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
446-
ctx->stream.next_out = ctx->buffer;
447-
ctx->stream.avail_out = c->bufferSize;
451+
if (deflate_len > 0) {
452+
consume_buffer(ctx, c, deflate_len, crc, ctx->bb);
448453
}
449454

450455
if (done)
@@ -560,6 +565,7 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
560565
request_rec *r = f->r;
561566
deflate_ctx *ctx = f->ctx;
562567
int zRC;
568+
apr_status_t rv;
563569
apr_size_t len = 0, blen;
564570
const char *data;
565571
deflate_filter_config *c;
@@ -891,8 +897,7 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
891897

892898
ctx->stream.avail_in = 0; /* should be zero already anyway */
893899
/* flush the remaining data from the zlib buffers */
894-
flush_libz_buffer(ctx, c, f->c->bucket_alloc, deflate, Z_FINISH,
895-
NO_UPDATE_CRC);
900+
flush_libz_buffer(ctx, c, deflate, Z_FINISH, NO_UPDATE_CRC);
896901

897902
buf = apr_palloc(r->pool, VALIDATION_SIZE);
898903
putLong((unsigned char *)&buf[0], ctx->crc);
@@ -935,6 +940,10 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
935940
}
936941

937942
deflateEnd(&ctx->stream);
943+
944+
/* We've ended the libz stream, so remove ourselves. */
945+
ap_remove_output_filter(f);
946+
938947
/* No need for cleanup any longer */
939948
apr_pool_cleanup_kill(r->pool, ctx, deflate_ctx_cleanup);
940949

@@ -945,15 +954,15 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
945954
/* Okay, we've seen the EOS.
946955
* Time to pass it along down the chain.
947956
*/
948-
return ap_pass_brigade(f->next, ctx->bb);
957+
rv = ap_pass_brigade(f->next, ctx->bb);
958+
apr_brigade_cleanup(ctx->bb);
959+
return rv;
949960
}
950961

951962
if (APR_BUCKET_IS_FLUSH(e)) {
952-
apr_status_t rv;
953-
954963
/* flush the remaining data from the zlib buffers */
955-
zRC = flush_libz_buffer(ctx, c, f->c->bucket_alloc, deflate,
956-
Z_SYNC_FLUSH, NO_UPDATE_CRC);
964+
zRC = flush_libz_buffer(ctx, c, deflate, Z_SYNC_FLUSH,
965+
NO_UPDATE_CRC);
957966
if (zRC != Z_OK) {
958967
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01385)
959968
"Zlib error %d flushing zlib output buffer (%s)",
@@ -965,6 +974,7 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
965974
APR_BUCKET_REMOVE(e);
966975
APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
967976
rv = ap_pass_brigade(f->next, ctx->bb);
977+
apr_brigade_cleanup(ctx->bb);
968978
if (rv != APR_SUCCESS) {
969979
return rv;
970980
}
@@ -982,7 +992,12 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
982992
}
983993

984994
/* read */
985-
apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
995+
rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
996+
if (rv) {
997+
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(10298)
998+
"failed reading from %s bucket", e->type->name);
999+
return rv;
1000+
}
9861001
if (!len) {
9871002
apr_bucket_delete(e);
9881003
continue;
@@ -999,21 +1014,15 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
9991014
ctx->stream.next_in = (unsigned char *)data; /* We just lost const-ness,
10001015
* but we'll just have to
10011016
* trust zlib */
1002-
ctx->stream.avail_in = len;
1017+
ctx->stream.avail_in = (int)len;
10031018

10041019
while (ctx->stream.avail_in != 0) {
10051020
if (ctx->stream.avail_out == 0) {
1006-
apr_status_t rv;
1021+
consume_buffer(ctx, c, c->bufferSize, NO_UPDATE_CRC, ctx->bb);
10071022

1008-
ctx->stream.next_out = ctx->buffer;
1009-
len = c->bufferSize - ctx->stream.avail_out;
1010-
1011-
b = apr_bucket_heap_create((char *)ctx->buffer, len,
1012-
NULL, f->c->bucket_alloc);
1013-
APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
1014-
ctx->stream.avail_out = c->bufferSize;
10151023
/* Send what we have right now to the next filter. */
10161024
rv = ap_pass_brigade(f->next, ctx->bb);
1025+
apr_brigade_cleanup(ctx->bb);
10171026
if (rv != APR_SUCCESS) {
10181027
return rv;
10191028
}
@@ -1310,44 +1319,40 @@ static apr_status_t deflate_in_filter(ap_filter_t *f,
13101319
if (APR_BUCKET_IS_FLUSH(bkt)) {
13111320
apr_bucket *tmp_b;
13121321

1313-
ctx->inflate_total += ctx->stream.avail_out;
1314-
zRC = inflate(&(ctx->stream), Z_SYNC_FLUSH);
1315-
ctx->inflate_total -= ctx->stream.avail_out;
1316-
if (zRC != Z_OK) {
1317-
inflateEnd(&ctx->stream);
1318-
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01391)
1319-
"Zlib error %d inflating data (%s)", zRC,
1320-
ctx->stream.msg);
1321-
return APR_EGENERAL;
1322-
}
1322+
if (!ctx->done) {
1323+
ctx->inflate_total += ctx->stream.avail_out;
1324+
zRC = inflate(&(ctx->stream), Z_SYNC_FLUSH);
1325+
ctx->inflate_total -= ctx->stream.avail_out;
1326+
if (zRC != Z_OK) {
1327+
inflateEnd(&ctx->stream);
1328+
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01391)
1329+
"Zlib error %d inflating data (%s)", zRC,
1330+
ctx->stream.msg);
1331+
return APR_EGENERAL;
1332+
}
13231333

1324-
if (inflate_limit && ctx->inflate_total > inflate_limit) {
1325-
inflateEnd(&ctx->stream);
1326-
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02647)
1327-
"Inflated content length of %" APR_OFF_T_FMT
1328-
" is larger than the configured limit"
1329-
" of %" APR_OFF_T_FMT,
1330-
ctx->inflate_total, inflate_limit);
1331-
return APR_ENOSPC;
1332-
}
1333-
1334-
if (!check_ratio(r, ctx, dc)) {
1335-
inflateEnd(&ctx->stream);
1336-
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02805)
1337-
"Inflated content ratio is larger than the "
1338-
"configured limit %i by %i time(s)",
1339-
dc->ratio_limit, dc->ratio_burst);
1340-
return APR_EINVAL;
1341-
}
1334+
if (inflate_limit && ctx->inflate_total > inflate_limit) {
1335+
inflateEnd(&ctx->stream);
1336+
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02647)
1337+
"Inflated content length of %" APR_OFF_T_FMT
1338+
" is larger than the configured limit"
1339+
" of %" APR_OFF_T_FMT,
1340+
ctx->inflate_total, inflate_limit);
1341+
return APR_ENOSPC;
1342+
}
13421343

1343-
len = c->bufferSize - ctx->stream.avail_out;
1344-
ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
1345-
tmp_b = apr_bucket_heap_create((char *)ctx->buffer, len,
1346-
NULL, f->c->bucket_alloc);
1347-
APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_b);
1344+
if (!check_ratio(r, ctx, dc)) {
1345+
inflateEnd(&ctx->stream);
1346+
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02805)
1347+
"Inflated content ratio is larger than the "
1348+
"configured limit %i by %i time(s)",
1349+
dc->ratio_limit, dc->ratio_burst);
1350+
return APR_EINVAL;
1351+
}
13481352

1349-
ctx->stream.next_out = ctx->buffer;
1350-
ctx->stream.avail_out = c->bufferSize;
1353+
consume_buffer(ctx, c, c->bufferSize - ctx->stream.avail_out,
1354+
UPDATE_CRC, ctx->proc_bb);
1355+
}
13511356

13521357
/* Flush everything so far in the returning brigade, but continue
13531358
* reading should EOS/more follow (don't lose them).
@@ -1393,16 +1398,8 @@ static apr_status_t deflate_in_filter(ap_filter_t *f,
13931398
if (!ctx->validation_buffer) {
13941399
while (ctx->stream.avail_in != 0) {
13951400
if (ctx->stream.avail_out == 0) {
1396-
apr_bucket *tmp_heap;
1397-
1398-
ctx->stream.next_out = ctx->buffer;
1399-
len = c->bufferSize - ctx->stream.avail_out;
1400-
1401-
ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
1402-
tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
1403-
NULL, f->c->bucket_alloc);
1404-
APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
1405-
ctx->stream.avail_out = c->bufferSize;
1401+
consume_buffer(ctx, c, c->bufferSize, UPDATE_CRC,
1402+
ctx->proc_bb);
14061403
}
14071404

14081405
ctx->inflate_total += ctx->stream.avail_out;
@@ -1445,7 +1442,6 @@ static apr_status_t deflate_in_filter(ap_filter_t *f,
14451442
}
14461443

14471444
if (ctx->validation_buffer) {
1448-
apr_bucket *tmp_heap;
14491445
apr_size_t avail, valid;
14501446
unsigned char *buf = ctx->validation_buffer;
14511447

@@ -1474,13 +1470,8 @@ static apr_status_t deflate_in_filter(ap_filter_t *f,
14741470
(apr_uint64_t)ctx->stream.total_in,
14751471
(apr_uint64_t)ctx->stream.total_out, r->uri);
14761472

1477-
len = c->bufferSize - ctx->stream.avail_out;
1478-
1479-
ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
1480-
tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
1481-
NULL, f->c->bucket_alloc);
1482-
APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
1483-
ctx->stream.avail_out = c->bufferSize;
1473+
consume_buffer(ctx, c, c->bufferSize - ctx->stream.avail_out,
1474+
UPDATE_CRC, ctx->proc_bb);
14841475

14851476
{
14861477
unsigned long compCRC, compLen;
@@ -1526,16 +1517,8 @@ static apr_status_t deflate_in_filter(ap_filter_t *f,
15261517
if (block == APR_BLOCK_READ &&
15271518
APR_BRIGADE_EMPTY(ctx->proc_bb) &&
15281519
ctx->stream.avail_out < c->bufferSize) {
1529-
apr_bucket *tmp_heap;
1530-
apr_size_t len;
1531-
ctx->stream.next_out = ctx->buffer;
1532-
len = c->bufferSize - ctx->stream.avail_out;
1533-
1534-
ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
1535-
tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
1536-
NULL, f->c->bucket_alloc);
1537-
APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
1538-
ctx->stream.avail_out = c->bufferSize;
1520+
consume_buffer(ctx, c, c->bufferSize - ctx->stream.avail_out,
1521+
UPDATE_CRC, ctx->proc_bb);
15391522
}
15401523

15411524
if (!APR_BRIGADE_EMPTY(ctx->proc_bb)) {
@@ -1651,7 +1634,6 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
16511634
while (!APR_BRIGADE_EMPTY(bb))
16521635
{
16531636
const char *data;
1654-
apr_bucket *b;
16551637
apr_size_t len;
16561638

16571639
e = APR_BRIGADE_FIRST(bb);
@@ -1673,8 +1655,7 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
16731655
* fails, whereas in the deflate case you can empty a filled output
16741656
* buffer and call it again until no more output can be created.
16751657
*/
1676-
flush_libz_buffer(ctx, c, f->c->bucket_alloc, inflate, Z_SYNC_FLUSH,
1677-
UPDATE_CRC);
1658+
flush_libz_buffer(ctx, c, inflate, Z_SYNC_FLUSH, UPDATE_CRC);
16781659
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01398)
16791660
"Zlib: Inflated %" APR_UINT64_T_FMT
16801661
" to %" APR_UINT64_T_FMT " : URL %s",
@@ -1716,15 +1697,14 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
17161697
* Okay, we've seen the EOS.
17171698
* Time to pass it along down the chain.
17181699
*/
1719-
return ap_pass_brigade(f->next, ctx->bb);
1700+
rv = ap_pass_brigade(f->next, ctx->bb);
1701+
apr_brigade_cleanup(ctx->bb);
1702+
return rv;
17201703
}
17211704

17221705
if (APR_BUCKET_IS_FLUSH(e)) {
1723-
apr_status_t rv;
1724-
17251706
/* flush the remaining data from the zlib buffers */
1726-
zRC = flush_libz_buffer(ctx, c, f->c->bucket_alloc, inflate,
1727-
Z_SYNC_FLUSH, UPDATE_CRC);
1707+
zRC = flush_libz_buffer(ctx, c, inflate, Z_SYNC_FLUSH, UPDATE_CRC);
17281708
if (zRC == Z_STREAM_END) {
17291709
if (ctx->validation_buffer == NULL) {
17301710
ctx->validation_buffer = apr_pcalloc(f->r->pool,
@@ -1742,6 +1722,7 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
17421722
APR_BUCKET_REMOVE(e);
17431723
APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
17441724
rv = ap_pass_brigade(f->next, ctx->bb);
1725+
apr_brigade_cleanup(ctx->bb);
17451726
if (rv != APR_SUCCESS) {
17461727
return rv;
17471728
}
@@ -1858,16 +1839,11 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
18581839

18591840
while (ctx->stream.avail_in != 0) {
18601841
if (ctx->stream.avail_out == 0) {
1861-
ctx->stream.next_out = ctx->buffer;
1862-
len = c->bufferSize - ctx->stream.avail_out;
1863-
1864-
ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
1865-
b = apr_bucket_heap_create((char *)ctx->buffer, len,
1866-
NULL, f->c->bucket_alloc);
1867-
APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
1868-
ctx->stream.avail_out = c->bufferSize;
1842+
consume_buffer(ctx, c, c->bufferSize, UPDATE_CRC, ctx->bb);
1843+
18691844
/* Send what we have right now to the next filter. */
18701845
rv = ap_pass_brigade(f->next, ctx->bb);
1846+
apr_brigade_cleanup(ctx->bb);
18711847
if (rv != APR_SUCCESS) {
18721848
return rv;
18731849
}
@@ -1882,6 +1858,7 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
18821858
return APR_EGENERAL;
18831859
}
18841860

1861+
/* Don't check length limits on inflate_out */
18851862
if (!check_ratio(r, ctx, dc)) {
18861863
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02650)
18871864
"Inflated content ratio is larger than the "

0 commit comments

Comments
 (0)