Author: joes
Date: Tue Mar 15 06:46:10 2005
New Revision: 157544
URL: http://svn.apache.org/viewcvs?view=rev&rev=157544
Log:
Protect against the possibility of apache2_body_get
going quadratic on a "single-character-brigade" attack
against ap_http_filter. apreq_hook_find_param ensures
the prefetch behavior is always (at worst) O(n).
Modified:
httpd/apreq/branches/multi-env-unstable/include/apreq_parser.h
httpd/apreq/branches/multi-env-unstable/library/parser.c
httpd/apreq/branches/multi-env-unstable/module/apache2/apreq_private_apache2.h
httpd/apreq/branches/multi-env-unstable/module/apache2/handle.c
Modified: httpd/apreq/branches/multi-env-unstable/include/apreq_parser.h
URL:
http://svn.apache.org/viewcvs/httpd/apreq/branches/multi-env-unstable/include/apreq_parser.h?view=diff&r1=157543&r2=157544
==============================================================================
--- httpd/apreq/branches/multi-env-unstable/include/apreq_parser.h (original)
+++ httpd/apreq/branches/multi-env-unstable/include/apreq_parser.h Tue Mar 15
06:46:10 2005
@@ -266,6 +266,19 @@
*/
APREQ_DECLARE_HOOK(apreq_hook_discard_brigade);
+/**
+ * Special purpose utility for locating a parameter
+ * during parsing. The hook's ctx shoud be initialized
+ * to a const char *, which is a pointer to the desired
+ * param name. The hook's ctx will be reassigned to the
+ * first param found.
+ *
+ * @remarks When used, this should always be the first hook
+ * invoked, so add it manually as parser->hook instead of
+ * using apreq_parser_add_hook.
+ */
+APREQ_DECLARE_HOOK(apreq_hook_find_param);
+
#ifdef __cplusplus
}
Modified: httpd/apreq/branches/multi-env-unstable/library/parser.c
URL:
http://svn.apache.org/viewcvs/httpd/apreq/branches/multi-env-unstable/library/parser.c?view=diff&r1=157543&r2=157544
==============================================================================
--- httpd/apreq/branches/multi-env-unstable/library/parser.c (original)
+++ httpd/apreq/branches/multi-env-unstable/library/parser.c Tue Mar 15
06:46:10 2005
@@ -333,3 +333,15 @@
return APR_SUCCESS;
}
+APREQ_DECLARE_HOOK(apreq_hook_find_param)
+{
+ const char *key = hook->ctx;
+ int is_final = (bb == NULL) || APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb));
+ apr_status_t s = (hook->next == NULL)
+ ? APR_SUCCESS : apreq_hook_run(hook->next, param, bb);
+
+ if (is_final && strcasecmp(key, param->v.name) == 0)
+ hook->ctx = param;
+
+ return s;
+}
Modified:
httpd/apreq/branches/multi-env-unstable/module/apache2/apreq_private_apache2.h
URL:
http://svn.apache.org/viewcvs/httpd/apreq/branches/multi-env-unstable/module/apache2/apreq_private_apache2.h?view=diff&r1=157543&r2=157544
==============================================================================
---
httpd/apreq/branches/multi-env-unstable/module/apache2/apreq_private_apache2.h
(original)
+++
httpd/apreq/branches/multi-env-unstable/module/apache2/apreq_private_apache2.h
Tue Mar 15 06:46:10 2005
@@ -23,6 +23,7 @@
apr_bucket_brigade *spool; /* copied prefetch data for downstream filters
*/
apreq_parser_t *parser;
apreq_hook_t *hook_queue;
+ apreq_hook_t *find_param;
apr_table_t *body;
apr_status_t body_status;
apr_status_t filter_error;
Modified: httpd/apreq/branches/multi-env-unstable/module/apache2/handle.c
URL:
http://svn.apache.org/viewcvs/httpd/apreq/branches/multi-env-unstable/module/apache2/handle.c?view=diff&r1=157543&r2=157544
==============================================================================
--- httpd/apreq/branches/multi-env-unstable/module/apache2/handle.c (original)
+++ httpd/apreq/branches/multi-env-unstable/module/apache2/handle.c Tue Mar 15
06:46:10 2005
@@ -179,6 +179,7 @@
ap_filter_t *f = get_apreq_filter(env);
struct filter_ctx *ctx;
const char *val;
+ apreq_hook_t *h;
if (f->ctx == NULL)
apreq_filter_make_context(f);
@@ -194,35 +195,57 @@
return NULL;
apreq_filter_prefetch(f, APREQ_DEFAULT_READ_BLOCK_SIZE);
+
case APR_INCOMPLETE:
val = apr_table_get(ctx->body, name);
if (val != NULL)
return apreq_value_to_param(val);
+ /* Not seen yet, so we need to scan for
+ param while prefetching the body */
+
+ if (ctx->find_param == NULL)
+ ctx->find_param = apreq_hook_make(f->r->pool,
+ apreq_hook_find_param,
+ NULL, NULL);
+ h = ctx->find_param;
+ h->next = ctx->parser->hook;
+ ctx->parser->hook = h;
+ *(const char **)&h->ctx = name;
+
do {
- /* riff on Duff's device */
apreq_filter_prefetch(f, APREQ_DEFAULT_READ_BLOCK_SIZE);
+ if (h->ctx != name) {
+ ctx->parser->hook = h->next;
+ return h->ctx;
+ }
+ } while (ctx->body_status == APR_INCOMPLETE);
- case APR_SUCCESS:
+ ctx->parser->hook = h->next;
+ return NULL;
- val = apr_table_get(ctx->body, name);
- if (val != NULL)
- return apreq_value_to_param(val);
- } while (ctx->body_status == APR_INCOMPLETE);
+ case APR_SUCCESS:
- break;
+ val = apr_table_get(ctx->body, name);
+ if (val != NULL)
+ return apreq_value_to_param(val);
+ return NULL;
default:
- if (ctx->body != NULL) {
- val = apr_table_get(ctx->body, name);
- if (val != NULL)
- return apreq_value_to_param(val);
- }
+ if (ctx->body == NULL)
+ return NULL;
+
+ val = apr_table_get(ctx->body, name);
+ if (val != NULL)
+ return apreq_value_to_param(val);
+ return NULL;
+
}
+ /* not reached */
return NULL;
}