BUG: dns: Fix off-by-one write in dns_validate_dns_response()

The maximum number of bytes in a DNS name is indeed 255, but we
need to allocate one more byte for the NULL-terminating byte.
Otherwise dns_read_name() might return 255 for a very long name,
causing dns_validate_dns_response() to write a NULL value one
byte after the end of the buffer:

dns_answer_record->name[len] = 0;

The next fields in the struct being filled from the content of the
query, it might have been possible to fill them with non-0 values,
causing for example a strlen() of the name to read past the end of
the struct and access unintended parts of the memory, possibly
leading to a crash.

To be backported to 1.8, probably also 1.7.
This commit is contained in:
Remi Gacogne 2018-12-05 17:59:56 +01:00 committed by Willy Tarreau
parent bc552102ad
commit 00488ddef5

View File

@ -115,9 +115,9 @@ struct dns_question {
/* NOTE: big endian structure */ /* NOTE: big endian structure */
struct dns_query_item { struct dns_query_item {
char name[DNS_MAX_NAME_SIZE]; /* query name */ char name[DNS_MAX_NAME_SIZE+1]; /* query name */
unsigned short type; /* question type */ unsigned short type; /* question type */
unsigned short class; /* query class */ unsigned short class; /* query class */
struct list list; struct list list;
}; };
@ -138,17 +138,17 @@ struct dns_additional_record {
/* NOTE: big endian structure */ /* NOTE: big endian structure */
struct dns_answer_item { struct dns_answer_item {
/*For SRV type, name also includes service and protocol value */ /*For SRV type, name also includes service and protocol value */
char name[DNS_MAX_NAME_SIZE]; /* answer name */ char name[DNS_MAX_NAME_SIZE+1]; /* answer name */
int16_t type; /* question type */ int16_t type; /* question type */
int16_t class; /* query class */ int16_t class; /* query class */
int32_t ttl; /* response TTL */ int32_t ttl; /* response TTL */
int16_t priority; /* SRV type priority */ int16_t priority; /* SRV type priority */
uint16_t weight; /* SRV type weight */ uint16_t weight; /* SRV type weight */
int16_t port; /* SRV type port */ int16_t port; /* SRV type port */
uint16_t data_len; /* number of bytes in target below */ uint16_t data_len; /* number of bytes in target below */
struct sockaddr address; /* IPv4 or IPv6, network format */ struct sockaddr address; /* IPv4 or IPv6, network format */
char target[DNS_MAX_NAME_SIZE]; /* Response data: SRV or CNAME type target */ char target[DNS_MAX_NAME_SIZE+1]; /* Response data: SRV or CNAME type target */
time_t last_seen; /* When was the answer was last seen */ time_t last_seen; /* When was the answer was last seen */
struct list list; struct list list;
}; };