(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:
@@ -113,10 +113,10 @@ dns_free_data(struct dns_reply *r)
|
||||
static struct dns_reply*
|
||||
parse_reply(unsigned char *data, int len)
|
||||
{
|
||||
unsigned char *p;
|
||||
const unsigned char *p;
|
||||
char host[128];
|
||||
int status;
|
||||
|
||||
const unsigned char *end_data = data + len;
|
||||
struct dns_reply *r;
|
||||
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 */
|
||||
p += 12;
|
||||
#endif
|
||||
status = dn_expand(data, data + len, p, host, sizeof(host));
|
||||
status = dn_expand(data, end_data, p, host, sizeof(host));
|
||||
if(status < 0){
|
||||
dns_free_data(r);
|
||||
return NULL;
|
||||
@@ -143,19 +143,27 @@ parse_reply(unsigned char *data, int len)
|
||||
dns_free_data(r);
|
||||
return NULL;
|
||||
}
|
||||
if (p + status + 4 > end_data) {
|
||||
dns_free_data(r);
|
||||
return NULL;
|
||||
}
|
||||
p += status;
|
||||
r->q.type = (p[0] << 8 | p[1]);
|
||||
p += 2;
|
||||
r->q.class = (p[0] << 8 | p[1]);
|
||||
p += 2;
|
||||
rr = &r->head;
|
||||
while(p < data + len){
|
||||
while(p < end_data){
|
||||
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){
|
||||
dns_free_data(r);
|
||||
return NULL;
|
||||
}
|
||||
if (p + status + 10 > end_data) {
|
||||
dns_free_data(r);
|
||||
return NULL;
|
||||
}
|
||||
p += status;
|
||||
type = (p[0] << 8) | p[1];
|
||||
p += 2;
|
||||
@@ -165,6 +173,12 @@ parse_reply(unsigned char *data, int len)
|
||||
p += 4;
|
||||
size = (p[0] << 8) | p[1];
|
||||
p += 2;
|
||||
|
||||
if (p + size > end_data) {
|
||||
dns_free_data(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*rr = (struct resource_record*)calloc(1,
|
||||
sizeof(struct resource_record));
|
||||
if(*rr == NULL) {
|
||||
@@ -184,7 +198,7 @@ parse_reply(unsigned char *data, int len)
|
||||
case T_NS:
|
||||
case T_CNAME:
|
||||
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){
|
||||
dns_free_data(r);
|
||||
return NULL;
|
||||
@@ -197,11 +211,16 @@ parse_reply(unsigned char *data, int len)
|
||||
break;
|
||||
case T_MX:
|
||||
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){
|
||||
dns_free_data(r);
|
||||
return NULL;
|
||||
}
|
||||
if (status + 2 > size) {
|
||||
dns_free_data(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
|
||||
strlen(host));
|
||||
if((*rr)->u.mx == NULL) {
|
||||
@@ -213,11 +232,16 @@ parse_reply(unsigned char *data, int len)
|
||||
break;
|
||||
}
|
||||
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){
|
||||
dns_free_data(r);
|
||||
return NULL;
|
||||
}
|
||||
if (status + 6 > size) {
|
||||
dns_free_data(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(*rr)->u.srv =
|
||||
(struct srv_record*)malloc(sizeof(struct srv_record) +
|
||||
strlen(host));
|
||||
@@ -244,6 +268,11 @@ parse_reply(unsigned char *data, int len)
|
||||
case T_KEY : {
|
||||
size_t key_len;
|
||||
|
||||
if (size < 4) {
|
||||
dns_free_data (r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key_len = size - 4;
|
||||
(*rr)->u.key = malloc (sizeof(*(*rr)->u.key) + key_len - 1);
|
||||
if ((*rr)->u.key == NULL) {
|
||||
@@ -261,11 +290,16 @@ parse_reply(unsigned char *data, int len)
|
||||
case T_SIG : {
|
||||
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) {
|
||||
dns_free_data (r);
|
||||
return NULL;
|
||||
}
|
||||
if (status + 18 > size) {
|
||||
dns_free_data(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sig_len = len - 18 - status;
|
||||
(*rr)->u.sig = malloc(sizeof(*(*rr)->u.sig)
|
||||
+ strlen(host) + sig_len);
|
||||
@@ -293,6 +327,11 @@ parse_reply(unsigned char *data, int len)
|
||||
case T_CERT : {
|
||||
size_t cert_len;
|
||||
|
||||
if (size < 5) {
|
||||
dns_free_data(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cert_len = size - 5;
|
||||
(*rr)->u.cert = malloc (sizeof(*(*rr)->u.cert) + cert_len - 1);
|
||||
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];
|
||||
int len;
|
||||
struct dns_reply *r = NULL;
|
||||
#ifdef HAVE__RES
|
||||
u_long old_options = 0;
|
||||
#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",
|
||||
domain, rr_class, dns_type_to_string(rr_type), len);
|
||||
}
|
||||
if (len >= 0)
|
||||
r = parse_reply(reply, len);
|
||||
return r;
|
||||
if(len < 0) {
|
||||
return NULL;
|
||||
} else {
|
||||
len = min(len, sizeof(reply));
|
||||
return parse_reply(reply, len);
|
||||
}
|
||||
}
|
||||
|
||||
struct dns_reply *
|
||||
|
Reference in New Issue
Block a user