mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-02-04 22:20:30 +01:00
2003-04-24 Havoc Pennington <hp@redhat.com>
* test/data/valid-config-files/basic.conf: add <limit> tags to this test * bus/config-parser.h, bus/config-parser.c, bus/bus.c: Implement <limit> tag in configuration file.
This commit is contained in:
parent
1820f3bd0a
commit
3185d7edde
7 changed files with 270 additions and 47 deletions
|
|
@ -1,3 +1,11 @@
|
|||
2003-04-24 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* test/data/valid-config-files/basic.conf: add <limit> tags to
|
||||
this test
|
||||
|
||||
* bus/config-parser.h, bus/config-parser.c, bus/bus.c: Implement
|
||||
<limit> tag in configuration file.
|
||||
|
||||
2003-04-24 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* bus/dispatch.c: somehow missed some name_is
|
||||
|
|
|
|||
55
bus/bus.c
55
bus/bus.c
|
|
@ -45,14 +45,7 @@ struct BusContext
|
|||
BusRegistry *registry;
|
||||
BusPolicy *policy;
|
||||
DBusUserDatabase *user_database;
|
||||
long max_incoming_bytes; /**< How many incoming messages for a connection */
|
||||
long max_outgoing_bytes; /**< How many outgoing bytes can be queued for a connection */
|
||||
long max_message_size; /**< Max size of a single message in bytes */
|
||||
int activation_timeout; /**< How long to wait for an activation to time out */
|
||||
int auth_timeout; /**< How long to wait for an authentication to time out */
|
||||
int max_completed_connections; /**< Max number of authorized connections */
|
||||
int max_incomplete_connections; /**< Max number of incomplete connections */
|
||||
int max_connections_per_user; /**< Max number of connections auth'd as same user */
|
||||
BusLimits limits;
|
||||
};
|
||||
|
||||
static int server_data_slot = -1;
|
||||
|
|
@ -215,10 +208,10 @@ new_connection_callback (DBusServer *server,
|
|||
}
|
||||
|
||||
dbus_connection_set_max_received_size (new_connection,
|
||||
context->max_incoming_bytes);
|
||||
context->limits.max_incoming_bytes);
|
||||
|
||||
dbus_connection_set_max_message_size (new_connection,
|
||||
context->max_message_size);
|
||||
context->limits.max_message_size);
|
||||
|
||||
/* on OOM, we won't have ref'd the connection so it will die. */
|
||||
}
|
||||
|
|
@ -357,38 +350,14 @@ bus_context_new (const DBusString *config_file,
|
|||
|
||||
context->refcount = 1;
|
||||
|
||||
/* get our limits and timeout lengths */
|
||||
bus_config_parser_get_limits (parser, &context->limits);
|
||||
|
||||
/* we need another ref of the server data slot for the context
|
||||
* to own
|
||||
*/
|
||||
if (!server_data_slot_ref ())
|
||||
_dbus_assert_not_reached ("second ref of server data slot failed");
|
||||
|
||||
/* Make up some numbers! woot! */
|
||||
context->max_incoming_bytes = _DBUS_ONE_MEGABYTE * 63;
|
||||
context->max_outgoing_bytes = _DBUS_ONE_MEGABYTE * 63;
|
||||
context->max_message_size = _DBUS_ONE_MEGABYTE * 32;
|
||||
|
||||
#ifdef DBUS_BUILD_TESTS
|
||||
context->activation_timeout = 6000; /* 6 seconds */
|
||||
#else
|
||||
context->activation_timeout = 15000; /* 15 seconds */
|
||||
#endif
|
||||
|
||||
/* Making this long risks making a DOS attack easier, but too short
|
||||
* and legitimate auth will fail. If interactive auth (ask user for
|
||||
* password) is allowed, then potentially it has to be quite long.
|
||||
* Ultimately it needs to come from the configuration file.
|
||||
*/
|
||||
context->auth_timeout = 3000; /* 3 seconds */
|
||||
|
||||
context->max_incomplete_connections = 32;
|
||||
context->max_connections_per_user = 128;
|
||||
|
||||
/* Note that max_completed_connections / max_connections_per_user
|
||||
* is the number of users that would have to work together to
|
||||
* DOS all the other users.
|
||||
*/
|
||||
context->max_completed_connections = 1024;
|
||||
|
||||
context->user_database = _dbus_user_database_new ();
|
||||
if (context->user_database == NULL)
|
||||
|
|
@ -829,31 +798,31 @@ int
|
|||
bus_context_get_activation_timeout (BusContext *context)
|
||||
{
|
||||
|
||||
return context->activation_timeout;
|
||||
return context->limits.activation_timeout;
|
||||
}
|
||||
|
||||
int
|
||||
bus_context_get_auth_timeout (BusContext *context)
|
||||
{
|
||||
return context->auth_timeout;
|
||||
return context->limits.auth_timeout;
|
||||
}
|
||||
|
||||
int
|
||||
bus_context_get_max_completed_connections (BusContext *context)
|
||||
{
|
||||
return context->max_completed_connections;
|
||||
return context->limits.max_completed_connections;
|
||||
}
|
||||
|
||||
int
|
||||
bus_context_get_max_incomplete_connections (BusContext *context)
|
||||
{
|
||||
return context->max_incomplete_connections;
|
||||
return context->limits.max_incomplete_connections;
|
||||
}
|
||||
|
||||
int
|
||||
bus_context_get_max_connections_per_user (BusContext *context)
|
||||
{
|
||||
return context->max_connections_per_user;
|
||||
return context->limits.max_connections_per_user;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
|
|
@ -919,7 +888,7 @@ bus_context_check_security_policy (BusContext *context,
|
|||
/* See if limits on size have been exceeded */
|
||||
if (recipient &&
|
||||
dbus_connection_get_outgoing_size (recipient) >
|
||||
context->max_outgoing_bytes)
|
||||
context->limits.max_outgoing_bytes)
|
||||
{
|
||||
const char *dest = dbus_message_get_destination (message);
|
||||
dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
|
||||
|
|
|
|||
13
bus/bus.h
13
bus/bus.h
|
|
@ -41,6 +41,19 @@ typedef struct BusRegistry BusRegistry;
|
|||
typedef struct BusService BusService;
|
||||
typedef struct BusTransaction BusTransaction;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
long max_incoming_bytes; /**< How many incoming messages for a connection */
|
||||
long max_outgoing_bytes; /**< How many outgoing bytes can be queued for a connection */
|
||||
long max_message_size; /**< Max size of a single message in bytes */
|
||||
int activation_timeout; /**< How long to wait for an activation to time out */
|
||||
int auth_timeout; /**< How long to wait for an authentication to time out */
|
||||
int max_completed_connections; /**< Max number of authorized connections */
|
||||
int max_incomplete_connections; /**< Max number of incomplete connections */
|
||||
int max_connections_per_user; /**< Max number of connections auth'd as same user */
|
||||
} BusLimits;
|
||||
|
||||
BusContext* bus_context_new (const DBusString *config_file,
|
||||
int print_addr_fd,
|
||||
DBusError *error);
|
||||
|
|
|
|||
|
|
@ -78,6 +78,12 @@ typedef struct
|
|||
unsigned long gid_or_uid;
|
||||
} policy;
|
||||
|
||||
struct
|
||||
{
|
||||
char *name;
|
||||
long value;
|
||||
} limit;
|
||||
|
||||
} d;
|
||||
|
||||
} Element;
|
||||
|
|
@ -101,6 +107,8 @@ struct BusConfigParser
|
|||
DBusList *service_dirs; /**< Directories to look for services in */
|
||||
|
||||
BusPolicy *policy; /**< Security policy */
|
||||
|
||||
BusLimits limits; /**< Limits */
|
||||
|
||||
unsigned int fork : 1; /**< TRUE to fork into daemon mode */
|
||||
|
||||
|
|
@ -175,7 +183,9 @@ push_element (BusConfigParser *parser,
|
|||
static void
|
||||
element_free (Element *e)
|
||||
{
|
||||
|
||||
if (e->type == ELEMENT_LIMIT)
|
||||
dbus_free (e->d.limit.name);
|
||||
|
||||
dbus_free (e);
|
||||
}
|
||||
|
||||
|
|
@ -280,6 +290,32 @@ bus_config_parser_new (const DBusString *basedir)
|
|||
dbus_free (parser);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make up some numbers! woot! */
|
||||
parser->limits.max_incoming_bytes = _DBUS_ONE_MEGABYTE * 63;
|
||||
parser->limits.max_outgoing_bytes = _DBUS_ONE_MEGABYTE * 63;
|
||||
parser->limits.max_message_size = _DBUS_ONE_MEGABYTE * 32;
|
||||
|
||||
#ifdef DBUS_BUILD_TESTS
|
||||
parser->limits.activation_timeout = 6000; /* 6 seconds */
|
||||
#else
|
||||
parser->limits.activation_timeout = 15000; /* 15 seconds */
|
||||
#endif
|
||||
|
||||
/* Making this long risks making a DOS attack easier, but too short
|
||||
* and legitimate auth will fail. If interactive auth (ask user for
|
||||
* password) is allowed, then potentially it has to be quite long.
|
||||
*/
|
||||
parser->limits.auth_timeout = 3000; /* 3 seconds */
|
||||
|
||||
parser->limits.max_incomplete_connections = 32;
|
||||
parser->limits.max_connections_per_user = 128;
|
||||
|
||||
/* Note that max_completed_connections / max_connections_per_user
|
||||
* is the number of users that would have to work together to
|
||||
* DOS all the other users.
|
||||
*/
|
||||
parser->limits.max_completed_connections = 1024;
|
||||
|
||||
parser->refcount = 1;
|
||||
|
||||
|
|
@ -711,6 +747,41 @@ start_busconfig_child (BusConfigParser *parser,
|
|||
_dbus_assert_not_reached ("all <policy> attributes null and we didn't set error");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (strcmp (element_name, "limit") == 0)
|
||||
{
|
||||
Element *e;
|
||||
const char *name;
|
||||
|
||||
if ((e = push_element (parser, ELEMENT_LIMIT)) == NULL)
|
||||
{
|
||||
BUS_SET_OOM (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!locate_attributes (parser, "limit",
|
||||
attribute_names,
|
||||
attribute_values,
|
||||
error,
|
||||
"name", &name,
|
||||
NULL))
|
||||
return FALSE;
|
||||
|
||||
if (name == NULL)
|
||||
{
|
||||
dbus_set_error (error, DBUS_ERROR_FAILED,
|
||||
"<limit> element must have a \"name\" attribute");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
e->d.limit.name = _dbus_strdup (name);
|
||||
if (e->d.limit.name == NULL)
|
||||
{
|
||||
BUS_SET_OOM (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
|
|
@ -1087,6 +1158,91 @@ bus_config_parser_start_element (BusConfigParser *parser,
|
|||
}
|
||||
}
|
||||
|
||||
static dbus_bool_t
|
||||
set_limit (BusConfigParser *parser,
|
||||
const char *name,
|
||||
long value,
|
||||
DBusError *error)
|
||||
{
|
||||
dbus_bool_t must_be_positive;
|
||||
dbus_bool_t must_be_int;
|
||||
|
||||
must_be_int = FALSE;
|
||||
must_be_positive = FALSE;
|
||||
|
||||
if (strcmp (name, "max_incoming_bytes") == 0)
|
||||
{
|
||||
must_be_positive = TRUE;
|
||||
parser->limits.max_incoming_bytes = value;
|
||||
}
|
||||
else if (strcmp (name, "max_outgoing_bytes") == 0)
|
||||
{
|
||||
must_be_positive = TRUE;
|
||||
parser->limits.max_outgoing_bytes = value;
|
||||
}
|
||||
else if (strcmp (name, "max_message_size") == 0)
|
||||
{
|
||||
must_be_positive = TRUE;
|
||||
parser->limits.max_message_size = value;
|
||||
}
|
||||
else if (strcmp (name, "activation_timeout") == 0)
|
||||
{
|
||||
must_be_positive = TRUE;
|
||||
must_be_int = TRUE;
|
||||
parser->limits.activation_timeout = value;
|
||||
}
|
||||
else if (strcmp (name, "auth_timeout") == 0)
|
||||
{
|
||||
must_be_positive = TRUE;
|
||||
must_be_int = TRUE;
|
||||
parser->limits.auth_timeout = value;
|
||||
}
|
||||
else if (strcmp (name, "max_completed_connections") == 0)
|
||||
{
|
||||
must_be_positive = TRUE;
|
||||
must_be_int = TRUE;
|
||||
parser->limits.max_completed_connections = value;
|
||||
}
|
||||
else if (strcmp (name, "max_incomplete_connections") == 0)
|
||||
{
|
||||
must_be_positive = TRUE;
|
||||
must_be_int = TRUE;
|
||||
parser->limits.max_incomplete_connections = value;
|
||||
}
|
||||
else if (strcmp (name, "max_connections_per_user") == 0)
|
||||
{
|
||||
must_be_positive = TRUE;
|
||||
must_be_int = TRUE;
|
||||
parser->limits.max_connections_per_user = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
dbus_set_error (error, DBUS_ERROR_FAILED,
|
||||
"There is no limit called \"%s\"\n",
|
||||
name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (must_be_positive && value < 0)
|
||||
{
|
||||
dbus_set_error (error, DBUS_ERROR_FAILED,
|
||||
"<limit name=\"%s\"> must be a positive number\n",
|
||||
name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (must_be_int &&
|
||||
(value < _DBUS_INT_MIN || value > _DBUS_INT_MAX))
|
||||
{
|
||||
dbus_set_error (error, DBUS_ERROR_FAILED,
|
||||
"<limit name=\"%s\"> value is too large\n",
|
||||
name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
bus_config_parser_end_element (BusConfigParser *parser,
|
||||
const char *element_name,
|
||||
|
|
@ -1142,6 +1298,7 @@ bus_config_parser_end_element (BusConfigParser *parser,
|
|||
case ELEMENT_AUTH:
|
||||
case ELEMENT_SERVICEDIR:
|
||||
case ELEMENT_INCLUDEDIR:
|
||||
case ELEMENT_LIMIT:
|
||||
if (!e->had_content)
|
||||
{
|
||||
dbus_set_error (error, DBUS_ERROR_FAILED,
|
||||
|
|
@ -1149,11 +1306,17 @@ bus_config_parser_end_element (BusConfigParser *parser,
|
|||
element_type_to_name (e->type));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (e->type == ELEMENT_LIMIT)
|
||||
{
|
||||
if (!set_limit (parser, e->d.limit.name, e->d.limit.value,
|
||||
error))
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case ELEMENT_BUSCONFIG:
|
||||
case ELEMENT_POLICY:
|
||||
case ELEMENT_LIMIT:
|
||||
case ELEMENT_ALLOW:
|
||||
case ELEMENT_DENY:
|
||||
case ELEMENT_FORK:
|
||||
|
|
@ -1359,7 +1522,6 @@ bus_config_parser_content (BusConfigParser *parser,
|
|||
|
||||
case ELEMENT_BUSCONFIG:
|
||||
case ELEMENT_POLICY:
|
||||
case ELEMENT_LIMIT:
|
||||
case ELEMENT_ALLOW:
|
||||
case ELEMENT_DENY:
|
||||
case ELEMENT_FORK:
|
||||
|
|
@ -1534,6 +1696,29 @@ bus_config_parser_content (BusConfigParser *parser,
|
|||
_dbus_string_free (&full_path);
|
||||
}
|
||||
break;
|
||||
|
||||
case ELEMENT_LIMIT:
|
||||
{
|
||||
long val;
|
||||
|
||||
e->had_content = TRUE;
|
||||
|
||||
val = 0;
|
||||
if (!_dbus_string_parse_int (content, 0, &val, NULL))
|
||||
{
|
||||
dbus_set_error (error, DBUS_ERROR_FAILED,
|
||||
"<limit name=\"%s\"> element has invalid value (could not parse as integer)",
|
||||
e->d.limit.name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
e->d.limit.value = val;
|
||||
|
||||
_dbus_verbose ("Loaded value %ld for limit %s\n",
|
||||
e->d.limit.value,
|
||||
e->d.limit.name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
|
||||
|
|
@ -1625,6 +1810,14 @@ bus_config_parser_steal_policy (BusConfigParser *parser)
|
|||
return policy;
|
||||
}
|
||||
|
||||
/* Overwrite any limits that were set in the configuration file */
|
||||
void
|
||||
bus_config_parser_get_limits (BusConfigParser *parser,
|
||||
BusLimits *limits)
|
||||
{
|
||||
*limits = parser->limits;
|
||||
}
|
||||
|
||||
#ifdef DBUS_BUILD_TESTS
|
||||
#include <stdio.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ dbus_bool_t bus_config_parser_get_fork (BusConfigParser *parser);
|
|||
const char* bus_config_parser_get_pidfile (BusConfigParser *parser);
|
||||
DBusList** bus_config_parser_get_service_dirs (BusConfigParser *parser);
|
||||
BusPolicy* bus_config_parser_steal_policy (BusConfigParser *parser);
|
||||
void bus_config_parser_get_limits (BusConfigParser *parser,
|
||||
BusLimits *limits);
|
||||
|
||||
/* Loader functions (backended off one of the XML parsers). Returns a
|
||||
* finished ConfigParser.
|
||||
|
|
|
|||
|
|
@ -131,7 +131,35 @@ Elements:
|
|||
Appears below a <policy> element and establishes a resource
|
||||
limit. For example:
|
||||
<limit name="max_message_size">64</limit>
|
||||
<limit name="max_connections">512</limit>
|
||||
<limit name="max_completed_connections">512</limit>
|
||||
|
||||
Available limits are:
|
||||
"max_incoming_bytes" : total size in bytes of messages
|
||||
incoming from a connection
|
||||
"max_outgoing_bytes" : total size in bytes of messages
|
||||
queued up for a connection
|
||||
"max_message_size" : max size of a single message in
|
||||
bytes
|
||||
"activation_timeout" : milliseconds (thousandths) until
|
||||
an activated service has to connect
|
||||
"auth_timeout" : milliseconds (thousandths) a
|
||||
connection is given to
|
||||
authenticate
|
||||
"max_completed_connections" : max number of authenticated connections
|
||||
"max_incomplete_connections" : max number of unauthenticated
|
||||
connections
|
||||
"max_connections_per_user" : max number of completed connections from
|
||||
the same user
|
||||
|
||||
Some notes:
|
||||
|
||||
- the max incoming/outgoing queue sizes allow a new message
|
||||
to be queued if one byte remains below the max. So you can
|
||||
in fact exceed the max by max_message_size
|
||||
|
||||
- max_completed_connections / max_connections_per_user is
|
||||
the number of users that can work together to DOS all
|
||||
other users by using up all connections
|
||||
|
||||
<deny>
|
||||
send="messagename"
|
||||
|
|
|
|||
|
|
@ -10,4 +10,14 @@
|
|||
<policy context="default">
|
||||
<allow user="*"/>
|
||||
</policy>
|
||||
|
||||
<limit name="max_incoming_bytes">5000</limit>
|
||||
<limit name="max_outgoing_bytes">5000</limit>
|
||||
<limit name="max_message_size">300</limit>
|
||||
<limit name="activation_timeout">5000</limit>
|
||||
<limit name="auth_timeout">6000</limit>
|
||||
<limit name="max_completed_connections">50</limit>
|
||||
<limit name="max_incomplete_connections">80</limit>
|
||||
<limit name="max_connections_per_user">64</limit>
|
||||
|
||||
</busconfig>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue