Opened 13 years ago

Closed 12 years ago

#578 closed defect (fixed)

omega GET query parsing defects and fix

Reported by: Charles Owned by: Olly Betts
Priority: normal Milestone: 1.2.8
Component: Omega Version: 1.2.7
Severity: normal Keywords:
Cc: Blocked By:
Blocking: Operating System: All

Description (last modified by Olly Betts)

Without this patch:

  • if the QUERY_STRING ends with a '%', the parsing routine will overrun the QUERY_STRING (if it is followed in memory by only a single NUL byte).
  • omega stops parsing GET query parameters if there are two consecutive ampersands in QUERY_STRING.
  • omega tries to parse anything following a percent sign. Other implementations do not try to parse malformed escape sequences.

The patch is also attached as a file


diff -Naur xapian-omega-1.2.7-original/cgiparam.cc xapian-omega-1.2.7/cgiparam.cc
--- xapian-omega-1.2.7-original/cgiparam.cc	2011-08-10 09:49:12.000000000 +0300
+++ xapian-omega-1.2.7/cgiparam.cc	2011-11-13 08:10:15.021566998 +0200
@@ -180,20 +180,28 @@
 	while (1) {
 	    ch = *q_str++;
 	    if (ch == '\0' || ch == '&') {
-		if (name.empty()) return; // end on blank line
-		add_param(name, val);
+		if (!name.empty()) add_param(name, val);
+		if (ch == '\0')
+			return;
 		break;
 	    }
 	    char orig_ch = ch;
 	    if (ch == '+')
 		ch = ' ';
-	    else if (ch == '%') {
-		int c = *q_str++;
-		ch = (c & 0xf) + ((c & 64) ? 9 : 0);
-		if (c) c = *q_str++;
-		ch = ch << 4;
-		ch |= (c & 0xf) + ((c & 64) ? 9 : 0);
-		if (!c) return; // unfinished % code
+	    else if (ch == '%' &&
+		     ((q_str[0] >= '0' && q_str[0] <= '9') ||
+		      (q_str[0] >= 'A' && q_str[0] <= 'F') ||
+		      (q_str[0] >= 'a' && q_str[0] <= 'f')) &&
+		     ((q_str[1] >= '0' && q_str[1] <= '9') ||
+		      (q_str[1] >= 'A' && q_str[1] <= 'F') ||
+		      (q_str[1] >= 'a' && q_str[1] <= 'f'))) {
+		const int c1 = q_str[0], c2 = q_str[1];
+		int c;
+		c = ( (c1 & 0xf) + ((c1 & 64) ? 9 : 0) ) << 4
+		  + ( (c2 & 0xf) + ((c2 & 64) ? 9 : 0) );
+		q_str += 2;
+		if (!c)
+		    continue;
 	    }
 	    if (had_equals) {
 		val += char(ch);

Attachments (1)

Xapian ticket 578 attachment.txt (1.3 KB ) - added by Charles 13 years ago.
Generating command and patch

Download all attachments as: .zip

Change History (5)

by Charles, 13 years ago

Generating command and patch

comment:1 by Olly Betts, 13 years ago

Description: modified (diff)
Milestone: 1.2.8

Thanks.

We should fix these for 1.2.8.

comment:2 by Olly Betts, 13 years ago

Milestone: 1.2.81.3.0
Status: newassigned

Actually, I don't believe the current code can read beyond the trailing nul byte, since q_ptr is only advanced and read if c is non-zero.

So I wonder if it's better to fix this in trunk only - fixing the other two quirks would be good overall, but doesn't change anything for normal uses (browsers won't build these problematic query strings), yet might change behaviour for people building their own query URLs.

in reply to:  2 comment:3 by Charles, 12 years ago

Replying to olly:

Actually, I don't believe the current code can read beyond the trailing nul byte, since q_ptr is only advanced and read if c is non-zero.

Correct and sorry for the misinformation.

We stumbled across the real defect when using Apache rewriting to edit the query string and accidentally produced consecutive ampersands. Unintentional but should have been valid according to the CGI RFCs.

comment:4 by Olly Betts, 12 years ago

Milestone: 1.3.01.2.8
Resolution: fixed
Status: assignedclosed

There's similar code for handling POST too. I went for writing new code instead, and made it a template so we only need to maintain one copy. Committed to trunk in r16150, along with unit tests for the cases mentioned in the report and some other simple cases, and also unit tests for URL encoding.

Backported for 1.2.8 as r16151.

Note: See TracTickets for help on using tickets.