Add validity checking to TXT data parsing, this fixes a remotely exploitable vulnerab...
authorLennart Poettering <lennart@poettering.net>
Thu, 27 Oct 2005 14:30:46 +0000 (14:30 +0000)
committerLennart Poettering <lennart@poettering.net>
Thu, 27 Oct 2005 14:30:46 +0000 (14:30 +0000)
git-svn-id: file:///home/lennart/svn/public/avahi/trunk@888 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe

avahi-common/strlst-test.c
avahi-common/strlst.c
avahi-common/strlst.h
avahi-compat-howl/compat.c
avahi-compat-howl/text.c
avahi-compat-libdns_sd/compat.c
avahi-core/dns.c

index 68dc472..3cdcb12 100644 (file)
@@ -69,7 +69,7 @@ int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char *argv[]) {
 
     printf("\n");
     
-    b = avahi_string_list_parse(data, size);
+    assert(avahi_string_list_parse(data, size, &b) == 0);
 
     assert(avahi_string_list_equal(a, b));
     
@@ -119,7 +119,7 @@ int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char *argv[]) {
     assert(size == 1);
     assert(size == n);
 
-    a = avahi_string_list_parse(data, size);
+    assert(avahi_string_list_parse(data, size, &a) == 0);
     assert(!a);
     
     return 0;
index 04941b4..4b96112 100644 (file)
@@ -68,29 +68,45 @@ AvahiStringList *avahi_string_list_add(AvahiStringList *l, const char *text) {
     return avahi_string_list_add_arbitrary(l, (const uint8_t*) text, strlen(text));
 }
 
-AvahiStringList *avahi_string_list_parse(const void* data, size_t size) {
-    AvahiStringList *r = NULL;
+int avahi_string_list_parse(const void* data, size_t size, AvahiStringList **ret) {
     const uint8_t *c;
+    AvahiStringList *r;
     
     assert(data);
+    assert(ret);
+
+    r = NULL;
 
     c = data;
-    for (;;) {
+    while (size > 0) {
         size_t k;
         
-        if (size < 1)
-            break;
-
         k = *(c++);
+        size--;
 
-        if (k > 0) /* Ignore empty strings */
-            r = avahi_string_list_add_arbitrary(r, c, k);
-        c += k;
+        if (k > size)
+            goto fail; /* Overflow */
+
+        if (k > 0) { /* Ignore empty strings */
+            AvahiStringList *n;
 
-        size -= 1 + k;
+            if (!(n = avahi_string_list_add_arbitrary(r, c, k)))  
+                goto fail; /* OOM */
+
+            r = n;
+        }
+            
+        c += k;
+        size -= k;
     }
 
-    return r;
+    *ret = r;
+    
+    return 0;
+
+fail:
+    avahi_string_list_free(*ret);
+    return -1;
 }
 
 void avahi_string_list_free(AvahiStringList *l) {
index 1e69367..26708a5 100644 (file)
@@ -102,7 +102,7 @@ char* avahi_string_list_to_string(AvahiStringList *l);
 size_t avahi_string_list_serialize(AvahiStringList *l, void * data, size_t size);
 
 /** Inverse of avahi_string_list_serialize() */
-AvahiStringList *avahi_string_list_parse(const void *data, size_t size);
+int avahi_string_list_parse(const void *data, size_t size, AvahiStringList **ret);
 
 /** Compare to string lists */
 int avahi_string_list_equal(const AvahiStringList *a, const AvahiStringList *b);
index 9160fdb..18171f8 100644 (file)
@@ -769,6 +769,7 @@ sw_result sw_discovery_publish(
     oid_data *data;
     sw_result result = SW_E_UNKNOWN;
     service_data *sdata;
+    AvahiStringList *txt = NULL;
     
     assert(self);
     assert(name);
@@ -778,10 +779,17 @@ sw_result sw_discovery_publish(
     
     AVAHI_WARN_LINKAGE;
 
-    if ((*oid = oid_alloc(self, OID_ENTRY_GROUP)) == (sw_discovery_oid) -1)
+    if (text_record && text_record_len > 0)
+        if (avahi_string_list_parse(text_record, text_record_len, &txt) < 0)
+            return SW_E_UNKNOWN;
+
+    if ((*oid = oid_alloc(self, OID_ENTRY_GROUP)) == (sw_discovery_oid) -1) {
+        avahi_string_list_free(txt);
         return SW_E_UNKNOWN;
+    }
 
     if (!(sdata = service_data_new(self))) {
+        avahi_string_list_free(txt);
         oid_release(self, *oid);
         return SW_E_MEM;
     }
@@ -798,7 +806,7 @@ sw_result sw_discovery_publish(
     sdata->domain = domain ? avahi_normalize_name_strdup(domain) : NULL;
     sdata->host = host ? avahi_normalize_name_strdup(host) : NULL;
     sdata->port = port;
-    sdata->txt = text_record && text_record_len > 0 ? avahi_string_list_parse(text_record, text_record_len) : NULL;
+    sdata->txt = txt;
 
     /* Some OOM checking would be cool here */
 
index fb05acf..3b717be 100644 (file)
@@ -194,6 +194,7 @@ sw_result sw_text_record_iterator_init(
     sw_octets text_record,
     sw_uint32 text_record_len) {
 
+    AvahiStringList *txt;
     assert(self);
 
     AVAHI_WARN_LINKAGE;
@@ -203,7 +204,13 @@ sw_result sw_text_record_iterator_init(
         return SW_E_UNKNOWN;
     }
 
-    (*self)->index = (*self)->strlst = avahi_string_list_reverse(avahi_string_list_parse(text_record, text_record_len));
+    if (avahi_string_list_parse(text_record, text_record_len, &txt) < 0) {
+        avahi_free(*self);
+        *self = NULL;
+        return SW_E_UNKNOWN;
+    }
+
+    (*self)->index = (*self)->strlst = avahi_string_list_reverse(txt);
     
     return SW_OKAY;
 }
index afc9214..6a1b30d 100644 (file)
@@ -974,6 +974,7 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister (
     DNSServiceErrorType ret = kDNSServiceErr_Unknown;
     int error;
     DNSServiceRef sdref = NULL;
+    AvahiStringList *txt = NULL;
 
     AVAHI_WARN_LINKAGE;
 
@@ -986,8 +987,14 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister (
         return kDNSServiceErr_Unsupported;
     }
 
-    if (!(sdref = sdref_new()))
+    if (txtRecord && txtLen > 0) 
+        if (avahi_string_list_parse(txtRecord, txtLen, &txt) < 0)
+            return kDNSServiceErr_Invalid;
+    
+    if (!(sdref = sdref_new())) {
+        avahi_string_list_free(txt);
         return kDNSServiceErr_Unknown;
+    }
 
     sdref->context = context;
     sdref->service_register_callback = callback;
@@ -998,7 +1005,7 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister (
     sdref->service_host = host ? avahi_normalize_name_strdup(host) : NULL;
     sdref->service_interface = interface == kDNSServiceInterfaceIndexAny ? AVAHI_IF_UNSPEC : (AvahiIfIndex) interface;
     sdref->service_port = ntohs(port);
-    sdref->service_txt = txtRecord && txtLen > 0 ? avahi_string_list_parse(txtRecord, txtLen) : NULL;
+    sdref->service_txt = txt;
 
     /* Some OOM checking would be cool here */
     
index 63ea8a0..d237d55 100644 (file)
@@ -544,7 +544,8 @@ static int parse_rdata(AvahiDnsPacket *p, AvahiRecord *r, uint16_t rdlength) {
         case AVAHI_DNS_TYPE_TXT:
 
             if (rdlength > 0) {
-                r->data.txt.string_list = avahi_string_list_parse(avahi_dns_packet_get_rptr(p), rdlength);
+                if (avahi_string_list_parse(avahi_dns_packet_get_rptr(p), rdlength, &r->data.txt.string_list) < 0)
+                    return -1;
                 
                 if (avahi_dns_packet_skip(p, rdlength) < 0)
                     return -1;