Project

General

Profile

Actions

Bug #2843

closed

lighttpd segfault if /var/tmp is full

Added by wolfram about 7 years ago. Updated about 7 years ago.

Status:
Fixed
Priority:
Normal
Category:
core
Target version:
ASK QUESTIONS IN Forums:

Description

I have a cgi script which creates a tarball and sent it back. The output is 50-200MB huge. I noticed that at some point the script crashed, returned truncated data and that lighttpd died with a SIGSEGV

It turns out that on my machine /var/tmp was full and lighttpd wanted to write /var/tmp/lighttpd-upload-* and could not write.

How to repeat:

Install lighttpd-1.4.45 (or lighttpd-1.4.48) on debian9

# create a small /var/tmp/ filesystem:
$ sudo mount -t tmpfs none -o size=1k /var/tmp

fill up /var/tmp
$ date > /var/tmp/date

# install the cgi script tar.cgi
#!/bin/sh
echo "Content-type: application/x-tgz" 
echo "" 
tar czf - /usr/bin

# run the cgi script
$ curl http://localhost:8080/cgi/tar.cgi | wc
Segmentation fault (core dumped)

strace output:

getpid()                                = 16128
open("/var/tmp/lighttpd-upload-V1KMfW", O_RDWR|O_CREAT|O_EXCL, 0600) = 20
fcntl(20, F_GETFL)                      = 0x8002 (flags O_RDWR|O_LARGEFILE)
fcntl(20, F_SETFL, O_RDWR|O_APPEND|O_LARGEFILE) = 0
fcntl(20, F_SETFD, FD_CLOEXEC)          = 0
write(20, "\326&\16\241@T\375Zsx\335p\22>-\350o\360\301\264n\244-\324\224\232\320\327:\340\317,"..., 16384) = -1 ENOSPC (No space left on device)
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=127, ...}) = 0
write(5, "2017-11-25 15:46:23: (chunk.c.58"..., 94) = -1 ENOSPC (No space left on device)
unlink("/var/tmp/lighttpd-upload-V1KMfW") = 0
close(20)                               = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x58} ---
+++ killed by SIGSEGV +++

gdb -core output:

Reading symbols from ./tmp/lighttpd-1.4.48/src/lighttpd...done.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x000056550a189dae in chunkqueue_remove_empty_chunks (cq=0x56550c06dfb0) at chunk.c:744
744        for (c = cq->first; c->next; c = c->next) {
(gdb) bt
#0  0x000056550a189dae in chunkqueue_remove_empty_chunks (cq=0x56550c06dfb0) at chunk.c:744
#1  chunkqueue_append_mem_to_tempfile (srv=srv@entry=0x56550c009010, dest=dest@entry=0x56550c06dfb0, 
    mem=mem@entry=0x56550c0d0300 "[...]", len=len@entry=16384) at chunk.c:604
#2  0x000056550a18a59f in http_chunk_append_to_tempfile (con=0x56550c06d9e0, con=0x56550c06d9e0, len=16384, 
    mem=0x56550c0d0300 “[...]", srv=0x56550c009010) at http_chunk.c:112
#3  http_chunk_append_data (srv=0x56550c009010, con=0x56550c06d9e0, b=<optimized out>, mem=<optimized out>, len=16384) at http_chunk.c:142
#4  0x000056550a19d490 in http_response_read (srv=srv@entry=0x56550c009010, con=0x56550c06d9e0, opts=opts@entry=0x56550c0bd7f8, b=0x56550c0bd850, fd=12, fde_ndx=fde_ndx@entry=0x56550c0bd7cc) at http-header-glue.c:1286
#5  0x00007f9edd684cc5 in cgi_recv_response (srv=0x56550c009010, hctx=0x56550c0bd7c0) at mod_cgi.c:388
#6  0x00007f9edd685623 in cgi_handle_fdevent (srv=0x56550c009010, ctx=0x56550c0bd7c0, revents=1) at mod_cgi.c:415
#7  0x000056550a179833 in server_main (srv=0x56550c009010, argc=<optimized out>, argv=<optimized out>) at server.c:1977
#8  0x000056550a17752e in main (argc=4, argv=0x7ffe986caa58) at server.c:2044
Actions #1

Updated by gstrauss about 7 years ago

  • Description updated (diff)
Actions #2

Updated by gstrauss about 7 years ago

  • Description updated (diff)
Actions #3

Updated by gstrauss about 7 years ago

  • Category set to core
  • Status changed from New to Patch Pending
  • Target version changed from 1.4.x to 1.4.49

Thank you very much for the thorough test case. Just from reviewing the code, I see that if the chunkqueue is not empty, but the last chunk is empty, then a NULL pointer dereference can occur. I'll test this further, but expect the following patch to fix it:

--- a/src/chunk.c
+++ b/src/chunk.c
@@ -741,7 +741,7 @@ static void chunkqueue_remove_empty_chunks(chunkqueue *cq) {
        chunkqueue_remove_finished_chunks(cq);
        if (chunkqueue_is_empty(cq)) return;

-       for (c = cq->first; c->next; c = c->next) {
+       for (c = cq->first; c && c->next; c = c->next) {
                if (0 == chunk_remaining_length(c->next)) {
                        chunk *empty = c->next;
                        c->next = empty->next;

Actions #4

Updated by gstrauss about 7 years ago

  • Status changed from Patch Pending to Fixed
  • % Done changed from 0 to 100
Actions

Also available in: Atom