Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libhtp for openSUSE:Factory checked in at 2021-03-05 13:49:13 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libhtp (Old) and /work/SRC/openSUSE:Factory/.libhtp.new.2378 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libhtp" Fri Mar 5 13:49:13 2021 rev:8 rq:876951 version:0.5.37 Changes: -------- --- /work/SRC/openSUSE:Factory/libhtp/libhtp.changes 2020-12-17 17:09:00.845953533 +0100 +++ /work/SRC/openSUSE:Factory/.libhtp.new.2378/libhtp.changes 2021-03-05 13:51:29.751965104 +0100 @@ -1,0 +2,8 @@ +Wed Mar 3 20:52:34 UTC 2021 - Martin Hauke <mar...@gmx.de> + +- Update to version 0.5.37 + * support request body decompression + * several accuracy fixes + * fuzz improvments + +------------------------------------------------------------------- Old: ---- libhtp-0.5.36.tar.gz New: ---- libhtp-0.5.37.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libhtp.spec ++++++ --- /var/tmp/diff_new_pack.jfeYoH/_old 2021-03-05 13:51:30.275965607 +0100 +++ /var/tmp/diff_new_pack.jfeYoH/_new 2021-03-05 13:51:30.279965611 +0100 @@ -1,7 +1,7 @@ # # spec file for package libhtp # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,7 +19,7 @@ %define sover 2 %define lname %{name}%{sover} Name: libhtp -Version: 0.5.36 +Version: 0.5.37 Release: 0 Summary: HTTP normalizer and parser License: BSD-3-Clause ++++++ libhtp-0.5.36.tar.gz -> libhtp-0.5.37.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libhtp-0.5.36/ChangeLog new/libhtp-0.5.37/ChangeLog --- old/libhtp-0.5.36/ChangeLog 2020-12-03 12:05:03.000000000 +0100 +++ new/libhtp-0.5.37/ChangeLog 2021-02-27 15:16:55.000000000 +0100 @@ -1,3 +1,12 @@ +0.5.37 (2 March 2021) +--------------------- + +- support request body decompression + +- several accuracy fixes + +- fuzz improvments + 0.5.36 (3 December 2020) ------------------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libhtp-0.5.36/VERSION new/libhtp-0.5.37/VERSION --- old/libhtp-0.5.36/VERSION 2020-12-03 12:05:03.000000000 +0100 +++ new/libhtp-0.5.37/VERSION 2021-02-27 15:16:55.000000000 +0100 @@ -1,2 +1,2 @@ # This file is intended to be sourced by sh -PKG_VERSION=0.5.36 +PKG_VERSION=0.5.37 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libhtp-0.5.36/htp/htp_config.c new/libhtp-0.5.37/htp/htp_config.c --- old/libhtp-0.5.36/htp/htp_config.c 2020-12-03 12:05:03.000000000 +0100 +++ new/libhtp-0.5.37/htp/htp_config.c 2021-02-27 15:16:55.000000000 +0100 @@ -153,6 +153,7 @@ cfg->field_limit_soft = HTP_FIELD_LIMIT_SOFT; cfg->log_level = HTP_LOG_NOTICE; cfg->response_decompression_enabled = 1; + cfg->request_decompression_enabled = 0; // disabled by default cfg->parse_request_cookies = 1; cfg->parse_request_auth = 1; cfg->extract_request_files = 0; @@ -560,6 +561,11 @@ cfg->response_decompression_enabled = enabled; } +void htp_config_set_request_decompression(htp_cfg_t *cfg, int enabled) { + if (cfg == NULL) return; + cfg->request_decompression_enabled = enabled; +} + int htp_config_set_server_personality(htp_cfg_t *cfg, enum htp_server_personality_t personality) { if (cfg == NULL) return HTP_ERROR; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libhtp-0.5.36/htp/htp_config.h new/libhtp-0.5.37/htp/htp_config.h --- old/libhtp-0.5.36/htp/htp_config.h 2020-12-03 12:05:03.000000000 +0100 +++ new/libhtp-0.5.37/htp/htp_config.h 2021-02-27 15:16:55.000000000 +0100 @@ -577,6 +577,14 @@ void htp_config_set_response_decompression(htp_cfg_t *cfg, int enabled); /** + * Controls whether compressed request bodies will be automatically decompressed. + * + * @param[in] cfg + * @param[in] enabled set to 1 to enable decompression, 0 otherwise + */ +void htp_config_set_request_decompression(htp_cfg_t *cfg, int enabled); + +/** * Configure desired server personality. * * @param[in] cfg diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libhtp-0.5.36/htp/htp_config_private.h new/libhtp-0.5.37/htp/htp_config_private.h --- old/libhtp-0.5.36/htp/htp_config_private.h 2020-12-03 12:05:03.000000000 +0100 +++ new/libhtp-0.5.37/htp/htp_config_private.h 2021-02-27 15:16:55.000000000 +0100 @@ -354,6 +354,9 @@ /** How many layers of compression we will decompress (0 => no lzma). */ int response_lzma_layer_limit; + + /** Whether to decompress compressed request bodies. */ + int request_decompression_enabled; }; #ifdef __cplusplus diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libhtp-0.5.36/htp/htp_connection_parser_private.h new/libhtp-0.5.37/htp/htp_connection_parser_private.h --- old/libhtp-0.5.36/htp/htp_connection_parser_private.h 2020-12-03 12:05:03.000000000 +0100 +++ new/libhtp-0.5.37/htp/htp_connection_parser_private.h 2021-02-27 15:16:55.000000000 +0100 @@ -255,6 +255,9 @@ /** On a PUT request, this field contains additional file data. */ htp_file_t *put_file; + + /** Request decompressor used to decompress request body data. */ + htp_decompressor_t *req_decompressor; }; /** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libhtp-0.5.36/htp/htp_decompressors.c new/libhtp-0.5.37/htp/htp_decompressors.c --- old/libhtp-0.5.36/htp/htp_decompressors.c 2020-12-03 12:05:03.000000000 +0100 +++ new/libhtp-0.5.37/htp/htp_decompressors.c 2021-02-27 15:16:55.000000000 +0100 @@ -189,7 +189,7 @@ // Pass-through the NULL chunk, which indicates the end of the stream. - if (drec->passthrough) { + if (drec->super.passthrough) { htp_tx_data_t d2; d2.tx = d->tx; d2.data = d->data; @@ -391,7 +391,7 @@ drec->stream.next_out = drec->buffer; /* successfully passed through, lets continue doing that */ - drec->passthrough = 1; + drec->super.passthrough = 1; return HTP_OK; } } @@ -444,7 +444,7 @@ LzmaDec_Construct(&drec->state); } else { htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "LZMA decompression disabled"); - drec->passthrough = 1; + drec->super.passthrough = 1; } rc = Z_OK; break; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libhtp-0.5.36/htp/htp_decompressors.h new/libhtp-0.5.37/htp/htp_decompressors.h --- old/libhtp-0.5.36/htp/htp_decompressors.h 2020-12-03 12:05:03.000000000 +0100 +++ new/libhtp-0.5.37/htp/htp_decompressors.h 2021-02-27 15:16:55.000000000 +0100 @@ -62,6 +62,7 @@ struct timeval time_before; int32_t time_spent; uint32_t nb_callbacks; + uint8_t passthrough; /**< decompression failed, pass through raw data */ }; struct htp_decompressor_gzip_t { @@ -71,7 +72,6 @@ #endif int zlib_initialized; uint8_t restart; /**< deflate restarted to try rfc1950 instead of 1951 */ - uint8_t passthrough; /**< decompression failed, pass through raw data */ z_stream stream; uint8_t header[LZMA_PROPS_SIZE + 8]; uint8_t header_len; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libhtp-0.5.36/htp/htp_request.c new/libhtp-0.5.37/htp/htp_request.c --- old/libhtp-0.5.36/htp/htp_request.c 2020-12-03 12:05:03.000000000 +0100 +++ new/libhtp-0.5.37/htp/htp_request.c 2021-02-27 15:16:55.000000000 +0100 @@ -113,12 +113,12 @@ * @return HTP_OK, or a value returned from a callback. */ static htp_status_t htp_connp_req_receiver_set(htp_connp_t *connp, htp_hook_t *data_receiver_hook) { - htp_connp_req_receiver_finalize_clear(connp); + htp_status_t rc = htp_connp_req_receiver_finalize_clear(connp); connp->in_data_receiver_hook = data_receiver_hook; connp->in_current_receiver_offset = connp->in_current_read_offset; - return HTP_OK; + return rc; } /** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libhtp-0.5.36/htp/htp_response.c new/libhtp-0.5.37/htp/htp_response.c --- old/libhtp-0.5.36/htp/htp_response.c 2020-12-03 12:05:03.000000000 +0100 +++ new/libhtp-0.5.37/htp/htp_response.c 2021-02-27 15:16:55.000000000 +0100 @@ -132,12 +132,12 @@ * @return HTP_OK, or a value returned from a callback. */ static htp_status_t htp_connp_res_receiver_set(htp_connp_t *connp, htp_hook_t *data_receiver_hook) { - htp_connp_res_receiver_finalize_clear(connp); + htp_status_t rc = htp_connp_res_receiver_finalize_clear(connp); connp->out_data_receiver_hook = data_receiver_hook; connp->out_current_receiver_offset = connp->out_current_read_offset; - return HTP_OK; + return rc; } /** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libhtp-0.5.36/htp/htp_transaction.c new/libhtp-0.5.37/htp/htp_transaction.c --- old/libhtp-0.5.36/htp/htp_transaction.c 2020-12-03 12:05:03.000000000 +0100 +++ new/libhtp-0.5.37/htp/htp_transaction.c 2021-02-27 15:16:55.000000000 +0100 @@ -40,6 +40,9 @@ #include "htp_private.h" +static void htp_tx_req_destroy_decompressors(htp_connp_t *connp); +static htp_status_t htp_tx_req_process_body_data_decompressor_callback(htp_tx_data_t *d); + static bstr *copy_or_wrap_mem(const void *data, size_t len, enum htp_alloc_strategy_t alloc) { if (data == NULL) return NULL; @@ -362,6 +365,35 @@ htp_status_t rc = HTP_OK; + if (tx->connp->cfg->request_decompression_enabled) { + tx->request_content_encoding = HTP_COMPRESSION_NONE; + htp_header_t *ce = htp_table_get_c(tx->request_headers, "content-encoding"); + if (ce != NULL) { + /* fast paths: regular gzip and friends */ + if ((bstr_cmp_c_nocasenorzero(ce->value, "gzip") == 0) || + (bstr_cmp_c_nocasenorzero(ce->value, "x-gzip") == 0)) { + tx->request_content_encoding = HTP_COMPRESSION_GZIP; + } else if ((bstr_cmp_c_nocasenorzero(ce->value, "deflate") == 0) || + (bstr_cmp_c_nocasenorzero(ce->value, "x-deflate") == 0)) { + tx->request_content_encoding = HTP_COMPRESSION_DEFLATE; + } else if (bstr_cmp_c_nocasenorzero(ce->value, "lzma") == 0) { + tx->request_content_encoding = HTP_COMPRESSION_LZMA; + } + //ignore other cases such as inflate, ot multiple layers + if ((tx->request_content_encoding != HTP_COMPRESSION_NONE)) + { + if (tx->connp->req_decompressor != NULL) { + htp_tx_req_destroy_decompressors(tx->connp); + } + tx->connp->req_decompressor = htp_gzip_decompressor_create(tx->connp, tx->request_content_encoding); + if (tx->connp->req_decompressor == NULL) + return HTP_ERROR; + + tx->connp->req_decompressor->callback = htp_tx_req_process_body_data_decompressor_callback; + } + } + } + htp_header_t *cl = htp_table_get_c(tx->request_headers, "content-length"); htp_header_t *te = htp_table_get_c(tx->request_headers, "transfer-encoding"); @@ -574,9 +606,6 @@ // NULL data is allowed in this private function; it's // used to indicate the end of request body. - // Keep track of the body length. - tx->request_entity_len += len; - // Send data to the callbacks. htp_tx_data_t d; @@ -584,10 +613,41 @@ d.data = (unsigned char *) data; d.len = len; - htp_status_t rc = htp_req_run_hook_body_data(tx->connp, &d); - if (rc != HTP_OK) { - htp_log(tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request body data callback returned error (%d)", rc); - return HTP_ERROR; + switch(tx->request_content_encoding) { + case HTP_COMPRESSION_UNKNOWN: + case HTP_COMPRESSION_NONE: + // When there's no decompression, request_entity_len. + // is identical to request_message_len. + tx->request_entity_len += d.len; + htp_status_t rc = htp_req_run_hook_body_data(tx->connp, &d); + if (rc != HTP_OK) { + htp_log(tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request body data callback returned error (%d)", rc); + return HTP_ERROR; + } + break; + + case HTP_COMPRESSION_GZIP: + case HTP_COMPRESSION_DEFLATE: + case HTP_COMPRESSION_LZMA: + // In severe memory stress these could be NULL + if (tx->connp->req_decompressor == NULL || tx->connp->req_decompressor->decompress == NULL) + return HTP_ERROR; + + // Send data buffer to the decompressor. + tx->connp->req_decompressor->decompress(tx->connp->req_decompressor, &d); + + if (data == NULL) { + // Shut down the decompressor, if we used one. + htp_tx_req_destroy_decompressors(tx->connp); + } + break; + + default: + // Internal error. + htp_log(tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, + "[Internal Error] Invalid tx->request_content_encoding value: %d", + tx->request_content_encoding); + return HTP_ERROR; } return HTP_OK; @@ -756,7 +816,13 @@ return HTP_OK; } -void htp_connp_destroy_decompressors(htp_connp_t *connp) { +/** \internal + * + * Clean up decompressor(s). + * + * @param[in] tx + */ +static void htp_tx_res_destroy_decompressors(htp_connp_t *connp) { htp_decompressor_t *comp = connp->out_decompressor; while (comp) { htp_decompressor_t *next = comp->next; @@ -766,14 +832,19 @@ connp->out_decompressor = NULL; } -/** \internal - * - * Clean up decompressor(s). - * - * @param[in] tx - */ -static void htp_tx_res_destroy_decompressors(htp_tx_t *tx) { - htp_connp_destroy_decompressors(tx->connp); +static void htp_tx_req_destroy_decompressors(htp_connp_t *connp) { + htp_decompressor_t *comp = connp->req_decompressor; + while (comp) { + htp_decompressor_t *next = comp->next; + comp->destroy(comp); + comp = next; + } + connp->req_decompressor = NULL; +} + +void htp_connp_destroy_decompressors(htp_connp_t *connp) { + htp_tx_res_destroy_decompressors(connp); + htp_tx_req_destroy_decompressors(connp); } static htp_status_t htp_timer_track(int32_t *time_spent, struct timeval * after, struct timeval *before) { @@ -789,6 +860,48 @@ } return HTP_OK; } + +static htp_status_t htp_tx_req_process_body_data_decompressor_callback(htp_tx_data_t *d) { + if (d == NULL) return HTP_ERROR; + + #if HTP_DEBUG + fprint_raw_data(stderr, __func__, d->data, d->len); + #endif + + // Keep track of actual request body length. + d->tx->request_entity_len += d->len; + + // Invoke all callbacks. + htp_status_t rc = htp_req_run_hook_body_data(d->tx->connp, d); + if (rc != HTP_OK) return HTP_ERROR; + d->tx->connp->req_decompressor->nb_callbacks++; + if (d->tx->connp->req_decompressor->nb_callbacks % HTP_COMPRESSION_TIME_FREQ_TEST == 0) { + struct timeval after; + gettimeofday(&after, NULL); + // sanity check for race condition if system time changed + if ( htp_timer_track(&d->tx->connp->req_decompressor->time_spent, &after, &d->tx->connp->req_decompressor->time_before) == HTP_OK) { + // updates last tracked time + d->tx->connp->req_decompressor->time_before = after; + if (d->tx->connp->req_decompressor->time_spent > d->tx->connp->cfg->compression_time_limit ) { + htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, + "Compression bomb: spent %"PRId32" us decompressing", + d->tx->connp->req_decompressor->time_spent); + d->tx->connp->req_decompressor->passthrough = 1; + } + } + + } + if (d->tx->request_entity_len > d->tx->connp->cfg->compression_bomb_limit && + d->tx->request_entity_len > HTP_COMPRESSION_BOMB_RATIO * d->tx->request_message_len) { + htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, + "Compression bomb: decompressed %"PRId64" bytes out of %"PRId64, + d->tx->request_entity_len, d->tx->request_message_len); + return HTP_ERROR; + } + + return HTP_OK; +} + static htp_status_t htp_tx_res_process_body_data_decompressor_callback(htp_tx_data_t *d) { if (d == NULL) return HTP_ERROR; @@ -812,9 +925,9 @@ d->tx->connp->out_decompressor->time_before = after; if (d->tx->connp->out_decompressor->time_spent > d->tx->connp->cfg->compression_time_limit ) { htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Compression bomb: spent %"PRId64" us decompressing", + "Compression bomb: spent %"PRId32" us decompressing", d->tx->connp->out_decompressor->time_spent); - return HTP_ERROR; + d->tx->connp->out_decompressor->passthrough = 1; } } @@ -874,15 +987,15 @@ if ( htp_timer_track(&tx->connp->out_decompressor->time_spent, &after, &tx->connp->out_decompressor->time_before) == HTP_OK) { if ( tx->connp->out_decompressor->time_spent > tx->connp->cfg->compression_time_limit ) { htp_log(tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Compression bomb: spent %"PRId64" us decompressing", + "Compression bomb: spent %"PRId32" us decompressing", tx->connp->out_decompressor->time_spent); - return HTP_ERROR; + tx->connp->out_decompressor->passthrough = 1; } } if (data == NULL) { // Shut down the decompressor, if we used one. - htp_tx_res_destroy_decompressors(tx); + htp_tx_res_destroy_decompressors(tx->connp); } break; @@ -921,6 +1034,8 @@ // Run hook REQUEST_COMPLETE. htp_status_t rc = htp_hook_run_all(tx->connp->cfg->hook_request_complete, tx); if (rc != HTP_OK) return rc; + rc = htp_connp_req_receiver_finalize_clear(tx->connp); + if (rc != HTP_OK) return rc; // Clean-up. if (tx->connp->put_file != NULL) { @@ -1103,6 +1218,10 @@ // Run hook RESPONSE_COMPLETE. htp_status_t rc = htp_hook_run_all(tx->connp->cfg->hook_response_complete, tx); if (rc != HTP_OK) return rc; + + // Clear the data receivers hook if any + rc = htp_connp_res_receiver_finalize_clear(tx->connp); + if (rc != HTP_OK) return rc; } if (!hybrid_mode) { @@ -1266,7 +1385,7 @@ ce_multi_comp) { if (tx->connp->out_decompressor != NULL) { - htp_tx_res_destroy_decompressors(tx); + htp_tx_res_destroy_decompressors(tx->connp); } /* normal case */ @@ -1311,6 +1430,7 @@ break; } + nblzma++; if (bstr_util_mem_index_of_c_nocase(tok, tok_len, "gzip") != -1) { if (!(bstr_util_cmp_mem(tok, tok_len, "gzip", 4) == 0 || bstr_util_cmp_mem(tok, tok_len, "x-gzip", 6) == 0)) { @@ -1327,10 +1447,9 @@ cetype = HTP_COMPRESSION_DEFLATE; } else if (bstr_util_cmp_mem(tok, tok_len, "lzma", 4) == 0) { cetype = HTP_COMPRESSION_LZMA; - nblzma++; if (nblzma > tx->connp->cfg->response_lzma_layer_limit) { htp_log(tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Compression bomb: double lzma encoding"); + "Compression bomb: multiple encoding with lzma"); break; } } else if (bstr_util_cmp_mem(tok, tok_len, "inflate", 7) == 0) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libhtp-0.5.36/test/fuzz/fuzz_htp.c new/libhtp-0.5.37/test/fuzz/fuzz_htp.c --- old/libhtp-0.5.36/test/fuzz/fuzz_htp.c 2020-12-03 12:05:03.000000000 +0100 +++ new/libhtp-0.5.37/test/fuzz/fuzz_htp.c 2021-02-27 15:16:55.000000000 +0100 @@ -68,7 +68,7 @@ static int HTPCallbackRequestBodyData(htp_tx_data_t *tx_data) { fprintf(logfile, "HTPCallbackRequestBodyData %"PRIuMAX"\n", (uintmax_t)tx_data->len); - if (tx_data->len > 0) { + if (tx_data->len > 0 && tx_data->data != NULL) { fprintf(logfile, "HTPCallbackRequestBodyData %x %x\n", tx_data->data[0], tx_data->data[(uintmax_t)tx_data->len-1]); } return 0; @@ -77,7 +77,7 @@ static int HTPCallbackResponseBodyData(htp_tx_data_t *tx_data) { fprintf(logfile, "HTPCallbackResponseBodyData %"PRIuMAX"\n", (uintmax_t)tx_data->len); - if (tx_data->len > 0) { + if (tx_data->len > 0 && tx_data->data != NULL) { fprintf(logfile, "HTPCallbackResponseBodyData %x %x\n", tx_data->data[0], tx_data->data[(uintmax_t)tx_data->len-1]); } return 0; @@ -201,7 +201,11 @@ } } else { if (out_data_other) { - rc = htp_connp_res_data(connp, NULL, out_data + out_data_offset, out_data_len - out_data_offset); + if (out_data == NULL) { + rc = htp_connp_res_data(connp, NULL, NULL, out_data_len - out_data_offset); + } else { + rc = htp_connp_res_data(connp, NULL, out_data + out_data_offset, out_data_len - out_data_offset); + } if (rc == HTP_STREAM_ERROR) { break; } @@ -220,7 +224,11 @@ out_data_offset = htp_connp_res_data_consumed(connp); } if (in_data_other) { - rc = htp_connp_req_data(connp, NULL, in_data + in_data_offset, in_data_len - in_data_offset); + if (in_data == NULL) { + rc = htp_connp_req_data(connp, NULL, NULL, in_data_len - in_data_offset); + } else { + rc = htp_connp_req_data(connp, NULL, in_data + in_data_offset, in_data_len - in_data_offset); + } if (rc == HTP_STREAM_ERROR) { break; } @@ -229,7 +237,11 @@ } } if (out_data_other) { - htp_connp_res_data(connp, NULL, out_data + out_data_offset, out_data_len - out_data_offset); + if (out_data == NULL) { + (void) htp_connp_res_data(connp, NULL, NULL, out_data_len - out_data_offset); + } else { + (void) htp_connp_res_data(connp, NULL, out_data + out_data_offset, out_data_len - out_data_offset); + } } htp_connp_close(connp, NULL); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libhtp-0.5.36/test/test.c new/libhtp-0.5.37/test/test.c --- old/libhtp-0.5.36/test/test.c 2020-12-03 12:05:03.000000000 +0100 +++ new/libhtp-0.5.37/test/test.c 2021-02-27 15:16:55.000000000 +0100 @@ -73,7 +73,7 @@ // Check that there's enough room if (pos + 3 >= test->len) return -1; - if ((test->buf[pos] == '<') && (test->buf[pos + 1] == '<') && (test->buf[pos + 2] == '<')) { + if ((test->buf[pos] == '<') && (test->buf[pos + 1] == '<' || test->buf[pos + 1] == '>') && (test->buf[pos + 2] == '<')) { if (test->buf[pos + 3] == '\n') { return SERVER; } @@ -86,7 +86,7 @@ } } - if ((test->buf[pos] == '>') && (test->buf[pos + 1] == '>') && (test->buf[pos + 2] == '>')) { + if ((test->buf[pos] == '>') && (test->buf[pos + 1] == '>' || test->buf[pos + 1] == '<') && (test->buf[pos + 2] == '>')) { if (test->buf[pos + 3] == '\n') { return CLIENT; } @@ -208,6 +208,10 @@ if ((test->chunk_len > 0) && (test->chunk[test->chunk_len - 1] == '\r')) { test->chunk_len--; } + if (test->buf[test->pos + 1] != test->buf[test->pos + 2]) { + // test gap + test->chunk = NULL; + } // Position at the next boundary line test->pos++;