[security] disable stat_cache if !follow-symlink (fixes #2724)

disable stat_cache if server.follow-symlink = "disable"
if server.stat-cache-engine = "simple".  Caching is still enabled
for server.stat-cache-engine = "fam" since the FAM notification is
almost immediate, however there is still a small race condition.

NOTE: server.follow-symlink = "disable" implementation still has
time-of-check versus time-of-use (ToC-ToU) race conditions and
its use is *not recommended* except to discourage symlinking.
It *does not* prevent symlinking by a determined attacker with
the ability to create files on the server.

server.stat-cache-engine = "disable" can also be used to discourage
symlinking, and also does not eliminate ToC-ToU race conditions.

While more modern systems might use openat() and other *at() routines
to eliminate the ToC-ToU race conditions, this is not currently
implemented in lighttpd.  Besides, for systems needing such
protections against actors able to modify local files, it would be
better to set up multiple lighttpd servers running in separate user
contexts with filesystem permissions preventing access, rather than
giving a single lighttpd server running under a single lighttpd user
access to files across security boundaries, and trying to prevent
access by lighttpd user if a file is a symlink.

Note that there are performance implications to setting either of
  server.follow-symlink = "disable"
  server.stat-cache-engine = "disable"
since stat cache normally reduces filesystem overhead for
frequently-accessed files.

  "security: stat cache *very large* race condition if caching when
follow_symlink disabled"
Glenn Strauss 6 years ago
parent 558bfc4e1e
commit acd5e450b5
  1. 2

@ -422,7 +422,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
if (buffer_is_equal(name, sce->name)) {
if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) {
if (sce->stat_ts == srv->cur_ts) {
if (sce->stat_ts == srv->cur_ts && con->conf.follow_symlink) {
*ret_sce = sce;