Skip to content

Commit a14a6a3

Browse files
committed
deps: c-ares, avoid single-byte buffer overwrite
Backport of #8849 for c-ares 1.9.0. Incorrect string length calculation when passing escaped dot. - CVE: CVE-2016-5180 - Upstream bug: https://c-ares.haxx.se/adv_20160929.html PR-URL: #9108 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
1 parent b798f59 commit a14a6a3

File tree

1 file changed

+37
-43
lines changed

1 file changed

+37
-43
lines changed

deps/cares/src/ares_mkquery.c

Lines changed: 37 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -86,56 +86,29 @@
8686
*/
8787

8888
int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
89-
int rd, unsigned char **buf, int *buflen)
89+
int rd, unsigned char **bufp, int *buflenp)
9090
{
91-
int len;
91+
size_t len;
9292
unsigned char *q;
9393
const char *p;
94+
size_t buflen;
95+
unsigned char *buf;
9496

9597
/* Set our results early, in case we bail out early with an error. */
96-
*buflen = 0;
97-
*buf = NULL;
98+
*buflenp = 0;
99+
*bufp = NULL;
98100

99-
/* Compute the length of the encoded name so we can check buflen.
100-
* Start counting at 1 for the zero-length label at the end. */
101-
len = 1;
102-
for (p = name; *p; p++)
103-
{
104-
if (*p == '\\' && *(p + 1) != 0)
105-
p++;
106-
len++;
107-
}
108-
/* If there are n periods in the name, there are n + 1 labels, and
109-
* thus n + 1 length fields, unless the name is empty or ends with a
110-
* period. So add 1 unless name is empty or ends with a period.
111-
*/
112-
if (*name && *(p - 1) != '.')
113-
len++;
114-
115-
/* Immediately reject names that are longer than the maximum of 255
116-
* bytes that's specified in RFC 1035 ("To simplify implementations,
117-
* the total length of a domain name (i.e., label octets and label
118-
* length octets) is restricted to 255 octets or less."). We aren't
119-
* doing this just to be a stickler about RFCs. For names that are
120-
* too long, 'dnscache' closes its TCP connection to us immediately
121-
* (when using TCP) and ignores the request when using UDP, and
122-
* BIND's named returns ServFail (TCP or UDP). Sending a request
123-
* that we know will cause 'dnscache' to close the TCP connection is
124-
* painful, since that makes any other outstanding requests on that
125-
* connection fail. And sending a UDP request that we know
126-
* 'dnscache' will ignore is bad because resources will be tied up
127-
* until we time-out the request.
101+
/* Allocate a memory area for the maximum size this packet might need. +2
102+
* is for the length byte and zero termination if no dots or ecscaping is
103+
* used.
128104
*/
129-
if (len > MAXCDNAME)
130-
return ARES_EBADNAME;
131-
132-
*buflen = len + HFIXEDSZ + QFIXEDSZ;
133-
*buf = malloc(*buflen);
134-
if (!*buf)
135-
return ARES_ENOMEM;
105+
len = strlen(name) + 2 + HFIXEDSZ + QFIXEDSZ;
106+
buf = malloc(len);
107+
if (!buf)
108+
return ARES_ENOMEM;
136109

137110
/* Set up the header. */
138-
q = *buf;
111+
q = buf;
139112
memset(q, 0, HFIXEDSZ);
140113
DNS_HEADER_SET_QID(q, id);
141114
DNS_HEADER_SET_OPCODE(q, QUERY);
@@ -155,8 +128,10 @@ int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
155128
q += HFIXEDSZ;
156129
while (*name)
157130
{
158-
if (*name == '.')
131+
if (*name == '.') {
132+
free (buf);
159133
return ARES_EBADNAME;
134+
}
160135

161136
/* Count the number of bytes in this label. */
162137
len = 0;
@@ -166,8 +141,10 @@ int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
166141
p++;
167142
len++;
168143
}
169-
if (len > MAXLABEL)
144+
if (len > MAXLABEL) {
145+
free (buf);
170146
return ARES_EBADNAME;
147+
}
171148

172149
/* Encode the length and copy the data. */
173150
*q++ = (unsigned char)len;
@@ -191,5 +168,22 @@ int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
191168
DNS_QUESTION_SET_TYPE(q, type);
192169
DNS_QUESTION_SET_CLASS(q, dnsclass);
193170

171+
q += QFIXEDSZ;
172+
173+
buflen = (q - buf);
174+
175+
/* Reject names that are longer than the maximum of 255 bytes that's
176+
* specified in RFC 1035 ("To simplify implementations, the total length of
177+
* a domain name (i.e., label octets and label length octets) is restricted
178+
* to 255 octets or less."). */
179+
if (buflen > (MAXCDNAME + HFIXEDSZ + QFIXEDSZ)) {
180+
free (buf);
181+
return ARES_EBADNAME;
182+
}
183+
184+
/* we know this fits in an int at this point */
185+
*buflenp = (int) buflen;
186+
*bufp = buf;
187+
194188
return ARES_SUCCESS;
195189
}

0 commit comments

Comments
 (0)