]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG: dns: Fix off-by-one write in dns_validate_dns_response()
authorRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 5 Dec 2018 16:59:56 +0000 (17:59 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 12 Dec 2018 13:44:52 +0000 (14:44 +0100)
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.

include/types/dns.h

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