This is the third patch.

In this patch also solved a small buffer overread which exist in the original httpHeaderParseQuotedString function. The loop:

while (end <= (start+len) && *end != '\\' && *end != '\"' && *end > 0x1F && *end != 0x7F)
  if (*end <= 0x1F || *end == 0x7F) {
 ...
allowed to access (and parsing affected by) the char after the end of parsed string. It did not have any bad effect for null terminated strings.


On 05/27/2011 03:12 PM, Amos Jeffries wrote:
On 27/05/11 23:21, Tsantilas Christos wrote:
Hi all,

Just trying to clarify what we want to implement at the end, because I
am confused. I am responsible for the confusion because I give two "(3)"
options, and I send buggy implementations for the "(1)" and the "second
(3)" option.

From what I can understand, currently, we have the following options:
1) Just ignore any "\r" or "\n" character. This is the fastest and
simpler approach
2) Require "[\r]\n " or "[\r]\n\t" as line separator and replace it with
a space.

From the discussion the (1) may be dangerous because strings like this
"1\r23" will be converted to "123" which maybe it is dangerous.

So I suppose we should implement the (2) option. Is it OK?

Agreed.

What we have been debugging in the other half of the thread was "\r\n "
or "\r\n\t".

I think it just needs:
* the two buffer overread bugs Alex spotted removed,
* the \r made optional.

Amos

=== modified file 'src/HttpHeaderTools.cc'
--- src/HttpHeaderTools.cc	2010-11-02 00:12:43 +0000
+++ src/HttpHeaderTools.cc	2011-05-30 13:29:36 +0000
@@ -325,60 +325,91 @@
 
 
 /**
  * Parses a quoted-string field (RFC 2616 section 2.2), complains if
  * something went wrong, returns non-zero on success.
  * Un-escapes quoted-pair characters found within the string.
  * start should point at the first double-quote.
  */
 int
 httpHeaderParseQuotedString(const char *start, const int len, String *val)
 {
     const char *end, *pos;
     val->clean();
     if (*start != '"') {
         debugs(66, 2, "failed to parse a quoted-string header field near '" << start << "'");
         return 0;
     }
     pos = start + 1;
 
     while (*pos != '"' && len > (pos-start)) {
+
+        if (*pos =='\r') {
+            pos++;
+            if ((pos-start) > len || *pos != '\n') {
+                debugs(66, 2, "failed to parse a quoted-string header field with \'\\r\' octet " << (start-pos)
+                       << " bytes into '" << start << "'");
+                val->clean();
+                return 0;
+            }
+        }
+
+        if (*pos == '\n') {
+            pos++;
+            if ( (pos-start) > len || (*pos != ' ' && *pos != '\t')) {
+                debugs(66, 2, "failed to parse multiline quoted-string header field '" << start << "'");
+                val->clean();
+                return 0;
+            }
+            val->append(" ");
+            pos++;
+            debugs(66, 2, "len < pos-start => " << len << " < " << (pos-start));
+            continue;
+        }
+
         bool quoted = (*pos == '\\');
-        if (quoted)
+        if (quoted) {
             pos++;
-        if (!*pos || (pos-start) > len) {
-            debugs(66, 2, "failed to parse a quoted-string header field near '" << start << "'");
-            val->clean();
-            return 0;
+            if (!*pos || (pos-start) > len) {
+                debugs(66, 2, "failed to parse a quoted-string header field near '" << start << "'");
+                val->clean();
+                return 0;
+            }
         }
         end = pos;
-        while (end <= (start+len) && *end != '\\' && *end != '\"' && *end > 0x1F && *end != 0x7F)
+        while (end < (start+len) && *end != '\\' && *end != '\"' && *end > 0x1F && *end != 0x7F)
             end++;
-        if (*end <= 0x1F || *end == 0x7F) {
+        if ((*end <= 0x1F && *end != '\r' && *end != '\n') || *end == 0x7F) {
             debugs(66, 2, "failed to parse a quoted-string header field with CTL octet " << (start-pos)
                    << " bytes into '" << start << "'");
             val->clean();
             return 0;
         }
         val->append(pos, end-pos);
         pos = end;
     }
+
+    if (*pos != '\"') {
+        debugs(66, 2, "failed to parse a quoted-string header field which did not end with \" ");
+        val->clean();
+        return 0;
+    }
     /* Make sure it's defined even if empty "" */
     if (!val->defined())
         val->limitInit("", 0);
     return 1;
 }
 
 /**
  * Checks the anonymizer (header_access) configuration.
  *
  * \retval 0    Header is explicitly blocked for removal
  * \retval 1    Header is explicitly allowed
  * \retval 1    Header has been replaced, the current version can be used.
  * \retval 1    Header has no access controls to test
  */
 static int
 httpHdrMangle(HttpHeaderEntry * e, HttpRequest * request, int req_or_rep)
 {
     int retval;
 
     /* check with anonymizer tables */

Reply via email to