java-topology/defects/dbus-0001/patch/dbus-0001-policy-optimize-o-n2.patch
russell@unturf.com decacb5dbd systemd+dbus: 5-MOAD scan; systemd-0004 CWE-407 seccomp strv O(K*A), dbus-0001 CWE-407 policy optimize O(R^2)
systemd-0004: seccomp_load_syscall_filter_set() in src/shared/seccomp-util.c uses
strv_contains(added, name) — O(|added|) linear scan — inside NULSTR_FOREACH over
~537 KNOWN syscalls. On x86_64 (3 arches): ~484,000 string comparisons per service
start with SeccompFilter=. Sibling function seccomp_load_syscall_filter_set_raw()
already uses hashmap_contains for O(1); this function was left behind.
Fix: build Set* from added strv before the NULSTR_FOREACH loop. MEDIUM severity.

dbus-0001: bus_client_policy_optimize() in bus/policy.c iterates R rules and for
each blanket deny/allow calls remove_rules_by_type_up_to() which scans backward
from current position to head — O(R^2) total per new connection creation.
At R=100 rules (realistic system bus): ~10,000 comparisons per connect.
Fix: single O(R) reverse pass tracking last-seen blanket per rule type. MEDIUM.

dbus 5-MOAD summary:
  MOAD-0001: dbus-0001 DEFECT (policy optimize O(R^2))
  MOAD-0002: CLEAN (BusContext is standard daemon context, not a god object)
  MOAD-0003: CLEAN (single-threaded event loop, no thread-local state)
  MOAD-0004: CLEAN (_dbus_verbose is no-op in production builds)
  MOAD-0005: CLEAN (pending_activations hash table coalesces duplicate requests)
2026-04-03 15:53:52 -04:00

110 lines
4 KiB
Diff

# 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",