BUG/MEDIUM: chunk: Review chunks usage to not retrieve a large buffer by error

All calls to get_trash_chunk_sz() and alloc_trash_chunk_sz() were reviewed
to be sure we never retrieve a large chunk when it is not expected. Some
calls were not upgrade, but several calls now rely on get_best_trash_chunk()
and alloc_best_trash_chunk() functions.

The idea of the fix is to get a large buffer only when the original buffer
is already a large buffer and the expected size of data exceeds the size of
a regular buffer. This should prevent unexpected memory usage.

This commit relies on the previous one:

  MINOR: chunk: Add function to get a large/regular chunk depending on a buffer

Both must be backported to 3.4.
This commit is contained in:
Christopher Faulet 2026-07-06 16:34:24 +02:00
parent 2b993de2da
commit ac37158a6d
3 changed files with 30 additions and 71 deletions

View file

@ -263,7 +263,7 @@ static int sample_conv_url_dec(const struct arg *args, struct sample *smp, void
* before decoding.
*/
if (smp->flags & SMP_F_CONST || smp->data.u.str.size <= smp->data.u.str.data) {
struct buffer *str = get_trash_chunk_sz(smp->data.u.str.data + 1);
struct buffer *str = get_best_trash_chunk(&smp->data.u.str, smp->data.u.str.data+1);
if (!str)
return 0;

View file

@ -679,8 +679,8 @@ static int smp_fetch_body(const struct arg *args, struct sample *smp, const char
/* More than one DATA block we must use a trash */
if (!chk) {
smp->flags &= ~SMP_F_CONST;
chk = get_trash_chunk_sz(htx->data);
if (!chunk_istcat(chk, body))
chk = get_best_trash_chunk(&chn->buf, htx->data);
if (!chk || !chunk_istcat(chk, body))
return 0;
}
if (!chunk_istcat(chk, htx_get_blk_value(htx, blk)))
@ -2122,8 +2122,8 @@ static int smp_fetch_body_param(const struct arg *args, struct sample *smp, cons
if (isttest(body)) {
/* More than one DATA block we must use a trash */
if (!chk) {
chk = get_trash_chunk_sz(htx->data);
if (!chunk_istcat(chk, body))
chk = get_best_trash_chunk(&chn->buf, htx->data);
if (!chk || !chunk_istcat(chk, body))
break;
}
if (!chunk_istcat(chk, htx_get_blk_value(htx, blk)))

View file

@ -903,7 +903,7 @@ int smp_dup(struct sample *smp)
case SMP_T_STR:
buf = (smp->data.type == SMP_T_STR ? &smp->data.u.str : &smp->data.u.meth.str);
trash = get_trash_chunk_sz(buf->data+1);
trash = get_best_trash_chunk(buf, buf->data+1);
if (!trash)
return 0;
trash->data = buf->data;
@ -1933,7 +1933,7 @@ static int sample_conv_base64url2bin(const struct arg *arg_p, struct sample *smp
static int sample_conv_bin2base64(const struct arg *arg_p, struct sample *smp, void *private)
{
struct buffer *trash = get_trash_chunk_sz((smp->data.u.str.data+2) * 4 / 3);
struct buffer *trash = get_best_trash_chunk(&smp->data.u.str, (smp->data.u.str.data+2) * 4 / 3);
int b64_len;
if (!trash)
@ -1953,7 +1953,7 @@ static int sample_conv_bin2base64(const struct arg *arg_p, struct sample *smp, v
static int sample_conv_bin2base64url(const struct arg *arg_p, struct sample *smp, void *private)
{
struct buffer *trash = get_trash_chunk_sz((smp->data.u.str.data+2) * 4 / 3);
struct buffer *trash = get_best_trash_chunk(&smp->data.u.str, (smp->data.u.str.data+2) * 4 / 3);
int b64_len;
if (!trash)
@ -2149,7 +2149,7 @@ static int sample_conv_be2hex_check(struct arg *args, struct sample_conv *conv,
*/
static int sample_conv_be2hex(const struct arg *args, struct sample *smp, void *private)
{
struct buffer *trash = get_trash_chunk_sz(smp->data.u.str.data * 2);
struct buffer *trash = get_best_trash_chunk(&smp->data.u.str, smp->data.u.str.size);
int chunk_size = args[1].data.sint;
const int last = args[2].data.sint ? smp->data.u.str.data - chunk_size + 1 : smp->data.u.str.data;
int i;
@ -2181,15 +2181,6 @@ static int sample_conv_be2hex(const struct arg *args, struct sample *smp, void *
trash->area[trash->data++] = hextab[(c >> 4) & 0xF];
trash->area[trash->data++] = hextab[c & 0xF];
}
if (trash->data >= max_size) {
struct buffer *trash2 = get_larger_trash_chunk(trash);
if (!trash2)
break;
max_size += trash2->size - trash->size;
trash = trash2;
}
}
smp->data.u.str = *trash;
@ -2200,7 +2191,7 @@ static int sample_conv_be2hex(const struct arg *args, struct sample *smp, void *
static int sample_conv_bin2hex(const struct arg *arg_p, struct sample *smp, void *private)
{
struct buffer *trash = get_trash_chunk_sz(smp->data.u.str.data*2);
struct buffer *trash = get_best_trash_chunk(&smp->data.u.str, smp->data.u.str.data*2);
unsigned char c;
int ptr = 0;
@ -2220,7 +2211,7 @@ static int sample_conv_bin2hex(const struct arg *arg_p, struct sample *smp, void
static int sample_conv_bin2base2(const struct arg *arg_p, struct sample *smp, void *private)
{
struct buffer *trash = get_trash_chunk_sz(smp->data.u.str.data);
struct buffer *trash = get_best_trash_chunk(&smp->data.u.str, smp->data.u.str.data*8);
unsigned char c;
int ptr = 0;
int bit = 0;
@ -2232,14 +2223,6 @@ static int sample_conv_bin2base2(const struct arg *arg_p, struct sample *smp, vo
c = smp->data.u.str.area[ptr++];
for (bit = 7; bit >= 0; bit--)
trash->area[trash->data++] = c & (1 << bit) ? '1' : '0';
if (trash->data >= trash->size - 8) {
struct buffer *trash2 = get_larger_trash_chunk(trash);
if (!trash2)
break;
trash = trash2;
}
}
smp->data.u.str = *trash;
smp->data.type = SMP_T_STR;
@ -2320,7 +2303,7 @@ static int sample_conv_reverse(const struct arg *arg_p, struct sample *smp, void
int input_len = smp->data.u.str.data;
int i;
trash = get_trash_chunk_sz(input_len + 1);
trash = get_best_trash_chunk(&smp->data.u.str, input_len+1);
if (!trash)
return 0;
@ -2360,7 +2343,7 @@ static int sample_conv_reverse_dom(const struct arg *arg_p, struct sample *smp,
if (input[0] == '.')
return 0;
trash = get_trash_chunk_sz(input_len + 1);
trash = get_best_trash_chunk(&smp->data.u.str, input_len+1);
if (!trash)
return 0;
@ -2855,7 +2838,9 @@ static int sample_conv_json(const struct arg *arg_p, struct sample *smp, void *p
input_type = arg_p->data.sint;
temp = get_trash_chunk();
temp = get_best_trash_chunk(&smp->data.u.str, smp->data.u.str.size);
if (!temp)
return 0;
temp->data = 0;
p = smp->data.u.str.area;
@ -2940,11 +2925,8 @@ static int sample_conv_json(const struct arg *arg_p, struct sample *smp, void *p
}
/* Check length */
if (temp->data + len > temp->size) {
temp = get_larger_trash_chunk(temp);
if (!temp)
return 0;
}
if (temp->data + len > temp->size)
return 0;
/* Copy string. */
memcpy(temp->area + temp->data, str, len);
@ -3334,7 +3316,6 @@ static int sample_conv_regsub(const struct arg *arg_p, struct sample *smp, void
struct my_regex *reg = arg_p[0].data.reg;
regmatch_t pmatch[MAX_MATCH];
struct buffer *trash = get_trash_chunk_sz(smp->data.u.str.data);
struct buffer *tmp;
struct buffer *output;
int flag, max;
int found;
@ -3358,13 +3339,6 @@ static int sample_conv_regsub(const struct arg *arg_p, struct sample *smp, void
if (!found)
pmatch[0].rm_so = end - start;
/* If too many data to copy try to get a larger chunk */
if (pmatch[0].rm_so > b_room(trash)) {
tmp = get_larger_trash_chunk(trash);
if (tmp)
trash = tmp;
}
/* copy the heading non-matching part (which may also be the tail if nothing matches) */
max = trash->size - trash->data;
if (max && pmatch[0].rm_so > 0) {
@ -3388,13 +3362,6 @@ static int sample_conv_regsub(const struct arg *arg_p, struct sample *smp, void
}
output->data = max;
/* If too many data to copy try to get a larger chunk */
if (output->data > b_room(trash)) {
tmp = get_larger_trash_chunk(trash);
if (tmp)
trash = tmp;
}
/* replace the matching part */
max = trash->size - trash->data;
if (max) {
@ -3411,13 +3378,6 @@ static int sample_conv_regsub(const struct arg *arg_p, struct sample *smp, void
if (start >= end)
break;
/* If too many data to copy try to get a larger chunk */
if (!b_room(trash)) {
tmp = get_larger_trash_chunk(trash);
if (tmp)
trash = tmp;
}
/* We have a special case for matches of length 0 (eg: "x*y*").
* These ones are considered to match in front of a character,
* so we have to copy that character and skip to the next one.
@ -3787,7 +3747,8 @@ static int sample_conv_concat(const struct arg *arg_p, struct sample *smp, void
var = ist2(b_orig(&tmp.data.u.str), b_data(&tmp.data.u.str));
}
trash = alloc_trash_chunk_sz(smp->data.u.str.data + arg_p[0].data.str.data + istlen(var) + arg_p[2].data.str.data);
trash = alloc_best_trash_chunk(&smp->data.u.str,
smp->data.u.str.data + arg_p[0].data.str.data + istlen(var) + arg_p[2].data.str.data);
if (!trash)
return 0;
@ -3871,7 +3832,8 @@ static int sample_conv_add_item(const struct arg *arg_p, struct sample *smp, voi
var = ist2(b_orig(&tmp.data.u.str), b_data(&tmp.data.u.str));
}
tmpbuf = alloc_trash_chunk_sz(smp->data.u.str.data + arg_p[0].data.str.data + istlen(var) + arg_p[2].data.str.data);
tmpbuf = alloc_best_trash_chunk(&smp->data.u.str,
smp->data.u.str.data + arg_p[0].data.str.data + istlen(var) + arg_p[2].data.str.data);
if (!tmpbuf)
return 0;
@ -4603,7 +4565,6 @@ static int sample_check_json_query(struct arg *arg, struct sample_conv *conv,
*/
static int sample_conv_json_query(const struct arg *args, struct sample *smp, void *private)
{
struct buffer *trash = get_trash_chunk();
const char *token; /* holds the temporary string from mjson_find */
int token_size; /* holds the length of <token> */
@ -4623,6 +4584,7 @@ static int sample_conv_json_query(const struct arg *args, struct sample *smp, vo
return 1;
} else {
struct buffer *trash = get_trash_chunk();
double double_val;
if (mjson_get_number(smp->data.u.str.area, smp->data.u.str.data, args[0].data.str.area, &double_val) == 0)
@ -4645,16 +4607,14 @@ static int sample_conv_json_query(const struct arg *args, struct sample *smp, vo
return 1;
case MJSON_TOK_STRING: {
struct buffer *trash = get_trash_chunk_sz(token_size);
int len;
retry:
if (!trash)
return 0;
len = mjson_get_string(smp->data.u.str.area, smp->data.u.str.data, args[0].data.str.area, trash->area, trash->size);
if (len == -1) {
trash = get_larger_trash_chunk(trash);
if (trash)
goto retry;
/* invalid string */
return 0;
}
@ -4666,13 +4626,12 @@ static int sample_conv_json_query(const struct arg *args, struct sample *smp, vo
return 1;
}
case MJSON_TOK_ARRAY: {
struct buffer *trash = get_trash_chunk_sz(token_size);
if (!trash)
return 0;
// We copy the complete array, including square brackets into the return buffer
// result looks like: ["manage-account","manage-account-links","view-profile"]
if (token_size > trash->size) {
trash = get_larger_trash_chunk(trash);
if (!trash)
return 0;
}
trash->data = b_putblk(trash, token, token_size);
smp->data.u.str = *trash;
smp->data.type = SMP_T_STR;