httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "William A. Rowe, Jr." <>
Subject Re: [2.0] lstat's in spite of AllowOverride None
Date Wed, 07 Nov 2001 14:02:17 GMT
From: "Martin Kraemer" <>
Sent: Wednesday, November 07, 2001 3:11 AM

> When I do a grep for "AllowOverride" in my current config, I get:
> 312:    AllowOverride None
> [...]
> In spite of this, when tracing an access to a read-only file, I see:
>  ...
>  lstat("/home",0xbfbff890)                        = 0 (0x0)
>  lstat("/home/www",0xbfbff890)                    = 0 (0x0)
>  lstat("/home/www/SERVER",0xbfbff890)             = 0 (0x0)
>  lstat("/home/www/SERVER/apa20",0xbfbff890)       = 0 (0x0)
>  lstat("/home/www/SERVER/apa20/htdocs",0xbfbff890) = 0 (0x0)
>  lstat("/home/www/SERVER/apa20/htdocs/noread.html",0xbfbff890) = 0 (0x0)
> Where do all the lstats() come from, and *WHY* do they happen at all?

> On Wed, Nov 07, 2001 at 09:32:37AM +0000, James A Sutherland wrote:
> > 
> > Checking for symlinks, I think? Check for Options FollowSymLinks.
> It is set for the dir in question (and everywhere above it), so it needn't
> (shouldn't) do any lstat()s IMHO.

Before the rewrite of dir_walk, a request for /noread.html/some/path/info 
would do the following;

stat("/home/www/SERVER/apa20/htdocs/noread.html/some/path/info") = ENOTDIR
stat("/home/www/SERVER/apa20/htdocs/noread.html/some/path") = ENOTDIR
stat("/home/www/SERVER/apa20/htdocs/noread.html/some") = ENOTDIR
stat("/home/www/SERVER/apa20/htdocs/noread.html") = 0

With a very long path, this actually amounted to a rather nasty denial of 
service.  Then we stat'ed forward, followed by an lstat, for each directory 
where FollowSymLinks was set to owner.

Now that we run the path forward, a request like /a/a/a/a/a... won't generate 
hundreds (thousands) of stat calls.  It will die as soon as a file is found/not 
found.  The rewrite of dir_walk first eliminated the get_path_info function and 
folded that code back into dir_walk.

The advantage to lstat() was trivial; we don't waste time checking symlinks 
where there are no symlinks.  Even symlinking to an evil entity (char/block 
device) won't succeed, because we only permit symlinks to regular files and 
directories.  Any non-symlink simply returns it's actual identity and the
'symlink check' is not required.

Now the question becomes, if walking the path backwards is (generally) not a 
good answer, what is?  I've suggested (in comments within the code) that we 
walk the path forward, and if we enounter a <Directory > block that identifies 
the path thus far and has followsymlinks set, we skip all stats (until we have 
no path info, then we must stat the final target, even as a directory).  Go on 
to the next element and then, if we get ENOTDIR, consider the result a 
misconfiguration, since the admin purported that /some/path is a <Directory >.

As FirstBill suggests, there are other means for caching the (l)stat results,
at least for the request duration, which need to be deployed.  But dropping the
path_info walk-backwards logic was step one.  Any optimization patches are
entertianed to speed up the server, if we don't lose stability.


View raw message