Skip to content

Commit

Permalink
apache2/mod_proxy_uwsgi: stricter backend HTTP response parsing/valid…
Browse files Browse the repository at this point in the history
…ation

HTTP Response Smuggling vulnerability in Apache HTTP Server via mod_proxy_uwsgi.
Special characters in the origin response header can truncate/split the response forwarded to the client.

Fix #2538

origin: https://github.com/apache/httpd/commit/d753ea76b5972a85349b68c31b59d04c60014f2d.patch
bug-cve: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-27522
  • Loading branch information
covener authored and xrmx committed Jul 25, 2023
1 parent 91e244f commit 58ee1df
Showing 1 changed file with 35 additions and 13 deletions.
48 changes: 35 additions & 13 deletions apache2/mod_proxy_uwsgi.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,27 +301,25 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
apr_bucket_brigade *pass_bb = apr_brigade_create(r->pool, c->bucket_alloc);

len = ap_getline(buffer, sizeof(buffer), rp, 1);

if (len <= 0) {
// oops
/* invalid or empty */
return HTTP_INTERNAL_SERVER_ERROR;
}

backend->worker->s->read += len;

if (len >= sizeof(buffer)-1) {
// oops
if ((apr_size_t)len >= sizeof(buffer)) {
/* too long */
return HTTP_INTERNAL_SERVER_ERROR;
}

/* Position of http status code */
int status_start;
if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
status_start = 9;
} else if (apr_date_checkmask(buffer, "HTTP/# ###*")) {
status_start = 7;
} else {
// oops
return HTTP_INTERNAL_SERVER_ERROR;
/* not HTTP */
return HTTP_BAD_GATEWAY;
}
int status_end = status_start + 3;

Expand All @@ -340,17 +338,41 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
}
r->status_line = apr_pstrdup(r->pool, &buffer[status_start]);

// start parsing headers;
/* parse headers */
while ((len = ap_getline(buffer, sizeof(buffer), rp, 1)) > 0) {
if ((apr_size_t)len >= sizeof(buffer)) {
/* too long */
len = -1;
break;
}
value = strchr(buffer, ':');
// invalid header skip
if (!value) continue;
*value = '\0';
++value;
if (!value) {
/* invalid header */
len = -1;
break;
}
*value++ = '\0';
if (*ap_scan_http_token(buffer)) {
/* invalid name */
len = -1;
break;
}
while (apr_isspace(*value)) ++value;
for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end) *end = '\0';
if (*ap_scan_http_field_content(value)) {
/* invalid value */
len = -1;
break;
}
apr_table_add(r->headers_out, buffer, value);
}
if (len < 0) {
/* Reset headers, but not to NULL because things below the chain expect
* this to be non NULL e.g. the ap_content_length_filter.
*/
r->headers_out = apr_table_make(r->pool, 1);
return HTTP_BAD_GATEWAY;
}

if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
ap_set_content_type(r, apr_pstrdup(r->pool, buf));
Expand Down

0 comments on commit 58ee1df

Please sign in to comment.