feat(go): port process access detectors

This commit is contained in:
Luna 2026-07-10 05:19:56 -07:00
parent f02509aab5
commit fc9b5f0448
22 changed files with 554 additions and 40 deletions

View file

@ -13,9 +13,24 @@ import (
"codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/model"
)
// Paths makes host filesystem inputs injectable for parity and unit tests.
type Paths struct {
ProcRoot string
LDPreloadPath string
}
// Capture reads process state once from procRoot. Transient per-process read
// failures degrade to empty fields, matching Python's fail-open Process view.
func Capture(procRoot string) (model.State, error) {
return CaptureWithPaths(Paths{
ProcRoot: procRoot,
LDPreloadPath: "/etc/ld.so.preload",
})
}
// CaptureWithPaths reads one process view and the global preload file.
func CaptureWithPaths(paths Paths) (model.State, error) {
procRoot := paths.ProcRoot
if procRoot == "" {
procRoot = "/proc"
}
@ -31,14 +46,52 @@ func Capture(procRoot string) (model.State, error) {
}
base := filepath.Join(procRoot, entry.Name())
processes = append(processes, model.Process{
PID: pid,
Comm: strings.TrimSpace(readText(filepath.Join(base, "comm"))),
Cmdline: strings.TrimSpace(strings.ReplaceAll(readText(filepath.Join(base, "cmdline")), "\x00", " ")),
Exe: readLink(filepath.Join(base, "exe")),
PID: pid,
Comm: strings.TrimSpace(readText(filepath.Join(base, "comm"))),
Cmdline: strings.TrimSpace(strings.ReplaceAll(readText(filepath.Join(base, "cmdline")), "\x00", " ")),
Exe: readLink(filepath.Join(base, "exe")),
Environ: parseEnviron(readText(filepath.Join(base, "environ"))),
FDTargets: readFDTargets(filepath.Join(base, "fd")),
})
}
sort.Slice(processes, func(i, j int) bool { return processes[i].PID < processes[j].PID })
return model.State{Processes: processes}, nil
return model.State{
Processes: processes,
LDPreload: strings.TrimSpace(readText(paths.LDPreloadPath)),
}, nil
}
func parseEnviron(raw string) map[string]string {
result := make(map[string]string)
for _, item := range strings.Split(raw, "\x00") {
key, value, ok := strings.Cut(item, "=")
if ok {
result[key] = value
}
}
return result
}
func readFDTargets(path string) map[string]string {
result := make(map[string]string)
entries, err := os.ReadDir(path)
if err != nil {
return result
}
sort.Slice(entries, func(i, j int) bool {
left, leftErr := strconv.Atoi(entries[i].Name())
right, rightErr := strconv.Atoi(entries[j].Name())
if leftErr == nil && rightErr == nil {
return left < right
}
return entries[i].Name() < entries[j].Name()
})
for _, entry := range entries {
if target := readLink(filepath.Join(path, entry.Name())); target != "" {
result[entry.Name()] = target
}
}
return result
}
func readText(path string) string {