From: Willy Tarreau Date: Fri, 9 Mar 2012 14:03:30 +0000 (+0100) Subject: MEDIUM: buffers: fix unsafe use of buffer_ignore at some places X-Git-Tag: v1.5-dev9~74 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ec1bc82a1d435923d18dae8a005b876900c91be9;p=thirdparty%2Fhaproxy.git MEDIUM: buffers: fix unsafe use of buffer_ignore at some places buffer_ignore may only be used when the output of a buffer is empty, but it's not granted it is always the case when sending HTTP error responses. Better use buffer_cut_tail() instead, and use buffer_ignore only on non-wrapping data. --- diff --git a/include/proto/buffers.h b/include/proto/buffers.h index a95e5a1f81..f35da6496a 100644 --- a/include/proto/buffers.h +++ b/include/proto/buffers.h @@ -343,17 +343,16 @@ static inline void buffer_cut_tail(struct buffer *buf) buf->flags |= BF_FULL; } -/* Cut the next unsent bytes of the buffer. The caller must ensure that - * is smaller than the actual buffer's length. This is mainly used to remove - * empty lines at the beginning of a request or a response. +/* Cut the first pending bytes in a contiguous buffer. It is illegal to + * call this function with remaining data waiting to be sent (o > 0). The + * caller must ensure that is smaller than the actual buffer's length. + * This is mainly used to remove empty lines at the beginning of a request + * or a response. */ static inline void buffer_ignore(struct buffer *buf, int n) { buf->i -= n; - buf->p = buffer_wrap_add(buf, buf->p + n); - buf->flags &= ~BF_FULL; - if (buffer_len(buf) >= buffer_max_len(buf)) - buf->flags |= BF_FULL; + buf->p += n; } /* marks the buffer as "shutdown" ASAP for reads */ diff --git a/src/proto_http.c b/src/proto_http.c index f81e71e3d9..0dc2b51d62 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -4067,7 +4067,7 @@ int http_sync_res_state(struct session *s) if (txn->rsp.msg_state == HTTP_MSG_CLOSED) { http_msg_closed: /* drop any pending data */ - buffer_ignore(buf, buf->i); + buffer_cut_tail(buf); buffer_auto_close(buf); buffer_auto_read(buf); goto wait_other_side; @@ -4133,7 +4133,7 @@ int http_resync_states(struct session *s) buffer_abort(s->req); buffer_auto_close(s->req); buffer_auto_read(s->req); - buffer_ignore(s->req, s->req->i); + buffer_cut_tail(s->req); } else if (txn->req.msg_state == HTTP_MSG_CLOSED && txn->rsp.msg_state == HTTP_MSG_DONE && @@ -4542,7 +4542,7 @@ int http_wait_for_response(struct session *s, struct buffer *rep, int an_bit) rep->analysers = 0; txn->status = 502; rep->prod->flags |= SI_FL_NOLINGER; - buffer_ignore(rep, rep->i); + buffer_cut_tail(rep); stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_502)); if (!(s->flags & SN_ERR_MASK)) @@ -4575,7 +4575,7 @@ int http_wait_for_response(struct session *s, struct buffer *rep, int an_bit) rep->analysers = 0; txn->status = 502; rep->prod->flags |= SI_FL_NOLINGER; - buffer_ignore(rep, rep->i); + buffer_cut_tail(rep); stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_502)); if (!(s->flags & SN_ERR_MASK)) @@ -4600,7 +4600,7 @@ int http_wait_for_response(struct session *s, struct buffer *rep, int an_bit) rep->analysers = 0; txn->status = 504; rep->prod->flags |= SI_FL_NOLINGER; - buffer_ignore(rep, rep->i); + buffer_cut_tail(rep); stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_504)); if (!(s->flags & SN_ERR_MASK)) @@ -4625,7 +4625,7 @@ int http_wait_for_response(struct session *s, struct buffer *rep, int an_bit) rep->analysers = 0; txn->status = 502; rep->prod->flags |= SI_FL_NOLINGER; - buffer_ignore(rep, rep->i); + buffer_cut_tail(rep); stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_502)); if (!(s->flags & SN_ERR_MASK)) @@ -4975,7 +4975,7 @@ int http_process_res_common(struct session *t, struct buffer *rep, int an_bit, s rep->analysers = 0; txn->status = 502; rep->prod->flags |= SI_FL_NOLINGER; - buffer_ignore(rep, rep->i); + buffer_cut_tail(rep); stream_int_retnclose(rep->cons, error_message(t, HTTP_ERR_502)); if (!(t->flags & SN_ERR_MASK)) t->flags |= SN_ERR_PRXCOND;