]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: channel: bi_putblk() must not wrap before the end of buffer
authorWilly Tarreau <w@1wt.eu>
Thu, 24 Apr 2014 15:02:57 +0000 (17:02 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 24 Apr 2014 15:19:21 +0000 (17:19 +0200)
The errors reported by Igor Chan on the stats interface in chunked mode
were caused by data wrapping at the wrong place in the buffer. It could
be reliably reproduced by picking random buffer sizes until the issue
appeared (for a given conf, 5300 with 1024 maxrewrite was OK).

The issue is that the stats interface uses bi_putchk() to emit data,
which relies on bi_putblk(). This code checks the largest part that can
be emitted while preserving the rewrite reserve, but uses that result to
compute the wrapping offset, which is wrong. If some data remain present
in the buffer, the wrapping may be allowed and will happen before the
end of the buffer, leaving some old data in the buffer.

The reason it did not happen before keep-alive is simply that the buffer
was much less likely to contain older data. It also used to happen only
for certain configs after a certain amount of time because the size of
the counters used to inflate the output till the point wrapping started
to happen.

The fix is trivial, buffer_contig_space_with_res() simply needs to be
replaced by buffer_contig_space().

Note that peers were using the same function so it is possible that they
were affected as well.

This issue was introduced in 1.5-dev8. No backport to stable is needed.

src/channel.c

index 1250370767a04d8f73c502c11a5003ec5c00a233..2f983960db867a018dd8e7256d2ae93d4f32ab2a 100644 (file)
@@ -174,7 +174,7 @@ int bi_putblk(struct channel *chn, const char *blk, int len)
                return 0;
 
        /* OK so the data fits in the buffer in one or two blocks */
-       max = buffer_contig_space_with_res(chn->buf, chn->buf->size - max);
+       max = buffer_contig_space(chn->buf);
        memcpy(bi_end(chn->buf), blk, MIN(len, max));
        if (len > max)
                memcpy(chn->buf->data, blk + max, len - max);