haproxy/include/proto
Willy Tarreau 379357af58 BUG/MAJOR: http: always ensure response buffer has some room for a response
Since 1.5-dev12 and commit 3bf1b2b8 (MAJOR: channel: stop relying on
BF_FULL to take action), the HTTP parser switched to channel_full()
instead of BF_FULL to decide whether a buffer had enough room to start
parsing a request or response. The problem is that channel_full()
intentionally ignores outgoing data, so a corner case exists where a
large response might still be left in a response buffer with just a
few bytes left (much less than the reserve), enough to accept a second
response past the last data, but not enough to permit the HTTP processor
to add some headers. Since all the processing relies on this space being
available, we can get some random crashes when clients pipeline requests.

The analysis of a core from haproxy configured with 20480 bytes buffers
shows this : with enough "luck", when sending back the response for the
first request, the client is slow, the TCP window is congested, the socket
buffers are full, and haproxy's buffer fills up. We still have 20230 bytes
of response data in a 20480 response buffer. The second request is sent to
the server which returns 214 bytes which fit in the small 250 bytes left
in this buffer. And the buffer arrangement makes it possible to escape all
the controls in http_wait_for_response() :

    |<------ response buffer = 20480 bytes ------>|
    [ 2/2  | 3 | 4 |          1/2                 ]
           ^ start of circular buffer

      1/2 = beginning of previous response (18240)
      2/2 = end of previous response       (1990)
        3 = current response               (214)
        4 = free space                     (36)

  - channel_full() returns false (20230 bytes are going to leave)
  - the response headers does not wrap at the end of the buffer
  - the remaining linear room after the headers is larger than the
    reserve, because it's the previous response which wraps :
  => response is processed

Header rewriting causes it to reach 260 bytes, 10 bytes larger than what
the buffer could hold. So all computations during header addition are
wrong and lead to the corruption we've observed.

All the conditions are very hard to meet (which explains why it took
almost one year for this bug to show up) and are almost impossible to
reproduce on purpose on a test platform. But the bug is clearly there.

This issue was reported by Dinko Korunic who kindly devoted a lot of
time to provide countless traces and cores, and to experiment with
troubleshooting patches to knock the bug down. Thanks Dinko!

No backport is needed, but all 1.5-dev versions between dev12 and dev18
included must be upgraded. A workaround consists in setting option
forceclose to prevent pipelined requests from being processed.
2013-06-08 13:14:17 +02:00
..
acl.h MAJOR: sample: maintain a per-proxy list of the fetch args to resolve 2013-04-03 02:13:02 +02:00
arg.h MAJOR: sample: maintain a per-proxy list of the fetch args to resolve 2013-04-03 02:13:02 +02:00
auth.h MAJOR: acl: make use of the new sample struct and get rid of acl_test 2012-05-08 20:57:14 +02:00
backend.h REORG/MAJOR: use "struct channel" instead of "struct buffer" 2012-09-02 21:54:55 +02:00
channel.h BUG/MAJOR: http: always ensure response buffer has some room for a response 2013-06-08 13:14:17 +02:00
checks.h MINOR: cli: report connection status in "show sess xxx" 2012-11-19 16:22:22 +01:00
compression.h MINOR: compression: CPU usage limit 2012-11-21 02:15:16 +01:00
connection.h BUG/MEDIUM: connection: always update connection flags prior to computing polling 2012-12-17 01:14:25 +01:00
cttproxy.h [MEDIUM] check for cttproxy support when required 2007-03-24 17:24:39 +01:00
dumpstats.h MEDIUM: stats: add proxy name filtering on the statistic page 2013-04-15 22:50:33 +02:00
fd.h OPTIM: poll: optimize fd management functions for low register count CPUs 2012-12-13 23:34:18 +01:00
freq_ctr.h [MINOR] freq_ctr: add new types and functions for periods different from 1s 2010-08-10 14:01:09 +02:00
frontend.h REORG: connection: move the PROXY protocol management to connection.c 2012-10-05 00:32:33 +02:00
hdr_idx.h OPTIM/MINOR: move the hdr_idx pools out of the proxy struct 2011-10-24 18:15:04 +02:00
lb_chash.h [MEDIUM] backend: implement consistent hashing variation 2009-10-09 07:17:58 +02:00
lb_fas.h MEDIUM: backend: add the 'first' balancing algorithm 2012-02-21 22:27:27 +01:00
lb_fwlc.h [CLEANUP] backend: move LB algos to individual files 2009-10-01 11:19:37 +02:00
lb_fwrr.h [CLEANUP] backend: move LB algos to individual files 2009-10-01 11:19:37 +02:00
lb_map.h [MINOR] lb_map: reorder code in order to ease integration of new hash functions 2009-10-01 21:11:15 +02:00
listener.h REORG: listener: move unix perms from the listener to the bind_conf 2012-09-20 18:07:14 +02:00
log.h MINOR: log: indicate it when some unreliable sample fetches are logged 2013-04-03 02:12:56 +02:00
obj_type.h MINOR: stats: add a few more information on session dump 2012-12-08 17:48:47 +01:00
payload.h MEDIUM: samples: move payload-based fetches and ACLs to their own file 2013-04-03 02:12:57 +02:00
peers.h [CLEANUP] peers.h: fix declarations 2011-06-18 20:27:19 +02:00
pipe.h [MEDIUM] introduce pipe pools 2009-01-25 13:49:53 +01:00
port_range.h [MEDIUM] add support for binding to source port ranges during connect 2009-06-10 12:23:32 +02:00
proto_http.h REORG: config: move the http redirect rule parser to proto_http.c 2012-12-28 14:47:19 +01:00
proto_tcp.h MINOR: counters: make it easier to extend the amount of tracked counters 2013-05-28 17:43:40 +02:00
proto_uxst.h BUG/MEDIUM: stream_interface: restore get_src/get_dst 2012-05-11 16:48:10 +02:00
protocol.h REORG: split "protocols" files into protocol and listener 2012-09-15 22:29:32 +02:00
proxy.h REORG: split "protocols" files into protocol and listener 2012-09-15 22:29:32 +02:00
queue.h BUG/MEDIUM: zero-weight servers must not dequeue requests from the backend 2012-01-20 16:18:53 +01:00
raw_sock.h REORG: connection: rename the data layer the "transport layer" 2012-10-04 22:26:09 +02:00
sample.h MAJOR: sample: maintain a per-proxy list of the fetch args to resolve 2013-04-03 02:13:02 +02:00
server.h MEDIUM: server: Break out set weight processing code 2013-02-13 10:53:40 +01:00
session.h MINOR: counters: make it easier to extend the amount of tracked counters 2013-05-28 17:43:40 +02:00
shctx.h MINOR: ssl: Setting global tune.ssl.cachesize value to 0 disables SSL session cache. 2012-12-28 14:48:13 +01:00
signal.h CLEANUP: includes: fix includes for a number of users of fd.h 2012-09-03 20:49:14 +02:00
ssl_sock.h MEDIUM: log: report SSL ciphers and version in logs using logformat %sslc/%sslv 2012-10-12 20:48:51 +02:00
stick_table.h MEDIUM: stick-table: allocate the table key of size buffer size 2012-10-29 21:56:59 +01:00
stream_interface.h MINOR: stats: add a few more information on session dump 2012-12-08 17:48:47 +01:00
task.h [MAJOR] proxy: finally get rid of maintain_proxies() 2011-07-25 16:33:49 +02:00
template.h [CLEANUP] included common/version.h everywhere 2006-06-29 18:54:54 +02:00