mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-21 22:01:31 +02:00
Vedran Furac reported a strange problem where the "base" sample fetch would not always work for tracking purposes. In fact, it happens that commit bc8c404 ("MAJOR: stick-tables: use sample types in place of dedicated types") merged in 1.6 exposed a fundamental bug related to the way samples use chunks as strings. The problem is that chunks convey a base pointer, a length and an optional size, which may be zero when unknown or when the chunk is allocated from a read-only location. The sole purpose of this size is to know whether or not the chunk may be appended new data. This size cause some semantics issue in the sample, which has its own SMP_F_CONST flag to indicate read-only contents. The problem was emphasized by the commit above because it made use of new calls to smp_dup() to convert a sample to a table key. And since smp_dup() would only check the SMP_F_CONST flag, it would happily return read-write samples indicating size=0. So some tests were added upon smp_dup() return to ensure that the actual length is smaller than size, but this in fact made things even worse. For example, the "sni" server directive does some bad stuff on many occasions because it limits len to size-1 and effectively sets it to -1 and writes the zero byte before the beginning of the string! It is therefore obvious that smp_dup() needs to be modified to take this nature of the chunks into account. It's not enough but is needed. The core of the problem comes from the fact that smp_dup() is called for 5 distinct needs which are not always fulfilled : 1) duplicate a sample to keep a copy of it during some operations 2) ensure that the sample is rewritable for a converter like upper() 3) ensure that the sample is terminated with a \0 4) set a correct size on the sample 5) grow the sample in case it was extracted from a partial chunk Case 1 is not used for now, so we can ignore it. Case 2 indicates the wish to modify the sample, so its R/O status must be removed if any, but there's no implied requirement that the chunk becomes larger. Case 3 is used when the sample has to be made compatible with libc's str* functions. There's no need to make it R/W nor to duplicate it if it is already correct. Case 4 can happen when the sample's size is required (eg: before performing some changes that must fit in the buffer). Case 5 is more or less similar but will happen when the sample by be grown but we want to ensure we're not bound by the current small size. So the proposal is to have different functions for various operations. One will ensure a sample is safe for use with str* functions. Another one will ensure it may be rewritten in place. And smp_dup() will have to perform an inconditional duplication to guarantee at least #5 above, and implicitly all other ones. This patch only modifies smp_dup() to make the duplication inconditional. It is enough to fix both the "base" sample fetch and the "sni" server directive, and all use cases in general though not always optimally. More patches will follow to address them more optimally and even better than the current situation (eg: avoid a dup just to add a \0 when possible). The bug comes from an ambiguous design, so its roots are old. 1.6 is affected and a backport is needed. In 1.5, the function already existed but was only used by two converters modifying the data in place, so the bug has no effect there.