mirror of
https://github.com/haproxy/haproxy.git
synced 2026-07-11 18:15:49 -04:00
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:
parent
2b993de2da
commit
ac37158a6d
3 changed files with 30 additions and 71 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
|
|
|
|||
91
src/sample.c
91
src/sample.c
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue