From: Christopher Faulet Date: Tue, 28 Jul 2026 08:23:37 +0000 (+0200) Subject: BUG/MEDIUM: tools: make string encoding possible to fail instead of truncating X-Git-Tag: v3.5-dev4~99 X-Git-Url: https://git.kaiwu.me/%7B@url%7D?a=commitdiff_plain;h=b947f6075542030160a35d7f8c25beaa1c0e7584;p=haproxy.git BUG/MEDIUM: tools: make string encoding possible to fail instead of truncating encode_string() and encode_chunk() functions were silently truncated the output string if it is too small. encode_string() is not used but encode_chunk() is used to encode urls (url_enc converter and ocsp). In this context it is not expected to have an url partially encoded. So let's slightly change the API to add an extra argument to these functions to be able to fail when the output string is too small. must be set to 0 to return an error (NULL) instead of truncate the output string. url_enc converter and ocsp were also update to trigger an error in that case. The issue is pretty minor but it remains an API change, so it is tagged as MEDIUM. It could be backported to 3.4 and probably as far as 3.2 or 3.0. --- diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index 148d56f13..c4d95d096 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -433,8 +433,9 @@ int addr_is_local(const struct netns_entry *ns, * with the hexadecimal representation of their ASCII-code (2 digits) * prefixed by , and will store the result between (included) * and (excluded), and will always terminate the string with a '\0' - * before . If bytes are missing between and , then the - * conversion will be incomplete and truncated. + * before . If bytes are missing between and , if + * is non zero, then the conversion will be incomplete and + * truncated. Otherwise an error is returned. * The input string must also be zero-terminated. * * Return the address of the \0 character, or NULL on error @@ -443,14 +444,14 @@ extern const char hextab[]; extern long query_encode_map[]; char *encode_string(char *start, char *stop, const char escape, const long *map, - const char *string); + const char *string, int truncate); /* * Same behavior, except that it encodes chunk instead of a string. */ char *encode_chunk(char *start, char *stop, const char escape, const long *map, - const struct buffer *chunk); + const struct buffer *chunk, int truncate); /* * Tries to prefix characters tagged in the with the diff --git a/src/http_conv.c b/src/http_conv.c index 65b75239e..9e7012692 100644 --- a/src/http_conv.c +++ b/src/http_conv.c @@ -356,7 +356,7 @@ static int sample_conv_url_enc(const struct arg *args, struct sample *smp, void return 0; ret = encode_chunk(trash->area, trash->area + trash->size, '%', - encode_map, &smp->data.u.str); + encode_map, &smp->data.u.str, 0); if (ret == NULL || *ret != '\0') return 0; trash->data = ret - trash->area; diff --git a/src/ssl_ocsp.c b/src/ssl_ocsp.c index 366ff574d..b665bd945 100644 --- a/src/ssl_ocsp.c +++ b/src/ssl_ocsp.c @@ -820,7 +820,7 @@ int ssl_ocsp_create_request_details(const OCSP_CERTID *certid, struct buffer *re b64buf->data = base64_ret; ret = encode_chunk((char*)b_stop(req_url), b_orig(req_url) + b_size(req_url), '%', - query_encode_map, b64buf); + query_encode_map, b64buf, 0); if (ret && *ret == '\0') { req_url->data = ret - b_orig(req_url); errcode = 0; diff --git a/src/tools.c b/src/tools.c index afb29460b..cb2f89db5 100644 --- a/src/tools.c +++ b/src/tools.c @@ -2036,8 +2036,9 @@ int addr_is_local(const struct netns_entry *ns, * with the hexadecimal representation of their ASCII-code (2 digits) * prefixed by , and will store the result between (included) * and (excluded), and will always terminate the string with a '\0' - * before . If bytes are missing between and , then the - * conversion will be incomplete and truncated. + * before . If bytes are missing between and , if + * is non zero, then the conversion will be incomplete and + * truncated. Otherwise an error is returned. * The input string must also be zero-terminated. * * Return the address of the \0 character, or NULL on error @@ -2045,7 +2046,7 @@ int addr_is_local(const struct netns_entry *ns, const char hextab[16] __nonstring = "0123456789ABCDEF"; char *encode_string(char *start, char *stop, const char escape, const long *map, - const char *string) + const char *string, int truncate) { if (start < stop) { stop--; /* reserve one byte for the final '\0' */ @@ -2053,8 +2054,11 @@ char *encode_string(char *start, char *stop, if (!ha_bit_test((unsigned char)(*string), map)) *start++ = *string; else { - if (start + 3 >= stop) - break; + if (start + 3 >= stop) { + if (truncate) + break; + goto error; + } *start++ = escape; *start++ = hextab[(*string >> 4) & 15]; *start++ = hextab[*string & 15]; @@ -2064,6 +2068,7 @@ char *encode_string(char *start, char *stop, *start = '\0'; return start; } + error: return NULL; } @@ -2072,8 +2077,8 @@ char *encode_string(char *start, char *stop, * instead of a string. */ char *encode_chunk(char *start, char *stop, - const char escape, const long *map, - const struct buffer *chunk) + const char escape, const long *map, + const struct buffer *chunk, int truncate) { char *str = chunk->area; char *end = chunk->area + chunk->data; @@ -2084,8 +2089,11 @@ char *encode_chunk(char *start, char *stop, if (!ha_bit_test((unsigned char)(*str), map)) *start++ = *str; else { - if (start + 3 >= stop) - break; + if (start + 3 >= stop) { + if (truncate) + break; + goto error; + } *start++ = escape; *start++ = hextab[(*str >> 4) & 15]; *start++ = hextab[*str & 15]; @@ -2095,6 +2103,7 @@ char *encode_chunk(char *start, char *stop, *start = '\0'; return start; } + error: return NULL; }