diff --git a/daemon/procmon/activepids.go b/daemon/procmon/activepids.go new file mode 100644 index 00000000..c6620015 --- /dev/null +++ b/daemon/procmon/activepids.go @@ -0,0 +1,85 @@ +package procmon + +import ( + "fmt" + "github.com/evilsocket/opensnitch/daemon/log" + "io/ioutil" + "strconv" + "strings" + "sync" + "time" +) + +type value struct { + Process *Process + //Starttime uniquely identifies a process, it is the 22nd value in /proc//stat + //if another process starts with the same PID, it's Starttime will be unique + Starttime uint32 +} + +var ( + activePids = make(map[uint32]value) + activePidsLock = sync.RWMutex{} +) + +//monitorActivePids checks that each process in activePids +//is still running and if not running (or another process with the same pid is running), +//removes the pid from activePids +func monitorActivePids() { + for { + time.Sleep(time.Second) + activePidsLock.Lock() + for k, v := range activePids { + data, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/stat", k)) + if err != nil { + //file does not exists, pid has quit + delete(activePids, k) + continue + } + startTime, err := strconv.Atoi(strings.Split(string(data), " ")[21]) + if err != nil { + log.Error("Could not find or convert Starttime. This should never happen. Please report this incident to the Opensnitch developers.") + delete(activePids, k) + continue + } + if uint32(startTime) != v.Starttime { + //extremely unlikely: the original process has quit and another process + //was started with the same PID - all this in less than 1 second + log.Error("Same PID but different Starttime. Please report this incident to the Opensnitch developers.") + delete(activePids, k) + continue + } + } + activePidsLock.Unlock() + } +} + +func findProcessInActivePidsCache(pid uint32) *Process { + activePidsLock.Lock() + defer activePidsLock.Unlock() + if value, ok := activePids[pid]; ok { + return value.Process + } + return nil +} + +func addToActivePidsCache(pid uint32, proc *Process) { + + data, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/stat", pid)) + if err != nil { + //most likely the process has quit by now + return + } + startTime, err2 := strconv.Atoi(strings.Split(string(data), " ")[21]) + if err2 != nil { + log.Error("Could not find or convert Starttime. This should never happen. Please report this incident to the Opensnitch developers.") + return + } + + activePidsLock.Lock() + activePids[pid] = value{ + Process: proc, + Starttime: uint32(startTime), + } + activePidsLock.Unlock() +} diff --git a/daemon/procmon/parse.go b/daemon/procmon/parse.go index e3f97d1e..efeeba3a 100644 --- a/daemon/procmon/parse.go +++ b/daemon/procmon/parse.go @@ -107,6 +107,10 @@ func FindProcess(pid int, interceptUnknown bool) *Process { } } + if proc := findProcessInActivePidsCache(uint32(pid)); proc != nil { + return proc + } + linkName := fmt.Sprint("/proc/", pid, "/exe") if _, err := os.Lstat(linkName); err != nil { return nil @@ -120,6 +124,7 @@ func FindProcess(pid int, interceptUnknown bool) *Process { proc.readEnv() proc.cleanPath() + addToActivePidsCache(uint32(pid), proc) return proc } return nil diff --git a/daemon/procmon/process.go b/daemon/procmon/process.go index bd763911..d601d6ec 100644 --- a/daemon/procmon/process.go +++ b/daemon/procmon/process.go @@ -125,4 +125,5 @@ func Init() { // if any of the above methods have failed, fallback to proc log.Info("Process monitor method /proc") SetMonitorMethod(MethodProc) + go monitorActivePids() }