diff options
author | Yann Ylavic <ylavic@apache.org> | 2020-05-20 16:01:17 +0200 |
---|---|---|
committer | Yann Ylavic <ylavic@apache.org> | 2020-05-20 16:01:17 +0200 |
commit | 11d03dc86a9642a4af44c40122299b7efad47775 (patch) | |
tree | 23576af687aa6d5ad87abb8307bb4e3006741f1e | |
parent | lognos (diff) | |
download | apache2-11d03dc86a9642a4af44c40122299b7efad47775.tar.xz apache2-11d03dc86a9642a4af44c40122299b7efad47775.zip |
core,modules: provide/use ap_parse_strict_length() helper.
It helps simplifying a lot of duplicated code based on apr_strtoff(), while
also rejecting leading plus/minus signs which are dissalowed in Content-Length
and (Content-)Range headers.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1877954 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | docs/log-message-tags/next-number | 2 | ||||
-rw-r--r-- | include/ap_mmn.h | 3 | ||||
-rw-r--r-- | include/httpd.h | 9 | ||||
-rw-r--r-- | modules/apreq/filter.c | 8 | ||||
-rw-r--r-- | modules/cache/mod_cache.c | 23 | ||||
-rw-r--r-- | modules/cache/mod_cache_disk.c | 24 | ||||
-rw-r--r-- | modules/cache/mod_cache_socache.c | 25 | ||||
-rw-r--r-- | modules/dav/main/mod_dav.c | 23 | ||||
-rw-r--r-- | modules/filters/mod_data.c | 4 | ||||
-rw-r--r-- | modules/filters/mod_reflector.c | 11 | ||||
-rw-r--r-- | modules/filters/mod_request.c | 12 | ||||
-rw-r--r-- | modules/http/byterange_filter.c | 7 | ||||
-rw-r--r-- | modules/http/http_filters.c | 18 | ||||
-rw-r--r-- | modules/mappers/mod_negotiation.c | 8 | ||||
-rw-r--r-- | modules/proxy/mod_proxy.c | 10 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_ajp.c | 19 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_http.c | 4 | ||||
-rw-r--r-- | server/apreq_module_cgi.c | 9 | ||||
-rw-r--r-- | server/util.c | 28 |
19 files changed, 118 insertions, 129 deletions
diff --git a/docs/log-message-tags/next-number b/docs/log-message-tags/next-number index a45d5ebc99..70e6b624f9 100644 --- a/docs/log-message-tags/next-number +++ b/docs/log-message-tags/next-number @@ -1 +1 @@ -10242 +10244 diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 8ac21c15f4..2a8ce4c2ca 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -631,6 +631,7 @@ * 20200420.0 (2.5.1-dev) Add flags to listen_rec in place of use_specific_errors * 20200420.1 (2.5.1-dev) Add ap_filter_adopt_brigade() * 20200420.2 (2.5.1-dev) Add ap_proxy_worker_can_upgrade() + * 20200420.3 (2.5.1-dev) Add ap_parse_strict_length() */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ @@ -638,7 +639,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20200420 #endif -#define MODULE_MAGIC_NUMBER_MINOR 2 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 3 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/httpd.h b/include/httpd.h index c3a81ba446..90293eb74c 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -2177,6 +2177,15 @@ AP_DECLARE(char *) ap_append_pid(apr_pool_t *p, const char *string, const char *delim); /** + * Parse a length string with decimal characters only, no leading sign nor + * trailing character, like Content-Length or (Content-)Range headers. + * @param len The parsed length (apr_off_t) + * @param str The string to parse + * @return 1 (success), 0 (failure) + */ +AP_DECLARE(int) ap_parse_strict_length(apr_off_t *len, const char *str); + +/** * Parse a given timeout parameter string into an apr_interval_time_t value. * The unit of the time interval is given as postfix string to the numeric * string. Currently the following units are understood (case insensitive): diff --git a/modules/apreq/filter.c b/modules/apreq/filter.c index d2d8996eda..b4a1a4ebac 100644 --- a/modules/apreq/filter.c +++ b/modules/apreq/filter.c @@ -121,18 +121,16 @@ void apreq_filter_init_context(ap_filter_t *f) } cl_header = apr_table_get(r->headers_in, "Content-Length"); - if (cl_header != NULL) { - char *dummy; - apr_uint64_t content_length = apr_strtoi64(cl_header, &dummy, 10); + apr_off_t cl; - if (dummy == NULL || *dummy != 0) { + if (!ap_parse_strict_length(&cl, cl_header)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r, APLOGNO(02045) "Invalid Content-Length header (%s)", cl_header); ctx->body_status = APREQ_ERROR_BADHEADER; return; } - else if (content_length > ctx->read_limit) { + if ((apr_uint64_t)cl > ctx->read_limit) { ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r, APLOGNO(02046) "Content-Length header (%s) exceeds configured " "max_body limit (%" APR_UINT64_T_FMT ")", diff --git a/modules/cache/mod_cache.c b/modules/cache/mod_cache.c index 46aec7e163..cb59aae992 100644 --- a/modules/cache/mod_cache.c +++ b/modules/cache/mod_cache.c @@ -1229,6 +1229,16 @@ static apr_status_t cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) return APR_SUCCESS; } + /* Set the content length if known. + */ + cl = apr_table_get(r->err_headers_out, "Content-Length"); + if (cl == NULL) { + cl = apr_table_get(r->headers_out, "Content-Length"); + } + if (cl && !ap_parse_strict_length(&size, cl)) { + reason = "invalid content length"; + } + if (reason) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00768) "cache: %s not cached for request %s. Reason: %s", @@ -1251,19 +1261,6 @@ static apr_status_t cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) /* Make it so that we don't execute this path again. */ cache->in_checked = 1; - /* Set the content length if known. - */ - cl = apr_table_get(r->err_headers_out, "Content-Length"); - if (cl == NULL) { - cl = apr_table_get(r->headers_out, "Content-Length"); - } - if (cl) { - char *errp; - if (apr_strtoff(&size, cl, &errp, 10) || *errp || size < 0) { - cl = NULL; /* parse error, see next 'if' block */ - } - } - if (!cl) { /* if we don't get the content-length, see if we have all the * buckets and use their length to calculate the size diff --git a/modules/cache/mod_cache_disk.c b/modules/cache/mod_cache_disk.c index 7392b9981a..4b1e0227bf 100644 --- a/modules/cache/mod_cache_disk.c +++ b/modules/cache/mod_cache_disk.c @@ -1276,9 +1276,9 @@ static apr_status_t store_body(cache_handle_t *h, request_rec *r, * sanity checks. */ if (seen_eos) { - const char *cl_header = apr_table_get(r->headers_out, "Content-Length"); - if (!dobj->disk_info.header_only) { + const char *cl_header; + apr_off_t cl; if (dobj->data.tempfd) { rv = apr_file_close(dobj->data.tempfd); @@ -1297,6 +1297,7 @@ static apr_status_t store_body(cache_handle_t *h, request_rec *r, apr_pool_destroy(dobj->data.pool); return APR_EGENERAL; } + if (dobj->file_size < dconf->minfs) { ap_log_rerror( APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00734) "URL %s failed the size check " @@ -1305,17 +1306,16 @@ static apr_status_t store_body(cache_handle_t *h, request_rec *r, apr_pool_destroy(dobj->data.pool); return APR_EGENERAL; } - if (cl_header) { - apr_int64_t cl = apr_atoi64(cl_header); - if ((errno == 0) && (dobj->file_size != cl)) { - ap_log_rerror( - APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00735) "URL %s didn't receive complete response, not caching", h->cache_obj->key); - /* Remove the intermediate cache file and return non-APR_SUCCESS */ - apr_pool_destroy(dobj->data.pool); - return APR_EGENERAL; - } - } + cl_header = apr_table_get(r->headers_out, "Content-Length"); + if (cl_header && (!ap_parse_strict_length(&cl, cl_header) + || cl != dobj->file_size)) { + ap_log_rerror( + APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00735) "URL %s didn't receive complete response, not caching", h->cache_obj->key); + /* Remove the intermediate cache file and return non-APR_SUCCESS */ + apr_pool_destroy(dobj->data.pool); + return APR_EGENERAL; + } } /* All checks were fine, we're good to go when the commit comes */ diff --git a/modules/cache/mod_cache_socache.c b/modules/cache/mod_cache_socache.c index cddda5dbbd..f369004a41 100644 --- a/modules/cache/mod_cache_socache.c +++ b/modules/cache/mod_cache_socache.c @@ -1046,7 +1046,8 @@ static apr_status_t store_body(cache_handle_t *h, request_rec *r, /* Was this the final bucket? If yes, perform sanity checks. */ if (seen_eos) { - const char *cl_header = apr_table_get(r->headers_out, "Content-Length"); + const char *cl_header; + apr_off_t cl; if (r->connection->aborted || r->no_cache) { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02380) @@ -1057,18 +1058,16 @@ static apr_status_t store_body(cache_handle_t *h, request_rec *r, sobj->pool = NULL; return APR_EGENERAL; } - if (cl_header) { - apr_off_t cl; - char *cl_endp; - if (apr_strtoff(&cl, cl_header, &cl_endp, 10) != APR_SUCCESS - || *cl_endp != '\0' || cl != sobj->body_length) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02381) - "URL %s didn't receive complete response, not caching", - h->cache_obj->key); - apr_pool_destroy(sobj->pool); - sobj->pool = NULL; - return APR_EGENERAL; - } + + cl_header = apr_table_get(r->headers_out, "Content-Length"); + if (cl_header && (!ap_parse_strict_length(&cl, cl_header) + || cl != sobj->body_length)) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02381) + "URL %s didn't receive complete response, not caching", + h->cache_obj->key); + apr_pool_destroy(sobj->pool); + sobj->pool = NULL; + return APR_EGENERAL; } /* All checks were fine, we're good to go when the commit comes */ diff --git a/modules/dav/main/mod_dav.c b/modules/dav/main/mod_dav.c index d84db03e09..721c57a16b 100644 --- a/modules/dav/main/mod_dav.c +++ b/modules/dav/main/mod_dav.c @@ -814,7 +814,6 @@ static int dav_parse_range(request_rec *r, char *range; char *dash; char *slash; - char *errp; range_c = apr_table_get(r->headers_in, "content-range"); if (range_c == NULL) @@ -831,20 +830,19 @@ static int dav_parse_range(request_rec *r, *dash++ = *slash++ = '\0'; /* detect invalid ranges */ - if (apr_strtoff(range_start, range + 6, &errp, 10) - || *errp || *range_start < 0) { + if (!ap_parse_strict_length(range_start, range + 6)) { return -1; } - if (apr_strtoff(range_end, dash, &errp, 10) - || *errp || *range_end < 0 || *range_end < *range_start) { + if (!ap_parse_strict_length(range_end, dash) + || *range_end < *range_start) { return -1; } if (*slash != '*') { apr_off_t dummy; - if (apr_strtoff(&dummy, slash, &errp, 10) - || *errp || dummy <= *range_end) { + if (!ap_parse_strict_length(&dummy, slash) + || dummy <= *range_end) { return -1; } } @@ -2538,20 +2536,13 @@ static int process_mkcol_body(request_rec *r) r->read_chunked = 1; } else if (lenp) { - const char *pos = lenp; - - while (apr_isdigit(*pos) || apr_isspace(*pos)) { - ++pos; - } - - if (*pos != '\0') { + if (!ap_parse_strict_length(&r->remaining, lenp)) { + r->remaining = 0; /* This supplies additional information for the default message. */ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00590) "Invalid Content-Length %s", lenp); return HTTP_BAD_REQUEST; } - - r->remaining = apr_atoi64(lenp); } if (r->read_chunked || r->remaining > 0) { diff --git a/modules/filters/mod_data.c b/modules/filters/mod_data.c index d083d32204..ddadd1b360 100644 --- a/modules/filters/mod_data.c +++ b/modules/filters/mod_data.c @@ -107,8 +107,8 @@ static apr_status_t data_out_filter(ap_filter_t *f, apr_bucket_brigade *bb) if (content_length) { apr_off_t len, clen; apr_brigade_length(ctx->bb, 1, &len); - clen = apr_atoi64(content_length); - if (clen >= 0 && clen < APR_INT32_MAX) { + if (ap_parse_strict_length(&clen, content_length) + && clen < APR_INT32_MAX) { ap_set_content_length(r, len + apr_base64_encode_len((int)clen) - 1); } diff --git a/modules/filters/mod_reflector.c b/modules/filters/mod_reflector.c index 961092d0ea..5979cb8f72 100644 --- a/modules/filters/mod_reflector.c +++ b/modules/filters/mod_reflector.c @@ -91,11 +91,16 @@ static int reflector_handler(request_rec * r) /* reflect the content length, if present */ if ((content_length = apr_table_get(r->headers_in, "Content-Length"))) { - apr_off_t offset; + apr_off_t clen; - apr_strtoff(&offset, content_length, NULL, 10); - ap_set_content_length(r, offset); + if (!ap_parse_strict_length(&clen, content_length)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10243) + "reflector_handler: invalid content-length '%s'", + content_length); + return HTTP_BAD_REQUEST; + } + ap_set_content_length(r, clen); } /* reflect the content type, if present */ diff --git a/modules/filters/mod_request.c b/modules/filters/mod_request.c index 21db7de36c..daa8e5977b 100644 --- a/modules/filters/mod_request.c +++ b/modules/filters/mod_request.c @@ -76,7 +76,6 @@ static apr_status_t keep_body_filter(ap_filter_t *f, apr_bucket_brigade *b, if (!ctx) { const char *lenp; - char *endstr = NULL; request_dir_conf *dconf = ap_get_module_config(f->r->per_dir_config, &request_module); @@ -93,13 +92,12 @@ static apr_status_t keep_body_filter(ap_filter_t *f, apr_bucket_brigade *b, if (lenp) { /* Protects against over/underflow, non-digit chars in the - * string (excluding leading space) (the endstr checks) - * and a negative number. */ - if (apr_strtoff(&ctx->remaining, lenp, &endstr, 10) - || endstr == lenp || *endstr || ctx->remaining < 0) { - + * string, leading plus/minus signs, trailing characters and + * a negative number. + */ + if (!ap_parse_strict_length(&ctx->remaining, lenp)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01411) - "Invalid Content-Length"); + "Invalid Content-Length '%s'", lenp); ap_remove_input_filter(f); return bail_out_on_error(b, f, HTTP_REQUEST_ENTITY_TOO_LARGE); diff --git a/modules/http/byterange_filter.c b/modules/http/byterange_filter.c index 5ed90aaa91..8c5a670c6c 100644 --- a/modules/http/byterange_filter.c +++ b/modules/http/byterange_filter.c @@ -137,7 +137,6 @@ static int ap_set_byterange(request_rec *r, apr_off_t clength, *indexes = apr_array_make(r->pool, ranges, sizeof(indexes_t)); while ((cur = ap_getword(r->pool, &range, ','))) { char *dash; - char *errp; apr_off_t number, start, end; if (!*cur) @@ -154,7 +153,7 @@ static int ap_set_byterange(request_rec *r, apr_off_t clength, if (dash == cur) { /* In the form "-5" */ - if (apr_strtoff(&number, dash+1, &errp, 10) || *errp) { + if (!ap_parse_strict_length(&number, dash+1)) { return 0; } if (number < 1) { @@ -165,12 +164,12 @@ static int ap_set_byterange(request_rec *r, apr_off_t clength, } else { *dash++ = '\0'; - if (apr_strtoff(&number, cur, &errp, 10) || *errp) { + if (!ap_parse_strict_length(&number, cur)) { return 0; } start = number; if (*dash) { - if (apr_strtoff(&number, dash, &errp, 10) || *errp) { + if (!ap_parse_strict_length(&number, dash)) { return 0; } end = number; diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c index 5bebe2c500..016bcf5e97 100644 --- a/modules/http/http_filters.c +++ b/modules/http/http_filters.c @@ -364,16 +364,13 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, lenp = NULL; } if (lenp) { - char *endstr; - ctx->state = BODY_LENGTH; /* Protects against over/underflow, non-digit chars in the - * string (excluding leading space) (the endstr checks) - * and a negative number. */ - if (apr_strtoff(&ctx->remaining, lenp, &endstr, 10) - || endstr == lenp || *endstr || ctx->remaining < 0) { - + * string, leading plus/minus signs, trailing characters and + * a negative number. + */ + if (!ap_parse_strict_length(&ctx->remaining, lenp)) { ctx->remaining = 0; ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(01587) "Invalid Content-Length"); @@ -1667,13 +1664,10 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) r->read_chunked = 1; } else if (lenp) { - char *endstr; - - if (apr_strtoff(&r->remaining, lenp, &endstr, 10) - || *endstr || r->remaining < 0) { + if (!ap_parse_strict_length(&r->remaining, lenp)) { r->remaining = 0; ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01594) - "Invalid Content-Length"); + "Invalid Content-Length '%s'", lenp); return HTTP_BAD_REQUEST; } } diff --git a/modules/mappers/mod_negotiation.c b/modules/mappers/mod_negotiation.c index dc0211487c..c056b28455 100644 --- a/modules/mappers/mod_negotiation.c +++ b/modules/mappers/mod_negotiation.c @@ -988,19 +988,17 @@ static int read_type_map(apr_file_t **map, negotiation_state *neg, has_content = 1; } else if (!strncmp(buffer, "content-length:", 15)) { - char *errp; - apr_off_t number; + apr_off_t clen; body1 = ap_get_token(neg->pool, &body, 0); - if (apr_strtoff(&number, body1, &errp, 10) != APR_SUCCESS - || *errp || number < 0) { + if (!ap_parse_strict_length(&clen, body1)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00684) "Parse error in type map, Content-Length: " "'%s' in %s is invalid.", body1, r->filename); break; } - mime_info.bytes = number; + mime_info.bytes = clen; has_content = 1; } else if (!strncmp(buffer, "content-language:", 17)) { diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index c0a44222c8..edbf1bcc94 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -1225,7 +1225,6 @@ static int proxy_handler(request_rec *r) /* Did the scheme handler process the request? */ if (access_status != DECLINED) { const char *cl_a; - char *end; apr_off_t cl; /* @@ -1235,18 +1234,17 @@ static int proxy_handler(request_rec *r) if (access_status != HTTP_BAD_GATEWAY) { goto cleanup; } + cl_a = apr_table_get(r->headers_in, "Content-Length"); - if (cl_a) { - apr_strtoff(&cl, cl_a, &end, 10); + if (cl_a && (!ap_parse_strict_length(&cl, cl_a) + || cl > 0)) { /* * The request body is of length > 0. We cannot * retry with a direct connection since we already * sent (parts of) the request body to the proxy * and do not have any longer. */ - if (cl > 0) { - goto cleanup; - } + goto cleanup; } /* * Transfer-Encoding was set as input header, so we had diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c index aa8bc94d7e..9ae0f437da 100644 --- a/modules/proxy/mod_proxy_ajp.c +++ b/modules/proxy/mod_proxy_ajp.c @@ -126,11 +126,8 @@ static apr_off_t get_content_length(request_rec * r) if (r->main == NULL) { const char *clp = apr_table_get(r->headers_in, "Content-Length"); - if (clp) { - char *errp; - if (apr_strtoff(&len, clp, &errp, 10) || *errp || len < 0) { - len = 0; /* parse error */ - } + if (clp && !ap_parse_strict_length(&len, clp)) { + len = -1; /* parse error */ } } @@ -253,10 +250,14 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, } else { /* Get client provided Content-Length header */ content_length = get_content_length(r); - status = ap_get_brigade(r->input_filters, input_brigade, - AP_MODE_READBYTES, APR_BLOCK_READ, - maxsize - AJP_HEADER_SZ); - + if (content_length < 0) { + status = APR_EINVAL; + } + else { + status = ap_get_brigade(r->input_filters, input_brigade, + AP_MODE_READBYTES, APR_BLOCK_READ, + maxsize - AJP_HEADER_SZ); + } if (status != APR_SUCCESS) { /* We had a failure: Close connection to backend */ conn->close = 1; diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index 739050d2e3..f2857439d2 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -804,9 +804,7 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req, } else if (req->old_cl_val) { if (r->input_filters == r->proto_input_filters) { - char *endstr; - status = apr_strtoff(&req->cl_val, req->old_cl_val, &endstr, 10); - if (status != APR_SUCCESS || *endstr || req->cl_val < 0) { + if (!ap_parse_strict_length(&req->cl_val, req->old_cl_val)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01085) "could not parse request Content-Length (%s)", req->old_cl_val); diff --git a/server/apreq_module_cgi.c b/server/apreq_module_cgi.c index 3b03c378e0..779115dd6e 100644 --- a/server/apreq_module_cgi.c +++ b/server/apreq_module_cgi.c @@ -24,6 +24,8 @@ #include "apr_env.h" #include "apreq_util.h" +#include "httpd.h" + #define USER_DATA_KEY "apreq" /* Parroting APLOG_* ... */ @@ -351,16 +353,15 @@ static void init_body(apreq_handle_t *handle) apr_bucket *eos, *pipe; if (cl_header != NULL) { - char *dummy; - apr_int64_t content_length = apr_strtoi64(cl_header, &dummy, 10); + apr_off_t content_length; - if (dummy == NULL || *dummy != 0) { + if (!ap_parse_strict_length(&content_length, cl_header)) { req->body_status = APREQ_ERROR_BADHEADER; cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, handle, "Invalid Content-Length header (%s)", cl_header); return; } - else if ((apr_uint64_t)content_length > req->read_limit) { + if ((apr_uint64_t)content_length > req->read_limit) { req->body_status = APREQ_ERROR_OVERLIMIT; cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, handle, "Content-Length header (%s) exceeds configured " diff --git a/server/util.c b/server/util.c index 7603895e02..59e273e911 100644 --- a/server/util.c +++ b/server/util.c @@ -2673,6 +2673,15 @@ AP_DECLARE(apr_status_t) ap_timeout_parameter_parse( return APR_SUCCESS; } +AP_DECLARE(int) ap_parse_strict_length(apr_off_t *len, const char *str) +{ + char *end; + + return (apr_isdigit(*str) + && apr_strtoff(len, str, &end, 10) == APR_SUCCESS + && *end == '\0'); +} + /** * Determine if a request has a request body or not. * @@ -2682,20 +2691,13 @@ AP_DECLARE(apr_status_t) ap_timeout_parameter_parse( AP_DECLARE(int) ap_request_has_body(request_rec *r) { apr_off_t cl; - char *estr; const char *cls; - int has_body; - - has_body = (!r->header_only - && (r->kept_body - || apr_table_get(r->headers_in, "Transfer-Encoding") - || ( (cls = apr_table_get(r->headers_in, "Content-Length")) - && (apr_strtoff(&cl, cls, &estr, 10) == APR_SUCCESS) - && (!*estr) - && (cl > 0) ) - ) - ); - return has_body; + + return (!r->header_only + && (r->kept_body + || apr_table_get(r->headers_in, "Transfer-Encoding") + || ((cls = apr_table_get(r->headers_in, "Content-Length")) + && ap_parse_strict_length(&cl, cls) && cl > 0))); } /** |