From 70285cc6a1514d0a638bcc33112d8d76f1b7399a Mon Sep 17 00:00:00 2001 From: Andre Malo Date: Sat, 1 Mar 2003 18:35:50 +0000 Subject: [PATCH] Prevent endless loops of internal redirects in mod_rewrite by aborting after exceeding a limit of internal redirects. The limit defaults to 10 and can be changed using the RewriteOptions directive with the new MaxRedirects=n argument. (The latter required some restructuring of the RewriteOptions evaluation code). (Documentation patch follows asap) PR: 17462 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@98863 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 7 +- modules/mappers/mod_rewrite.c | 127 ++++++++++++++++++++++++++++------ modules/mappers/mod_rewrite.h | 15 +++- 3 files changed, 125 insertions(+), 24 deletions(-) diff --git a/CHANGES b/CHANGES index 636a780066..559c078738 100644 --- a/CHANGES +++ b/CHANGES @@ -2,12 +2,17 @@ Changes with Apache 2.1.0-dev [Remove entries to the current 2.0 section below, when backported] + *) Prevent endless loops of internal redirects in mod_rewrite by + aborting after exceeding a limit of internal redirects. The + limit defaults to 10 and can be changed using the RewriteOptions + directive. PR 17462. [André Malo] + *) mod_rewrite: Fix some problems reporting errors with mapping programs (RewriteMap prg:/something). [Jeff Trawick] *) Win32: Avoid busy wait (consuming all the CPU idle cycles) when all worker threads are busy. - [Igor Nazarenko ] + [Igor Nazarenko ] *) When using Redirect in directory context, append requested query string if there's no one supplied by configuration. PR 10961. diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index 2d38bccdd2..a5b8fdc7ef 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -206,6 +206,7 @@ static void *config_server_create(apr_pool_t *p, server_rec *s) a->rewriteconds = apr_array_make(p, 2, sizeof(rewritecond_entry)); a->rewriterules = apr_array_make(p, 2, sizeof(rewriterule_entry)); a->server = s; + a->redirect_limit = 0; /* unset (use default) */ return (void *)a; } @@ -222,6 +223,9 @@ static void *config_server_merge(apr_pool_t *p, void *basev, void *overridesv) a->state = overrides->state; a->options = overrides->options; a->server = overrides->server; + a->redirect_limit = overrides->redirect_limit + ? overrides->redirect_limit + : base->redirect_limit; if (a->options & OPTION_INHERIT) { /* @@ -278,6 +282,7 @@ static void *config_perdir_create(apr_pool_t *p, char *path) a->baseurl = NULL; a->rewriteconds = apr_array_make(p, 2, sizeof(rewritecond_entry)); a->rewriterules = apr_array_make(p, 2, sizeof(rewriterule_entry)); + a->redirect_limit = 0; /* unset (use server config) */ if (path == NULL) { a->directory = NULL; @@ -308,6 +313,9 @@ static void *config_perdir_merge(apr_pool_t *p, void *basev, void *overridesv) a->options = overrides->options; a->directory = overrides->directory; a->baseurl = overrides->baseurl; + a->redirect_limit = overrides->redirect_limit + ? overrides->redirect_limit + : base->redirect_limit; if (a->options & OPTION_INHERIT) { a->rewriteconds = apr_array_append(p, overrides->rewriteconds, @@ -351,34 +359,48 @@ static const char *cmd_rewriteengine(cmd_parms *cmd, static const char *cmd_rewriteoptions(cmd_parms *cmd, void *in_dconf, const char *option) { - rewrite_perdir_conf *dconf = in_dconf; - rewrite_server_conf *sconf; - const char *err; + int options = 0, limit = 0; + char *w; - sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module); + while (*option) { + w = ap_getword_conf(cmd->pool, &option); - if (cmd->path == NULL) { /* is server command */ - err = cmd_rewriteoptions_setoption(cmd->pool, - &(sconf->options), option); - } - else { /* is per-directory command */ - err = cmd_rewriteoptions_setoption(cmd->pool, - &(dconf->options), option); + if (!strcasecmp(w, "inherit")) { + options |= OPTION_INHERIT; + } + else if (!strncasecmp(w, "MaxRedirects=", 13)) { + limit = atoi(&w[13]); + if (limit <= 0) { + return "RewriteOptions: MaxRedirects takes a number greater " + "than zero."; + } + } + else if (!strcasecmp(w, "MaxRedirects")) { /* be nice */ + return "RewriteOptions: MaxRedirects has the format MaxRedirects" + "=n."; + } + else { + return apr_pstrcat(cmd->pool, "RewriteOptions: unknown option '", + w, "'", NULL); + } } - return err; -} + /* put it into the appropriate config */ + if (cmd->path == NULL) { /* is server command */ + rewrite_server_conf *conf = + ap_get_module_config(cmd->server->module_config, + &rewrite_module); -static const char *cmd_rewriteoptions_setoption(apr_pool_t *p, int *options, - const char *name) -{ - if (strcasecmp(name, "inherit") == 0) { - *options |= OPTION_INHERIT; + conf->options |= options; + conf->redirect_limit = limit; } - else { - return apr_pstrcat(p, "RewriteOptions: unknown option '", - name, "'", NULL); + else { /* is per-directory command */ + rewrite_perdir_conf *conf = in_dconf; + + conf->options |= options; + conf->redirect_limit = limit; } + return NULL; } @@ -1656,6 +1678,15 @@ static int handler_redirect(request_rec *r) return DECLINED; } + if (is_redirect_limit_exceeded(r)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "mod_rewrite: maximum number of internal redirects " + "reached. Assuming configuration error. Use " + "'RewriteOptions MaxRedirects' to increase the limit " + "if neccessary."); + return HTTP_INTERNAL_SERVER_ERROR; + } + /* now do the internal redirect */ ap_internal_redirect(apr_pstrcat(r->pool, r->filename+9, r->args ? "?" : NULL, r->args, NULL), r); @@ -1664,6 +1695,60 @@ static int handler_redirect(request_rec *r) return OK; } +/* + * check whether redirect limit is reached + */ +static int is_redirect_limit_exceeded(request_rec *r) +{ + request_rec *top = r; + rewrite_request_conf *reqc; + rewrite_perdir_conf *dconf; + + /* we store it in the top request */ + while (top->main) { + top = top->main; + } + while (top->prev) { + top = top->prev; + } + + /* fetch our config */ + reqc = (rewrite_request_conf *) ap_get_module_config(top->request_config, + &rewrite_module); + + /* no config there? create one. */ + if (!reqc) { + rewrite_server_conf *sconf; + + reqc = apr_palloc(top->pool, sizeof(rewrite_request_conf)); + sconf = ap_get_module_config(r->server->module_config, &rewrite_module); + + reqc->redirects = 0; + reqc->redirect_limit = sconf->redirect_limit + ? sconf->redirect_limit + : REWRITE_REDIRECT_LIMIT; + + /* associate it with this request */ + ap_set_module_config(top->request_config, &rewrite_module, reqc); + } + + /* allow to change the limit during redirects. */ + dconf = (rewrite_perdir_conf *)ap_get_module_config(r->per_dir_config, + &rewrite_module); + + /* 0 == unset; take server conf ... */ + if (dconf->redirect_limit) { + reqc->redirect_limit = dconf->redirect_limit; + } + + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "mod_rewrite's internal redirect status: %d/%d.", + reqc->redirects, reqc->redirect_limit); + + /* and now give the caller a hint */ + return (reqc->redirects++ >= reqc->redirect_limit); +} + /* ** +-------------------------------------------------------+ diff --git a/modules/mappers/mod_rewrite.h b/modules/mappers/mod_rewrite.h index 5a4b904354..2a46b6199b 100644 --- a/modules/mappers/mod_rewrite.h +++ b/modules/mappers/mod_rewrite.h @@ -212,6 +212,8 @@ #define MAX_NMATCH 10 +/* default maximum number of internal redirects */ +#define REWRITE_REDIRECT_LIMIT 10 /* @@ -271,6 +273,7 @@ typedef struct { apr_array_header_t *rewriteconds; /* the RewriteCond entries (temporary) */ apr_array_header_t *rewriterules; /* the RewriteRule entries */ server_rec *server; /* the corresponding server indicator */ + int redirect_limit; /* maximum number of internal redirects */ } rewrite_server_conf; @@ -284,9 +287,18 @@ typedef struct { apr_array_header_t *rewriterules; /* the RewriteRule entries */ char *directory; /* the directory where it applies */ const char *baseurl; /* the base-URL where it applies */ + int redirect_limit; /* maximum number of internal redirects */ } rewrite_perdir_conf; + /* the per-request configuration + */ +typedef struct { + int redirects; /* current number of redirects */ + int redirect_limit; /* maximum number of redirects */ +} rewrite_request_conf; + + /* the cache structures, * a 4-way hash apr_table_t with LRU functionality */ @@ -343,8 +355,6 @@ static const char *cmd_rewriteengine(cmd_parms *cmd, static const char *cmd_rewriteoptions(cmd_parms *cmd, void *dconf, const char *option); -static const char *cmd_rewriteoptions_setoption(apr_pool_t *p, int *options, - const char *name); static const char *cmd_rewritelog (cmd_parms *cmd, void *dconf, const char *a1); static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, const char *a1); static const char *cmd_rewritemap (cmd_parms *cmd, void *dconf, @@ -467,6 +477,7 @@ static int prefix_stat(const char *path, apr_pool_t *pool); static void add_env_variable(request_rec *r, char *s); static void add_cookie(request_rec *r, char *s); static int subreq_ok(request_rec *r); +static int is_redirect_limit_exceeded(request_rec *r); /* Lexicographic Comparison */ static int compare_lexicography(char *cpNum1, char *cpNum2); -- 2.40.0