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, ©[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;
}