[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