]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: tools: make string encoding possible to fail instead of truncating
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 28 Jul 2026 08:23:37 +0000 (10:23 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Tue, 28 Jul 2026 13:21:58 +0000 (15:21 +0200)
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. <truncate> 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.

include/haproxy/tools.h
src/http_conv.c
src/ssl_ocsp.c
src/tools.c

index 148d56f1313661e154e2520ef284fda5eb5e4049..c4d95d096e58d5a23787d246e2692e22fea462c9 100644 (file)
@@ -433,8 +433,9 @@ int addr_is_local(const struct netns_entry *ns,
  * <map> with the hexadecimal representation of their ASCII-code (2 digits)
  * prefixed by <escape>, and will store the result between <start> (included)
  * and <stop> (excluded), and will always terminate the string with a '\0'
- * before <stop>. If bytes are missing between <start> and <stop>, then the
- * conversion will be incomplete and truncated.
+ * before <stop>. If bytes are missing between <start> and <stop>,  if
+ * <truncate> 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 <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 <map> with the <escape>
index 65b75239ec9ab9c996d8f41c6ad56a2a1e7264b2..9e701269200899dc9c4b1c1ad8d11b6a77abaead 100644 (file)
@@ -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;
index 366ff574de93222934e4099828fe9845b0e5c5a3..b665bd945a37bdd43a4f88d71a74fd5df1c6cbfc 100644 (file)
@@ -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;
index afb29460b6ad31ebde97cb28e7083a429e34b9b2..cb2f89db524094861e60301a9a6fa37767fcd1dd 100644 (file)
@@ -2036,8 +2036,9 @@ int addr_is_local(const struct netns_entry *ns,
  * <map> with the hexadecimal representation of their ASCII-code (2 digits)
  * prefixed by <escape>, and will store the result between <start> (included)
  * and <stop> (excluded), and will always terminate the string with a '\0'
- * before <stop>. If bytes are missing between <start> and <stop>, then the
- * conversion will be incomplete and truncated.
+ * before <stop>. If bytes are missing between <start> and <stop>, if
+ * <truncate> 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,
  * <chunk> 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;
 }