bastion 0.53.2
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
//go:build linux
|
||||
|
||||
package main
|
||||
|
||||
// Every process, not only the ones a signature table already recognises.
|
||||
//
|
||||
// THE DEFECT THIS FIXES DEFEATED THE FEATURE. The baseline is meant to walk
|
||||
// the box and account for every pid. It was built from
|
||||
// scanAgents(), which is signature-FILTERED — it returns a known agent binary,
|
||||
// an interpreter-wrapped agent, or a process caught talking to a model
|
||||
// (agents.go:248-252). So the accounting of "what is normal here" contained
|
||||
// only things already recognised as agents.
|
||||
//
|
||||
// Follow that through and the whole detection story collapses: a brand-new
|
||||
// unknown binary — precisely the rogue process the product exists to catch — is
|
||||
// not in the baseline, and the delta built on that baseline would never compare
|
||||
// against it either. The baseline has to hold EVERYTHING so that "not baseline"
|
||||
// can mean something; what a process IS stays a property recorded on the entry,
|
||||
// never a condition for being recorded at all.
|
||||
//
|
||||
// Found while answering a narrower review question (schedulers missing
|
||||
// from a baseline whose own Kind field documented them).
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// baselineAllProcesses returns one observation per live process, unfiltered.
|
||||
// The fields are the ones the fingerprint needs and nothing more.
|
||||
func baselineAllProcesses() ([]agentObs, bool) {
|
||||
entries, err := os.ReadDir("/proc")
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
facts := procFactsReader()
|
||||
self := os.Getpid()
|
||||
out := make([]agentObs, 0, 256)
|
||||
for _, e := range entries {
|
||||
if !e.IsDir() {
|
||||
continue
|
||||
}
|
||||
pid, err := strconv.Atoi(e.Name())
|
||||
if err != nil || pid == self {
|
||||
continue
|
||||
}
|
||||
raw, err := os.ReadFile("/proc/" + e.Name() + "/cmdline")
|
||||
if err != nil || len(raw) == 0 {
|
||||
// A kernel thread has an empty cmdline. It is not a program anybody
|
||||
// installed and it cannot be a rogue agent; excluding it keeps the
|
||||
// baseline about userland without needing a name list.
|
||||
continue
|
||||
}
|
||||
argv := splitNul(raw)
|
||||
full := strings.Join(argv, " ")
|
||||
a := agentObs{
|
||||
PID: pid, User: procUser(pid), Cmdline: truncate(full, 200),
|
||||
Exe: procExe(pid), raw: full,
|
||||
}
|
||||
if f, ok := facts(pid); ok {
|
||||
a.Unit = f.Unit
|
||||
a.PPID = f.PPID
|
||||
}
|
||||
// The signature when there IS one, as a PROPERTY of the entry. An
|
||||
// unrecognised process is still recorded; it simply has no signature,
|
||||
// which is itself the interesting fact about it.
|
||||
if sig, auto, ok := matchSignature(argv); ok {
|
||||
a.Signature, a.automation = sig, auto
|
||||
}
|
||||
out = append(out, a)
|
||||
}
|
||||
return out, true
|
||||
}
|
||||
Reference in New Issue
Block a user