Changes with Apache 2.0.48
+ *) SECURITY: CAN-2003-0542 (cve.mitre.org)
+ Fix buffer overflows in mod_alias and mod_rewrite which occurred if
+ one configured a regular expression with more than 9 captures.
+ [André Malo]
+
*) mod_include: fix segfault which occured if the filename was not
set, for example, when processing some error conditions.
PR 23836. [Brian Akins <bakins@web.turner.com>, André Malo]
/** The size of the server's internal read-write buffers */
#define AP_IOBUFSIZE 8192
+/** The max number of regex captures that can be expanded by ap_pregsub */
+#define AP_MAX_REG_MATCH 10
+
/**
* APR_HAS_LARGE_FILES introduces the problem of spliting sendfile into
* mutiple buckets, no greater than MAX(apr_size_t), and more granular
apr_size_t value_len;
} arg_item_t;
-#define MAX_NMATCH 10
-
typedef struct {
const char *source;
const char *rexp;
apr_size_t nsub;
- regmatch_t match[MAX_NMATCH];
+ regmatch_t match[AP_MAX_REG_MATCH];
} backref_t;
typedef struct {
return NULL;
}
else {
- if (re->nsub < idx) {
+ if (re->nsub < idx || idx >= AP_MAX_REG_MATCH) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
"regex capture $%" APR_SIZE_T_FMT
" is out of range (last regex was: '%s') in %s",
re->source = apr_pstrdup(ctx->pool, string);
re->rexp = apr_pstrdup(ctx->pool, rexp);
re->nsub = compiled->re_nsub;
- rc = !ap_regexec(compiled, string, MAX_NMATCH, re->match, 0);
+ rc = !ap_regexec(compiled, string, AP_MAX_REG_MATCH, re->match, 0);
ap_pregfree(ctx->dpool, compiled);
return rc;
int doesc, int *status)
{
alias_entry *entries = (alias_entry *) aliases->elts;
- regmatch_t regm[10];
+ regmatch_t regm[AP_MAX_REG_MATCH];
char *found = NULL;
int i;
int l;
if (p->regexp) {
- if (!ap_regexec(p->regexp, r->uri, p->regexp->re_nsub + 1, regm,
- 0)) {
+ if (!ap_regexec(p->regexp, r->uri, AP_MAX_REG_MATCH, regm, 0)) {
if (p->real) {
found = ap_pregsub(r->pool, p->real, r->uri,
- p->regexp->re_nsub + 1, regm);
+ AP_MAX_REG_MATCH, regm);
if (found && doesc) {
apr_uri_t uri;
apr_uri_parse(r->pool, found, &uri);
/* XXX: not used at all. We should do a check somewhere and/or cut the cookie */
#define MAX_COOKIE_LEN 4096
-/* max number of regex captures */
-#define MAX_NMATCH 10
-
/* default maximum number of internal redirects */
#define REWRITE_REDIRECT_LIMIT 10
typedef struct backrefinfo {
char *source;
int nsub;
- regmatch_t regmatch[10];
+ regmatch_t regmatch[AP_MAX_REG_MATCH];
} backrefinfo;
/* single linked list used for
backrefinfo *bri = (*p == '$') ? &ctx->briRR : &ctx->briRC;
/* see ap_pregsub() in server/util.c */
- if (bri->source && n <= bri->nsub
+ if (bri->source && n < AP_MAX_REG_MATCH
&& bri->regmatch[n].rm_eo > bri->regmatch[n].rm_so) {
span = bri->regmatch[n].rm_eo - bri->regmatch[n].rm_so;
char *input = do_expand(p->input, ctx);
apr_finfo_t sb;
request_rec *rsub, *r = ctx->r;
- regmatch_t regmatch[MAX_NMATCH];
+ regmatch_t regmatch[AP_MAX_REG_MATCH];
int rc = 0;
switch (p->ptype) {
default:
/* it is really a regexp pattern, so apply it */
- rc = !ap_regexec(p->regexp, input, p->regexp->re_nsub+1, regmatch, 0);
+ rc = !ap_regexec(p->regexp, input, AP_MAX_REG_MATCH, regmatch, 0);
/* update briRC backref info */
if (rc && !(p->flags & CONDFLAG_NOTMATCH)) {
*/
static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
{
- regmatch_t regmatch[MAX_NMATCH];
+ regmatch_t regmatch[AP_MAX_REG_MATCH];
apr_array_header_t *rewriteconds;
rewritecond_entry *conds;
int i, rc;
rewritelog((r, 3, ctx->perdir, "applying pattern '%s' to uri '%s'",
p->pattern, ctx->uri));
- rc = !ap_regexec(p->regexp, ctx->uri, p->regexp->re_nsub+1, regmatch, 0);
+ rc = !ap_regexec(p->regexp, ctx->uri, AP_MAX_REG_MATCH, regmatch, 0);
if (! (( rc && !(p->flags & RULEFLAG_NOTMATCH)) ||
(!rc && (p->flags & RULEFLAG_NOTMATCH)) ) ) {
return 0;
apr_size_t val_len = 0;
int i, j;
char *last_name;
- regmatch_t regm[10];
+ regmatch_t regm[AP_MAX_REG_MATCH];
if (!ap_get_module_config(r->request_config, &setenvif_module)) {
ap_set_module_config(r->request_config, &setenvif_module,
}
if ((b->pattern && apr_strmatch(b->pattern, val, val_len)) ||
- (!b->pattern && !ap_regexec(b->preg, val, b->preg->re_nsub + 1,
- regm, 0))) {
+ (!b->pattern && !ap_regexec(b->preg, val, AP_MAX_REG_MATCH, regm,
+ 0))) {
const apr_array_header_t *arr = apr_table_elts(b->features);
elts = (const apr_table_entry_t *) arr->elts;
else {
if (!b->pattern) {
char *replaced = ap_pregsub(r->pool, elts[j].val, val,
- b->preg->re_nsub + 1, regm);
+ AP_MAX_REG_MATCH, regm);
if (replaced) {
apr_table_setn(r->subprocess_env, elts[j].key,
replaced);
} state;
} proxy_dir_ctx_t;
+/* fallback regex for ls -s1; ($0..$2) == 3 */
+#define LS_REG_PATTERN "^ *([0-9]+) +([^ ]+)$"
+#define LS_REG_MATCH 3
+
apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *in)
{
request_rec *r = f->r;
int eos = 0;
regex_t *re = NULL;
- regmatch_t re_result[3];
+ regmatch_t re_result[LS_REG_MATCH];
/* Compile the output format of "ls -s1" as a fallback for non-unix ftp listings */
- re = ap_pregcomp(p, "^ *([0-9]+) +([^ ]+)$", REG_EXTENDED);
+ re = ap_pregcomp(p, LS_REG_PATTERN, REG_EXTENDED);
/* get a complete line */
/* if the buffer overruns - throw data away */
}
}
/* Try a fallback for listings in the format of "ls -s1" */
- else if (0 == ap_regexec(re, ctx->buffer, 3, re_result, 0)) {
+ else if (0 == ap_regexec(re, ctx->buffer, LS_REG_MATCH, re_result, 0)) {
filename = apr_pstrndup(p, &ctx->buffer[re_result[2].rm_so], re_result[2].rm_eo - re_result[2].rm_so);