Files
mesh-host/internal/apply/root_moved.go
T
jochen 2410796869 Let the setuid search run to completion and judge from the last complete one (hq issue 361)
A machine with millions of files never finished the walk within fifteen
minutes, so its agent account was never judged and the router refused to
link. Only root can make a setuid-root file, so a complete search stays
sound until root acts: it now runs at idle priority with no bound, is kept
beside the engine's state, judges for rootsearch.FreshFor from its start,
runs again daily and after an apply that moves accounts, packages, actions
or sudo rules, and an incomplete or stale search is never free.
2026-10-10 00:53:05 +02:00

47 lines
1.6 KiB
Go

package apply
import (
"path/filepath"
"strings"
"github.com/novox/mesh-host/internal/declaration"
)
// rootPaths are the files and directories through which an account comes to root, or by which it is told who it
// is: the user and group databases, sudo's, doas's and polkit's rules. A file written there changes what the
// judge of an agent account reads (novox/hq ADR 0266).
var rootPaths = []string{"/etc/passwd", "/etc/shadow", "/etc/group", "/etc/gshadow", "/etc/sudoers",
"/etc/sudoers.d", "/etc/doas.conf", "/etc/doas.d", "/etc/polkit-1", "/usr/share/polkit-1"}
// MovesRoot says an apply changed something through which root's reach could have changed — an account, a
// package, an action run as root, or a file in rootPaths (novox/hq issue 361). The engine then asks for a new
// search for setuid programs: root acted, and a complete search is sound only until root acts. Outcomes that
// moved nothing (unchanged, held, waiting, held still) do not count.
func MovesRoot(outcomes []Outcome) bool {
for _, o := range outcomes {
switch o.Action {
case "unchanged", "held", "waiting", heldStill:
continue
}
switch declaration.Type(o.Type) {
case declaration.TypeUser, declaration.TypePackage, declaration.TypeAction:
return true
case declaration.TypeFile, declaration.TypeDirectory, declaration.TypeArchive:
if underRootPath(o.Target) {
return true
}
}
}
return false
}
func underRootPath(target string) bool {
t := filepath.Clean(target)
for _, p := range rootPaths {
if t == p || strings.HasPrefix(t, p+"/") {
return true
}
}
return false
}