72 lines
2.1 KiB
Diff
72 lines
2.1 KiB
Diff
# UNDF: UNDF-2026-000000770
|
|
# UNDF: (leave blank)
|
|
# minio-0003: isGroupDescEqual/isUserInfoEqual use slices.Contains in loop → O(M²)
|
|
#
|
|
# File: cmd/site-replication.go
|
|
# Functions: isGroupDescEqual() line 5677, isUserInfoEqual() line 5698
|
|
#
|
|
# Both functions compare two string slices for set equality by iterating one
|
|
# slice and calling slices.Contains on the other — O(M²) where M is the
|
|
# number of members/groups. In LDAP-backed deployments, groups can have
|
|
# 1000+ members, making this 1M+ operations per comparison.
|
|
#
|
|
# Called from site replication healing (lines 5493, 5653) — per-user and
|
|
# per-group, across deployment sites.
|
|
#
|
|
# Fix: build a map[string]struct{} from one slice, then probe with the other.
|
|
# Severity: MEDIUM (O(M²) per group/user comparison during site-replication heal)
|
|
# Overhead ratio: ~250x at M=500
|
|
#
|
|
--- a/cmd/site-replication.go
|
|
+++ b/cmd/site-replication.go
|
|
@@ -5677,16 +5677,14 @@
|
|
func isGroupDescEqual(g1, g2 madmin.GroupDesc) bool {
|
|
if g1.Name != g2.Name ||
|
|
g1.Status != g2.Status ||
|
|
g1.Policy != g2.Policy {
|
|
return false
|
|
}
|
|
if len(g1.Members) != len(g2.Members) {
|
|
return false
|
|
}
|
|
- for _, v1 := range g1.Members {
|
|
- var found bool
|
|
- if slices.Contains(g2.Members, v1) {
|
|
- found = true
|
|
- }
|
|
- if !found {
|
|
+ memberSet := make(map[string]struct{}, len(g2.Members))
|
|
+ for _, m := range g2.Members {
|
|
+ memberSet[m] = struct{}{}
|
|
+ }
|
|
+ for _, v1 := range g1.Members {
|
|
+ if _, ok := memberSet[v1]; !ok {
|
|
return false
|
|
}
|
|
}
|
|
@@ -5698,16 +5696,14 @@
|
|
func isUserInfoEqual(u1, u2 madmin.UserInfo) bool {
|
|
if u1.PolicyName != u2.PolicyName ||
|
|
u1.Status != u2.Status ||
|
|
u1.SecretKey != u2.SecretKey {
|
|
return false
|
|
}
|
|
- for len(u1.MemberOf) != len(u2.MemberOf) {
|
|
+ if len(u1.MemberOf) != len(u2.MemberOf) {
|
|
return false
|
|
}
|
|
- for _, v1 := range u1.MemberOf {
|
|
- var found bool
|
|
- if slices.Contains(u2.MemberOf, v1) {
|
|
- found = true
|
|
- }
|
|
- if !found {
|
|
+ groupSet := make(map[string]struct{}, len(u2.MemberOf))
|
|
+ for _, g := range u2.MemberOf {
|
|
+ groupSet[g] = struct{}{}
|
|
+ }
|
|
+ for _, v1 := range u1.MemberOf {
|
|
+ if _, ok := groupSet[v1]; !ok {
|
|
return false
|
|
}
|
|
}
|