mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-01-29 13:30:31 +01:00
Always remove, invalidate and free watches before closing watched sockets
This should mean we don't get invalid fds in the main loop. The BSD (kqueue) and Windows code paths are untested, but follow the same patterns as the tested Linux/generic Unix versions. DBusTransportSocket was already OK (it called free_watches() before _dbus_close_socket, and that did the remove, invalidate, unref dance). Bug: https://bugs.freedesktop.org/show_bug.cgi?id=33336 Reviewed-by: Will Thompson <will.thompson@collabora.co.uk> Reviewed-by: Thiago Macieira <thiago@kde.org>
This commit is contained in:
parent
a2e330980d
commit
58f968a2cc
8 changed files with 124 additions and 78 deletions
|
|
@ -204,16 +204,18 @@ _shutdown_inotify (void *data)
|
|||
|
||||
_set_watched_dirs_internal (&empty);
|
||||
|
||||
close (inotify_fd);
|
||||
inotify_fd = -1;
|
||||
if (watch != NULL)
|
||||
{
|
||||
_dbus_loop_remove_watch (loop, watch, _inotify_watch_callback, NULL);
|
||||
_dbus_watch_invalidate (watch);
|
||||
_dbus_watch_unref (watch);
|
||||
_dbus_loop_unref (loop);
|
||||
}
|
||||
watch = NULL;
|
||||
loop = NULL;
|
||||
|
||||
close (inotify_fd);
|
||||
inotify_fd = -1;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ _handle_kqueue_watch (DBusWatch *watch, unsigned int flags, void *data)
|
|||
if (watch != NULL)
|
||||
{
|
||||
_dbus_loop_remove_watch (loop, watch, _kqueue_watch_callback, NULL);
|
||||
_dbus_watch_invalidate (watch);
|
||||
_dbus_watch_unref (watch);
|
||||
watch = NULL;
|
||||
}
|
||||
|
|
@ -124,10 +125,11 @@ _init_kqueue (BusContext *context)
|
|||
NULL, NULL))
|
||||
{
|
||||
_dbus_warn ("Unable to add reload watch to main loop");
|
||||
close (kq);
|
||||
kq = -1;
|
||||
_dbus_watch_invalidate (watch);
|
||||
_dbus_watch_unref (watch);
|
||||
watch = NULL;
|
||||
close (kq);
|
||||
kq = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
22
bus/main.c
22
bus/main.c
|
|
@ -43,7 +43,8 @@ static int reload_pipe[2];
|
|||
#define RELOAD_READ_END 0
|
||||
#define RELOAD_WRITE_END 1
|
||||
|
||||
static void close_reload_pipe (void);
|
||||
static void close_reload_pipe (DBusWatch **);
|
||||
static void close_reload_pipe_write (void);
|
||||
|
||||
static void
|
||||
signal_handler (int sig)
|
||||
|
|
@ -64,7 +65,7 @@ signal_handler (int sig)
|
|||
!_dbus_write_socket (reload_pipe[RELOAD_WRITE_END], &str, 0, 1))
|
||||
{
|
||||
_dbus_warn ("Unable to write to reload pipe.\n");
|
||||
close_reload_pipe ();
|
||||
close_reload_pipe_write ();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -178,7 +179,7 @@ handle_reload_watch (DBusWatch *watch,
|
|||
_dbus_read_socket (reload_pipe[RELOAD_READ_END], &str, 1) != 1)
|
||||
{
|
||||
_dbus_warn ("Couldn't read from reload pipe.\n");
|
||||
close_reload_pipe ();
|
||||
close_reload_pipe (&watch);
|
||||
return TRUE;
|
||||
}
|
||||
_dbus_string_free (&str);
|
||||
|
|
@ -249,11 +250,24 @@ setup_reload_pipe (DBusLoop *loop)
|
|||
}
|
||||
|
||||
static void
|
||||
close_reload_pipe (void)
|
||||
close_reload_pipe (DBusWatch **watch)
|
||||
{
|
||||
_dbus_loop_remove_watch (bus_context_get_loop (context),
|
||||
*watch, reload_watch_callback, NULL);
|
||||
_dbus_watch_invalidate (*watch);
|
||||
_dbus_watch_unref (*watch);
|
||||
*watch = NULL;
|
||||
|
||||
_dbus_close_socket (reload_pipe[RELOAD_READ_END], NULL);
|
||||
reload_pipe[RELOAD_READ_END] = -1;
|
||||
|
||||
close_reload_pipe_write ();
|
||||
}
|
||||
|
||||
/* this is the only bit that's safe to do from an async signal handler */
|
||||
static void
|
||||
close_reload_pipe_write (void)
|
||||
{
|
||||
_dbus_close_socket (reload_pipe[RELOAD_WRITE_END], NULL);
|
||||
reload_pipe[RELOAD_WRITE_END] = -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -832,11 +832,14 @@ _dbus_loop_iterate (DBusLoop *loop,
|
|||
|
||||
if (_DBUS_UNLIKELY (fds[i].revents & _DBUS_POLLNVAL))
|
||||
{
|
||||
DBusWatch *watch = _dbus_watch_ref (wcb->watch);
|
||||
|
||||
_dbus_warn ("invalid request, socket fd %d not open\n",
|
||||
fds[i].fd);
|
||||
_dbus_watch_invalidate (wcb->watch);
|
||||
_dbus_loop_remove_watch (loop, wcb->watch, wcb->function,
|
||||
_dbus_loop_remove_watch (loop, watch, wcb->function,
|
||||
((Callback *)wcb)->data);
|
||||
_dbus_watch_invalidate (watch);
|
||||
_dbus_watch_unref (watch);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -236,6 +236,7 @@ socket_disconnect (DBusServer *server)
|
|||
{
|
||||
_dbus_server_remove_watch (server,
|
||||
socket_server->watch[i]);
|
||||
_dbus_watch_invalidate (socket_server->watch[i]);
|
||||
_dbus_watch_unref (socket_server->watch[i]);
|
||||
socket_server->watch[i] = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,6 +154,27 @@ _dbus_babysitter_ref (DBusBabysitter *sitter)
|
|||
return sitter;
|
||||
}
|
||||
|
||||
static void
|
||||
close_socket_to_babysitter (DBusBabysitter *sitter)
|
||||
{
|
||||
_dbus_verbose ("Closing babysitter\n");
|
||||
|
||||
if (sitter->sitter_watch != NULL)
|
||||
{
|
||||
_dbus_assert (sitter->watches != NULL);
|
||||
_dbus_watch_list_remove_watch (sitter->watches, sitter->sitter_watch);
|
||||
_dbus_watch_invalidate (sitter->sitter_watch);
|
||||
_dbus_watch_unref (sitter->sitter_watch);
|
||||
sitter->sitter_watch = NULL;
|
||||
}
|
||||
|
||||
if (sitter->socket_to_babysitter != -1)
|
||||
{
|
||||
_dbus_close_socket (sitter->socket_to_babysitter, NULL);
|
||||
sitter->socket_to_babysitter = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement the reference count on the babysitter object.
|
||||
*
|
||||
|
|
@ -172,11 +193,7 @@ _dbus_babysitter_unref (DBusBabysitter *sitter)
|
|||
|
||||
if (sitter->refcount == 0)
|
||||
{
|
||||
if (sitter->socket_to_babysitter != -1)
|
||||
{
|
||||
_dbus_close_socket (sitter->socket_to_babysitter, NULL);
|
||||
sitter->socket_to_babysitter = -1;
|
||||
}
|
||||
close_socket_to_babysitter (sitter);
|
||||
|
||||
if (sitter->socket_to_main != -1)
|
||||
{
|
||||
|
|
@ -372,9 +389,8 @@ handle_watch (DBusWatch *watch,
|
|||
*/
|
||||
|
||||
PING();
|
||||
_dbus_close_socket (sitter->socket_to_babysitter, NULL);
|
||||
close_socket_to_babysitter (sitter);
|
||||
PING();
|
||||
sitter->socket_to_babysitter = -1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -668,6 +684,12 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
|
|||
PING();
|
||||
if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
|
||||
{
|
||||
/* we need to free it early so the destructor won't try to remove it
|
||||
* without it having been added, which DBusLoop doesn't allow */
|
||||
_dbus_watch_invalidate (sitter->sitter_watch);
|
||||
_dbus_watch_unref (sitter->sitter_watch);
|
||||
sitter->sitter_watch = NULL;
|
||||
|
||||
_DBUS_SET_OOM (error);
|
||||
goto out0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -257,6 +257,9 @@ _dbus_babysitter_ref (DBusBabysitter *sitter)
|
|||
return sitter;
|
||||
}
|
||||
|
||||
static void close_socket_to_babysitter (DBusBabysitter *sitter);
|
||||
static void close_error_pipe_from_child (DBusBabysitter *sitter);
|
||||
|
||||
/**
|
||||
* Decrement the reference count on the babysitter object.
|
||||
* When the reference count of the babysitter object reaches
|
||||
|
|
@ -273,25 +276,17 @@ _dbus_babysitter_unref (DBusBabysitter *sitter)
|
|||
|
||||
sitter->refcount -= 1;
|
||||
if (sitter->refcount == 0)
|
||||
{
|
||||
if (sitter->socket_to_babysitter >= 0)
|
||||
{
|
||||
/* If we haven't forked other babysitters
|
||||
* since this babysitter and socket were
|
||||
* created then this close will cause the
|
||||
* babysitter to wake up from poll with
|
||||
* a hangup and then the babysitter will
|
||||
* quit itself.
|
||||
*/
|
||||
_dbus_close_socket (sitter->socket_to_babysitter, NULL);
|
||||
sitter->socket_to_babysitter = -1;
|
||||
}
|
||||
{
|
||||
/* If we haven't forked other babysitters
|
||||
* since this babysitter and socket were
|
||||
* created then this close will cause the
|
||||
* babysitter to wake up from poll with
|
||||
* a hangup and then the babysitter will
|
||||
* quit itself.
|
||||
*/
|
||||
close_socket_to_babysitter (sitter);
|
||||
|
||||
if (sitter->error_pipe_from_child >= 0)
|
||||
{
|
||||
_dbus_close_socket (sitter->error_pipe_from_child, NULL);
|
||||
sitter->error_pipe_from_child = -1;
|
||||
}
|
||||
close_error_pipe_from_child (sitter);
|
||||
|
||||
if (sitter->sitter_pid > 0)
|
||||
{
|
||||
|
|
@ -341,21 +336,7 @@ _dbus_babysitter_unref (DBusBabysitter *sitter)
|
|||
|
||||
sitter->sitter_pid = -1;
|
||||
}
|
||||
|
||||
if (sitter->error_watch)
|
||||
{
|
||||
_dbus_watch_invalidate (sitter->error_watch);
|
||||
_dbus_watch_unref (sitter->error_watch);
|
||||
sitter->error_watch = NULL;
|
||||
}
|
||||
|
||||
if (sitter->sitter_watch)
|
||||
{
|
||||
_dbus_watch_invalidate (sitter->sitter_watch);
|
||||
_dbus_watch_unref (sitter->sitter_watch);
|
||||
sitter->sitter_watch = NULL;
|
||||
}
|
||||
|
||||
if (sitter->watches)
|
||||
_dbus_watch_list_free (sitter->watches);
|
||||
|
||||
|
|
@ -476,16 +457,42 @@ static void
|
|||
close_socket_to_babysitter (DBusBabysitter *sitter)
|
||||
{
|
||||
_dbus_verbose ("Closing babysitter\n");
|
||||
_dbus_close_socket (sitter->socket_to_babysitter, NULL);
|
||||
sitter->socket_to_babysitter = -1;
|
||||
|
||||
if (sitter->sitter_watch != NULL)
|
||||
{
|
||||
_dbus_assert (sitter->watches != NULL);
|
||||
_dbus_watch_list_remove_watch (sitter->watches, sitter->sitter_watch);
|
||||
_dbus_watch_invalidate (sitter->sitter_watch);
|
||||
_dbus_watch_unref (sitter->sitter_watch);
|
||||
sitter->sitter_watch = NULL;
|
||||
}
|
||||
|
||||
if (sitter->socket_to_babysitter >= 0)
|
||||
{
|
||||
_dbus_close_socket (sitter->socket_to_babysitter, NULL);
|
||||
sitter->socket_to_babysitter = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
close_error_pipe_from_child (DBusBabysitter *sitter)
|
||||
{
|
||||
_dbus_verbose ("Closing child error\n");
|
||||
_dbus_close_socket (sitter->error_pipe_from_child, NULL);
|
||||
sitter->error_pipe_from_child = -1;
|
||||
|
||||
if (sitter->error_watch != NULL)
|
||||
{
|
||||
_dbus_assert (sitter->watches != NULL);
|
||||
_dbus_watch_list_remove_watch (sitter->watches, sitter->error_watch);
|
||||
_dbus_watch_invalidate (sitter->error_watch);
|
||||
_dbus_watch_unref (sitter->error_watch);
|
||||
sitter->error_watch = NULL;
|
||||
}
|
||||
|
||||
if (sitter->error_pipe_from_child >= 0)
|
||||
{
|
||||
_dbus_close_socket (sitter->error_pipe_from_child, NULL);
|
||||
sitter->error_pipe_from_child = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -752,7 +759,7 @@ handle_watch (DBusWatch *watch,
|
|||
unsigned int condition,
|
||||
void *data)
|
||||
{
|
||||
DBusBabysitter *sitter = data;
|
||||
DBusBabysitter *sitter = _dbus_babysitter_ref (data);
|
||||
int revents;
|
||||
int fd;
|
||||
|
||||
|
|
@ -775,31 +782,12 @@ handle_watch (DBusWatch *watch,
|
|||
babysitter_iteration (sitter, FALSE))
|
||||
;
|
||||
|
||||
/* Those might have closed the sockets we're watching. Before returning
|
||||
* to the main loop, we must sort that out. */
|
||||
|
||||
if (sitter->error_watch != NULL && sitter->error_pipe_from_child == -1)
|
||||
{
|
||||
_dbus_watch_invalidate (sitter->error_watch);
|
||||
|
||||
if (sitter->watches != NULL)
|
||||
_dbus_watch_list_remove_watch (sitter->watches, sitter->error_watch);
|
||||
|
||||
_dbus_watch_unref (sitter->error_watch);
|
||||
sitter->error_watch = NULL;
|
||||
}
|
||||
|
||||
if (sitter->sitter_watch != NULL && sitter->socket_to_babysitter == -1)
|
||||
{
|
||||
_dbus_watch_invalidate (sitter->sitter_watch);
|
||||
|
||||
if (sitter->watches != NULL)
|
||||
_dbus_watch_list_remove_watch (sitter->watches, sitter->sitter_watch);
|
||||
|
||||
_dbus_watch_unref (sitter->sitter_watch);
|
||||
sitter->sitter_watch = NULL;
|
||||
}
|
||||
/* fd.o #32992: if the handle_* methods closed their sockets, they previously
|
||||
* didn't always remove the watches. Check that we don't regress. */
|
||||
_dbus_assert (sitter->socket_to_babysitter != -1 || sitter->sitter_watch == NULL);
|
||||
_dbus_assert (sitter->error_pipe_from_child != -1 || sitter->error_watch == NULL);
|
||||
|
||||
_dbus_babysitter_unref (sitter);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -1189,6 +1177,12 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
|
|||
|
||||
if (!_dbus_watch_list_add_watch (sitter->watches, sitter->error_watch))
|
||||
{
|
||||
/* we need to free it early so the destructor won't try to remove it
|
||||
* without it having been added, which DBusLoop doesn't allow */
|
||||
_dbus_watch_invalidate (sitter->error_watch);
|
||||
_dbus_watch_unref (sitter->error_watch);
|
||||
sitter->error_watch = NULL;
|
||||
|
||||
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
|
||||
goto cleanup_and_fail;
|
||||
}
|
||||
|
|
@ -1204,6 +1198,12 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
|
|||
|
||||
if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
|
||||
{
|
||||
/* we need to free it early so the destructor won't try to remove it
|
||||
* without it having been added, which DBusLoop doesn't allow */
|
||||
_dbus_watch_invalidate (sitter->sitter_watch);
|
||||
_dbus_watch_unref (sitter->sitter_watch);
|
||||
sitter->sitter_watch = NULL;
|
||||
|
||||
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
|
||||
goto cleanup_and_fail;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1278,8 +1278,10 @@ _dbus_transport_new_for_socket (int fd,
|
|||
return (DBusTransport*) socket_transport;
|
||||
|
||||
failed_4:
|
||||
_dbus_watch_invalidate (socket_transport->read_watch);
|
||||
_dbus_watch_unref (socket_transport->read_watch);
|
||||
failed_3:
|
||||
_dbus_watch_invalidate (socket_transport->write_watch);
|
||||
_dbus_watch_unref (socket_transport->write_watch);
|
||||
failed_2:
|
||||
_dbus_string_free (&socket_transport->encoded_incoming);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue