[nginx] svn commit: r4481 - trunk/src/core

mdounin at mdounin.ru mdounin at mdounin.ru
Wed Feb 15 12:18:55 UTC 2012


Author: mdounin
Date: 2012-02-15 12:18:55 +0000 (Wed, 15 Feb 2012)
New Revision: 4481

Log:
Disable symlinks: fixed edge cases of path handling.

This includes non-absolute pathnames, multiple slashes and trailing
slashes.  In collaboration with Valentin Bartenev.


Modified:
   trunk/src/core/ngx_open_file_cache.c

Modified: trunk/src/core/ngx_open_file_cache.c
===================================================================
--- trunk/src/core/ngx_open_file_cache.c	2012-02-15 12:17:24 UTC (rev 4480)
+++ trunk/src/core/ngx_open_file_cache.c	2012-02-15 12:18:55 UTC (rev 4481)
@@ -562,9 +562,10 @@
 
 #else
 
-    u_char     *p, *cp, *end;
-    ngx_fd_t    at_fd;
-    ngx_str_t   at_name;
+    u_char           *p, *cp, *end;
+    ngx_fd_t          at_fd;
+    ngx_str_t         at_name;
+    ngx_file_info_t   fi;
 
     if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) {
         fd = ngx_open_file(name->data, mode, create, access);
@@ -578,27 +579,38 @@
         return fd;
     }
 
-    at_fd = ngx_openat_file(AT_FDCWD, "/", NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
-                            NGX_FILE_OPEN, 0);
+    p = name->data;
+    end = p + name->len;
 
-    if (at_fd == NGX_INVALID_FILE) {
-        of->err = ngx_errno;
-        of->failed = ngx_openat_file_n;
-        return NGX_INVALID_FILE;
-    }
-
+    at_fd = AT_FDCWD;
     at_name = *name;
-    at_name.len = 1;
 
-    end = name->data + name->len;
-    p = name->data + 1;
+    if (p[0] == '/') {
+        at_fd = ngx_openat_file(at_fd, "/",
+                                NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
+                                NGX_FILE_OPEN, 0);
 
+        if (at_fd == NGX_FILE_ERROR) {
+            of->err = ngx_errno;
+            of->failed = ngx_openat_file_n;
+            return NGX_FILE_ERROR;
+        }
+
+        at_name.len = 1;
+        p++;
+    }
+
     for ( ;; ) {
         cp = ngx_strlchr(p, end, '/');
         if (cp == NULL) {
             break;
         }
 
+        if (cp == p) {
+            p++;
+            continue;
+        }
+
         *cp = '\0';
 
         if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) {
@@ -630,6 +642,40 @@
         at_name.len = cp - at_name.data;
     }
 
+    if (p == end && at_fd != AT_FDCWD) {
+
+        /*
+         * If pathname ends with a trailing slash, check if last path
+         * component is a directory; if not, fail with ENOTDIR as per
+         * POSIX.
+         *
+         * We use separate check instead of O_DIRECTORY in the loop above,
+         * as O_DIRECTORY doesn't work on FreeBSD 8.
+         *
+         * Note this returns already opened file descriptor, with different
+         * mode/create/access.  This is believed to be safe as we don't
+         * use this codepath to create directories.
+         */
+
+        if (ngx_fd_info(at_fd, &fi) == NGX_FILE_ERROR) {
+            of->err = ngx_errno;
+            of->failed = ngx_fd_info_n;
+            fd = NGX_INVALID_FILE;
+
+            goto failed;
+        }
+
+        if (ngx_is_dir(&fi)) {
+            return at_fd;
+        }
+
+        of->err = ENOTDIR;
+        of->failed = ngx_openat_file_n;
+        fd = NGX_INVALID_FILE;
+
+        goto failed;
+    }
+
     if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) {
         fd = ngx_openat_file_owner(at_fd, p, mode, create, access, log);
 



More information about the nginx-devel mailing list