diff --git a/src/lib/ares__buf.c b/src/lib/ares__buf.c index 0663383d..2203662f 100644 --- a/src/lib/ares__buf.c +++ b/src/lib/ares__buf.c @@ -941,9 +941,9 @@ ares_status_t ares__buf_set_position(ares__buf_t *buf, size_t idx) return ARES_SUCCESS; } -ares_status_t ares__buf_parse_dns_binstr(ares__buf_t *buf, size_t remaining_len, - unsigned char **bin, size_t *bin_len, - ares_bool_t allow_multiple) +static ares_status_t ares__buf_parse_dns_binstr_int( + ares__buf_t *buf, size_t remaining_len, unsigned char **bin, size_t *bin_len, + ares_bool_t allow_multiple, ares_bool_t validate_printable) { unsigned char len; ares_status_t status; @@ -970,7 +970,17 @@ ares_status_t ares__buf_parse_dns_binstr(ares__buf_t *buf, size_t remaining_len, } if (len) { - /* XXX: Maybe we should scan to make sure it is printable? */ + /* When used by the _str() parser, it really needs to be validated to + * be a valid printable ascii string. Do that here */ + if (validate_printable && ares__buf_len(buf) >= len) { + size_t mylen; + const char *data = (const char *)ares__buf_peek(buf, &mylen); + if (!ares__str_isprint(data, len)) { + status = ARES_EBADSTR; + break; + } + } + if (bin != NULL) { status = ares__buf_fetch_bytes_into_buf(buf, binbuf, len); } else { @@ -1003,12 +1013,21 @@ ares_status_t ares__buf_parse_dns_binstr(ares__buf_t *buf, size_t remaining_len, return status; } +ares_status_t ares__buf_parse_dns_binstr(ares__buf_t *buf, size_t remaining_len, + unsigned char **bin, size_t *bin_len, + ares_bool_t allow_multiple) +{ + return ares__buf_parse_dns_binstr_int(buf, remaining_len, bin, bin_len, + allow_multiple, ARES_FALSE); +} + ares_status_t ares__buf_parse_dns_str(ares__buf_t *buf, size_t remaining_len, char **str, ares_bool_t allow_multiple) { size_t len; - return ares__buf_parse_dns_binstr(buf, remaining_len, (unsigned char **)str, - &len, allow_multiple); + + return ares__buf_parse_dns_binstr_int( + buf, remaining_len, (unsigned char **)str, &len, allow_multiple, ARES_TRUE); } ares_status_t ares__buf_append_num_dec(ares__buf_t *buf, size_t num, size_t len) diff --git a/src/lib/ares_str.c b/src/lib/ares_str.c index 5f25cfea..9483a4bc 100644 --- a/src/lib/ares_str.c +++ b/src/lib/ares_str.c @@ -260,6 +260,10 @@ ares_bool_t ares__is_hostnamech(int ch) ares_bool_t ares__is_hostname(const char *str) { size_t i; + + if (str == NULL) + return ARES_FALSE; + for (i = 0; str[i] != 0; i++) { if (!ares__is_hostnamech(str[i])) { return ARES_FALSE; @@ -267,3 +271,18 @@ ares_bool_t ares__is_hostname(const char *str) } return ARES_TRUE; } + +ares_bool_t ares__str_isprint(const char *str, size_t len) +{ + size_t i; + + if (str == NULL && len != 0) + return ARES_FALSE; + + for (i = 0; i < len; i++) { + if (!ares__isprint(str[i])) { + return ARES_FALSE; + } + } + return ARES_TRUE; +} diff --git a/src/lib/ares_str.h b/src/lib/ares_str.h index 8d869073..526a927a 100644 --- a/src/lib/ares_str.h +++ b/src/lib/ares_str.h @@ -62,5 +62,18 @@ ares_bool_t ares__is_hostnamech(int ch); ares_bool_t ares__is_hostname(const char *str); +/*! Validate the string provided is printable. The length specified must be + * at least the size of the buffer provided. If a NULL-terminator is hit + * before the length provided is hit, this will not be considered a valid + * printable string. This does not validate that the string is actually + * NULL terminated. + * + * \param[in] str Buffer containing string to evaluate. + * \param[in] len Number of characters to evaluate within provided buffer. + * If 0, will return TRUE since it did not hit an exception. + * \return ARES_TRUE if the entire string is printable, ARES_FALSE if not. + */ +ares_bool_t ares__str_isprint(const char *str, size_t len); + #endif /* __ARES_STR_H */