Technical details of the CVE-2013-4365 mod_fcgid bug

This post is technical, and intended for programmers and security experts — it doesn’t affect our customers.

A few weeks back, one of our hosting customers had a PHP script that would constantly crash an Apache Web server process. We spent a while tracking down the cause, and eventually found a bug in the excellent Apache mod_fcgid FastCGI software that was causing it.

The bug corrupts the memory of the Apache process, which is potentially a security issue, so it was assigned CVE-2013-4365.

The Apache description of the bug fix doesn’t really explain much, though, and the original bug report wasn’t made public because of the security implications. I thought I’d spend a few minutes describing the problem for anyone searching the Internet for technical details.

The basic problem is that you can crash an Apache process running mod_fcgid with this trivial one-line PHP script:

error_log(str_repeat("x", 20000));

The crash happens in fcgid_header_bucket_read() of fcgid_bucket.c, which does a memcpy of the 20000 bytes into an 8000 byte buffer.

In the “if (header.type == FCGI_STDERR)” section beginning at line 112, the code allocates a buffer of APR_BUCKET_BUFF_SIZE, which is 8000 bytes. However, the FastCGI spec says that the message can be up to 65535 bytes.

fcgid_header_bucket_read() then uses fcgid_feed_data() to read in a loop from the FastCGI record in FCGID_FEED_LEN chunks, where FCGID_FEED_LEN is 8192. The code has protection to prevent it from overflowing the 8000 byte buffer if it reads between 8000 and 8192 bytes the first time through the loop: On an initial read of 8192 bytes, willput will be 7999, preventing a buffer overflow (the remaining 193 bytes are discarded).

However, it does not have protection against overwriting the buffer on the second time through the loop. If it reads 8192 bytes a second time, then “hasread” will be 8192 and the result of “APR_BUCKET_BUFF_SIZE – hasread – 1” will be negative (8000 – 8192 – 1 = -193). But fcgid_min treats that as a large unsigned positive number and returns the value of canput instead, which will be 8192.

So when it reads 20000 bytes total, the loop ends up doing:

memcpy(logbuf + 0, buffer, 7999);
memcpy(logbuf + 8192, buffer, 8192);
memcpy(logbuf + 16384, buffer, 3616);

… which is obviously bad since logbuf is only 8000 bytes.

This may not seem much of a security issue, because a remote attacker can’t usually control what gets sent to the error log. However, in the original crash we saw, the remote client was (unknowingly) controlling it: The large error log entry was caused by a WordPress plugin that logged a copy of “spam” data passed to it, complete with 8-bit characters. So a security problem is unlikely, but not impossible.

The patch fixes the crash by discarding the extra bytes beyond 7999 because the willput parameter passed to memcpy ends up being zero once hasput reaches 7999. This perhaps isn’t the most obvious way to do it, but it follows the intended logic of the original code with minimal changes.

Anyway, at the very least, the patch avoids a reproducible segfault crash that was orphaning FastCGI slots in the “busy” state until an Apache reload. If you use mod_fcgid on your own servers, and you’re seeing that problem, this is likely the cause.