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)
110 lines
4 KiB
Diff
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",
|