BUG/MINOR: log: improper behavior when escaping log data

Patrick Hemmer reported an improper log behavior when using
log-format to escape log data (+E option):
Some bytes were truncated from the output:

- escape_string() function now takes an extra parameter that
  allow the caller to specify input string stop pointer in
  case the input string is not guaranteed to be zero-terminated.
- Minors checks were added into lf_text_len() to make sure dst
  string will not overflow.
- lf_text_len() now makes proper use of escape_string() function.

This should be backported as far as 1.8.
This commit is contained in:
Aurelien DARRAGON 2022-09-20 14:33:18 +02:00 committed by Christopher Faulet
parent b0b8e9bbd2
commit c5bff8e550
3 changed files with 15 additions and 8 deletions

View File

@ -424,7 +424,8 @@ char *encode_chunk(char *start, char *stop,
/* /*
* Tries to prefix characters tagged in the <map> with the <escape> * Tries to prefix characters tagged in the <map> with the <escape>
* character. The input <string> must be zero-terminated. The result will * character. The input <string> is processed until string_stop
* is reached or NULL-byte is encountered. The result will
* be stored between <start> (included) and <stop> (excluded). This * be stored between <start> (included) and <stop> (excluded). This
* function will always try to terminate the resulting string with a '\0' * function will always try to terminate the resulting string with a '\0'
* before <stop>, and will return its position if the conversion * before <stop>, and will return its position if the conversion
@ -432,7 +433,7 @@ char *encode_chunk(char *start, char *stop,
*/ */
char *escape_string(char *start, char *stop, char *escape_string(char *start, char *stop,
const char escape, const long *map, const char escape, const long *map,
const char *string); const char *string, const char *string_stop);
/* /*
* Tries to prefix characters tagged in the <map> with the <escape> * Tries to prefix characters tagged in the <map> with the <escape>

View File

@ -1184,17 +1184,21 @@ char *lf_text_len(char *dst, const char *src, size_t len, size_t size, const str
} }
if (src && len) { if (src && len) {
if (++len > size) /* escape_string and strlcpy2 will both try to add terminating NULL-byte
len = size; * to dst, so we need to make sure that extra byte will fit into dst
* before calling them
*/
if (node->options & LOG_OPT_ESC) { if (node->options & LOG_OPT_ESC) {
char *ret; char *ret;
ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src); ret = escape_string(dst, (dst + size - 1), '\\', rfc5424_escape_map, src, src + len);
if (ret == NULL || *ret != '\0') if (ret == NULL || *ret != '\0')
return NULL; return NULL;
len = ret - dst; len = ret - dst;
} }
else { else {
if (++len > size)
len = size;
len = strlcpy2(dst, src, len); len = strlcpy2(dst, src, len);
} }
@ -1205,6 +1209,7 @@ char *lf_text_len(char *dst, const char *src, size_t len, size_t size, const str
if (size < 2) if (size < 2)
return NULL; return NULL;
*(dst++) = '-'; *(dst++) = '-';
size -= 1;
} }
if (node->options & LOG_OPT_QUOTE) { if (node->options & LOG_OPT_QUOTE) {

View File

@ -1975,7 +1975,8 @@ char *encode_chunk(char *start, char *stop,
/* /*
* Tries to prefix characters tagged in the <map> with the <escape> * Tries to prefix characters tagged in the <map> with the <escape>
* character. The input <string> must be zero-terminated. The result will * character. The input <string> is processed until string_stop
* is reached or NULL-byte is encountered. The result will
* be stored between <start> (included) and <stop> (excluded). This * be stored between <start> (included) and <stop> (excluded). This
* function will always try to terminate the resulting string with a '\0' * function will always try to terminate the resulting string with a '\0'
* before <stop>, and will return its position if the conversion * before <stop>, and will return its position if the conversion
@ -1983,11 +1984,11 @@ char *encode_chunk(char *start, char *stop,
*/ */
char *escape_string(char *start, char *stop, char *escape_string(char *start, char *stop,
const char escape, const long *map, const char escape, const long *map,
const char *string) const char *string, const char *string_stop)
{ {
if (start < stop) { if (start < stop) {
stop--; /* reserve one byte for the final '\0' */ stop--; /* reserve one byte for the final '\0' */
while (start < stop && *string != '\0') { while (start < stop && string < string_stop && *string != '\0') {
if (!ha_bit_test((unsigned char)(*string), map)) if (!ha_bit_test((unsigned char)(*string), map))
*start++ = *string; *start++ = *string;
else { else {