opensnitch/daemon/procmon/watcher.go

137 lines
2.7 KiB
Go
Raw Normal View History

package procmon
import (
"io/ioutil"
"strconv"
"sync"
"github.com/evilsocket/ftrace"
2020-12-09 18:18:42 +01:00
"github.com/evilsocket/opensnitch/daemon/log"
)
const (
probeName = "opensnitch_exec_probe"
syscallName = "do_execve"
)
type procData struct {
path string
args []string
}
var (
subEvents = []string{
"sched/sched_process_fork",
"sched/sched_process_exec",
"sched/sched_process_exit",
}
watcher = ftrace.NewProbe(probeName, syscallName, subEvents)
isAvailable = false
monitorMethod = MethodProc
index = make(map[int]*procData)
lock = sync.RWMutex{}
)
func forEachProcess(cb func(pid int, path string, args []string) bool) {
lock.RLock()
defer lock.RUnlock()
for pid, data := range index {
if cb(pid, data.path, data.args) == true {
break
}
}
}
func trackProcess(pid int) {
lock.Lock()
defer lock.Unlock()
if _, found := index[pid]; found == false {
index[pid] = &procData{}
}
}
func trackProcessArgs(e ftrace.Event) {
lock.Lock()
defer lock.Unlock()
if d, found := index[e.PID]; found == false {
index[e.PID] = &procData{
args: e.Argv(),
path: "",
}
} else {
d.args = e.Argv()
}
}
func trackProcessPath(e ftrace.Event) {
lock.Lock()
defer lock.Unlock()
if d, found := index[e.PID]; found == false {
index[e.PID] = &procData{
path: e.Args["filename"],
}
} else {
d.path = e.Args["filename"]
}
}
func trackProcessExit(e ftrace.Event) {
lock.Lock()
defer lock.Unlock()
delete(index, e.PID)
}
func eventConsumer() {
for event := range watcher.Events() {
if event.IsSyscall == true {
trackProcessArgs(event)
} else if _, ok := event.Args["filename"]; ok && event.Name == "sched_process_exec" {
trackProcessPath(event)
} else if event.Name == "sched_process_exit" {
trackProcessExit(event)
}
}
}
// Start enables the ftrace monitor method.
// This method configures a kprobe to intercept execve() syscalls.
// The kernel must have configured and enabled debugfs.
func Start() (err error) {
// start from a clean state
if err := watcher.Reset(); err != nil && watcher.Enabled() {
log.Warning("ftrace.Reset() error: %v", err)
}
if err = watcher.Enable(); err == nil {
isAvailable = true
go eventConsumer()
// track running processes
if ls, err := ioutil.ReadDir("/proc/"); err == nil {
for _, f := range ls {
if pid, err := strconv.Atoi(f.Name()); err == nil && f.IsDir() {
trackProcess(pid)
}
}
}
} else {
isAvailable = false
}
return
}
// Stop disables ftrace monitor method, removing configured kprobe.
func Stop() error {
isAvailable = false
return watcher.Disable()
}
// IsWatcherAvailable checks if ftrace (debugfs) is
func IsWatcherAvailable() bool {
return isAvailable
}