From 4dc1f6c7e90209ab537395926e4c75090a33a2c3 Mon Sep 17 00:00:00 2001
From: Patrick Oppenlander <patrick@motec.com.au>
Date: Wed, 27 Jan 2010 13:57:45 +1100
Subject: [PATCH] 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.
---
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
|
b
|
|
| 144 | 144 | |
| 145 | 145 | if (s->need_browser_cleanup) |
| 146 | 146 | avahi_browser_cleanup(s); |
| | 147 | |
| | 148 | if (s->cleanup_time_event) { |
| | 149 | avahi_time_event_free(s->cleanup_time_event); |
| | 150 | s->cleanup_time_event = NULL; |
| | 151 | } |
| 147 | 152 | } |
| 148 | 153 | |
| 149 | 154 | static int check_record_conflict(AvahiServer *s, AvahiIfIndex interface, AvahiProtocol protocol, AvahiRecord *r, AvahiPublishFlags flags) { |
| … |
… |
|
| 1066 | 1071 | return g; |
| 1067 | 1072 | } |
| 1068 | 1073 | |
| | 1074 | static void cleanup_time_event_callback(AVAHI_GCC_UNUSED AvahiTimeEvent *e, void* userdata) { |
| | 1075 | AvahiServer *s = userdata; |
| | 1076 | |
| | 1077 | assert(s); |
| | 1078 | |
| | 1079 | avahi_cleanup_dead_entries(s); |
| | 1080 | } |
| | 1081 | |
| | 1082 | static void schedule_cleanup(AvahiServer *s) { |
| | 1083 | struct timeval tv; |
| | 1084 | |
| | 1085 | assert(s); |
| | 1086 | |
| | 1087 | if (!s->cleanup_time_event) |
| | 1088 | s->cleanup_time_event = avahi_time_event_new(s->time_event_queue, avahi_elapse_time(&tv, 1000, 0), &cleanup_time_event_callback, s); |
| | 1089 | } |
| | 1090 | |
| 1069 | 1091 | void avahi_s_entry_group_free(AvahiSEntryGroup *g) { |
| 1070 | 1092 | AvahiEntry *e; |
| 1071 | 1093 | |
| … |
… |
|
| 1089 | 1111 | g->server->need_group_cleanup = 1; |
| 1090 | 1112 | g->server->need_entry_cleanup = 1; |
| 1091 | 1113 | |
| 1092 | | avahi_cleanup_dead_entries(g->server); |
| | 1114 | schedule_cleanup(g->server); |
| 1093 | 1115 | } |
| 1094 | 1116 | |
| 1095 | 1117 | static void entry_group_commit_real(AvahiSEntryGroup *g) { |
| … |
… |
|
| 1170 | 1192 | |
| 1171 | 1193 | avahi_s_entry_group_change_state(g, AVAHI_ENTRY_GROUP_UNCOMMITED); |
| 1172 | 1194 | |
| 1173 | | avahi_cleanup_dead_entries(g->server); |
| | 1195 | schedule_cleanup(g->server); |
| 1174 | 1196 | } |
| 1175 | 1197 | |
| 1176 | 1198 | int avahi_entry_is_commited(AvahiEntry *e) { |
diff --git a/avahi-core/internal.h b/avahi-core/internal.h
index d0a10d6..3933a8c 100644
|
a
|
b
|
|
| 122 | 122 | AVAHI_LLIST_HEAD(AvahiSDNSServerBrowser, dns_server_browsers); |
| 123 | 123 | |
| 124 | 124 | int need_entry_cleanup, need_group_cleanup, need_browser_cleanup; |
| | 125 | |
| | 126 | /* Used for scheduling cleanup */ |
| | 127 | AvahiTimeEvent *cleanup_time_event; |
| 125 | 128 | |
| 126 | 129 | AvahiTimeEventQueue *time_event_queue; |
| 127 | 130 | |
diff --git a/avahi-core/server.c b/avahi-core/server.c
index 810ccc0..b05b8ff 100644
|
a
|
b
|
|
| 1390 | 1390 | s->need_entry_cleanup = 0; |
| 1391 | 1391 | s->need_group_cleanup = 0; |
| 1392 | 1392 | s->need_browser_cleanup = 0; |
| | 1393 | s->cleanup_time_event = NULL; |
| 1393 | 1394 | s->hinfo_entry_group = NULL; |
| 1394 | 1395 | s->browse_domain_entry_group = NULL; |
| 1395 | 1396 | s->error = AVAHI_OK; |
| … |
… |
|
| 1491 | 1492 | if (AVAHI_CFG_ENABLE_MULTICAST_LOOKUP) |
| 1492 | 1493 | avahi_multicast_lookup_engine_free(s->multicast_lookup_engine); |
| 1493 | 1494 | |
| | 1495 | if (s->cleanup_time_event) |
| | 1496 | avahi_time_event_free(s->cleanup_time_event); |
| | 1497 | |
| 1494 | 1498 | avahi_time_event_queue_free(s->time_event_queue); |
| 1495 | 1499 | |
| 1496 | 1500 | /* Free watches */ |