diff options
author | Patrick Oppenlander <patrick@motec.com.au> | 2010-06-29 01:08:26 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2010-06-29 01:09:28 +0200 |
commit | 3544d4584c70debc7bbf93c6dad00b303ff8919a (patch) | |
tree | fa72289ea4e76189732d70ab3e3b158da7f0dfea /avahi-core | |
parent | 4cee342544b5d31022462ba522eed9959ebbd9dd (diff) |
core: fix potential crash on service name collision
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
Diffstat (limited to 'avahi-core')
-rw-r--r-- | avahi-core/entry.c | 26 | ||||
-rw-r--r-- | avahi-core/internal.h | 3 | ||||
-rw-r--r-- | 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 b02964c..0d86213 100644 --- a/avahi-core/entry.c +++ b/avahi-core/entry.c @@ -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) { diff --git a/avahi-core/internal.h b/avahi-core/internal.h index a4b10ed..eb7f146 100644 --- a/avahi-core/internal.h +++ b/avahi-core/internal.h @@ -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; diff --git a/avahi-core/server.c b/avahi-core/server.c index a149f0f..d7fd71b 100644 --- a/avahi-core/server.c +++ b/avahi-core/server.c @@ -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 */ |