diff options
author | Simon McVittie <smcv@debian.org> | 2014-09-15 12:55:54 +0100 |
---|---|---|
committer | Simon McVittie <smcv@debian.org> | 2014-09-15 12:55:54 +0100 |
commit | 403920f796c3cbeca1bba58bda497da4770e7d0a (patch) | |
tree | 22c59d2418690f68e169ff7500b22f92d410f55f /dbus | |
parent | d35dfa78f7ee90bebc3c8a290a7f5877feb7eb8b (diff) | |
download | dbus-403920f796c3cbeca1bba58bda497da4770e7d0a.tar.gz |
Imported Upstream version 1.8.8upstream/1.8.8
Diffstat (limited to 'dbus')
-rw-r--r-- | dbus/Makefile.in | 1 | ||||
-rw-r--r-- | dbus/dbus-connection-internal.h | 6 | ||||
-rw-r--r-- | dbus/dbus-connection.c | 27 | ||||
-rw-r--r-- | dbus/dbus-internals.h | 2 | ||||
-rw-r--r-- | dbus/dbus-macros.h | 3 | ||||
-rw-r--r-- | dbus/dbus-message-internal.h | 4 | ||||
-rw-r--r-- | dbus/dbus-message-private.h | 2 | ||||
-rw-r--r-- | dbus/dbus-message.c | 41 | ||||
-rw-r--r-- | dbus/dbus-server-protected.h | 5 | ||||
-rw-r--r-- | dbus/dbus-server.c | 19 | ||||
-rw-r--r-- | dbus/dbus-sysdeps-unix.c | 49 | ||||
-rw-r--r-- | dbus/dbus-sysdeps.h | 8 | ||||
-rw-r--r-- | dbus/dbus-transport.c | 27 | ||||
-rw-r--r-- | dbus/dbus-transport.h | 4 | ||||
-rw-r--r-- | dbus/dbus-watch.c | 21 | ||||
-rw-r--r-- | dbus/dbus-watch.h | 2 |
16 files changed, 196 insertions, 25 deletions
diff --git a/dbus/Makefile.in b/dbus/Makefile.in index d10ebb31..43e3c7d0 100644 --- a/dbus/Makefile.in +++ b/dbus/Makefile.in @@ -514,7 +514,6 @@ DBUS_USER = @DBUS_USER@ DBUS_VERSION = @DBUS_VERSION@ DBUS_X_CFLAGS = @DBUS_X_CFLAGS@ DBUS_X_LIBS = @DBUS_X_LIBS@ -DEFAULT_MESSAGE_UNIX_FDS = @DEFAULT_MESSAGE_UNIX_FDS@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index 2842f2f4..28974040 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -44,6 +44,8 @@ typedef enum /** default timeout value when waiting for a message reply, 25 seconds */ #define _DBUS_DEFAULT_TIMEOUT_VALUE (25 * 1000) +typedef void (* DBusPendingFdsChangeFunction) (void *data); + void _dbus_connection_lock (DBusConnection *connection); void _dbus_connection_unlock (DBusConnection *connection); DBusConnection * _dbus_connection_ref_unlocked (DBusConnection *connection); @@ -100,6 +102,10 @@ void _dbus_connection_test_get_locks (DBusConnectio DBusMutex **io_path_mutex_loc, DBusCondVar **dispatch_cond_loc, DBusCondVar **io_path_cond_loc); +int _dbus_connection_get_pending_fds_count (DBusConnection *connection); +void _dbus_connection_set_pending_fds_function (DBusConnection *connection, + DBusPendingFdsChangeFunction callback, + void *data); /* if DBUS_ENABLE_STATS */ void _dbus_connection_get_stats (DBusConnection *connection, diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index f0b6871e..b574207d 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -2549,6 +2549,33 @@ _dbus_connection_block_pending_call (DBusPendingCall *pending) dbus_pending_call_unref (pending); } +/** + * Return how many file descriptors are pending in the loader + * + * @param connection the connection + */ +int +_dbus_connection_get_pending_fds_count (DBusConnection *connection) +{ + return _dbus_transport_get_pending_fds_count (connection->transport); +} + +/** + * Register a function to be called whenever the number of pending file + * descriptors in the loader change. + * + * @param connection the connection + * @param callback the callback + */ +void +_dbus_connection_set_pending_fds_function (DBusConnection *connection, + DBusPendingFdsChangeFunction callback, + void *data) +{ + _dbus_transport_set_pending_fds_function (connection->transport, + callback, data); +} + /** @} */ /** diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index c64d7566..4658b67b 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -371,7 +371,7 @@ dbus_bool_t _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str); #define _DBUS_PASTE(a, b) _DBUS_PASTE2 (a, b) #define _DBUS_STATIC_ASSERT(expr) \ typedef struct { char _assertion[(expr) ? 1 : -1]; } \ - _DBUS_PASTE (_DBUS_STATIC_ASSERT_, __LINE__) + _DBUS_PASTE (_DBUS_STATIC_ASSERT_, __LINE__) _DBUS_GNUC_UNUSED DBUS_END_DECLS diff --git a/dbus/dbus-macros.h b/dbus/dbus-macros.h index cae4100e..8d6c3000 100644 --- a/dbus/dbus-macros.h +++ b/dbus/dbus-macros.h @@ -69,9 +69,12 @@ __attribute__((__format__ (__printf__, format_idx, arg_idx))) #define _DBUS_GNUC_NORETURN \ __attribute__((__noreturn__)) +#define _DBUS_GNUC_UNUSED \ + __attribute__((__unused__)) #else /* !__GNUC__ */ #define _DBUS_GNUC_PRINTF( format_idx, arg_idx ) #define _DBUS_GNUC_NORETURN +#define _DBUS_GNUC_UNUSED #endif /* !__GNUC__ */ #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) diff --git a/dbus/dbus-message-internal.h b/dbus/dbus-message-internal.h index 5d6594e3..e9a9ec01 100644 --- a/dbus/dbus-message-internal.h +++ b/dbus/dbus-message-internal.h @@ -96,6 +96,10 @@ long _dbus_message_loader_get_max_message_size (DBusMessageLoader void _dbus_message_loader_set_max_message_unix_fds(DBusMessageLoader *loader, long n); long _dbus_message_loader_get_max_message_unix_fds(DBusMessageLoader *loader); +int _dbus_message_loader_get_pending_fds_count (DBusMessageLoader *loader); +void _dbus_message_loader_set_pending_fds_function (DBusMessageLoader *loader, + void (* callback) (void *), + void *data); typedef struct DBusInitialFDs DBusInitialFDs; DBusInitialFDs *_dbus_check_fdleaks_enter (void); diff --git a/dbus/dbus-message-private.h b/dbus/dbus-message-private.h index e1578abd..a611b095 100644 --- a/dbus/dbus-message-private.h +++ b/dbus/dbus-message-private.h @@ -80,6 +80,8 @@ struct DBusMessageLoader int *unix_fds; /**< File descriptors that have been read from the transport but not yet been handed to any message. Array will be allocated at first use. */ unsigned n_unix_fds_allocated; /**< Number of file descriptors this array has space for */ unsigned n_unix_fds; /**< Number of valid file descriptors in array */ + void (* unix_fds_change) (void *); /**< Notify when the pending fds change */ + void *unix_fds_change_data; #endif }; diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 78df7558..3e74fc54 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -35,6 +35,7 @@ #include "dbus-list.h" #include "dbus-threads-internal.h" #ifdef HAVE_UNIX_FD_PASSING +#include "dbus-sysdeps.h" #include "dbus-sysdeps-unix.h" #endif @@ -4058,6 +4059,9 @@ _dbus_message_loader_return_unix_fds(DBusMessageLoader *loader, loader->n_unix_fds += n_fds; loader->unix_fds_outstanding = FALSE; + + if (n_fds && loader->unix_fds_change) + loader->unix_fds_change (loader->unix_fds_change_data); #else _dbus_assert_not_reached("Platform doesn't support unix fd passing"); #endif @@ -4205,6 +4209,9 @@ load_message (DBusMessageLoader *loader, message->n_unix_fds_allocated = message->n_unix_fds = n_unix_fds; loader->n_unix_fds -= n_unix_fds; memmove (loader->unix_fds, loader->unix_fds + n_unix_fds, loader->n_unix_fds * sizeof (loader->unix_fds[0])); + + if (loader->unix_fds_change) + loader->unix_fds_change (loader->unix_fds_change_data); } else message->unix_fds = NULL; @@ -4498,6 +4505,40 @@ _dbus_message_loader_get_max_message_unix_fds (DBusMessageLoader *loader) return loader->max_message_unix_fds; } +/** + * Return how many file descriptors are pending in the loader + * + * @param loader the loader + */ +int +_dbus_message_loader_get_pending_fds_count (DBusMessageLoader *loader) +{ +#ifdef HAVE_UNIX_FD_PASSING + return loader->n_unix_fds; +#else + return 0; +#endif +} + +/** + * Register a function to be called whenever the number of pending file + * descriptors in the loader change. + * + * @param loader the loader + * @param callback the callback + * @param data the data for the callback + */ +void +_dbus_message_loader_set_pending_fds_function (DBusMessageLoader *loader, + void (* callback) (void *), + void *data) +{ +#ifdef HAVE_UNIX_FD_PASSING + loader->unix_fds_change = callback; + loader->unix_fds_change_data = data; +#endif +} + static DBusDataSlotAllocator slot_allocator = _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (message_slots)); diff --git a/dbus/dbus-server-protected.h b/dbus/dbus-server-protected.h index dd5234b9..e6dbd1e1 100644 --- a/dbus/dbus-server-protected.h +++ b/dbus/dbus-server-protected.h @@ -99,9 +99,8 @@ dbus_bool_t _dbus_server_add_watch (DBusServer *server, DBusWatch *watch); void _dbus_server_remove_watch (DBusServer *server, DBusWatch *watch); -void _dbus_server_toggle_watch (DBusServer *server, - DBusWatch *watch, - dbus_bool_t enabled); +void _dbus_server_toggle_all_watches (DBusServer *server, + dbus_bool_t enabled); dbus_bool_t _dbus_server_add_timeout (DBusServer *server, DBusTimeout *timeout); void _dbus_server_remove_timeout (DBusServer *server, diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c index 19d8590c..c1d5f6e5 100644 --- a/dbus/dbus-server.c +++ b/dbus/dbus-server.c @@ -312,26 +312,17 @@ _dbus_server_remove_watch (DBusServer *server, } /** - * Toggles a watch and notifies app via server's - * DBusWatchToggledFunction if available. It's an error to call this - * function on a watch that was not previously added. + * Toggles all watch and notifies app via server's + * DBusWatchToggledFunction if available. * * @param server the server. - * @param watch the watch to toggle. * @param enabled whether to enable or disable */ void -_dbus_server_toggle_watch (DBusServer *server, - DBusWatch *watch, - dbus_bool_t enabled) +_dbus_server_toggle_all_watches (DBusServer *server, + dbus_bool_t enabled) { - _dbus_assert (watch != NULL); - - HAVE_LOCK_CHECK (server); - protected_change_watch (server, watch, - NULL, NULL, - _dbus_watch_list_toggle_watch, - enabled); + _dbus_watch_list_toggle_all_watches (server->watches, enabled); } /** Function to be called in protected_change_timeout() with refcount held */ diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index e81e52c3..fe891ab7 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -320,6 +320,12 @@ _dbus_read_socket_with_unix_fds (int fd, m.msg_control = alloca(m.msg_controllen); memset(m.msg_control, 0, m.msg_controllen); + /* Do not include the padding at the end when we tell the kernel + * how much we're willing to receive. This avoids getting + * the padding filled with additional fds that we weren't expecting, + * if a (potentially malicious) sender included them. (fd.o #83622) */ + m.msg_controllen = CMSG_LEN (*n_fds * sizeof(int)); + again: bytes_read = recvmsg(fd, &m, 0 @@ -359,18 +365,49 @@ _dbus_read_socket_with_unix_fds (int fd, for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm)) if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_RIGHTS) { - unsigned i; - - _dbus_assert(cm->cmsg_len <= CMSG_LEN(*n_fds * sizeof(int))); - *n_fds = (cm->cmsg_len - CMSG_LEN(0)) / sizeof(int); + size_t i; + int *payload = (int *) CMSG_DATA (cm); + size_t payload_len_bytes = (cm->cmsg_len - CMSG_LEN (0)); + size_t payload_len_fds = payload_len_bytes / sizeof (int); + size_t fds_to_use; + + /* Every non-negative int fits in a size_t without truncation, + * and we already know that *n_fds is non-negative, so + * casting (size_t) *n_fds is OK */ + _DBUS_STATIC_ASSERT (sizeof (size_t) >= sizeof (int)); + + if (_DBUS_LIKELY (payload_len_fds <= (size_t) *n_fds)) + { + /* The fds in the payload will fit in our buffer */ + fds_to_use = payload_len_fds; + } + else + { + /* Too many fds in the payload. This shouldn't happen + * any more because we're setting m.msg_controllen to + * the exact number we can accept, but be safe and + * truncate. */ + fds_to_use = (size_t) *n_fds; + + /* Close the excess fds to avoid DoS: if they stayed open, + * someone could send us an extra fd per message + * and we'd eventually run out. */ + for (i = fds_to_use; i < payload_len_fds; i++) + { + close (payload[i]); + } + } - memcpy(fds, CMSG_DATA(cm), *n_fds * sizeof(int)); + memcpy (fds, payload, fds_to_use * sizeof (int)); found = TRUE; + /* This cannot overflow because we have chosen fds_to_use + * to be <= *n_fds */ + *n_fds = (int) fds_to_use; /* Linux doesn't tell us whether MSG_CMSG_CLOEXEC actually worked, hence we need to go through this list and set CLOEXEC everywhere in any case */ - for (i = 0; i < *n_fds; i++) + for (i = 0; i < fds_to_use; i++) _dbus_fd_set_close_on_exec(fds[i]); break; diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 21033ebf..47ba2f43 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -558,6 +558,14 @@ void _dbus_request_file_descriptor_limit (unsigned int limit); const char * _dbus_replace_install_prefix (const char *configure_time_path); +/* Do not set this too high: it is a denial-of-service risk. + * See <https://bugs.freedesktop.org/show_bug.cgi?id=82820> + * + * (This needs to be in the non-Unix-specific header so that + * the config-parser can use it.) + */ +#define DBUS_DEFAULT_MESSAGE_UNIX_FDS 16 + /** @} */ DBUS_END_DECLS diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c index ecc31827..f63e0ced 100644 --- a/dbus/dbus-transport.c +++ b/dbus/dbus-transport.c @@ -1512,6 +1512,33 @@ _dbus_transport_set_allow_anonymous (DBusTransport *transport, transport->allow_anonymous = value != FALSE; } +/** + * Return how many file descriptors are pending in the loader + * + * @param transport the transport + */ +int +_dbus_transport_get_pending_fds_count (DBusTransport *transport) +{ + return _dbus_message_loader_get_pending_fds_count (transport->loader); +} + +/** + * Register a function to be called whenever the number of pending file + * descriptors in the loader change. + * + * @param transport the transport + * @param callback the callback + */ +void +_dbus_transport_set_pending_fds_function (DBusTransport *transport, + void (* callback) (void *), + void *data) +{ + _dbus_message_loader_set_pending_fds_function (transport->loader, + callback, data); +} + #ifdef DBUS_ENABLE_STATS void _dbus_transport_get_stats (DBusTransport *transport, diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h index 80fa24ef..39c74c46 100644 --- a/dbus/dbus-transport.h +++ b/dbus/dbus-transport.h @@ -97,6 +97,10 @@ dbus_bool_t _dbus_transport_set_auth_mechanisms (DBusTransport const char **mechanisms); void _dbus_transport_set_allow_anonymous (DBusTransport *transport, dbus_bool_t value); +int _dbus_transport_get_pending_fds_count (DBusTransport *transport); +void _dbus_transport_set_pending_fds_function (DBusTransport *transport, + void (* callback) (void *), + void *data); /* if DBUS_ENABLE_STATS */ void _dbus_transport_get_stats (DBusTransport *transport, diff --git a/dbus/dbus-watch.c b/dbus/dbus-watch.c index b82c57d4..76a5d641 100644 --- a/dbus/dbus-watch.c +++ b/dbus/dbus-watch.c @@ -455,6 +455,27 @@ _dbus_watch_list_toggle_watch (DBusWatchList *watch_list, } /** + * Sets all watches to the given enabled state, invoking the + * application's DBusWatchToggledFunction if appropriate. + * + * @param watch_list the watch list. + * @param enabled #TRUE to enable + */ +void +_dbus_watch_list_toggle_all_watches (DBusWatchList *watch_list, + dbus_bool_t enabled) +{ + DBusList *link; + + for (link = _dbus_list_get_first_link (&watch_list->watches); + link != NULL; + link = _dbus_list_get_next_link (&watch_list->watches, link)) + { + _dbus_watch_list_toggle_watch (watch_list, link->data, enabled); + } +} + +/** * Sets the handler for the watch. * * @todo this function only exists because of the weird diff --git a/dbus/dbus-watch.h b/dbus/dbus-watch.h index c5832141..321740ed 100644 --- a/dbus/dbus-watch.h +++ b/dbus/dbus-watch.h @@ -76,6 +76,8 @@ void _dbus_watch_list_remove_watch (DBusWatchList *watch_li void _dbus_watch_list_toggle_watch (DBusWatchList *watch_list, DBusWatch *watch, dbus_bool_t enabled); +void _dbus_watch_list_toggle_all_watches (DBusWatchList *watch_list, + dbus_bool_t enabled); dbus_bool_t _dbus_watch_get_enabled (DBusWatch *watch); dbus_bool_t _dbus_watch_get_oom_last_time (DBusWatch *watch); |