]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MAJOR: buffer: check the space left is enough or not when input data in a buffer...
authorGodbach <nylzhaowei@gmail.com>
Fri, 31 Oct 2014 05:16:37 +0000 (13:16 +0800)
committerWilly Tarreau <w@1wt.eu>
Fri, 31 Oct 2014 06:39:34 +0000 (07:39 +0100)
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 <nylzhaowei@gmail.com>
src/buffer.c

index 91bee637be25a8fa71e24e7b747fc9cfca68822f..9037dd3febfce042529ca8640432f7ddd8977dee 100644 (file)
@@ -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);