From: Tim Duesterhus Date: Thu, 3 Jan 2019 23:11:59 +0000 (+0100) Subject: BUG/MINOR: stick_table: Prevent conn_cur from underflowing X-Git-Tag: v2.0-dev1~201 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8b87c01c4d59247d9fb51a38cd12d5d94324b6a4;p=thirdparty%2Fhaproxy.git BUG/MINOR: stick_table: Prevent conn_cur from underflowing When using the peers feature a race condition could prevent a connection from being properly counted. When this connection exits it is being "uncounted" nonetheless, leading to a possible underflow (-1) of the conn_curr stick table entry in the following scenario : - Connect to peer A (A=1, B=0) - Peer A sends 1 to B (A=1, B=1) - Kill connection to A (A=0, B=1) - Connect to peer B (A=0, B=2) - Peer A sends 0 to B (A=0, B=0) - Peer B sends 0/2 to A (A=?, B=0) - Kill connection to B (A=?, B=-1) - Peer B sends -1 to A (A=-1, B=-1) This fix may be backported to all supported branches. --- diff --git a/include/proto/session.h b/include/proto/session.h index d54e9454b5..0b7d08d995 100644 --- a/include/proto/session.h +++ b/include/proto/session.h @@ -62,7 +62,8 @@ static inline void session_store_counters(struct session *sess) if (ptr) { HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock); - stktable_data_cast(ptr, conn_cur)--; + if (stktable_data_cast(ptr, conn_cur) > 0) + stktable_data_cast(ptr, conn_cur)--; HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); diff --git a/include/proto/stream.h b/include/proto/stream.h index f448209770..a8c2992142 100644 --- a/include/proto/stream.h +++ b/include/proto/stream.h @@ -103,7 +103,8 @@ static inline void stream_store_counters(struct stream *s) if (ptr) { HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock); - stktable_data_cast(ptr, conn_cur)--; + if (stktable_data_cast(ptr, conn_cur) > 0) + stktable_data_cast(ptr, conn_cur)--; HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); @@ -141,7 +142,8 @@ static inline void stream_stop_content_counters(struct stream *s) if (ptr) { HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock); - stktable_data_cast(ptr, conn_cur)--; + if (stktable_data_cast(ptr, conn_cur) > 0) + stktable_data_cast(ptr, conn_cur)--; HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);