From: Willy Tarreau Date: Mon, 7 Sep 2015 17:32:33 +0000 (+0200) Subject: BUG/MAJOR: http: don't call http_send_name_header() after an error X-Git-Tag: v1.6-dev5~22 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9c03b33329cb4924716edc1c851913a18b0670dc;p=thirdparty%2Fhaproxy.git BUG/MAJOR: http: don't call http_send_name_header() after an error A crash was reported when using the "famous" http-send-name-header directive. This time it's a bit tricky, it requires a certain number of conditions to be met including maxconn on a server, queuing, timeout in the queue and cookie-based persistence. The problem is that in stream.c, before calling http_send_name_header(), we check a number of conditions to know if we have to replace the header name. But prior to reaching this place, it's possible for sess_update_stream_int() to fail and change the stream-int's state to SI_ST_CLO, send an error 503 to the client, and flush all buffers. But http_send_name_header() can only be called with valid buffer contents matching the http_msg's description. So when it rewinds the stream to modify the header, buf->o becomes negative by the size of the incoming request and is used as the argument to memmove() which basically displaces 4GB of memory off a few bytes to write the new name, resulting in a core and a core file that's really not fun to play with. The solution obviously consists in refraining from calling this nasty function when the stream interface is already closed. This bug also affects 1.5 and possibly 1.4, so the fix must be backported there. --- diff --git a/src/stream.c b/src/stream.c index b8973544f2..dadb80f703 100644 --- a/src/stream.c +++ b/src/stream.c @@ -2119,7 +2119,7 @@ struct task *process_stream(struct task *t) /* Now we can add the server name to a header (if requested) */ /* check for HTTP mode and proxy server_name_hdr_name != NULL */ - if ((si_b->state >= SI_ST_CON) && + if ((si_b->state >= SI_ST_CON) && (si_b->state < SI_ST_CLO) && (s->be->server_id_hdr_name != NULL) && (s->be->mode == PR_MODE_HTTP) && objt_server(s->target)) {