diff --git a/modules/dav/main/ms_wdv.c b/modules/dav/main/ms_wdv.c index cd9bb10cf53..96c220ddde0 100644 --- a/modules/dav/main/ms_wdv.c +++ b/modules/dav/main/ms_wdv.c @@ -91,7 +91,14 @@ static const char *mswdv_urlencode(request_rec *r, const char *str) char *output; char *op; - output = apr_palloc(r->pool, 3 * strlen(str) + 1); + apr_size_t slen = strlen(str); + if (slen > (APR_SIZE_MAX - 1) / 3) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "mswdv_urlencode: input length too large (%zu), rejecting to avoid allocation overflow", + (size_t)slen); + return ""; + } + output = apr_palloc(r->pool, 3 * slen + 1); op = output; for (ip = str; *ip; ip++) { diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index c89b2adc786..16858dfab1b 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -722,7 +722,14 @@ static char *escape_backref(apr_pool_t *p, const char *path, const char *escapeme, const char *noescapeme, int flags) { - char *copy = apr_palloc(p, 3 * strlen(path) + 1); + apr_size_t plen = strlen(path); + if (plen > (APR_SIZE_MAX - 1) / 3) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "escape_backref: input length too large (%zu), rejecting to avoid allocation overflow", + (size_t)plen); + return apr_pstrdup(p, ""); + } + char *copy = apr_palloc(p, 3 * plen + 1); const unsigned char *s = (const unsigned char *)path; unsigned char *d = (unsigned char *)copy; int noplus = (flags & RULEFLAG_ESCAPENOPLUS) != 0; diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c index d535d2415d4..e45d0b85170 100644 --- a/modules/proxy/mod_proxy_ftp.c +++ b/modules/proxy/mod_proxy_ftp.c @@ -147,7 +147,14 @@ static const char *ftp_escape_globbingchars(apr_pool_t *p, const char *path, pro return path; } - ret = apr_palloc(p, 2*strlen(path)+sizeof("")); + apr_size_t plen = strlen(path); + if (plen > (APR_SIZE_MAX - sizeof("")) / 2) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "ftp_escape_globbingchars: input length too large (%zu), rejecting to avoid allocation overflow", + (size_t)plen); + return apr_pstrdup(p, path); + } + ret = apr_palloc(p, 2 * plen + sizeof("")); for (d = ret; *path; ++path) { if (strchr(FTP_GLOBBING_CHARS, *path) != NULL) *d++ = '\\'; diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index a57c35ce0d2..01ffb0093fb 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -262,6 +262,12 @@ PROXY_DECLARE(char *)ap_proxy_canonenc_ex(apr_pool_t *p, const char *x, int len, reserved = ""; } + if (len > (APR_SIZE_MAX - 1) / 3) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "ap_proxy_canonenc_ex: input length too large (%d), rejecting to avoid allocation overflow", + len); + return NULL; + } y = apr_palloc(p, 3 * len + 1); for (i = 0, j = 0; i < len; i++, j++) { @@ -1093,7 +1099,54 @@ PROXY_DECLARE(const char *) ap_proxy_cookie_reverse_map(request_rec *r, } if (newpath) { - ret = apr_palloc(r->pool, len + pdiff + ddiff + 1); + /* Compute required size safely, checking for overflow/underflow. */ + apr_size_t need = (apr_size_t)len; + if (pdiff >= 0) { + if ((apr_size_t)pdiff > APR_SIZE_MAX - need) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "ap_proxy_cookie: pdiff too large, rejecting to avoid allocation overflow (len=%zu, pdiff=%d)", + (size_t)len, pdiff); + return NULL; + } + need += (apr_size_t)pdiff; + } + else { + apr_size_t neg = (apr_size_t)(-pdiff); + if (neg > need) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "ap_proxy_cookie: pdiff underflow, rejecting (len=%zu, pdiff=%d)", + (size_t)len, pdiff); + return NULL; + } + need -= neg; + } + if (ddiff >= 0) { + if ((apr_size_t)ddiff > APR_SIZE_MAX - need) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "ap_proxy_cookie: ddiff too large, rejecting to avoid allocation overflow (len=%zu, ddiff=%d)", + (size_t)len, ddiff); + return NULL; + } + need += (apr_size_t)ddiff; + } + else { + apr_size_t neg = (apr_size_t)(-ddiff); + if (neg > need) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "ap_proxy_cookie: ddiff underflow, rejecting (len=%zu, ddiff=%d)", + (size_t)len, ddiff); + return NULL; + } + need -= neg; + } + if (need > APR_SIZE_MAX - 1) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "ap_proxy_cookie: required allocation too large (need=%zu), rejecting", + (size_t)need); + return NULL; + } + need += 1; /* for trailing NUL */ + ret = apr_palloc(r->pool, need); l1 = strlen(newpath); if (newdomain) { l2 = strlen(newdomain); @@ -1119,7 +1172,35 @@ PROXY_DECLARE(const char *) ap_proxy_cookie_reverse_map(request_rec *r, } } else if (newdomain) { - ret = apr_palloc(r->pool, len + ddiff + 1); + /* Compute required size safely for len + ddiff + 1 */ + apr_size_t need = (apr_size_t)len; + if (ddiff >= 0) { + if ((apr_size_t)ddiff > APR_SIZE_MAX - need) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "ap_proxy_cookie: ddiff too large, rejecting to avoid allocation overflow (len=%zu, ddiff=%d)", + (size_t)len, ddiff); + return NULL; + } + need += (apr_size_t)ddiff; + } + else { + apr_size_t neg = (apr_size_t)(-ddiff); + if (neg > need) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "ap_proxy_cookie: ddiff underflow, rejecting (len=%zu, ddiff=%d)", + (size_t)len, ddiff); + return NULL; + } + need -= neg; + } + if (need > APR_SIZE_MAX - 1) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "ap_proxy_cookie: required allocation too large (need=%zu), rejecting", + (size_t)need); + return NULL; + } + need += 1; + ret = apr_palloc(r->pool, need); l2 = strlen(newdomain); memcpy(ret, str, doffs); memcpy(ret + doffs, newdomain, l2); diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c index 83344bf8600..173bbbcee35 100644 --- a/modules/ssl/ssl_engine_vars.c +++ b/modules/ssl/ssl_engine_vars.c @@ -1055,39 +1055,91 @@ static const char *ssl_var_lookup_ssl_clienthello(apr_pool_t *p, const SSLConnRe if (strEQ(var, "VERSION")) { return apr_psprintf(p, "%04x", (uint16_t) clienthello_vars->version); } - else if (strEQ(var, "CIPHERS") && (clienthello_vars->ciphers_len > 0)) { - value = apr_palloc(p, clienthello_vars->ciphers_len * 2 + 1); + if (strEQ(var, "CIPHERS") && (clienthello_vars->ciphers_len > 0)) { + apr_size_t n = clienthello_vars->ciphers_len; + if (n > (APR_SIZE_MAX - 1) / 2) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "ssl_var_lookup_ssl_clienthello: ciphers_len too large (%zu), rejecting to avoid allocation overflow", + (size_t)n); + return NULL; + } + value = apr_palloc(p, n * 2 + 1); ap_bin2hex(clienthello_vars->ciphers_data, clienthello_vars->ciphers_len, value); return value; } else if (strEQ(var, "EXTENSIONS") && (clienthello_vars->extids_len > 0)) { - value = apr_palloc(p, clienthello_vars->extids_len * 4 + 1); + apr_size_t n = clienthello_vars->extids_len; + if (n > (APR_SIZE_MAX - 1) / 4) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "ssl_var_lookup_ssl_clienthello: extids_len too large (%zu), rejecting to avoid allocation overflow", + (size_t)n); + return NULL; + } + value = apr_palloc(p, n * 4 + 1); for (i = 0; i < clienthello_vars->extids_len; i++) { apr_snprintf(value + i * 4, 5, "%04x", (uint16_t) clienthello_vars->extids_data[i]); } return value; } else if (strEQ(var, "GROUPS") && (clienthello_vars->ecgroups_len > 2)) { + apr_size_t n = clienthello_vars->ecgroups_len; + /* required = 2*n + 1 - 2 = 2*n - 1 */ + if (n > (APR_SIZE_MAX + 1) / 2) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "ssl_var_lookup_ssl_clienthello: ecgroups_len too large (%zu), rejecting to avoid allocation overflow", + (size_t)n); + return NULL; + } value = apr_palloc(p, clienthello_vars->ecgroups_len * 2 + 1 - 2); ap_bin2hex(clienthello_vars->ecgroups_data + 2, clienthello_vars->ecgroups_len - 2, value); return value; } else if (strEQ(var, "EC_FORMATS") && (clienthello_vars->ecformats_len > 1)) { + apr_size_t n = clienthello_vars->ecformats_len; + /* required = 2*n + 1 - 1 = 2*n */ + if (n > APR_SIZE_MAX / 2) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "ssl_var_lookup_ssl_clienthello: ecformats_len too large (%zu), rejecting to avoid allocation overflow", + (size_t)n); + return NULL; + } value = apr_palloc(p, clienthello_vars->ecformats_len * 2 + 1 - 1); ap_bin2hex(clienthello_vars->ecformats_data + 1, clienthello_vars->ecformats_len - 1, value); return value; } else if (strEQ(var, "SIG_ALGOS") && (clienthello_vars->sigalgos_len > 2)) { + apr_size_t n = clienthello_vars->sigalgos_len; + /* required = 2*n + 1 - 2 = 2*n -1 */ + if (n > (APR_SIZE_MAX + 1) / 2) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "ssl_var_lookup_ssl_clienthello: sigalgos_len too large (%zu), rejecting to avoid allocation overflow", + (size_t)n); + return NULL; + } value = apr_palloc(p, clienthello_vars->sigalgos_len * 2 + 1 - 2); ap_bin2hex(clienthello_vars->sigalgos_data + 2, clienthello_vars->sigalgos_len - 2, value); return value; } else if (strEQ(var, "ALPN") && (clienthello_vars->alpn_len > 2)) { + apr_size_t n = clienthello_vars->alpn_len; + if (n > (APR_SIZE_MAX + 1) / 2) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "ssl_var_lookup_ssl_clienthello: alpn_len too large (%zu), rejecting to avoid allocation overflow", + (size_t)n); + return NULL; + } value = apr_palloc(p, clienthello_vars->alpn_len * 2 + 1 - 2); ap_bin2hex(clienthello_vars->alpn_data + 2, clienthello_vars->alpn_len - 2, value); return value; } else if (strEQ(var, "VERSIONS") && (clienthello_vars->versions_len > 1)) { + apr_size_t n = clienthello_vars->versions_len; + if (n > APR_SIZE_MAX / 2) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "ssl_var_lookup_ssl_clienthello: versions_len too large (%zu), rejecting to avoid allocation overflow", + (size_t)n); + return NULL; + } value = apr_palloc(p, clienthello_vars->versions_len * 2 + 1 - 1); ap_bin2hex(clienthello_vars->versions_data + 1, clienthello_vars->versions_len - 1, value); return value; diff --git a/server/core.c b/server/core.c index 315d6b5bace..a1b9cb96675 100644 --- a/server/core.c +++ b/server/core.c @@ -148,6 +148,55 @@ AP_DECLARE_DATA int ap_main_state = AP_SQ_MS_INITIAL_STARTUP; AP_DECLARE_DATA int ap_run_mode = AP_SQ_RM_UNKNOWN; AP_DECLARE_DATA int ap_config_generation = 0; +/* Safe integer parsing with overflow detection. + * Replaces unsafe atoi() to prevent integer overflow attacks. + * Returns APR_SUCCESS if valid integer parsed, APR_EINVAL otherwise. + */ +static apr_status_t ap_parse_int(const char *str, int *result, int min_val, int max_val) +{ + char *endp; + long val; + apr_status_t status; + + if (!str || !result) { + return APR_EINVAL; + } + + /* Skip whitespace */ + while (apr_isspace(*str)) { + str++; + } + + if (*str == '\0') { + return APR_EINVAL; + } + + errno = 0; + val = strtol(str, &endp, 10); + status = errno; + + /* Check for conversion errors */ + if (status != 0) { + return status; /* ERANGE or other errno value */ + } + + /* Check that entire string was consumed (except trailing whitespace) */ + while (apr_isspace(*endp)) { + endp++; + } + if (*endp != '\0') { + return APR_EINVAL; /* Invalid characters in string */ + } + + /* Check range constraints */ + if (val < min_val || val > max_val) { + return APR_ERANGE; + } + + *result = (int)val; + return APR_SUCCESS; +} + typedef struct { apr_ipsubnet_t *subnet; struct ap_logconf log; @@ -1733,12 +1782,17 @@ static const char *set_error_document(cmd_parms *cmd, void *conf_, { core_dir_config *conf = conf_; int error_number, index_number, idx500; + apr_status_t status; enum { MSG, LOCAL_PATH, REMOTE_PATH } what = MSG; /* 1st parameter should be a 3 digit number, which we recognize; * convert it into an array index */ - error_number = atoi(errno_str); + status = ap_parse_int(errno_str, &error_number, 0, 599); + if (status != APR_SUCCESS) { + return apr_pstrcat(cmd->pool, "Invalid HTTP response code ", + errno_str, NULL); + } idx500 = ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR); if (error_number == HTTP_INTERNAL_SERVER_ERROR) { @@ -3256,11 +3310,12 @@ static const char *server_hostname_port(cmd_parms *cmd, void *dummy, const char portstr = ap_strchr_c(part, ':'); if (portstr) { + apr_status_t status; cmd->server->server_hostname = apr_pstrndup(cmd->pool, part, portstr - part); portstr++; - port = atoi(portstr); - if (port <= 0 || port >= 65536) { /* 65536 == 1<<16 */ + status = ap_parse_int(portstr, &port, 1, 65535); + if (status != APR_SUCCESS) { return apr_pstrcat(cmd->temp_pool, "The port number \"", arg, "\" is outside the appropriate range " "(i.e., 1..65535).", NULL); @@ -3353,12 +3408,19 @@ static const char *set_state_dir(cmd_parms *cmd, void *dummy, const char *arg) static const char *set_timeout(cmd_parms *cmd, void *dummy, const char *arg) { const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_CONTEXT); + int timeout_val; + apr_status_t status; if (err != NULL) { return err; } - cmd->server->timeout = apr_time_from_sec(atoi(arg)); + status = ap_parse_int(arg, &timeout_val, 1, 86400); /* Allow 1 sec to 1 day */ + if (status != APR_SUCCESS) { + return apr_pstrcat(cmd->temp_pool, "Timeout \"", arg, + "\" must be a positive integer (in seconds)", NULL); + } + cmd->server->timeout = apr_time_from_sec(timeout_val); return NULL; } @@ -3837,13 +3899,14 @@ static const char *set_limit_req_line(cmd_parms *cmd, void *dummy, { const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_CONTEXT); int lim; + apr_status_t status; if (err != NULL) { return err; } - lim = atoi(arg); - if (lim < 0) { + status = ap_parse_int(arg, &lim, 0, INT_MAX); + if (status != APR_SUCCESS) { return apr_pstrcat(cmd->temp_pool, "LimitRequestLine \"", arg, "\" must be a non-negative integer", NULL); } @@ -3857,13 +3920,14 @@ static const char *set_limit_req_fieldsize(cmd_parms *cmd, void *dummy, { const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_CONTEXT); int lim; + apr_status_t status; if (err != NULL) { return err; } - lim = atoi(arg); - if (lim < 0) { + status = ap_parse_int(arg, &lim, 0, INT_MAX); + if (status != APR_SUCCESS) { return apr_pstrcat(cmd->temp_pool, "LimitRequestFieldsize \"", arg, "\" must be a non-negative integer", NULL); @@ -3878,13 +3942,14 @@ static const char *set_limit_req_fields(cmd_parms *cmd, void *dummy, { const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_CONTEXT); int lim; + apr_status_t status; if (err != NULL) { return err; } - lim = atoi(arg); - if (lim < 0) { + status = ap_parse_int(arg, &lim, 0, INT_MAX); + if (status != APR_SUCCESS) { return apr_pstrcat(cmd->temp_pool, "LimitRequestFields \"", arg, "\" must be a non-negative integer (0 = no limit)", NULL); @@ -3931,6 +3996,7 @@ static const char *set_max_ranges(cmd_parms *cmd, void *conf_, const char *arg) { core_dir_config *conf = conf_; int val = 0; + apr_status_t status; if (!ap_cstr_casecmp(arg, "none")) { val = AP_MAXRANGES_NORANGES; @@ -3942,8 +4008,8 @@ static const char *set_max_ranges(cmd_parms *cmd, void *conf_, const char *arg) val = AP_MAXRANGES_UNLIMITED; } else { - val = atoi(arg); - if (val <= 0) + status = ap_parse_int(arg, &val, 1, INT_MAX); + if (status != APR_SUCCESS) return "MaxRanges requires 'none', 'default', 'unlimited' or " "a positive integer"; } @@ -3957,6 +4023,7 @@ static const char *set_max_overlaps(cmd_parms *cmd, void *conf_, const char *arg { core_dir_config *conf = conf_; int val = 0; + apr_status_t status; if (!ap_cstr_casecmp(arg, "none")) { val = AP_MAXRANGES_NORANGES; @@ -3968,8 +4035,8 @@ static const char *set_max_overlaps(cmd_parms *cmd, void *conf_, const char *arg val = AP_MAXRANGES_UNLIMITED; } else { - val = atoi(arg); - if (val <= 0) + status = ap_parse_int(arg, &val, 1, INT_MAX); + if (status != APR_SUCCESS) return "MaxRangeOverlaps requires 'none', 'default', 'unlimited' or " "a positive integer"; } @@ -3983,6 +4050,7 @@ static const char *set_max_reversals(cmd_parms *cmd, void *conf_, const char *ar { core_dir_config *conf = conf_; int val = 0; + apr_status_t status; if (!ap_cstr_casecmp(arg, "none")) { val = AP_MAXRANGES_NORANGES; @@ -3994,8 +4062,8 @@ static const char *set_max_reversals(cmd_parms *cmd, void *conf_, const char *ar val = AP_MAXRANGES_UNLIMITED; } else { - val = atoi(arg); - if (val <= 0) + status = ap_parse_int(arg, &val, 1, INT_MAX); + if (status != APR_SUCCESS) return "MaxRangeReversals requires 'none', 'default', 'unlimited' or " "a positive integer"; } @@ -4074,9 +4142,11 @@ static const char *set_recursion_limit(cmd_parms *cmd, void *dummy, { core_server_config *conf = ap_get_core_module_config(cmd->server->module_config); - int limit = atoi(arg1); + int limit; + apr_status_t status; - if (limit <= 0) { + status = ap_parse_int(arg1, &limit, 1, INT_MAX); + if (status != APR_SUCCESS) { return "The recursion limit must be greater than zero."; } if (limit < 4) { @@ -4088,9 +4158,8 @@ static const char *set_recursion_limit(cmd_parms *cmd, void *dummy, conf->redirect_limit = limit; if (arg2) { - limit = atoi(arg2); - - if (limit <= 0) { + status = ap_parse_int(arg2, &limit, 1, INT_MAX); + if (status != APR_SUCCESS) { return "The recursion limit must be greater than zero."; } if (limit < 4) { diff --git a/server/util.c b/server/util.c index d1d06fc15b4..49626633268 100644 --- a/server/util.c +++ b/server/util.c @@ -1818,7 +1818,14 @@ AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str) const unsigned char *s; apr_size_t len = strlen(str); - ap_assert(len <= (APR_SIZE_MAX - 1) / 2); + if (len > (APR_SIZE_MAX - 1) / 2) { + /* Prevent allocation overflow: log and return an empty string to + * preserve the non-NULL contract for callers. */ + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "ap_escape_shell_cmd: input length too large (%zu), rejecting to avoid allocation overflow", + (size_t)len); + return apr_pstrdup(p, ""); + } cmd = apr_palloc(p, 2 * len + 1); d = (unsigned char *)cmd; s = (const unsigned char *)str; @@ -2076,7 +2083,13 @@ AP_DECLARE(char *) ap_escape_path_segment_buffer(char *copy, const char *segment AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment) { apr_size_t len = strlen(segment); - ap_assert(len <= (APR_SIZE_MAX - 1) / 3); + if (len > (APR_SIZE_MAX - 1) / 3) { + /* Prevent allocation overflow: log and return empty string. */ + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "ap_escape_path_segment: input length too large (%zu), rejecting to avoid allocation overflow", + (size_t)len); + return apr_pstrdup(p, ""); + } return ap_escape_path_segment_buffer(apr_palloc(p, 3 * len + 1), segment); } @@ -2092,7 +2105,13 @@ AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partia unsigned char *d; unsigned c; - ap_assert(len <= (APR_SIZE_MAX - 4) / 3); + if (len > (APR_SIZE_MAX - 4) / 3) { + /* Prevent allocation overflow: log and return empty string. */ + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "ap_os_escape_path: input length too large (%zu), rejecting to avoid allocation overflow", + (size_t)len); + return apr_pstrdup(p, ""); + } copy = apr_palloc(p, 3 * len + 3 + 1); s = (const unsigned char *)path; d = (unsigned char *)copy; @@ -2144,7 +2163,13 @@ AP_DECLARE(char *) ap_escape_urlencoded_buffer(char *copy, const char *buffer) AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer) { apr_size_t len = strlen(buffer); - ap_assert(len <= (APR_SIZE_MAX - 1) / 3); + if (len > (APR_SIZE_MAX - 1) / 3) { + /* Prevent allocation overflow: log and return empty string. */ + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "ap_escape_urlencoded: input length too large (%zu), rejecting to avoid allocation overflow", + (size_t)len); + return apr_pstrdup(p, ""); + } return ap_escape_urlencoded_buffer(apr_palloc(p, 3 * len + 1), buffer); } @@ -2158,7 +2183,13 @@ AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc) /* first, count the number of extra characters */ for (i = 0, j = 0; s[i] != '\0'; i++) { if (i + j > APR_SIZE_MAX - 6) { - abort(); + /* Input too large to safely escape. Log and return an empty + * allocated string to preserve the non-NULL contract and avoid + * providing truncated output which might be misleading. */ + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "ap_escape_html2: input too large to escape safely (processed=%zu, extra=%zu)", + (size_t)i, (size_t)j); + return apr_pstrdup(p, ""); } if (s[i] == '<' || s[i] == '>') j += 3; @@ -2230,6 +2261,12 @@ AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str) } /* Each escaped character needs up to 3 extra bytes (0 --> \x00) */ + if (escapes > (APR_SIZE_MAX - length) / 3) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + "ap_escape_logitem: input too large (length=%zu, escapes=%zu), rejecting to avoid allocation overflow", + (size_t)length, (size_t)escapes); + return apr_pstrdup(p, ""); + } ret = apr_palloc(p, length + 3 * escapes); d = (unsigned char *)ret; s = (const unsigned char *)str; @@ -2373,9 +2410,15 @@ AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1, len1 = strlen(src1); len2 = strlen(src2); - /* allocate +3 for '/' delimiter, trailing NULL and overallocate - * one extra byte to allow the caller to add a trailing '/' - */ + /* allocate +3 for '/' delimiter, trailing NULL and overallocate + * one extra byte to allow the caller to add a trailing '/' + */ + if (len1 > APR_SIZE_MAX - len2 - 3) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, a, + "ap_make_full_path: combined path lengths too large (len1=%zu, len2=%zu), rejecting to avoid allocation overflow", + (size_t)len1, (size_t)len2); + return apr_pstrdup(a, ""); + } path = (char *)apr_palloc(a, len1 + len2 + 3); if (len1 == 0) { *path = '/';