Skip to content

Commit

Permalink
Validate ares_dns_rr_get_str() can't return non-valid ASCII strings
Browse files Browse the repository at this point in the history
The DNS message protocol when using non-binary strings needs to be in
the ASCII printable range.  The function prototype does elude to this
but it was not actually validating the string was in anyway valid and
could be used.  DNS parsing will now fail if an expected string isn't
an ASCII string.

Fixes Issue: #769
Fix By: Brad House (@bradh352)
  • Loading branch information
bradh352 committed May 26, 2024
1 parent 4137b78 commit 52952aa
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 6 deletions.
31 changes: 25 additions & 6 deletions src/lib/ares__buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down
19 changes: 19 additions & 0 deletions src/lib/ares_str.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,29 @@ 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;
}
}
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;
}
13 changes: 13 additions & 0 deletions src/lib/ares_str.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

0 comments on commit 52952aa

Please sign in to comment.