From d58b220e564c00c9b4f3cfa8d5d5848e1c808713 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Sep 24 2014 04:25:31 +0000 Subject: import haproxy-1.5.2-3.el7_0 --- diff --git a/SOURCES/haproxy-dont-update-msg-sov.patch b/SOURCES/haproxy-dont-update-msg-sov.patch new file mode 100644 index 0000000..098073a --- /dev/null +++ b/SOURCES/haproxy-dont-update-msg-sov.patch @@ -0,0 +1,106 @@ +From b4d05093bc89f71377230228007e69a1434c1a0c Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Mon, 1 Sep 2014 20:35:55 +0200 +Subject: [PATCH] BUG/CRITICAL: http: don't update msg->sov once data start to + leave the buffer + +Commit bb2e669 ("BUG/MAJOR: http: correctly rewind the request body +after start of forwarding") was incorrect/incomplete. It used to rely on +CF_READ_ATTACHED to stop updating msg->sov once data start to leave the +buffer, but this is unreliable because since commit a6eebb3 ("[BUG] +session: clear BF_READ_ATTACHED before next I/O") merged in 1.5-dev1, +this flag is only ephemeral and is cleared once all analysers have +seen it. So we can start updating msg->sov again each time we pass +through this place with new data. With a sufficiently large amount of +data, it is possible to make msg->sov wrap and validate the if() +condition at the top, causing the buffer to advance by about 2GB and +crash the process. + +Note that the offset cannot be controlled by the attacker because it is +a sum of millions of small random sizes depending on how many bytes were +read by the server and how many were left in the buffer, only because +of the speed difference between reading and writing. Also, nothing is +written, the invalid pointer resulting from this operation is only read. + +Many thanks to James Dempsey for reporting this bug and to Chris Forbes for +narrowing down the faulty area enough to make its root cause analysable. + +This fix must be backported to haproxy 1.5. +(cherry picked from commit a2d002aeb669a9bbca2dcd3e6be71615f435e9e6) +--- + include/types/channel.h | 2 +- + src/proto_http.c | 8 ++++---- + src/stream_interface.c | 4 ++-- + 3 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/include/types/channel.h b/include/types/channel.h +index 88a52a4..8bc3958 100644 +--- a/include/types/channel.h ++++ b/include/types/channel.h +@@ -105,7 +105,7 @@ + #define CF_STREAMER 0x00010000 /* the producer is identified as streaming data */ + #define CF_STREAMER_FAST 0x00020000 /* the consumer seems to eat the stream very fast */ + +-/* unused: 0x00040000 */ ++#define CF_WROTE_DATA 0x00040000 /* some data were sent from this buffer */ + #define CF_ANA_TIMEOUT 0x00080000 /* the analyser timeout has expired */ + #define CF_READ_ATTACHED 0x00100000 /* the read side is attached for the first time */ + #define CF_KERN_SPLICING 0x00200000 /* kernel splicing desired for this channel */ +diff --git a/src/proto_http.c b/src/proto_http.c +index a47f0a1..4d27b2c 100644 +--- a/src/proto_http.c ++++ b/src/proto_http.c +@@ -4886,8 +4886,8 @@ void http_end_txn_clean_session(struct session *s) + s->req->cons->conn_retries = 0; /* used for logging too */ + s->req->cons->exp = TICK_ETERNITY; + s->req->cons->flags &= SI_FL_DONT_WAKE; /* we're in the context of process_session */ +- s->req->flags &= ~(CF_SHUTW|CF_SHUTW_NOW|CF_AUTO_CONNECT|CF_WRITE_ERROR|CF_STREAMER|CF_STREAMER_FAST|CF_NEVER_WAIT|CF_WAKE_CONNECT); +- s->rep->flags &= ~(CF_SHUTR|CF_SHUTR_NOW|CF_READ_ATTACHED|CF_READ_ERROR|CF_READ_NOEXP|CF_STREAMER|CF_STREAMER_FAST|CF_WRITE_PARTIAL|CF_NEVER_WAIT); ++ s->req->flags &= ~(CF_SHUTW|CF_SHUTW_NOW|CF_AUTO_CONNECT|CF_WRITE_ERROR|CF_STREAMER|CF_STREAMER_FAST|CF_NEVER_WAIT|CF_WAKE_CONNECT|CF_WROTE_DATA); ++ s->rep->flags &= ~(CF_SHUTR|CF_SHUTR_NOW|CF_READ_ATTACHED|CF_READ_ERROR|CF_READ_NOEXP|CF_STREAMER|CF_STREAMER_FAST|CF_WRITE_PARTIAL|CF_NEVER_WAIT|CF_WROTE_DATA); + s->flags &= ~(SN_DIRECT|SN_ASSIGNED|SN_ADDR_SET|SN_BE_ASSIGNED|SN_FORCE_PRST|SN_IGNORE_PRST); + s->flags &= ~(SN_CURR_SESS|SN_REDIRECTABLE|SN_SRV_REUSED); + +@@ -5430,7 +5430,7 @@ int http_request_forward_body(struct session *s, struct channel *req, int an_bit + * such as last chunk of data or trailers. + */ + b_adv(req->buf, msg->next); +- if (unlikely(!(s->rep->flags & CF_READ_ATTACHED))) ++ if (unlikely(!(s->req->flags & CF_WROTE_DATA))) + msg->sov -= msg->next; + msg->next = 0; + +@@ -5482,7 +5482,7 @@ int http_request_forward_body(struct session *s, struct channel *req, int an_bit + missing_data: + /* we may have some pending data starting at req->buf->p */ + b_adv(req->buf, msg->next); +- if (unlikely(!(s->rep->flags & CF_READ_ATTACHED))) ++ if (unlikely(!(s->req->flags & CF_WROTE_DATA))) + msg->sov -= msg->next + MIN(msg->chunk_len, req->buf->i); + + msg->next = 0; +diff --git a/src/stream_interface.c b/src/stream_interface.c +index 67a5234..9f7e979 100644 +--- a/src/stream_interface.c ++++ b/src/stream_interface.c +@@ -658,7 +658,7 @@ static void si_conn_send(struct connection *conn) + if (chn->pipe && conn->xprt->snd_pipe) { + ret = conn->xprt->snd_pipe(conn, chn->pipe); + if (ret > 0) +- chn->flags |= CF_WRITE_PARTIAL; ++ chn->flags |= CF_WRITE_PARTIAL | CF_WROTE_DATA; + + if (!chn->pipe->data) { + put_pipe(chn->pipe); +@@ -702,7 +702,7 @@ static void si_conn_send(struct connection *conn) + + ret = conn->xprt->snd_buf(conn, chn->buf, send_flag); + if (ret > 0) { +- chn->flags |= CF_WRITE_PARTIAL; ++ chn->flags |= CF_WRITE_PARTIAL | CF_WROTE_DATA; + + if (!chn->buf->o) { + /* Always clear both flags once everything has been sent, they're one-shot */ +-- +1.9.3 + diff --git a/SPECS/haproxy.spec b/SPECS/haproxy.spec index b2de127..20c2e60 100644 --- a/SPECS/haproxy.spec +++ b/SPECS/haproxy.spec @@ -8,7 +8,7 @@ Name: haproxy Version: 1.5.2 -Release: 2%{?dist} +Release: 3%{?dist} Summary: HA-Proxy is a TCP/HTTP reverse proxy for high availability environments Group: System Environment/Daemons @@ -21,6 +21,7 @@ Source2: %{name}.cfg Source3: %{name}.logrotate Patch0: halog-unused-variables.patch +Patch1: haproxy-dont-update-msg-sov.patch BuildRequires: pcre-devel BuildRequires: zlib-devel @@ -48,6 +49,7 @@ availability environments. Indeed, it can: %prep %setup -q %patch0 -p0 +%patch1 -p1 %build # No configure script is present, it is all done via make flags @@ -136,6 +138,9 @@ exit 0 %attr(-,%{haproxy_user},%{haproxy_group}) %dir %{haproxy_home} %changelog +* Thu Sep 04 2014 Ryan O'Hara - 1.5.2-3 +- Fix remote client denial of service vulnerability (#1138191) + * Thu Jul 31 2014 Ryan O'Hara - 1.5.2-2 - Bump release number (#1120228)