#! /bin/sh /usr/share/dpatch/dpatch-run
## 084_CVE-2011-3192_regression.dpatch by Steve Beattie <sbeattie@ubuntu.com>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: backport of fixes for debian bug 639825
#
# Subject: fix regressions introduced by CVE-2011-3192 fixes
# Origin: upstream
# Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=639825
#
# When asked for byte range 0-, should return 206 not 200.
# When asked for byte range entirely outside of the file should return
# 416 not 200.
#
# Contains backported upstream commits
# http://svn.apache.org/viewvc?view=revision&sortby=date&revision=1163851
# and
# http://svn.apache.org/viewvc?view=revision&sortby=date&revision=1163833
#
# See also http://marc.info/?l=apache-httpd-dev&m=131482445624089&w=2
# and http://marc.info/?l=apache-httpd-dev&m=131482610125970&w=2

@DPATCH@
diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' apache2-2.2.17~/modules/http/byterange_filter.c apache2-2.2.17/modules/http/byterange_filter.c
--- apache2-2.2.17~/modules/http/byterange_filter.c	2011-08-31 23:09:33.000000000 -0700
+++ apache2-2.2.17/modules/http/byterange_filter.c	2011-08-31 23:41:36.000000000 -0700
@@ -248,6 +248,20 @@
     apr_off_t end;
 } indexes_t;
 
+static apr_status_t send_416(ap_filter_t *f, apr_bucket_brigade *tmpbb)
+{
+    apr_bucket *e;
+    conn_rec *c = f->r->connection;
+    ap_remove_output_filter(f);
+    f->r->status = HTTP_OK;
+    e = ap_bucket_error_create(HTTP_RANGE_NOT_SATISFIABLE, NULL,
+                               f->r->pool, c->bucket_alloc);
+    APR_BRIGADE_INSERT_TAIL(tmpbb, e);
+    e = apr_bucket_eos_create(c->bucket_alloc);
+    APR_BRIGADE_INSERT_TAIL(tmpbb, e);
+    return ap_pass_brigade(f->next, tmpbb);
+}
+
 AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f,
                                                          apr_bucket_brigade *bb)
 {
@@ -301,6 +315,12 @@
         return ap_pass_brigade(f->next, bb);
     }
 
+    /* this brigade holds what we will be sending */
+    bsend = apr_brigade_create(r->pool, c->bucket_alloc);
+
+    if (num_ranges < 0)
+        return send_416(f, bsend);
+
     if (num_ranges > 1) {
         /* Is ap_make_content_type required here? */
         const char *orig_ct = ap_make_content_type(r, r->content_type);
@@ -330,8 +350,6 @@
         ap_xlate_proto_to_ascii(bound_head, strlen(bound_head));
     }
 
-    /* this brigade holds what we will be sending */
-    bsend = apr_brigade_create(r->pool, c->bucket_alloc);
     tmpbb = apr_brigade_create(r->pool, c->bucket_alloc);
 
     idx = (indexes_t *)indexes->elts;
@@ -389,15 +407,8 @@
     }
 
     if (found == 0) {
-        ap_remove_output_filter(f);
-        r->status = HTTP_OK;
         /* bsend is assumed to be empty if we get here. */
-        e = ap_bucket_error_create(HTTP_RANGE_NOT_SATISFIABLE, NULL,
-                                   r->pool, c->bucket_alloc);
-        APR_BRIGADE_INSERT_TAIL(bsend, e);
-        e = apr_bucket_eos_create(c->bucket_alloc);
-        APR_BRIGADE_INSERT_TAIL(bsend, e);
-        return ap_pass_brigade(f->next, bsend);
+        return send_416(f, bsend);
     }
 
     if (num_ranges > 1) {
@@ -429,7 +440,7 @@
     const char *match;
     const char *ct;
     char *cur;
-    int num_ranges = 0;
+    int num_ranges = 0, unsatisfiable = 0;
     apr_off_t sum_lengths = 0;
     indexes_t *idx;
     int ranges = 1;
@@ -502,14 +513,22 @@
         char *errp;
         apr_off_t number, start, end;
 
+	if (!*cur)
+	    break;
+
+        /*
+         * Per RFC 2616 14.35.1: If there is at least one syntactically invalid
+         * byte-range-spec, we must ignore the whole header.
+         */
+
         if (!(dash = strchr(cur, '-'))) {
-            break;
+            return 0;
         }
 
         if (dash == range) {
             /* In the form "-5" */
             if (apr_strtoff(&number, dash+1, &errp, 10) || *errp) {
-                break;
+                return 0;
             }
             start = clength - number;
             end = clength - 1;
@@ -517,14 +536,17 @@
         else {
             *dash++ = '\0';
             if (apr_strtoff(&number, cur, &errp, 10) || *errp) {
-                break;
+                return 0;
             }
             start = number;
             if (*dash) {
                 if (apr_strtoff(&number, dash, &errp, 10) || *errp) {
-                    break;
+                    return 0;
                 }
                 end = number;
+                if (start > end) {
+                    return 0;
+                }
             }
             else {                  /* "5-" */
                 end = clength - 1;
@@ -534,15 +556,14 @@
         if (start < 0) {
             start = 0;
         }
+        if (start >= clength) {
+            unsatisfiable = 1;
+            continue;
+        }
         if (end >= clength) {
             end = clength - 1;
         }
 
-        if (start > end) {
-            /* ignore? count? */
-            break;
-        }
-
         idx = (indexes_t *)apr_array_push(*indexes);
         idx->start = start;
         idx->end = end;
@@ -551,9 +572,14 @@
         num_ranges++;
     }
 
-    if (sum_lengths >= clength) {
+    if (num_ranges == 0 && unsatisfiable) {
+        /* If all ranges are unsatisfiable, we should return 416 */
+        	ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "0U");
+        return -1;
+    }
+    if (sum_lengths > clength) {
         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                      "Sum of ranges not smaller than file, ignoring.");
+                      "Sum of ranges larger than file, ignoring.");
         return 0;
     }
 
