From: Godbach Date: Fri, 31 Oct 2014 05:16:37 +0000 (+0800) Subject: BUG/MAJOR: buffer: check the space left is enough or not when input data in a buffer... X-Git-Tag: v1.6-dev1~280 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a6547c1338ab139332a66096d449e7ac1a56a591;p=thirdparty%2Fhaproxy.git BUG/MAJOR: buffer: check the space left is enough or not when input data in a buffer is wrapped HAProxy will crash with the following configuration: global ... tune.bufsize 1024 tune.maxrewrite 0 frontend xxx ... backend yyy ... cookie cookie insert maxidle 300s If client sends a request of which object size is more than tune.bufsize (1024 bytes), HAProxy will crash. After doing some debugging, the crash was caused by http_header_add_tail2() -> buffer_insert_line2() while inserting cookie at the end of response header. Part codes of buffer_insert_line2() are as below: int buffer_insert_line2(struct buffer *b, char *pos, const char *str, int len) { int delta; delta = len + 2; if (bi_end(b) + delta >= b->data + b->size) return 0; /* no space left */ /* first, protect the end of the buffer */ memmove(pos + delta, pos, bi_end(b) - pos); ... } Since tune.maxrewrite is 0, HAProxy can receive 1024 bytes once which is equals to full buffer size. Under such condition, the buffer is full and bi_end(b) will be wrapped to the start of buffer which pointed to b->data. As a result, though there is no space left in buffer, the check condition if (bi_end(b) + delta >= b->data + b->size) will be true, then memmove() is called, and (pos + delta) will exceed the end of buffer (b->data + b->size), HAProxy crashes Just take buffer_replace2() as a reference, the other check when input data in a buffer is wrapped should be also added into buffer_insert_line2(). This fix must be backported to 1.5. Signed-off-by: Godbach --- diff --git a/src/buffer.c b/src/buffer.c index 91bee637be..9037dd3feb 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -88,6 +88,11 @@ int buffer_insert_line2(struct buffer *b, char *pos, const char *str, int len) if (bi_end(b) + delta >= b->data + b->size) return 0; /* no space left */ + if (buffer_not_empty(b) && + bi_end(b) + delta > bo_ptr(b) && + bo_ptr(b) >= bi_end(b)) + return 0; /* no space left before wrapping data */ + /* first, protect the end of the buffer */ memmove(pos + delta, pos, bi_end(b) - pos);