httpd: fix /../ sanitization (had one extra semicolon). rewrote it
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 16 Dec 2011 00:37:02 +0000 (01:37 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Fri, 16 Dec 2011 00:37:02 +0000 (01:37 +0100)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/httpd.c

index 0356e4c1b274e0ff3a9e92a3a7d729bccba0cd11..f52785bf4f4d782079dfb54772cfe46b3fca5f05 100644 (file)
@@ -2012,30 +2012,36 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
        /* Algorithm stolen from libbb bb_simplify_path(),
         * but don't strdup, retain trailing slash, protect root */
        urlp = tptr = urlcopy;
-       do {
+       for (;;) {
                if (*urlp == '/') {
                        /* skip duplicate (or initial) slash */
                        if (*tptr == '/') {
-                               continue;
+                               goto next_char;
                        }
                        if (*tptr == '.') {
-                               /* skip extra "/./" */
-                               if (tptr[1] == '/' || !tptr[1]) {
-                                       continue;
-                               }
-                               /* "..": be careful */
-                               if (tptr[1] == '.' && (tptr[2] == '/' || !tptr[2])) {
-                                       ++tptr;
-                                       if (urlp == urlcopy) /* protect root */
+                               if (tptr[1] == '.' && (tptr[2] == '/' || tptr[2] == '\0')) {
+                                       /* "..": be careful */
+                                       /* protect root */
+                                       if (urlp == urlcopy)
                                                send_headers_and_exit(HTTP_BAD_REQUEST);
-                                       while (*--urlp != '/') /* omit previous dir */;
+                                       /* omit previous dir */
+                                       while (*--urlp != '/')
                                                continue;
+                                       /* skip to "./" or ".<NUL>" */
+                                       tptr++;
+                               }
+                               if (tptr[1] == '/' || tptr[1] == '\0') {
+                                       /* skip extra "/./" */
+                                       goto next_char;
                                }
                        }
                }
                *++urlp = *tptr;
-       } while (*++tptr);
-       *++urlp = '\0';       /* terminate after last character */
+               if (*urlp == '\0')
+                       break;
+ next_char:
+               tptr++;
+       }
 
        /* If URL is a directory, add '/' */
        if (urlp[-1] != '/') {