diff options
author | Simon McVittie <smcv@collabora.com> | 2017-07-19 17:56:38 +0100 |
---|---|---|
committer | Simon McVittie <smcv@debian.org> | 2017-07-28 11:36:51 +0100 |
commit | b22bdc39fd28e1461c337edd6a717fadfb3647b8 (patch) | |
tree | 87ea4ef8c4ef4cb86416afb8138786e490cf82b2 | |
parent | f876edd342b87815a55baf65fa7c2fe2aad5e92e (diff) |
policy: Add max_fds, min_fds qualifiers for send, receive rules
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=101848
Reviewed-by: Thiago Macieira <thiago@kde.org>
[smcv: Revert an incorrect comment change]
Signed-off-by: Simon McVittie <smcv@collabora.com>
-rw-r--r-- | bus/config-parser.c | 77 | ||||
-rw-r--r-- | bus/policy.c | 32 | ||||
-rw-r--r-- | bus/policy.h | 4 | ||||
-rw-r--r-- | dbus/dbus-message-internal.h | 1 | ||||
-rw-r--r-- | dbus/dbus-message-util.c | 16 | ||||
-rw-r--r-- | doc/dbus-daemon.1.xml.in | 20 |
6 files changed, 146 insertions, 4 deletions
diff --git a/bus/config-parser.c b/bus/config-parser.c index 52576e9d..7f095bd5 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -1276,6 +1276,43 @@ start_busconfig_child (BusConfigParser *parser, } } +/* + * Parse an attribute named name, whose content is content, or NULL if + * missing. It is meant to be a (long) integer between min and max inclusive. + * If it is missing, use def as the default value (which does not + * necessarily need to be between min and max). + */ +static dbus_bool_t +parse_int_attribute (const char *name, + const char *content, + long min, + long max, + long def, + long *value, + DBusError *error) +{ + DBusString parse_string; + + *value = def; + + if (content == NULL) + return TRUE; + + _dbus_string_init_const (&parse_string, content); + + if (!_dbus_string_parse_int (&parse_string, 0, value, NULL) || + *value < min || *value > max) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Bad value \"%s\" for %s attribute, must be an " + "integer in range %ld to %ld inclusive", + content, name, min, max); + return FALSE; + } + + return TRUE; +} + static dbus_bool_t append_rule_from_element (BusConfigParser *parser, const char *element_name, @@ -1311,6 +1348,10 @@ append_rule_from_element (BusConfigParser *parser, /* Group: message-matching modifiers that can go on send_ or receive_ */ const char *eavesdrop; + const char *max_fds_attr; + long max_fds = DBUS_MAXIMUM_MESSAGE_UNIX_FDS; + const char *min_fds_attr; + long min_fds = 0; /* TRUE if any message-matching modifier is present */ dbus_bool_t any_message_attribute; @@ -1340,6 +1381,8 @@ append_rule_from_element (BusConfigParser *parser, "receive_path", &receive_path, "receive_type", &receive_type, "eavesdrop", &eavesdrop, + "max_fds", &max_fds_attr, + "min_fds", &min_fds_attr, "send_requested_reply", &send_requested_reply, "receive_requested_reply", &receive_requested_reply, "own", &own, @@ -1373,7 +1416,9 @@ append_rule_from_element (BusConfigParser *parser, (!any_send_attribute && eavesdrop != NULL)); any_message_attribute = (any_send_attribute || any_receive_attribute || - eavesdrop != NULL); + eavesdrop != NULL || + max_fds_attr != NULL || + min_fds_attr != NULL); if (!(any_send_attribute || any_receive_attribute || @@ -1518,7 +1563,19 @@ append_rule_from_element (BusConfigParser *parser, "send_requested_reply", send_requested_reply); return FALSE; } - + + /* Matching only messages with DBUS_MAXIMUM_MESSAGE_UNIX_FDS or fewer + * fds is the same as matching all messages, so we always set a maximum, + * but perhaps an unrealistically high one. */ + if (!parse_int_attribute ("max_fds", max_fds_attr, + 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS, + DBUS_MAXIMUM_MESSAGE_UNIX_FDS, &max_fds, + error) || + !parse_int_attribute ("min_fds", min_fds_attr, + 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS, 0, &min_fds, + error)) + return FALSE; + rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); if (rule == NULL) goto nomem; @@ -1550,6 +1607,9 @@ append_rule_from_element (BusConfigParser *parser, rule->d.send.member = _dbus_strdup (send_member); rule->d.send.error = _dbus_strdup (send_error); rule->d.send.destination = _dbus_strdup (send_destination); + rule->d.send.max_fds = max_fds; + rule->d.send.min_fds = min_fds; + if (send_path && rule->d.send.path == NULL) goto nomem; if (send_interface && rule->d.send.interface == NULL) @@ -1611,7 +1671,16 @@ append_rule_from_element (BusConfigParser *parser, "receive_requested_reply", receive_requested_reply); return FALSE; } - + + if (!parse_int_attribute ("max_fds", max_fds_attr, + 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS, + DBUS_MAXIMUM_MESSAGE_UNIX_FDS, &max_fds, + error) || + !parse_int_attribute ("min_fds", min_fds_attr, + 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS, 0, &min_fds, + error)) + return FALSE; + rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); if (rule == NULL) goto nomem; @@ -1628,6 +1697,8 @@ append_rule_from_element (BusConfigParser *parser, rule->d.receive.member = _dbus_strdup (receive_member); rule->d.receive.error = _dbus_strdup (receive_error); rule->d.receive.origin = _dbus_strdup (receive_sender); + rule->d.receive.max_fds = max_fds; + rule->d.receive.min_fds = min_fds; if (receive_path && rule->d.receive.path == NULL) goto nomem; diff --git a/bus/policy.c b/bus/policy.c index d8d82f41..a37be804 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -29,6 +29,7 @@ #include <dbus/dbus-list.h> #include <dbus/dbus-hash.h> #include <dbus/dbus-internals.h> +#include <dbus/dbus-message-internal.h> BusPolicyRule* bus_policy_rule_new (BusPolicyRuleType type, @@ -1063,6 +1064,20 @@ bus_client_policy_check_can_send (BusClientPolicy *policy, } } + if (rule->d.send.min_fds > 0 || + rule->d.send.max_fds < DBUS_MAXIMUM_MESSAGE_UNIX_FDS) + { + unsigned int n_fds = _dbus_message_get_n_unix_fds (message); + + if (n_fds < rule->d.send.min_fds || n_fds > rule->d.send.max_fds) + { + _dbus_verbose (" (policy) skipping rule because message has %u fds " + "and that is outside range [%u,%u]", + n_fds, rule->d.send.min_fds, rule->d.send.max_fds); + continue; + } + } + /* Use this rule */ allowed = rule->allow; *log = rule->d.send.log; @@ -1263,7 +1278,22 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, } } } - + + if (rule->d.receive.min_fds > 0 || + rule->d.receive.max_fds < DBUS_MAXIMUM_MESSAGE_UNIX_FDS) + { + unsigned int n_fds = _dbus_message_get_n_unix_fds (message); + + if (n_fds < rule->d.receive.min_fds || n_fds > rule->d.receive.max_fds) + { + _dbus_verbose (" (policy) skipping rule because message has %u fds " + "and that is outside range [%u,%u]", + n_fds, rule->d.receive.min_fds, + rule->d.receive.max_fds); + continue; + } + } + /* Use this rule */ allowed = rule->allow; (*toggles)++; diff --git a/bus/policy.h b/bus/policy.h index c5275a7b..ec43ffa5 100644 --- a/bus/policy.h +++ b/bus/policy.h @@ -70,6 +70,8 @@ struct BusPolicyRule char *member; char *error; char *destination; + unsigned int max_fds; + unsigned int min_fds; unsigned int eavesdrop : 1; unsigned int requested_reply : 1; unsigned int log : 1; @@ -86,6 +88,8 @@ struct BusPolicyRule char *member; char *error; char *origin; + unsigned int max_fds; + unsigned int min_fds; unsigned int eavesdrop : 1; unsigned int requested_reply : 1; } receive; diff --git a/dbus/dbus-message-internal.h b/dbus/dbus-message-internal.h index 6f113169..f8fe383f 100644 --- a/dbus/dbus-message-internal.h +++ b/dbus/dbus-message-internal.h @@ -55,6 +55,7 @@ void _dbus_message_get_unix_fds (DBusMessage *message, const int **fds, unsigned *n_fds); +unsigned int _dbus_message_get_n_unix_fds (DBusMessage *message); void _dbus_message_lock (DBusMessage *message); void _dbus_message_unlock (DBusMessage *message); dbus_bool_t _dbus_message_add_counter (DBusMessage *message, diff --git a/dbus/dbus-message-util.c b/dbus/dbus-message-util.c index bedf6b4f..ebf00e27 100644 --- a/dbus/dbus-message-util.c +++ b/dbus/dbus-message-util.c @@ -45,6 +45,22 @@ * @{ */ +/** + * Gets the number of unix fds attached to this message. + * + * @param message the message + * @returns the number of file descriptors + */ +unsigned int +_dbus_message_get_n_unix_fds (DBusMessage *message) +{ +#ifdef HAVE_UNIX_FD_PASSING + return message->n_unix_fds; +#else + return 0; +#endif +} + #ifdef DBUS_ENABLE_EMBEDDED_TESTS /** * Reads arguments from a message iterator given a variable argument diff --git a/doc/dbus-daemon.1.xml.in b/doc/dbus-daemon.1.xml.in index 067fdcd5..b029232d 100644 --- a/doc/dbus-daemon.1.xml.in +++ b/doc/dbus-daemon.1.xml.in @@ -906,6 +906,13 @@ rules in the config file allow it).</para> recipient, and any broadcast message). </para> +<para> + The <literal>eavesdrop</literal>, <literal>min_fds</literal> and + <literal>max_fds</literal> attributes are modifiers that can be applied + to either <literal>send_</literal>* or <literal>receive_</literal>* + rules, and are documented below. +</para> + <para>send_destination and receive_sender rules mean that messages may not be sent to or received from the *owner* of the given name, not that they may not be sent *to that name*. That is, if a connection @@ -969,6 +976,19 @@ the rule matches only when the reply was not requested. [send|receive]_requested_reply="true" indicates that the rule applies always, regardless of pending reply state.</para> +<para> + The <literal>min_fds</literal> and <literal>max_fds</literal> attributes + modify either <literal>send_</literal>* or <literal>receive_</literal>* + rules. A rule with the <literal>min_fds</literal> attribute only matches + messages if they have at least that many Unix file descriptors attached. + Conversely, a rule with the <literal>max_fds</literal> attribute only + matches messages if they have no more than that many file descriptors + attached. In practice, rules with these attributes will most commonly + take the form + <literal><allow send_destination="…" max_fds="0"/></literal>, + <literal><deny send_destination="…" min_fds="1"/></literal> or + <literal><deny receive_sender="*" min_fds="1"/></literal>. +</para> <para> Rules with the <literal>user</literal> or <literal>group</literal> |