maintain a cache of struct Process for currently active PIDs (#342)

* maintain a cache of struct Process for currently active PIDs
decreases PID lookup time from ~100usec to ~5usec

* Update activepids.go

remove import "os"

Co-authored-by: themighty1 <you@example.com>
This commit is contained in:
themighty1 2021-02-06 10:30:59 +00:00 committed by GitHub
parent b0e50f2f11
commit af9c17ceb8
Failed to generate hash of commit
3 changed files with 91 additions and 0 deletions

View file

@ -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/<PID>/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()
}

View file

@ -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

View file

@ -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()
}