You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Dean Gaudet <dg...@arctic.org> on 1998/01/06 23:29:34 UTC

[PATCH] yet another slow function

The beck attack (at least against 1.3) also tickles lameness in the
os_escape_path() routine.  Calling ind() is way too expensive.  This patch
fixes that lameness.  Oh yeah, calling sprintf() to convert a byte to hex
seems like a waste too.  Fix that as well.  I'll backport to 1.2 sometime. 

Dean

Index: main/util.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/util.c,v
retrieving revision 1.81
diff -u -r1.81 util.c
--- util.c	1997/12/30 19:55:48	1.81
+++ util.c	1998/01/06 22:11:09
@@ -1051,7 +1051,14 @@
 		   uri, NULL);
 }
 
-#define c2x(what,where) sprintf(where,"%%%02x",(unsigned char)what)
+static const char c2x_table[] = "0123456789abcdef";
+
+static ap_inline void c2x(unsigned char what, char *where)
+{
+    where[0] = '%';
+    where[1] = c2x_table[what >> 4];
+    where[2] = c2x_table[what & 0xf];
+}
 
 /*
  * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
@@ -1068,15 +1075,73 @@
  * something with a '/' in it (and thus does not prefix "./").
  */
 
+#if 0
+/* this little program generates the following table */
+void main(void)
+{
+    int c;
+    int ok;
+
+    for (c = 0; c < 256; ++c) {
+	switch(c) {
+	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
+	case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
+	case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
+	case 'v': case 'w': case 'x': case 'y': case 'z':
+
+	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+	case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+	case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+	case 'V': case 'W': case 'X': case 'Y': case 'Z':
+
+	case '0': case '1': case '2': case '3': case '4': case '5': case '6':
+	case '7': case '8': case '9':
+
+	case '$': case '-': case '_': case '.': case '+': case '!': case '*':
+	case '(': case ')': case ',': case ':': case '@': case '&': case '=':
+	case '~': case '\'': case '/':
+	    ok = 1;
+	    break;
+
+	default:
+	    ok = 0;
+	    break;
+	}
+	printf(" %d,", ok);
+	if ((c & 0xf) == 0xf) {
+	    printf("\n");
+	}
+    }
+}
+#endif
+
+static const unsigned char safe_path_chars[256] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
 API_EXPORT(char *) escape_path_segment(pool *p, const char *segment)
 {
     register int x, y;
     char *copy = palloc(p, 3 * strlen(segment) + 1);
 
     for (x = 0, y = 0; segment[x]; x++, y++) {
-	char c = segment[x];
-	if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c > '9')
-	    && ind("$-_.+!*'(),:@&=~", c) == -1) {
+	unsigned char c = segment[x];
+	if (c == '/' || !safe_path_chars[c]) {
 	    c2x(c, &copy[y]);
 	    y += 2;
 	}
@@ -1102,9 +1167,8 @@
 	}
     }
     for (; *path; ++path) {
-	char c = *path;
-	if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c > '9')
-	    && ind("$-_.+!*'(),:@&=/~", c) == -1) {
+	unsigned char c = *path;
+	if (!safe_path_chars[c]) {
 	    c2x(c, s);
 	    s += 3;
 	}