From: Willy Tarreau Date: Wed, 20 Apr 2016 18:09:22 +0000 (+0200) Subject: BUG/MEDIUM: channel: don't allow to overwrite the reserve until connected X-Git-Tag: v1.7-dev3~25 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4b46a3e8cce58db03ee90718e39fb3bffb2b7273;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: channel: don't allow to overwrite the reserve until connected Commit 9c06ee4 ("BUG/MEDIUM: channel: don't schedule data in transit for leaving until connected") took care of an issue involving POST in conjunction with http-send-name-header, where we absolutely never want to touch the reserve until we're sure not to touch the buffer contents anymore, which is indicated by the output stream-interface being connected. But channel_may_recv() was not equipped with such a test, so in some situations it might decide that it is possible to poll for reads, and later channel_recv_limit() will decide it's not possible to read, causing a loop. So we must add a similar test there. Since the fix above was backported to 1.6 and 1.5, this fix must as well. --- diff --git a/include/proto/channel.h b/include/proto/channel.h index 31993faf45..76754e18ff 100644 --- a/include/proto/channel.h +++ b/include/proto/channel.h @@ -165,7 +165,9 @@ static inline int channel_may_send(const struct channel *chn) * end of transfer is close to happen. Note that both ->buf->o and ->to_forward * are considered as available since they're supposed to leave the buffer. The * test is optimized to avoid as many operations as possible for the fast case - * and to be used as an "if" condition. + * and to be used as an "if" condition. Just like channel_recv_limit(), we + * never allow to overwrite the reserve until the output stream interface is + * connected, otherwise we could spin on a POST with http-send-name-header. */ static inline int channel_may_recv(const struct channel *chn) { @@ -179,6 +181,9 @@ static inline int channel_may_recv(const struct channel *chn) if (!rem) return 0; /* buffer already full */ + if (rem <= global.tune.maxrewrite && !channel_may_send(chn)) + return 0; + /* now we know there's some room left, verify if we're touching * the reserve with some permanent input data. */