]> git.meshlink.io Git - catta/commitdiff
core: fix potential crash on service name collision
authorPatrick Oppenlander <patrick@motec.com.au>
Mon, 28 Jun 2010 23:08:26 +0000 (01:08 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 28 Jun 2010 23:09:28 +0000 (01:09 +0200)
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.

http://avahi.org/ticket/302

avahi-core/entry.c
avahi-core/internal.h
avahi-core/server.c

index b02964cabeda8d651b0d98f2cc79c3b01f07cc65..0d862133db9996fa90f9aca938fa91bd5b22be98 100644 (file)
@@ -141,6 +141,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) {
@@ -1063,6 +1068,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;
 
@@ -1086,7 +1108,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) {
@@ -1167,7 +1189,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) {
index a4b10ed2f762c1fdc3cedd2b90c8112027c0f8b2..eb7f14637bd0bc6847b7b47c45b89e55dca15b53 100644 (file)
@@ -121,6 +121,9 @@ struct AvahiServer {
 
     int need_entry_cleanup, need_group_cleanup, need_browser_cleanup;
 
+    /* Used for scheduling RR cleanup */
+    AvahiTimeEvent *cleanup_time_event;
+
     AvahiTimeEventQueue *time_event_queue;
 
     char *host_name, *host_name_fqdn, *domain_name;
index a149f0fbc68bd68425cd610a9fd9aaac037b476e..d7fd71bc31714dba42825cd285c3d84d6a69a34d 100644 (file)
@@ -1387,6 +1387,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;
@@ -1486,6 +1487,9 @@ void avahi_server_free(AvahiServer* s) {
         avahi_wide_area_engine_free(s->wide_area_lookup_engine);
     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 */