Page MenuHomePhabricator
Paste P158

apache_sucks.php
ActivePublic

Authored by Joe on Dec 16 2014, 12:15 PM.
Tags
None
Referenced Files
F21392: apache_sucks.php
Dec 16 2014, 12:15 PM
Subscribers
None
<?php
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) header('Last-Modified: '.$_SERVER['HTTP_IF_MODIFIED_SINCE']);
echo str_repeat('x', (int) $_GET['len']);

Event Timeline

Joe changed the title of this paste from untitled to apache_sucks.php.
Joe updated the paste's language from autodetect to php.

Say we have any php fastcgi server (either HHVM or php-fpm), and we configure an apache vhost to do

ProxyPass /crash fastcgi://127.0.0.1:9000/my/docroot/apache_sucks.php retry=0

We can trigger the bug by calling

curl localhost/crash -v -H 'If-Modified-Since: Thu, 16 Oct 2014 09:12:36 GMT'

results in a log line as follows:

[Tue Dec 16 12:14:11.927301 2014] [proxy_fcgi:error] [pid 12871:tid 140613529855744] [client 127.0.0.1:58351] AH01070: Error parsing script headers

when the total response length exceeds 8192 bytes (so it's fragmented in more than one packet), e.g.:

curl localhost/crash?len=8081 -v -H 'If-Modified-Since: Thu, 16 Oct 2014 09:12:36 GMT'

it also causes curl to output this error:

* Excess found in a non pipelined read: excess = 373 url = /crash?len=8081 (zero-length body)

because the preset error page is returned as a body (!!!). In the logs we find

[Tue Dec 16 12:14:35.374423 2014] [proxy_fcgi:error] [pid 12872:tid 140613708728064] [client 127.0.0.1:58393] AH01070: Error parsing script headers
[Tue Dec 16 12:14:35.374470 2014] [proxy_fcgi:error] [pid 12872:tid 140613708728064] [client 127.0.0.1:58393] AH01068: Got bogus version 1
[Tue Dec 16 12:14:35.374476 2014] [proxy_fcgi:error] [pid 12872:tid 140613708728064] (22)Invalid argument: [client 127.0.0.1:58393] AH01075: Error dispatching request to :

and in the access.log:

127.0.0.1 - - [16/Dec/2014:12:14:35 +0000] "GET /crash?len=8081 HTTP/1.1" 503 470 "-" "curl/7.35.0"

but the client received a "304 Not Modified" response, so most clients (and Varnish, luckily, among those) do the right thing.

In fact, if using telnet, we get:

HTTP/1.1 304 Not Modified
Date: Tue, 16 Dec 2014 12:27:43 GMT
Server: Apache/2.4.7 (Ubuntu)
Connection: close

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>503 Service Unavailable</title>
</head><body>
<h1>Service Unavailable</h1>
<p>The server is temporarily unable to service your
request due to maintenance downtime or capacity
problems. Please try again later.</p>
<hr>
<address>Apache/2.4.7 (Ubuntu) Server at hhvm-img.eqiad.wmflabs Port 80</address>
</body></html>
Connection closed by foreign host.

And we don't get the "error dispatching request" line, because telnet will not disconnect after the headers are received.

This is clearly a bug in how mod_proxy_fastcgi handles the parsing of fastcgi packets when the final response should be 304.