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...
              */
openSUSE Build Service is sponsored by