Bug #1116
closedlighttpd 1.4.13 reproducible (every time) segfault when file cannot be stat-ed (with simple test-case)
Description
'_*Short version*_
If you have files which can't be accessed by lighttpd 1.4.13's normal user (i.e. are run via suexec), then lighttpd can easily be tricked into trying to open() them, causing a segfault every time. Do this by post-fixing a slash.
'_*Long version*_
I have a lighttpd 1.4.13 + FastCGI with SuExec, running on some files which can't be read by the normal lighttpd user.
This all works fine... unless you try to access specially crafted URLs - which cause lighty to crash every time.
Here's my (slightly obscured) set-up:
server.name = "1.2.3.4" server.document-root = "/var/www/html/" server.indexfiles = ( "index.html", "index.htm", "index.php" ) fastcgi.server = ( ".php" => ( "localhost" => ( "socket" => "/tmp/webadmin.socket", "bin-path" => "/etc/lighttpd/suexec.sh", "idle-timeout" => 30, "check-local" => "disable", "min-procs" => 1, "max-procs" => 1, ) ) )
I have a file /var/www/html/x.php. Its contents can be anything. For a test case, I used:
<? phpinfo(); ?>
My suexec script is not relevant to the crash, but is completely simple (just execs a shell script that calls php-cgi).
The test file x.php is only accessible by the SuExec user:
[root@ ~]# ls -l /var/www/html/x.php -rwxr-x--- 1 suexecuser suexecgroup 19 Apr 12 22:06 /var/www/html/x.php
If I access it as http://1.2.3.4/x.php then all is fine - I get what I'd expect. No problems.
However, if I try http://1.2.3.4/x.php/y (i.e. appending a pseudo-directory), then - boom! segfault! This happens every single time. Not good on a live server... :-(
Here are the last few lines of the strace:
poll([{fd=4, events=POLLIN}, {fd=5, events=POLLIN}, {fd=25, events=POLLIN, revents=POLLIN}], 3, 1000) = 1 read(25, "\27\3\1\2\0\7\273)\315YK:\36j#\345\30\321\316\2623!\357"..., 18437) = 517 read(25, 0x8780820, 18437) = -1 EAGAIN (Resource temporarily unavailable) stat64("/var/www/html/x.php/y", 0xbffcaa70) = -1 ENOTDIR (Not a directory) stat64("/var/www/html/x.php/y", 0xbffcab30) = -1 ENOTDIR (Not a directory) stat64("/var/www/html/x.php", {st_mode=S_IFREG|0750, st_size=19, ...}) = 0 stat64("/var/www/html/x.php", {st_mode=S_IFREG|0750, st_size=19, ...}) = 0 open("/var/www/html/x.php", O_RDONLY|O_LARGEFILE) = -1 EACCES (Permission denied) --- SIGSEGV (Segmentation fault) @ 0 (0) ---
Updated by darix over 17 years ago
can you try to reproduce it with http://zen.sh.nu/~darix/lighttpd-1.4.x.r1745.tar.gz.
i cant reproduce it here.
do you have follow-symlinks enabled or disabled?
in my setup i had php running via external spawning.
Updated by scroffer52 over 17 years ago
The problem exists too in r1745, compiled with identical options.
But... I've now traced this by simplifying my configuration:
The offending lines in my configuration are:
compress.cache-dir = "/var/cache/lighttpd/compress/" compress.filetype = ("text/plain", "text/html") compress.max-filesize = 1024000
That compression directory isn't writable by the su-execed user; but I don't think that should matter (as mod_compress doesn't touch PHP output anyway, and as mod_compress is running as the correct user). In any case, changing it to a 777-ed directory doesn't fix the segfault.
Without those lines, no segfault. With those lines, a segfault happens.
Updated by scroffer52 over 17 years ago
Sorry - forgot to mention that I'm not using follow-symlinks anywhere, so it must be the default (on?).
Updated by scroffer52 over 17 years ago
Here's what I got from valgrind:
==3501== Invalid read of size 4 ==3501== at 0x44F69DE: (within /usr/lib/lighttpd/mod_compress.so) ==3501== by 0x805F4D4: plugins_call_handle_subrequest_start (in /usr/sbin/lighttpd) ==3501== by 0x804FDCA: http_response_prepare (in /usr/sbin/lighttpd) ==3501== by 0x8052CB4: connection_state_machine (in /usr/sbin/lighttpd) ==3501== by 0x8053C9B: network_server_handle_fdevent (in /usr/sbin/lighttpd) ==3501== by 0x804E4CE: main (in /usr/sbin/lighttpd) ==3501== Address 0x38 is not stack'd, malloc'd or (recently) free'd ==3501== ==3501== Process terminating with default action of signal 11 (SIGSEGV) ==3501== Access not within mapped region at address 0x38 ==3501== at 0x44F69DE: (within /usr/lib/lighttpd/mod_compress.so) ==3501== by 0x805F4D4: plugins_call_handle_subrequest_start (in /usr/sbin/lighttpd) ==3501== by 0x804FDCA: http_response_prepare (in /usr/sbin/lighttpd) ==3501== by 0x8052CB4: connection_state_machine (in /usr/sbin/lighttpd) ==3501== by 0x8053C9B: network_server_handle_fdevent (in /usr/sbin/lighttpd) ==3501== by 0x804E4CE: main (in /usr/sbin/lighttpd) --3501-- discard syms at 0x451C000-0x4527000 in /lib/libnss_files-2.3.4.so due to munmap()
Updated by scroffer52 over 17 years ago
Do the lighttpd developers count this as a low-priority bug?
I was expecting a consistently remotely exploitable crash to be the kind of thing that was a level 1 priority!
Updated by stbuehler over 16 years ago
I couldn't reproduce it either; if open (in stat_cache_get_entry) fails with EACCES, lighty returns 403 Forbidden and does not start mod_compress.
If you still have trouble with this in the current version, please provide a backtracke of a debug build (so we have the line number in which the segfault happens).
Updated by stbuehler over 16 years ago
- Status changed from Assigned to Fixed
- Resolution set to worksforme
Missing feedback.
Updated by stbuehler about 16 years ago
- Status changed from Fixed to Missing Feedback
Also available in: Atom