Validate `ares_dns_rr_get_str()` can't return non-valid ASCII strings

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)
v1.26
Brad House 6 months ago
parent 737dd65e49
commit 4939117e27
  1. 31
      src/lib/ares__buf.c
  2. 23
      src/lib/ares_str.c
  3. 22
      src/lib/ares_str.h

@ -955,9 +955,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;
@ -984,7 +984,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 {
@ -1017,12 +1027,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)

@ -151,3 +151,26 @@ ares_bool_t ares__memeq_ci(const unsigned char *ptr, const unsigned char *val,
}
return ARES_TRUE;
}
ares_bool_t ares__isprint(int ch)
{
if (ch >= 0x20 && ch <= 0x7E) {
return ARES_TRUE;
}
return ARES_FALSE;
}
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;
}

@ -24,8 +24,8 @@
*
* SPDX-License-Identifier: MIT
*/
#ifndef HEADER_CARES_STRDUP_H
#define HEADER_CARES_STRDUP_H
#ifndef ARES_STR_H
#define ARES_STR_H
#include "ares_setup.h"
#include "ares.h"
@ -52,4 +52,20 @@ unsigned char ares__tolower(unsigned char c);
ares_bool_t ares__memeq_ci(const unsigned char *ptr, const unsigned char *val,
size_t len);
#endif /* HEADER_CARES_STRDUP_H */
ares_bool_t ares__isprint(int ch);
/*! 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 */

Loading…
Cancel
Save