From 20011324500a728851e4888c890a756ecf71394b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 27 Oct 2005 14:30:46 +0000 Subject: [PATCH] Add validity checking to TXT data parsing, this fixes a remotely exploitable vulnerability. git-svn-id: file:///home/lennart/svn/public/avahi/trunk@888 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- avahi-common/strlst-test.c | 4 ++-- avahi-common/strlst.c | 38 +++++++++++++++++++++++---------- avahi-common/strlst.h | 2 +- avahi-compat-howl/compat.c | 12 +++++++++-- avahi-compat-howl/text.c | 9 +++++++- avahi-compat-libdns_sd/compat.c | 11 ++++++++-- avahi-core/dns.c | 3 ++- 7 files changed, 59 insertions(+), 20 deletions(-) diff --git a/avahi-common/strlst-test.c b/avahi-common/strlst-test.c index 68dc472..3cdcb12 100644 --- a/avahi-common/strlst-test.c +++ b/avahi-common/strlst-test.c @@ -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; diff --git a/avahi-common/strlst.c b/avahi-common/strlst.c index 04941b4..4b96112 100644 --- a/avahi-common/strlst.c +++ b/avahi-common/strlst.c @@ -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) { diff --git a/avahi-common/strlst.h b/avahi-common/strlst.h index 1e69367..26708a5 100644 --- a/avahi-common/strlst.h +++ b/avahi-common/strlst.h @@ -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); diff --git a/avahi-compat-howl/compat.c b/avahi-compat-howl/compat.c index 9160fdb..18171f8 100644 --- a/avahi-compat-howl/compat.c +++ b/avahi-compat-howl/compat.c @@ -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 */ diff --git a/avahi-compat-howl/text.c b/avahi-compat-howl/text.c index fb05acf..3b717be 100644 --- a/avahi-compat-howl/text.c +++ b/avahi-compat-howl/text.c @@ -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; } diff --git a/avahi-compat-libdns_sd/compat.c b/avahi-compat-libdns_sd/compat.c index afc9214..6a1b30d 100644 --- a/avahi-compat-libdns_sd/compat.c +++ b/avahi-compat-libdns_sd/compat.c @@ -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 */ diff --git a/avahi-core/dns.c b/avahi-core/dns.c index 63ea8a0..d237d55 100644 --- a/avahi-core/dns.c +++ b/avahi-core/dns.c @@ -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; -- 2.39.5