[PATCH] Fix potential crash on service name collision.

Patrick Oppenlander patrick at motec.com.au
Tue Jan 26 18:57:45 PST 2010


If there is a service name collision and the entry group callback calls avahi_s_entry_group_reset or avahi_s_entry_group free on the group in question, the entries were released. This could cause a crash in withdraw_rrset as it is walking a list of entries at this time.

The fix for this issue is to schedule a cleanup event to clean up entries after a a short timeout (currently one second). If a cleanup occurs for any other reason the event is cancelled.
---
 avahi-core/entry.c    |   26 ++++++++++++++++++++++++--
 avahi-core/internal.h |    3 +++
 avahi-core/server.c   |    4 ++++
 3 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/avahi-core/entry.c b/avahi-core/entry.c
index 8ac1da4..9ce07e4 100644
--- a/avahi-core/entry.c
+++ b/avahi-core/entry.c
@@ -144,6 +144,11 @@ void avahi_cleanup_dead_entries(AvahiServer *s) {
 
     if (s->need_browser_cleanup)
         avahi_browser_cleanup(s);
+
+    if (s->cleanup_time_event) {
+        avahi_time_event_free(s->cleanup_time_event);
+        s->cleanup_time_event = NULL;
+    }
 }
 
 static int check_record_conflict(AvahiServer *s, AvahiIfIndex interface, AvahiProtocol protocol, AvahiRecord *r, AvahiPublishFlags flags) {
@@ -1066,6 +1071,23 @@ AvahiSEntryGroup *avahi_s_entry_group_new(AvahiServer *s, AvahiSEntryGroupCallba
     return g;
 }
 
+static void cleanup_time_event_callback(AVAHI_GCC_UNUSED AvahiTimeEvent *e, void* userdata) {
+    AvahiServer *s = userdata;
+
+    assert(s);
+
+    avahi_cleanup_dead_entries(s);
+}
+
+static void schedule_cleanup(AvahiServer *s) {
+    struct timeval tv;
+
+    assert(s);
+
+    if (!s->cleanup_time_event)
+        s->cleanup_time_event = avahi_time_event_new(s->time_event_queue, avahi_elapse_time(&tv, 1000, 0), &cleanup_time_event_callback, s);
+}
+
 void avahi_s_entry_group_free(AvahiSEntryGroup *g) {
     AvahiEntry *e;
     
@@ -1089,7 +1111,7 @@ void avahi_s_entry_group_free(AvahiSEntryGroup *g) {
     g->server->need_group_cleanup = 1;
     g->server->need_entry_cleanup = 1;
 
-    avahi_cleanup_dead_entries(g->server);
+    schedule_cleanup(g->server);
 }
 
 static void entry_group_commit_real(AvahiSEntryGroup *g) {
@@ -1170,7 +1192,7 @@ void avahi_s_entry_group_reset(AvahiSEntryGroup *g) {
 
     avahi_s_entry_group_change_state(g, AVAHI_ENTRY_GROUP_UNCOMMITED);
 
-    avahi_cleanup_dead_entries(g->server);
+    schedule_cleanup(g->server);
 }
 
 int avahi_entry_is_commited(AvahiEntry *e) {
diff --git a/avahi-core/internal.h b/avahi-core/internal.h
index d0a10d6..3933a8c 100644
--- a/avahi-core/internal.h
+++ b/avahi-core/internal.h
@@ -122,6 +122,9 @@ struct AvahiServer {
     AVAHI_LLIST_HEAD(AvahiSDNSServerBrowser, dns_server_browsers);
 
     int need_entry_cleanup, need_group_cleanup, need_browser_cleanup;
+
+    /* Used for scheduling cleanup */
+    AvahiTimeEvent *cleanup_time_event;
     
     AvahiTimeEventQueue *time_event_queue;
     
diff --git a/avahi-core/server.c b/avahi-core/server.c
index 810ccc0..b05b8ff 100644
--- a/avahi-core/server.c
+++ b/avahi-core/server.c
@@ -1390,6 +1390,7 @@ AvahiServer *avahi_server_new(const AvahiPoll *poll_api, const AvahiServerConfig
     s->need_entry_cleanup = 0;
     s->need_group_cleanup = 0;
     s->need_browser_cleanup = 0;
+    s->cleanup_time_event = NULL;
     s->hinfo_entry_group = NULL;
     s->browse_domain_entry_group = NULL;
     s->error = AVAHI_OK;
@@ -1491,6 +1492,9 @@ void avahi_server_free(AvahiServer* s) {
 	if (AVAHI_CFG_ENABLE_MULTICAST_LOOKUP)
 	    avahi_multicast_lookup_engine_free(s->multicast_lookup_engine);
 
+    if (s->cleanup_time_event)
+        avahi_time_event_free(s->cleanup_time_event);
+
     avahi_time_event_queue_free(s->time_event_queue);
 
     /* Free watches */
-- 
1.6.6.1


--------------080109020708040700030309--


More information about the avahi mailing list