111 lines
4 KiB
Diff
111 lines
4 KiB
Diff
# UNDF: UNDF-2026-000001225
|
|
# UNDF: UNDF-PENDING
|
|
--- a/bus/policy.c
|
|
+++ b/bus/policy.c
|
|
@@ -780,38 +780,58 @@ remove_rules_by_type_up_to (BusClientPolicy *policy,
|
|
void
|
|
bus_client_policy_optimize (BusClientPolicy *policy)
|
|
{
|
|
- DBusList *link;
|
|
+ /* Replace O(R^2) backward-scan optimization with a single O(R) reverse pass.
|
|
+ *
|
|
+ * Original approach: for each blanket rule, call remove_rules_by_type_up_to()
|
|
+ * which walks from head to the current position — O(R) inner loop, O(R^2) total.
|
|
+ *
|
|
+ * Fixed approach: iterate from tail to head. The first (rightmost) blanket rule
|
|
+ * of each type supersedes all earlier rules of the same type. Track the last
|
|
+ * seen blanket per type and remove all preceding same-type rules in one pass.
|
|
+ */
|
|
+ DBusList *link;
|
|
+ dbus_bool_t seen_send_blanket = FALSE;
|
|
+ dbus_bool_t seen_receive_blanket = FALSE;
|
|
+ dbus_bool_t seen_own_blanket = FALSE;
|
|
|
|
_dbus_verbose ("Optimizing policy with %d rules\n",
|
|
_dbus_list_get_length (&policy->rules));
|
|
-
|
|
- link = _dbus_list_get_first_link (&policy->rules);
|
|
+
|
|
+ /* Walk from tail to head. Remove any rule that is shadowed by a later
|
|
+ * blanket rule of the same type. */
|
|
+ link = _dbus_list_get_last_link (&policy->rules);
|
|
while (link != NULL)
|
|
{
|
|
BusPolicyRule *rule;
|
|
- DBusList *next;
|
|
- dbus_bool_t remove_preceding;
|
|
+ DBusList *prev;
|
|
+ dbus_bool_t is_blanket;
|
|
+ dbus_bool_t already_shadowed;
|
|
|
|
- next = _dbus_list_get_next_link (&policy->rules, link);
|
|
+ prev = _dbus_list_get_prev_link (&policy->rules, link);
|
|
rule = link->data;
|
|
-
|
|
- remove_preceding = FALSE;
|
|
|
|
- _dbus_assert (rule != NULL);
|
|
-
|
|
+ is_blanket = FALSE;
|
|
+ already_shadowed = FALSE;
|
|
+
|
|
switch (rule->type)
|
|
{
|
|
case BUS_POLICY_RULE_SEND:
|
|
- remove_preceding =
|
|
- rule->d.send.message_type == DBUS_MESSAGE_TYPE_INVALID &&
|
|
+ is_blanket = (rule->d.send.message_type == DBUS_MESSAGE_TYPE_INVALID &&
|
|
rule->d.send.path == NULL &&
|
|
rule->d.send.interface == NULL &&
|
|
rule->d.send.member == NULL &&
|
|
rule->d.send.error == NULL &&
|
|
- rule->d.send.destination == NULL;
|
|
+ rule->d.send.destination == NULL);
|
|
+ already_shadowed = seen_send_blanket && !is_blanket;
|
|
+ if (is_blanket) seen_send_blanket = TRUE;
|
|
break;
|
|
case BUS_POLICY_RULE_RECEIVE:
|
|
- remove_preceding =
|
|
- rule->d.receive.message_type == DBUS_MESSAGE_TYPE_INVALID &&
|
|
+ is_blanket = (rule->d.receive.message_type == DBUS_MESSAGE_TYPE_INVALID &&
|
|
rule->d.receive.path == NULL &&
|
|
rule->d.receive.interface == NULL &&
|
|
rule->d.receive.member == NULL &&
|
|
rule->d.receive.error == NULL &&
|
|
- rule->d.receive.origin == NULL;
|
|
+ rule->d.receive.origin == NULL);
|
|
+ already_shadowed = seen_receive_blanket && !is_blanket;
|
|
+ if (is_blanket) seen_receive_blanket = TRUE;
|
|
break;
|
|
case BUS_POLICY_RULE_OWN:
|
|
- remove_preceding =
|
|
- rule->d.own.service_name == NULL;
|
|
+ is_blanket = (rule->d.own.service_name == NULL);
|
|
+ already_shadowed = seen_own_blanket && !is_blanket;
|
|
+ if (is_blanket) seen_own_blanket = TRUE;
|
|
break;
|
|
|
|
- /* The other rule types don't appear in this list */
|
|
case BUS_POLICY_RULE_USER:
|
|
case BUS_POLICY_RULE_GROUP:
|
|
default:
|
|
_dbus_assert_not_reached ("invalid rule");
|
|
break;
|
|
}
|
|
|
|
- if (remove_preceding)
|
|
- remove_rules_by_type_up_to (policy, rule->type,
|
|
- link);
|
|
-
|
|
- link = next;
|
|
+ if (already_shadowed)
|
|
+ {
|
|
+ /* This specific rule can never fire — remove it in O(1). */
|
|
+ _dbus_list_remove_link (&policy->rules, link);
|
|
+ bus_policy_rule_unref (rule);
|
|
+ }
|
|
+
|
|
+ link = prev;
|
|
}
|
|
|
|
_dbus_verbose ("After optimization, policy has %d rules\n",
|