You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Allen Pulsifer <pu...@comcast.net> on 2007/06/14 02:43:23 UTC

revised patch for spurious open attempt on ".../file.html/.htaccess"

After sending that last post, I realized that if the full path points to a
directory, it will do a final lstat even though it doesn't need to.

That's easy to fix.  Here is the revised code, the revised patch, and test
output.

CODE:

            if (r->finfo.filetype
#ifdef CASE_BLIND_FILESYSTEM
                && (filename_len <= canonical_len)
#endif
                && (opts.opts & OPT_SYM_LINKS) )
            {
                ++seg;

                if (r->finfo.filetype == APR_DIR || (r->path_info &&
*r->path_info))
                {
                    thisinfo.filetype = APR_DIR;
                    continue;
                }
                else if (r->finfo.filetype == APR_REG)
                {
                    thisinfo.filetype = APR_REG;
                    break;
                }
            }

PATCH:

--- .svn/text-base/request.c.svn-base   2007-06-04 23:40:23.801630400 -0400
+++ request.c   2007-06-13 19:54:37.050034200 -0400
@@ -931,13 +931,21 @@
 #ifdef CASE_BLIND_FILESYSTEM
                 && (filename_len <= canonical_len)
 #endif
-                && ((opts.opts & (OPT_SYM_OWNER | OPT_SYM_LINKS)) ==
OPT_SYM_LINKS))
+                && (opts.opts & OPT_SYM_LINKS) )
             {
+                ++seg;

+                if (r->finfo.filetype == APR_DIR || (r->path_info &&
*r->path_info))
+                {
                 thisinfo.filetype = APR_DIR;
-                ++seg;
                 continue;
             }
+                else if (r->finfo.filetype == APR_REG)
+                {
+                    thisinfo.filetype = APR_REG;
+                    break;
+                }
+            }

             /* We choose apr_stat with flag APR_FINFO_LINK here, rather
that
              * plain apr_stat, so that we capture this path object rather
than


TEST OUTPUT:

request: http://localhost/dir/subdir/ (with an index.html file)

[pid 14461] stat64("/usr/local/apache2/htdocs/dir/subdir/",
{st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
[pid 14461] open("/usr/local/apache2/htdocs/.htaccess",
O_RDONLY|O_LARGEFILE) = 12
[pid 14461] open("/usr/local/apache2/htdocs/dir/.htaccess",
O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
[pid 14461] open("/usr/local/apache2/htdocs/dir/subdir/.htaccess",
O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
[pid 14461] stat64("/usr/local/apache2/htdocs/dir/subdir/index.html",
{st_mode=S_IFREG|0755, st_size=51, ...}) = 0
[pid 14461] open("/usr/local/apache2/htdocs/dir/subdir/index.html",
O_RDONLY|O_LARGEFILE) = 12


request: http://localhost/dir/subdir/file.html

[pid 14462] stat64("/usr/local/apache2/htdocs/dir/subdir/file.html",
{st_mode=S_IFREG|0644, st_size=48, ...}) = 0
[pid 14462] open("/usr/local/apache2/htdocs/.htaccess",
O_RDONLY|O_LARGEFILE) = 12
[pid 14462] open("/usr/local/apache2/htdocs/dir/.htaccess",
O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
[pid 14462] open("/usr/local/apache2/htdocs/dir/subdir/.htaccess",
O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
[pid 14462] open("/usr/local/apache2/htdocs/dir/subdir/file.html",
O_RDONLY|O_LARGEFILE) = 12

revised(3) patch for spurious open attempt on ".../file.html/.htaccess"

Posted by Allen Pulsifer <pu...@comcast.net>.
I hate to have to do this...

I realized that ++seg should only be incremented when the optimization
results in either a "continue" or a "break".  Here is the correction:

CODE:

            if (r->finfo.filetype
#ifdef CASE_BLIND_FILESYSTEM
                && (filename_len <= canonical_len)
#endif
                && (opts.opts & OPT_SYM_LINKS) )
            {
                if ((r->path_info && *r->path_info) || r->finfo.filetype ==
APR_DIR)
                {
                    thisinfo.filetype = APR_DIR;
                    ++seg;
                    continue;
                }
                else if (r->finfo.filetype == APR_REG)
                {
                    thisinfo.filetype = APR_REG;
                    ++seg;
                    break;
                }
            }

PATCH:

--- .svn/text-base/request.c.svn-base   2007-06-04 23:40:23.801630400 -0400
+++ request.c   2007-06-13 21:34:01.659559100 -0400
@@ -931,13 +931,21 @@
 #ifdef CASE_BLIND_FILESYSTEM
                 && (filename_len <= canonical_len)
 #endif
-                && ((opts.opts & (OPT_SYM_OWNER | OPT_SYM_LINKS)) ==
OPT_SYM_LINKS))
+                && (opts.opts & OPT_SYM_LINKS) )
+            {
+                if ((r->path_info && *r->path_info) || r->finfo.filetype ==
APR_DIR)
             {
-
                 thisinfo.filetype = APR_DIR;
                 ++seg;
                 continue;
             }
+                else if (r->finfo.filetype == APR_REG)
+                {
+                    thisinfo.filetype = APR_REG;
+                    ++seg;
+                    break;
+                }
+            }

             /* We choose apr_stat with flag APR_FINFO_LINK here, rather
that
              * plain apr_stat, so that we capture this path object rather
than


ANALYSIS:

The optimization formerly skipped the lstat and went directly to the
htaccess check, even when it reached the point of checking the full path and
the full path referred to a file.  This resulted in a spurious open attempt
on .../file.html/.htaccess

The revised optimization also skips the lstat and goes directly to the
htaccess check, but only when (a) the directory walk has not yet reached the
full path; or (b) the full path refers to a directory.

Otherwise, when it reaches the full path, if the full path refers to a
regular file, it terminates the directory walk.  If the file type of the
full path is not a directory or a regular file, it continues on with the
unoptimized lstat of the full path.