(parse_reply): verify the lengths (both external and internal) are

consistent and not too long
(dns_lookup_int): be conservative in the length sent in to to
parse_reply


git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@11239 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
Assar Westerlund
2002-08-27 20:07:02 +00:00
parent f56f84cc41
commit d6a7b8a83e

View File

@@ -113,10 +113,10 @@ dns_free_data(struct dns_reply *r)
static struct dns_reply* static struct dns_reply*
parse_reply(unsigned char *data, int len) parse_reply(unsigned char *data, int len)
{ {
unsigned char *p; const unsigned char *p;
char host[128]; char host[128];
int status; int status;
const unsigned char *end_data = data + len;
struct dns_reply *r; struct dns_reply *r;
struct resource_record **rr; struct resource_record **rr;
@@ -133,7 +133,7 @@ parse_reply(unsigned char *data, int len)
memcpy(&r->h, p, 12); /* XXX this will probably be mostly garbage */ memcpy(&r->h, p, 12); /* XXX this will probably be mostly garbage */
p += 12; p += 12;
#endif #endif
status = dn_expand(data, data + len, p, host, sizeof(host)); status = dn_expand(data, end_data, p, host, sizeof(host));
if(status < 0){ if(status < 0){
dns_free_data(r); dns_free_data(r);
return NULL; return NULL;
@@ -143,19 +143,27 @@ parse_reply(unsigned char *data, int len)
dns_free_data(r); dns_free_data(r);
return NULL; return NULL;
} }
if (p + status + 4 > end_data) {
dns_free_data(r);
return NULL;
}
p += status; p += status;
r->q.type = (p[0] << 8 | p[1]); r->q.type = (p[0] << 8 | p[1]);
p += 2; p += 2;
r->q.class = (p[0] << 8 | p[1]); r->q.class = (p[0] << 8 | p[1]);
p += 2; p += 2;
rr = &r->head; rr = &r->head;
while(p < data + len){ while(p < end_data){
int type, class, ttl, size; int type, class, ttl, size;
status = dn_expand(data, data + len, p, host, sizeof(host)); status = dn_expand(data, end_data, p, host, sizeof(host));
if(status < 0){ if(status < 0){
dns_free_data(r); dns_free_data(r);
return NULL; return NULL;
} }
if (p + status + 10 > end_data) {
dns_free_data(r);
return NULL;
}
p += status; p += status;
type = (p[0] << 8) | p[1]; type = (p[0] << 8) | p[1];
p += 2; p += 2;
@@ -165,6 +173,12 @@ parse_reply(unsigned char *data, int len)
p += 4; p += 4;
size = (p[0] << 8) | p[1]; size = (p[0] << 8) | p[1];
p += 2; p += 2;
if (p + size > end_data) {
dns_free_data(r);
return NULL;
}
*rr = (struct resource_record*)calloc(1, *rr = (struct resource_record*)calloc(1,
sizeof(struct resource_record)); sizeof(struct resource_record));
if(*rr == NULL) { if(*rr == NULL) {
@@ -184,7 +198,7 @@ parse_reply(unsigned char *data, int len)
case T_NS: case T_NS:
case T_CNAME: case T_CNAME:
case T_PTR: case T_PTR:
status = dn_expand(data, data + len, p, host, sizeof(host)); status = dn_expand(data, end_data, p, host, sizeof(host));
if(status < 0){ if(status < 0){
dns_free_data(r); dns_free_data(r);
return NULL; return NULL;
@@ -197,11 +211,16 @@ parse_reply(unsigned char *data, int len)
break; break;
case T_MX: case T_MX:
case T_AFSDB:{ case T_AFSDB:{
status = dn_expand(data, data + len, p + 2, host, sizeof(host)); status = dn_expand(data, end_data, p + 2, host, sizeof(host));
if(status < 0){ if(status < 0){
dns_free_data(r); dns_free_data(r);
return NULL; return NULL;
} }
if (status + 2 > size) {
dns_free_data(r);
return NULL;
}
(*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) + (*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
strlen(host)); strlen(host));
if((*rr)->u.mx == NULL) { if((*rr)->u.mx == NULL) {
@@ -213,11 +232,16 @@ parse_reply(unsigned char *data, int len)
break; break;
} }
case T_SRV:{ case T_SRV:{
status = dn_expand(data, data + len, p + 6, host, sizeof(host)); status = dn_expand(data, end_data, p + 6, host, sizeof(host));
if(status < 0){ if(status < 0){
dns_free_data(r); dns_free_data(r);
return NULL; return NULL;
} }
if (status + 6 > size) {
dns_free_data(r);
return NULL;
}
(*rr)->u.srv = (*rr)->u.srv =
(struct srv_record*)malloc(sizeof(struct srv_record) + (struct srv_record*)malloc(sizeof(struct srv_record) +
strlen(host)); strlen(host));
@@ -244,6 +268,11 @@ parse_reply(unsigned char *data, int len)
case T_KEY : { case T_KEY : {
size_t key_len; size_t key_len;
if (size < 4) {
dns_free_data (r);
return NULL;
}
key_len = size - 4; key_len = size - 4;
(*rr)->u.key = malloc (sizeof(*(*rr)->u.key) + key_len - 1); (*rr)->u.key = malloc (sizeof(*(*rr)->u.key) + key_len - 1);
if ((*rr)->u.key == NULL) { if ((*rr)->u.key == NULL) {
@@ -261,11 +290,16 @@ parse_reply(unsigned char *data, int len)
case T_SIG : { case T_SIG : {
size_t sig_len; size_t sig_len;
status = dn_expand (data, data + len, p + 18, host, sizeof(host)); status = dn_expand (data, end_data, p + 18, host, sizeof(host));
if (status < 0) { if (status < 0) {
dns_free_data (r); dns_free_data (r);
return NULL; return NULL;
} }
if (status + 18 > size) {
dns_free_data(r);
return NULL;
}
sig_len = len - 18 - status; sig_len = len - 18 - status;
(*rr)->u.sig = malloc(sizeof(*(*rr)->u.sig) (*rr)->u.sig = malloc(sizeof(*(*rr)->u.sig)
+ strlen(host) + sig_len); + strlen(host) + sig_len);
@@ -293,6 +327,11 @@ parse_reply(unsigned char *data, int len)
case T_CERT : { case T_CERT : {
size_t cert_len; size_t cert_len;
if (size < 5) {
dns_free_data(r);
return NULL;
}
cert_len = size - 5; cert_len = size - 5;
(*rr)->u.cert = malloc (sizeof(*(*rr)->u.cert) + cert_len - 1); (*rr)->u.cert = malloc (sizeof(*(*rr)->u.cert) + cert_len - 1);
if ((*rr)->u.cert == NULL) { if ((*rr)->u.cert == NULL) {
@@ -327,7 +366,6 @@ dns_lookup_int(const char *domain, int rr_class, int rr_type)
{ {
unsigned char reply[1024]; unsigned char reply[1024];
int len; int len;
struct dns_reply *r = NULL;
#ifdef HAVE__RES #ifdef HAVE__RES
u_long old_options = 0; u_long old_options = 0;
#endif #endif
@@ -348,9 +386,12 @@ dns_lookup_int(const char *domain, int rr_class, int rr_type)
fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n", fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
domain, rr_class, dns_type_to_string(rr_type), len); domain, rr_class, dns_type_to_string(rr_type), len);
} }
if (len >= 0) if(len < 0) {
r = parse_reply(reply, len); return NULL;
return r; } else {
len = min(len, sizeof(reply));
return parse_reply(reply, len);
}
} }
struct dns_reply * struct dns_reply *