summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Menšík <pemensik@redhat.com>2023-04-17 20:55:31 +0100
committerSimon Kelley <simon@thekelleys.org.uk>2023-04-17 20:55:31 +0100
commit33635d8564f96cedcef9bf9826cbbca76f28aa81 (patch)
tree16c3b6b8db89a8750026e302dcc25f1096a40e4b
parentbd188e306a06ca0acb6c213ecc0e1dc0dc22c3f6 (diff)
downloaddnsmasq-33635d8564f96cedcef9bf9826cbbca76f28aa81.tar.gz
Fix crash in dbus code.
If I configure dnsmasq to use dbus and then restart dbus.service with watchers present, it crashes dnsmasq. The reason is simple, it uses loop to walk over watchers to call dbus handling code. But from that code the same list can be modified and watchers removed. But the list iteration continues anyway. Restart the loop if list were modified.
-rw-r--r--src/dbus.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/src/dbus.c b/src/dbus.c
index 24efcb8..34cf2f6 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -106,6 +106,7 @@ const char* introspection_xml_template =
"</node>\n";
static char *introspection_xml = NULL;
+static int watches_modified = 0;
struct watch {
DBusWatch *watch;
@@ -127,6 +128,7 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *data)
w->watch = watch;
w->next = daemon->watches;
daemon->watches = w;
+ watches_modified++;
(void)data; /* no warning */
return TRUE;
@@ -134,7 +136,7 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *data)
static void remove_watch(DBusWatch *watch, void *data)
{
- struct watch **up, *w, *tmp;
+ struct watch **up, *w, *tmp;
for (up = &(daemon->watches), w = daemon->watches; w; w = tmp)
{
@@ -143,6 +145,7 @@ static void remove_watch(DBusWatch *watch, void *data)
{
*up = tmp;
free(w);
+ watches_modified++;
}
else
up = &(w->next);
@@ -966,11 +969,11 @@ void set_dbus_listeners(void)
}
}
-void check_dbus_listeners()
+static int check_dbus_watches()
{
- DBusConnection *connection = (DBusConnection *)daemon->dbus;
struct watch *w;
+ watches_modified = 0;
for (w = daemon->watches; w; w = w->next)
if (dbus_watch_get_enabled(w->watch))
{
@@ -987,9 +990,22 @@ void check_dbus_listeners()
flags |= DBUS_WATCH_ERROR;
if (flags != 0)
- dbus_watch_handle(w->watch, flags);
+ {
+ dbus_watch_handle(w->watch, flags);
+ if (watches_modified)
+ return 0;
+ }
}
+ return 1;
+}
+
+void check_dbus_listeners()
+{
+ DBusConnection *connection = (DBusConnection *)daemon->dbus;
+
+ while (!check_dbus_watches()) ;
+
if (connection)
{
dbus_connection_ref (connection);