fix(model): restrict SystemCandidates to exact and canonical names to protect system paths
swadhinbiswas committed 2 months ago
3f85206
1 parent 010b6fe
commit 3f85206
2 files changed
+38 -2
Showing 2 changed files+38-2
▼internal/model/app.go
+23-2
| @@ -383,6 +383,8 @@ func HomeCandidates(source string, name string) []string { | ||
383 | 383 | } |
384 | 384 | |
385 | 385 | // SystemCandidates are root-owned locations probed during staging. |
386 | +// Uses only the original full name and primary reverse-domain forms to avoid | |
387 | +// matching broader system namespaces (e.g. /etc/google, /usr/share/gnome). | |
386 | 388 | func SystemCandidates(name string) []string { |
387 | 389 | var candidates []string |
388 | 390 | seen := make(map[string]bool) |
| @@ -393,8 +395,27 @@ func SystemCandidates(name string) []string { | ||
393 | 395 | } |
394 | 396 | } |
395 | 397 | |
396 | - variants := NameVariants(name) | |
397 | - for _, v := range variants { | |
398 | + name = strings.TrimSpace(name) | |
399 | + if name == "" { | |
400 | + return nil | |
401 | + } | |
402 | + | |
403 | + sysNames := []string{name} | |
404 | + if lower := strings.ToLower(name); lower != name { | |
405 | + sysNames = append(sysNames, lower) | |
406 | + } | |
407 | + if strings.Contains(name, ".") { | |
408 | + parts := strings.Split(name, ".") | |
409 | + last := parts[len(parts)-1] | |
410 | + if len(last) >= 2 { | |
411 | + sysNames = append(sysNames, last) | |
412 | + if lowerLast := strings.ToLower(last); lowerLast != last { | |
413 | + sysNames = append(sysNames, lowerLast) | |
414 | + } | |
415 | + } | |
416 | + } | |
417 | + | |
418 | + for _, v := range sysNames { | |
398 | 419 | add(filepath.Join("/etc", v)) |
399 | 420 | add(filepath.Join("/var/log", v)) |
400 | 421 | add(filepath.Join("/var/cache", v)) |
401 | 422 | |
▼internal/model/config_test.go
+15-0
| @@ -96,6 +96,21 @@ func TestCandidates(t *testing.T) { | ||
96 | 96 | if len(sysC) < 3 { |
97 | 97 | t.Fatalf("expected at least 3 system candidates, got %d", len(sysC)) |
98 | 98 | } |
99 | + | |
100 | + // Verify SystemCandidates avoids unsafe hyphen/domain sub-segments | |
101 | + chromeSys := SystemCandidates("google-chrome") | |
102 | + for _, c := range chromeSys { | |
103 | + if c == "/etc/google" || c == "/usr/share/google" || c == "/var/lib/google" { | |
104 | + t.Fatalf("SystemCandidates contained unsafe sub-segment path: %s", c) | |
105 | + } | |
106 | + } | |
107 | + | |
108 | + vlcSys := SystemCandidates("org.videolan.VLC") | |
109 | + for _, c := range vlcSys { | |
110 | + if c == "/etc/videolan" || c == "/etc/org" { | |
111 | + t.Fatalf("SystemCandidates contained unsafe intermediate domain path: %s", c) | |
112 | + } | |
113 | + } | |
99 | 114 | } |
100 | 115 | |
101 | 116 | func TestHumanSizeUnits(t *testing.T) { |
102 | 117 | |