Skip to content

Commit e5bf5a2

Browse files
committed
Add bounds checking to the functions building certs packets
1 parent ed79aca commit e5bf5a2

6 files changed

Lines changed: 36 additions & 12 deletions

File tree

dnscrypt.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ dnscrypt_server_curve(struct context *c, const dnsccert *cert,
391391
*/
392392
int
393393
dnscrypt_self_serve_cert_file(struct context *c, struct dns_header *header,
394-
size_t *dns_query_len)
394+
size_t *dns_query_len, size_t max_len)
395395
{
396396
unsigned char *p;
397397
unsigned char *ansp;
@@ -438,7 +438,7 @@ dnscrypt_self_serve_cert_file(struct context *c, struct dns_header *header,
438438

439439
for (int i=0; i < c->signed_certs_count; i++) {
440440
if (add_resource_record
441-
(header, nameoffset, &ansp, 0, NULL, T_TXT, C_IN, "t", size,
441+
(header, nameoffset, max_len, &ansp, 0, NULL, T_TXT, C_IN, "t", size,
442442
*(txt + i))) {
443443
anscount++;
444444
} else {

dnscrypt.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,6 @@ int dnscrypt_server_curve(struct context *c, const dnsccert *cert,
237237
* */
238238
int dnscrypt_self_serve_cert_file(struct context *c,
239239
struct dns_header *header,
240-
size_t *dns_query_len);
240+
size_t *dns_query_len, size_t max_len);
241241

242242
#endif

rfc1035.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ questions_hash(uint64_t *hash, struct dns_header *header, size_t plen,
186186
(name_len = strlen(name)) > MAXDNAME) {
187187
return -1;
188188
}
189-
crypto_shorthash((unsigned char *) hash, name, name_len, key);
189+
crypto_shorthash((unsigned char *) hash, (const unsigned char *) name, name_len, key);
190190

191191
return 0;
192192
}
@@ -278,7 +278,7 @@ do_rfc1035_name(unsigned char *p, char *sval)
278278
}
279279

280280
int
281-
add_resource_record(struct dns_header *header, unsigned int nameoffset,
281+
add_resource_record(struct dns_header *header, unsigned int nameoffset, size_t plen,
282282
unsigned char **pp, unsigned long ttl, unsigned int *offset,
283283
unsigned short type, unsigned short class, char *format,
284284
...)
@@ -290,6 +290,9 @@ add_resource_record(struct dns_header *header, unsigned int nameoffset,
290290
long lval;
291291
char *sval;
292292

293+
if (!CHECK_LEN(header, p, plen, 12)) {
294+
return 0;
295+
}
293296
PUTSHORT(nameoffset | 0xc000, p);
294297
PUTSHORT(type, p);
295298
PUTSHORT(class, p);
@@ -304,24 +307,36 @@ add_resource_record(struct dns_header *header, unsigned int nameoffset,
304307
switch (*format) {
305308
#ifdef HAVE_IPV6
306309
case '6':
310+
if (!CHECK_LEN(header, p, plen, IN6ADDRSZ)) {
311+
return 0;
312+
}
307313
sval = va_arg(ap, char *);
308314
memcpy(p, sval, IN6ADDRSZ);
309315
p += IN6ADDRSZ;
310316
break;
311317
#endif
312318

313319
case '4':
320+
if (!CHECK_LEN(header, p, plen, INADDRSZ)) {
321+
return 0;
322+
}
314323
sval = va_arg(ap, char *);
315324
memcpy(p, sval, INADDRSZ);
316325
p += INADDRSZ;
317326
break;
318327

319328
case 's':
329+
if (!CHECK_LEN(header, p, plen, 2)) {
330+
return 0;
331+
}
320332
usval = va_arg(ap, int);
321333
PUTSHORT(usval, p);
322334
break;
323335

324336
case 'l':
337+
if (!CHECK_LEN(header, p, plen, 4)) {
338+
return 0;
339+
}
325340
lval = va_arg(ap, long);
326341
PUTLONG(lval, p);
327342
break;
@@ -338,6 +353,9 @@ add_resource_record(struct dns_header *header, unsigned int nameoffset,
338353
case 't':
339354
usval = va_arg(ap, int);
340355
sval = va_arg(ap, char *);
356+
if (!CHECK_LEN(header, p, plen, usval)) {
357+
return 0;
358+
}
341359
if (usval != 0) {
342360
memcpy(p, sval, usval);
343361
}
@@ -350,6 +368,9 @@ add_resource_record(struct dns_header *header, unsigned int nameoffset,
350368
if (usval > 255) {
351369
usval = 255;
352370
}
371+
if (!CHECK_LEN(header, p, plen, (1 + usval))) {
372+
return 0;
373+
}
353374
*p++ = (unsigned char) usval;
354375
memcpy(p, sval, usval);
355376
p += usval;
@@ -359,6 +380,9 @@ add_resource_record(struct dns_header *header, unsigned int nameoffset,
359380
va_end(ap); /* clean up variable argument pointer */
360381

361382
j = p - sav - 2;
383+
if (!CHECK_LEN(header, sav, plen, 2)) {
384+
return 0;
385+
}
362386
PUTSHORT(j, sav); /* Now, store real RDLength */
363387

364388
*pp = p;

rfc1035.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
1313
char *name, int isExtract, int extrabytes);
1414

1515
int add_resource_record(struct dns_header *header, unsigned int nameoffset,
16-
unsigned char **pp, unsigned long ttl,
16+
size_t plen, unsigned char **pp, unsigned long ttl,
1717
unsigned int *offset, unsigned short type,
1818
unsigned short class, char *format, ...);
1919

tcp_request.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,10 @@ tcp_listener_kill_oldest_request(struct context *c)
8888
*/
8989
static int
9090
self_serve_cert_file(struct context *c, struct dns_header *header,
91-
size_t dns_query_len, TCPRequest *tcp_request)
91+
size_t dns_query_len, size_t max_len, TCPRequest *tcp_request)
9292
{
9393
uint8_t dns_query_len_buf[2];
94-
if (dnscrypt_self_serve_cert_file(c, header, &dns_query_len) == 0) {
94+
if (dnscrypt_self_serve_cert_file(c, header, &dns_query_len, max_len) == 0) {
9595
dns_query_len_buf[0] = (dns_query_len >> 8) & 0xff;
9696
dns_query_len_buf[1] = dns_query_len & 0xff;
9797
if (bufferevent_write(tcp_request->client_proxy_bev,
@@ -206,7 +206,7 @@ client_proxy_read_cb(struct bufferevent *const client_proxy_bev,
206206
struct dns_header *header = (struct dns_header *)dns_query;
207207
// self serve signed certificate for provider name?
208208
if (!tcp_request->is_dnscrypted) {
209-
if (self_serve_cert_file(c, header, dns_query_len, tcp_request) == 0)
209+
if (self_serve_cert_file(c, header, dns_query_len, sizeof_dns_query, tcp_request) == 0)
210210
return;
211211
if (!c->allow_not_dnscrypted) {
212212
logger(LOG_DEBUG, "Unauthenticated query received over TCP");

udp_request.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,9 @@ timeout_timer_cb(evutil_socket_t timeout_timer_handle, short ev_flags,
234234
*/
235235
static int
236236
self_serve_cert_file(struct context *c, struct dns_header *header,
237-
size_t dns_query_len, UDPRequest *udp_request)
237+
size_t dns_query_len, size_t max_len, UDPRequest *udp_request)
238238
{
239-
if (dnscrypt_self_serve_cert_file(c, header, &dns_query_len) == 0) {
239+
if (dnscrypt_self_serve_cert_file(c, header, &dns_query_len, max_len) == 0) {
240240
SendtoWithRetryCtx retry_ctx = {
241241
.udp_request = udp_request,
242242
.handle = udp_request->client_proxy_handle,
@@ -333,7 +333,7 @@ client_to_proxy_cb(evutil_socket_t client_proxy_handle, short ev_flags,
333333

334334
// self serve signed certificate for provider name?
335335
if (!udp_request->is_dnscrypted) {
336-
if (self_serve_cert_file(c, header, dns_query_len, udp_request) == 0)
336+
if (self_serve_cert_file(c, header, dns_query_len, sizeof_dns_query, udp_request) == 0)
337337
return;
338338
if (!c->allow_not_dnscrypted) {
339339
logger(LOG_DEBUG, "Unauthenticated query received over UDP");

0 commit comments

Comments
 (0)