File httpd-2.2.x-CVE-2011-3368-server_protocl_c.diff of Package apache2.import5347
diff -rNU 50 ../httpd-2.2.15-o/server/protocol.c ./server/protocol.c
--- ../httpd-2.2.15-o/server/protocol.c 2011-10-26 15:50:45.000000000 +0200
+++ ./server/protocol.c 2011-10-26 15:50:54.000000000 +0200
@@ -590,100 +590,125 @@
apr_status_t rv;
/* insure ap_rgetline allocates memory each time thru the loop
* if there are empty lines
*/
r->the_request = NULL;
rv = ap_rgetline(&(r->the_request), (apr_size_t)(r->server->limit_req_line + 2),
&len, r, 0, bb);
if (rv != APR_SUCCESS) {
r->request_time = apr_time_now();
/* ap_rgetline returns APR_ENOSPC if it fills up the
* buffer before finding the end-of-line. This is only going to
* happen if it exceeds the configured limit for a request-line.
*/
if (rv == APR_ENOSPC) {
r->status = HTTP_REQUEST_URI_TOO_LARGE;
r->proto_num = HTTP_VERSION(1,0);
r->protocol = apr_pstrdup(r->pool, "HTTP/1.0");
}
return 0;
}
} while ((len <= 0) && (++num_blank_lines < max_blank_lines));
/* we've probably got something to do, ignore graceful restart requests */
r->request_time = apr_time_now();
ll = r->the_request;
r->method = ap_getword_white(r->pool, &ll);
#if 0
/* XXX If we want to keep track of the Method, the protocol module should do
* it. That support isn't in the scoreboard yet. Hopefully next week
* sometime. rbb */
ap_update_connection_status(AP_CHILD_THREAD_FROM_ID(conn->id), "Method",
r->method);
#endif
uri = ap_getword_white(r->pool, &ll);
/* Provide quick information about the request method as soon as known */
r->method_number = ap_method_number_of(r->method);
if (r->method_number == M_GET && r->method[0] == 'H') {
r->header_only = 1;
}
ap_parse_uri(r, uri);
+/*
+ https://svn.apache.org/viewvc/httpd/httpd/trunk/server/protocol.c?r1=1178566&r2=1179239&pathrev=1179239&view=patch
+ This is the fix for CVE-2011-3368; via bnc#722545.
+ */
+
+ /* RFC 2616:
+ * Request-URI = "*" | absoluteURI | abs_path | authority
+ *
+ * authority is a special case for CONNECT. If the request is not
+ * using CONNECT, and the parsed URI does not have scheme, and
+ * it does not begin with '/', and it is not '*', then, fail
+ * and give a 400 response. */
+ if (r->method_number != M_CONNECT
+ && !r->parsed_uri.scheme
+ && uri[0] != '/'
+ && !(uri[0] == '*' && uri[1] == '\0')) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "invalid request-URI %s", uri);
+ r->args = NULL;
+ r->hostname = NULL;
+ r->status = HTTP_BAD_REQUEST;
+ r->uri = apr_pstrdup(r->pool, uri);
+ return 0;
+ }
+
if (ll[0]) {
r->assbackwards = 0;
pro = ll;
len = strlen(ll);
} else {
r->assbackwards = 1;
pro = "HTTP/0.9";
len = 8;
}
r->protocol = apr_pstrmemdup(r->pool, pro, len);
/* XXX ap_update_connection_status(conn->id, "Protocol", r->protocol); */
/* Avoid sscanf in the common case */
if (len == 8
&& pro[0] == 'H' && pro[1] == 'T' && pro[2] == 'T' && pro[3] == 'P'
&& pro[4] == '/' && apr_isdigit(pro[5]) && pro[6] == '.'
&& apr_isdigit(pro[7])) {
r->proto_num = HTTP_VERSION(pro[5] - '0', pro[7] - '0');
}
else if (3 == sscanf(r->protocol, "%4s/%u.%u", http, &major, &minor)
&& (strcasecmp("http", http) == 0)
&& (minor < HTTP_VERSION(1, 0)) ) /* don't allow HTTP/0.1000 */
r->proto_num = HTTP_VERSION(major, minor);
else
r->proto_num = HTTP_VERSION(1, 0);
return 1;
}
AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r, apr_bucket_brigade *bb)
{
char *last_field = NULL;
apr_size_t last_len = 0;
apr_size_t alloc_len = 0;
char *field;
char *value;
apr_size_t len;
int fields_read = 0;
char *tmp_field;
/*
* Read header lines until we get the empty separator line, a read error,
* the connection closes (EOF), reach the server limit, or we timeout.
*/
while(1) {
apr_status_t rv;
int folded = 0;
field = NULL;
@@ -842,103 +867,109 @@
int access_status;
apr_bucket_brigade *tmp_bb;
apr_socket_t *csd;
apr_interval_time_t cur_timeout;
apr_pool_create(&p, conn->pool);
apr_pool_tag(p, "request");
r = apr_pcalloc(p, sizeof(request_rec));
r->pool = p;
r->connection = conn;
r->server = conn->base_server;
r->user = NULL;
r->ap_auth_type = NULL;
r->allowed_methods = ap_make_method_list(p, 2);
r->headers_in = apr_table_make(r->pool, 25);
r->subprocess_env = apr_table_make(r->pool, 25);
r->headers_out = apr_table_make(r->pool, 12);
r->err_headers_out = apr_table_make(r->pool, 5);
r->notes = apr_table_make(r->pool, 5);
r->request_config = ap_create_request_config(r->pool);
/* Must be set before we run create request hook */
r->proto_output_filters = conn->output_filters;
r->output_filters = r->proto_output_filters;
r->proto_input_filters = conn->input_filters;
r->input_filters = r->proto_input_filters;
ap_run_create_request(r);
r->per_dir_config = r->server->lookup_defaults;
r->sent_bodyct = 0; /* bytect isn't for body */
r->read_length = 0;
r->read_body = REQUEST_NO_BODY;
r->status = HTTP_REQUEST_TIME_OUT; /* Until we get a request */
r->the_request = NULL;
/* Begin by presuming any module can make its own path_info assumptions,
* until some module interjects and changes the value.
*/
r->used_path_info = AP_REQ_DEFAULT_PATH_INFO;
tmp_bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
/* Get the request... */
if (!read_request_line(r, tmp_bb)) {
- if (r->status == HTTP_REQUEST_URI_TOO_LARGE) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ if (r->status == HTTP_REQUEST_URI_TOO_LARGE
+ || r->status == HTTP_BAD_REQUEST) {
+ if (r->status == HTTP_REQUEST_URI_TOO_LARGE) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"request failed: URI too long (longer than %d)", r->server->limit_req_line);
+ } else if (r->method == NULL) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "request failed: invalid characters in URI");
+ }
ap_send_error_response(r, 0);
ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
ap_run_log_transaction(r);
apr_brigade_destroy(tmp_bb);
return r;
}
apr_brigade_destroy(tmp_bb);
return NULL;
}
/* We may have been in keep_alive_timeout mode, so toggle back
* to the normal timeout mode as we fetch the header lines,
* as necessary.
*/
csd = ap_get_module_config(conn->conn_config, &core_module);
apr_socket_timeout_get(csd, &cur_timeout);
if (cur_timeout != conn->base_server->timeout) {
apr_socket_timeout_set(csd, conn->base_server->timeout);
cur_timeout = conn->base_server->timeout;
}
if (!r->assbackwards) {
ap_get_mime_headers_core(r, tmp_bb);
if (r->status != HTTP_REQUEST_TIME_OUT) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"request failed: error reading the headers");
ap_send_error_response(r, 0);
ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
ap_run_log_transaction(r);
apr_brigade_destroy(tmp_bb);
return r;
}
if (apr_table_get(r->headers_in, "Transfer-Encoding")
&& apr_table_get(r->headers_in, "Content-Length")) {
/* 2616 section 4.4, point 3: "if both Transfer-Encoding
* and Content-Length are received, the latter MUST be
* ignored"; so unset it here to prevent any confusion
* later. */
apr_table_unset(r->headers_in, "Content-Length");
}
}
else {
if (r->header_only) {
/*
* Client asked for headers only with HTTP/0.9, which doesn't send
* headers! Have to dink things just to make sure the error message
* comes through...
*/