mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2025-12-24 17:00:09 +01:00
Merge branch 'dbus-1.8'
Conflicts: NEWS configure.ac
This commit is contained in:
commit
51a609c8ba
7 changed files with 238 additions and 47 deletions
7
NEWS
7
NEWS
|
|
@ -3,6 +3,13 @@ D-Bus 1.9.2 (UNRELEASED)
|
|||
|
||||
The “structurally unsound flapjack” release.
|
||||
|
||||
Security fixes:
|
||||
|
||||
• Increase dbus-daemon's RLIMIT_NOFILE rlimit to 65536
|
||||
so that CVE-2014-3636 part A cannot exhaust the system bus'
|
||||
file descriptors, completing the incomplete fix in 1.8.8.
|
||||
(CVE-2014-7824, fd.o #85105; Simon McVittie, Alban Crequy)
|
||||
|
||||
Enhancements:
|
||||
|
||||
• D-Bus Specification version 0.25
|
||||
|
|
|
|||
|
|
@ -1688,6 +1688,31 @@ out:
|
|||
return retval;
|
||||
}
|
||||
|
||||
static void
|
||||
child_setup (void *user_data)
|
||||
{
|
||||
#ifdef DBUS_UNIX
|
||||
BusActivation *activation = user_data;
|
||||
DBusRLimit *initial_fd_limit;
|
||||
DBusError error;
|
||||
|
||||
dbus_error_init (&error);
|
||||
initial_fd_limit = bus_context_get_initial_fd_limit (activation->context);
|
||||
|
||||
if (initial_fd_limit != NULL &&
|
||||
!_dbus_rlimit_restore_fd_limit (initial_fd_limit, &error))
|
||||
{
|
||||
/* unfortunately we don't actually know the service name here */
|
||||
bus_context_log (activation->context,
|
||||
DBUS_SYSTEM_LOG_INFO,
|
||||
"Failed to reset fd limit before activating "
|
||||
"service: %s: %s",
|
||||
error.name, error.message);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
dbus_bool_t
|
||||
bus_activation_activate_service (BusActivation *activation,
|
||||
DBusConnection *connection,
|
||||
|
|
@ -2121,7 +2146,8 @@ bus_activation_activate_service (BusActivation *activation,
|
|||
service_name,
|
||||
argv,
|
||||
envp,
|
||||
NULL, activation,
|
||||
child_setup,
|
||||
activation,
|
||||
&tmp_error))
|
||||
{
|
||||
_dbus_verbose ("Failed to spawn child\n");
|
||||
|
|
|
|||
52
bus/bus.c
52
bus/bus.c
|
|
@ -64,6 +64,7 @@ struct BusContext
|
|||
BusPolicy *policy;
|
||||
BusMatchmaker *matchmaker;
|
||||
BusLimits limits;
|
||||
DBusRLimit *initial_fd_limit;
|
||||
unsigned int fork : 1;
|
||||
unsigned int syslog : 1;
|
||||
unsigned int keep_umask : 1;
|
||||
|
|
@ -659,19 +660,38 @@ oom:
|
|||
static void
|
||||
raise_file_descriptor_limit (BusContext *context)
|
||||
{
|
||||
#ifdef DBUS_UNIX
|
||||
DBusError error = DBUS_ERROR_INIT;
|
||||
|
||||
/* I just picked this out of thin air; we need some extra
|
||||
* descriptors for things like any internal pipes we create,
|
||||
* inotify, connections to SELinux, etc.
|
||||
/* we only do this once */
|
||||
if (context->initial_fd_limit != NULL)
|
||||
return;
|
||||
|
||||
context->initial_fd_limit = _dbus_rlimit_save_fd_limit (&error);
|
||||
|
||||
if (context->initial_fd_limit == NULL)
|
||||
{
|
||||
bus_context_log (context, DBUS_SYSTEM_LOG_INFO,
|
||||
"%s: %s", error.name, error.message);
|
||||
dbus_error_free (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We used to compute a suitable rlimit based on the configured number
|
||||
* of connections, but that breaks down as soon as we allow fd-passing,
|
||||
* because each connection is allowed to pass 64 fds to us, and if
|
||||
* they all did, we'd hit kernel limits. We now hard-code 64k as a
|
||||
* good limit, like systemd does: that's enough to avoid DoS from
|
||||
* anything short of multiple uids conspiring against us.
|
||||
*/
|
||||
unsigned int arbitrary_extra_fds = 32;
|
||||
unsigned int limit;
|
||||
|
||||
limit = context->limits.max_completed_connections +
|
||||
context->limits.max_incomplete_connections
|
||||
+ arbitrary_extra_fds;
|
||||
|
||||
_dbus_request_file_descriptor_limit (limit);
|
||||
if (!_dbus_rlimit_raise_fd_limit_if_privileged (65536, &error))
|
||||
{
|
||||
bus_context_log (context, DBUS_SYSTEM_LOG_INFO,
|
||||
"%s: %s", error.name, error.message);
|
||||
dbus_error_free (&error);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static dbus_bool_t
|
||||
|
|
@ -1130,6 +1150,10 @@ bus_context_unref (BusContext *context)
|
|||
|
||||
dbus_free (context->pidfile);
|
||||
}
|
||||
|
||||
if (context->initial_fd_limit)
|
||||
_dbus_rlimit_free (context->initial_fd_limit);
|
||||
|
||||
dbus_free (context);
|
||||
|
||||
dbus_server_free_data_slot (&server_data_slot);
|
||||
|
|
@ -1294,6 +1318,12 @@ bus_context_get_reply_timeout (BusContext *context)
|
|||
return context->limits.reply_timeout;
|
||||
}
|
||||
|
||||
DBusRLimit *
|
||||
bus_context_get_initial_fd_limit (BusContext *context)
|
||||
{
|
||||
return context->initial_fd_limit;
|
||||
}
|
||||
|
||||
void
|
||||
bus_context_log (BusContext *context, DBusSystemLogSeverity severity, const char *msg, ...) _DBUS_GNUC_PRINTF (3, 4);
|
||||
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ int bus_context_get_max_services_per_connection (BusContext
|
|||
int bus_context_get_max_match_rules_per_connection (BusContext *context);
|
||||
int bus_context_get_max_replies_per_connection (BusContext *context);
|
||||
int bus_context_get_reply_timeout (BusContext *context);
|
||||
DBusRLimit * bus_context_get_initial_fd_limit (BusContext *context);
|
||||
void bus_context_log (BusContext *context,
|
||||
DBusSystemLogSeverity severity,
|
||||
const char *msg,
|
||||
|
|
|
|||
|
|
@ -380,53 +380,140 @@ _dbus_change_to_daemon_user (const char *user,
|
|||
}
|
||||
#endif /* !HAVE_LIBAUDIT */
|
||||
|
||||
|
||||
/**
|
||||
* Attempt to ensure that the current process can open
|
||||
* at least @p limit file descriptors.
|
||||
*
|
||||
* If @p limit is lower than the current, it will not be
|
||||
* lowered. No error is returned if the request can
|
||||
* not be satisfied.
|
||||
*
|
||||
* @param limit number of file descriptors
|
||||
*/
|
||||
void
|
||||
_dbus_request_file_descriptor_limit (unsigned int limit)
|
||||
{
|
||||
#ifdef HAVE_SETRLIMIT
|
||||
|
||||
/* We assume that if we have setrlimit, we also have getrlimit and
|
||||
* struct rlimit.
|
||||
*/
|
||||
|
||||
struct DBusRLimit {
|
||||
struct rlimit lim;
|
||||
};
|
||||
|
||||
DBusRLimit *
|
||||
_dbus_rlimit_save_fd_limit (DBusError *error)
|
||||
{
|
||||
DBusRLimit *self;
|
||||
|
||||
self = dbus_new0 (DBusRLimit, 1);
|
||||
|
||||
if (self == NULL)
|
||||
{
|
||||
_DBUS_SET_OOM (error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (getrlimit (RLIMIT_NOFILE, &self->lim) < 0)
|
||||
{
|
||||
dbus_set_error (error, _dbus_error_from_errno (errno),
|
||||
"Failed to get fd limit: %s", _dbus_strerror (errno));
|
||||
dbus_free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
_dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired,
|
||||
DBusError *error)
|
||||
{
|
||||
struct rlimit lim;
|
||||
struct rlimit target_lim;
|
||||
|
||||
/* No point to doing this practically speaking
|
||||
* if we're not uid 0. We expect the system
|
||||
* bus to use this before we change UID, and
|
||||
* the session bus takes the Linux default
|
||||
* of 1024 for both cur and max.
|
||||
* the session bus takes the Linux default,
|
||||
* currently 1024 for cur and 4096 for max.
|
||||
*/
|
||||
if (getuid () != 0)
|
||||
return;
|
||||
{
|
||||
/* not an error, we're probably the session bus */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (getrlimit (RLIMIT_NOFILE, &lim) < 0)
|
||||
return;
|
||||
{
|
||||
dbus_set_error (error, _dbus_error_from_errno (errno),
|
||||
"Failed to get fd limit: %s", _dbus_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (lim.rlim_cur >= limit)
|
||||
return;
|
||||
if (lim.rlim_cur == RLIM_INFINITY || lim.rlim_cur >= desired)
|
||||
{
|
||||
/* not an error, everything is fine */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Ignore "maximum limit", assume we have the "superuser"
|
||||
* privileges. On Linux this is CAP_SYS_RESOURCE.
|
||||
*/
|
||||
target_lim.rlim_cur = target_lim.rlim_max = limit;
|
||||
/* Also ignore errors; if we fail, we will at least work
|
||||
* up to whatever limit we had, which seems better than
|
||||
* just outright aborting.
|
||||
*
|
||||
* However, in the future we should probably log this so OS builders
|
||||
* have a chance to notice any misconfiguration like dbus-daemon
|
||||
* being started without CAP_SYS_RESOURCE.
|
||||
*/
|
||||
setrlimit (RLIMIT_NOFILE, &target_lim);
|
||||
lim.rlim_cur = lim.rlim_max = desired;
|
||||
|
||||
if (setrlimit (RLIMIT_NOFILE, &lim) < 0)
|
||||
{
|
||||
dbus_set_error (error, _dbus_error_from_errno (errno),
|
||||
"Failed to set fd limit to %u: %s",
|
||||
desired, _dbus_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
_dbus_rlimit_restore_fd_limit (DBusRLimit *saved,
|
||||
DBusError *error)
|
||||
{
|
||||
if (setrlimit (RLIMIT_NOFILE, &saved->lim) < 0)
|
||||
{
|
||||
dbus_set_error (error, _dbus_error_from_errno (errno),
|
||||
"Failed to restore old fd limit: %s",
|
||||
_dbus_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#else /* !HAVE_SETRLIMIT */
|
||||
|
||||
static void
|
||||
fd_limit_not_supported (DBusError *error)
|
||||
{
|
||||
dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
|
||||
"cannot change fd limit on this platform");
|
||||
}
|
||||
|
||||
DBusRLimit *
|
||||
_dbus_rlimit_save_fd_limit (DBusError *error)
|
||||
{
|
||||
fd_limit_not_supported (error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
_dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired,
|
||||
DBusError *error)
|
||||
{
|
||||
fd_limit_not_supported (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
_dbus_rlimit_restore_fd_limit (DBusRLimit *saved,
|
||||
DBusError *error)
|
||||
{
|
||||
fd_limit_not_supported (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
_dbus_rlimit_free (DBusRLimit *lim)
|
||||
{
|
||||
dbus_free (lim);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -258,9 +258,42 @@ _dbus_change_to_daemon_user (const char *user,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_dbus_request_file_descriptor_limit (unsigned int limit)
|
||||
static void
|
||||
fd_limit_not_supported (DBusError *error)
|
||||
{
|
||||
dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
|
||||
"cannot change fd limit on this platform");
|
||||
}
|
||||
|
||||
DBusRLimit *
|
||||
_dbus_rlimit_save_fd_limit (DBusError *error)
|
||||
{
|
||||
fd_limit_not_supported (error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
_dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired,
|
||||
DBusError *error)
|
||||
{
|
||||
fd_limit_not_supported (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
_dbus_rlimit_restore_fd_limit (DBusRLimit *saved,
|
||||
DBusError *error)
|
||||
{
|
||||
fd_limit_not_supported (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
_dbus_rlimit_free (DBusRLimit *lim)
|
||||
{
|
||||
/* _dbus_rlimit_save_fd_limit() cannot return non-NULL on Windows
|
||||
* so there cannot be anything to free */
|
||||
_dbus_assert (lim == NULL);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -545,8 +545,6 @@ dbus_bool_t _dbus_change_to_daemon_user (const char *user,
|
|||
|
||||
void _dbus_flush_caches (void);
|
||||
|
||||
void _dbus_request_file_descriptor_limit (unsigned int limit);
|
||||
|
||||
/*
|
||||
* replaces the term DBUS_PREFIX in configure_time_path by the
|
||||
* current dbus installation directory. On unix this function is a noop
|
||||
|
|
@ -565,6 +563,15 @@ _dbus_replace_install_prefix (const char *configure_time_path);
|
|||
*/
|
||||
#define DBUS_DEFAULT_MESSAGE_UNIX_FDS 16
|
||||
|
||||
typedef struct DBusRLimit DBusRLimit;
|
||||
|
||||
DBusRLimit *_dbus_rlimit_save_fd_limit (DBusError *error);
|
||||
dbus_bool_t _dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired,
|
||||
DBusError *error);
|
||||
dbus_bool_t _dbus_rlimit_restore_fd_limit (DBusRLimit *saved,
|
||||
DBusError *error);
|
||||
void _dbus_rlimit_free (DBusRLimit *lim);
|
||||
|
||||
/** @} */
|
||||
|
||||
DBUS_END_DECLS
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue