Revamp profile and process handling
Also, introduce the Internal flag to Profiles
This commit is contained in:
@@ -106,32 +106,33 @@ func CleanProcessStorage(activePIDs map[int]struct{}) {
|
||||
|
||||
// clean primary processes
|
||||
for _, p := range processesCopy {
|
||||
p.Lock()
|
||||
// The PID of a process does not change.
|
||||
|
||||
_, active := activePIDs[p.Pid]
|
||||
switch {
|
||||
case p.Pid == UnidentifiedProcessID:
|
||||
// internal
|
||||
case p.Pid == SystemProcessID:
|
||||
// internal
|
||||
case active:
|
||||
// process in system process table or recently seen on the network
|
||||
default:
|
||||
// delete now or soon
|
||||
switch {
|
||||
case p.LastSeen == 0:
|
||||
// add last
|
||||
p.LastSeen = time.Now().Unix()
|
||||
case p.LastSeen > threshold:
|
||||
// within keep period
|
||||
default:
|
||||
// delete now
|
||||
log.Tracef("process.clean: deleted %s", p.DatabaseKey())
|
||||
go p.Delete()
|
||||
}
|
||||
// Check if this is a special process.
|
||||
if p.Pid == UnidentifiedProcessID || p.Pid == SystemProcessID {
|
||||
p.profile.MarkStillActive()
|
||||
continue
|
||||
}
|
||||
|
||||
p.Unlock()
|
||||
// Check if process is active.
|
||||
_, active := activePIDs[p.Pid]
|
||||
if active {
|
||||
p.profile.MarkStillActive()
|
||||
continue
|
||||
}
|
||||
|
||||
// Process is inactive, start deletion process
|
||||
switch {
|
||||
case p.LastSeen == 0:
|
||||
// add last
|
||||
p.LastSeen = time.Now().Unix()
|
||||
case p.LastSeen > threshold:
|
||||
// within keep period
|
||||
default:
|
||||
// delete now
|
||||
p.Delete()
|
||||
log.Tracef("process: cleaned %s", p.DatabaseKey())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,10 +30,14 @@ func GetProcessByConnection(ctx context.Context, pktInfo *packet.Info) (process
|
||||
return nil, connInbound, err
|
||||
}
|
||||
|
||||
err = process.GetProfile(ctx)
|
||||
changed, err := process.GetProfile(ctx)
|
||||
if err != nil {
|
||||
log.Tracer(ctx).Errorf("process: failed to get profile for process %s: %s", process, err)
|
||||
}
|
||||
|
||||
if changed {
|
||||
process.Save()
|
||||
}
|
||||
|
||||
return process, connInbound, nil
|
||||
}
|
||||
|
||||
@@ -30,39 +30,35 @@ type Process struct {
|
||||
record.Base
|
||||
sync.Mutex
|
||||
|
||||
// Constant attributes.
|
||||
|
||||
Name string
|
||||
UserID int
|
||||
UserName string
|
||||
UserHome string
|
||||
Pid int
|
||||
ParentPid int
|
||||
Path string
|
||||
ExecName string
|
||||
Cwd string
|
||||
CmdLine string
|
||||
FirstArg string
|
||||
|
||||
ExecName string
|
||||
ExecHashes map[string]string
|
||||
// ExecOwner ...
|
||||
// ExecSignature ...
|
||||
|
||||
LocalProfileKey string
|
||||
profile *profile.LayeredProfile
|
||||
Name string
|
||||
Icon string
|
||||
// Icon is a path to the icon and is either prefixed "f:" for filepath, "d:" for database cache path or "c:"/"a:" for a the icon key to fetch it from a company / authoritative node and cache it in its own cache.
|
||||
|
||||
// Mutable attributes.
|
||||
|
||||
FirstSeen int64
|
||||
LastSeen int64
|
||||
Virtual bool // This process is either merged into another process or is not needed.
|
||||
Error string // Cache errors
|
||||
|
||||
Virtual bool // This process is either merged into another process or is not needed.
|
||||
Error string // Cache errors
|
||||
ExecHashes map[string]string
|
||||
}
|
||||
|
||||
// Profile returns the assigned layered profile.
|
||||
func (p *Process) Profile() *profile.LayeredProfile {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
return p.profile
|
||||
}
|
||||
|
||||
@@ -72,8 +68,6 @@ func (p *Process) String() string {
|
||||
return "?"
|
||||
}
|
||||
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
return fmt.Sprintf("%s:%s:%d", p.UserName, p.Path, p.Pid)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,35 +8,58 @@ import (
|
||||
)
|
||||
|
||||
// GetProfile finds and assigns a profile set to the process.
|
||||
func (p *Process) GetProfile(ctx context.Context) error {
|
||||
func (p *Process) GetProfile(ctx context.Context) (changed bool, err error) {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
// only find profiles if not already done.
|
||||
if p.profile != nil {
|
||||
log.Tracer(ctx).Trace("process: profile already loaded")
|
||||
// mark profile as used
|
||||
// Mark profile as used.
|
||||
p.profile.MarkUsed()
|
||||
return nil
|
||||
return false, nil
|
||||
}
|
||||
log.Tracer(ctx).Trace("process: loading profile")
|
||||
|
||||
// get profile
|
||||
localProfile, new, err := profile.FindOrCreateLocalProfileByPath(p.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
// Check if we need a special profile.
|
||||
profileID := ""
|
||||
switch p.Pid {
|
||||
case UnidentifiedProcessID:
|
||||
profileID = profile.UnidentifiedProfileID
|
||||
case SystemProcessID:
|
||||
profileID = profile.SystemProfileID
|
||||
}
|
||||
// add more information if new
|
||||
|
||||
// Get the (linked) local profile.
|
||||
localProfile, new, err := profile.GetProfile(profile.SourceLocal, profileID, p.Path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// If the local profile is new, add some information from the process.
|
||||
if new {
|
||||
localProfile.Name = p.ExecName
|
||||
|
||||
// Special profiles will only have a name, but not an ExecName.
|
||||
if localProfile.Name == "" {
|
||||
localProfile.Name = p.Name
|
||||
}
|
||||
}
|
||||
|
||||
// mark profile as used
|
||||
localProfile.MarkUsed()
|
||||
// Mark profile as used.
|
||||
profileChanged := localProfile.MarkUsed()
|
||||
|
||||
// Save the profile if we changed something.
|
||||
if new || profileChanged {
|
||||
err := localProfile.Save()
|
||||
if err != nil {
|
||||
log.Warningf("process: failed to save profile %s: %s", localProfile.ScopedID(), err)
|
||||
}
|
||||
}
|
||||
|
||||
// Assign profile to process.
|
||||
p.LocalProfileKey = localProfile.Key()
|
||||
p.profile = profile.NewLayeredProfile(localProfile)
|
||||
p.profile = localProfile.LayeredProfile()
|
||||
|
||||
go p.Save()
|
||||
return nil
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -2,10 +2,11 @@ package process
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portmaster/profile"
|
||||
"golang.org/x/sync/singleflight"
|
||||
)
|
||||
|
||||
// Special Process IDs
|
||||
@@ -32,53 +33,41 @@ var (
|
||||
ParentPid: SystemProcessID,
|
||||
Name: "Operating System",
|
||||
}
|
||||
|
||||
getSpecialProcessSingleInflight singleflight.Group
|
||||
)
|
||||
|
||||
// GetUnidentifiedProcess returns the special process assigned to unidentified processes.
|
||||
func GetUnidentifiedProcess(ctx context.Context) *Process {
|
||||
return getSpecialProcess(ctx, UnidentifiedProcessID, unidentifiedProcess, profile.GetUnidentifiedProfile)
|
||||
return getSpecialProcess(ctx, UnidentifiedProcessID, unidentifiedProcess)
|
||||
}
|
||||
|
||||
// GetSystemProcess returns the special process used for the Kernel.
|
||||
func GetSystemProcess(ctx context.Context) *Process {
|
||||
return getSpecialProcess(ctx, SystemProcessID, systemProcess, profile.GetSystemProfile)
|
||||
return getSpecialProcess(ctx, SystemProcessID, systemProcess)
|
||||
}
|
||||
|
||||
func getSpecialProcess(ctx context.Context, pid int, template *Process, getProfile func() *profile.Profile) *Process {
|
||||
// check storage
|
||||
p, ok := GetProcessFromStorage(pid)
|
||||
if ok {
|
||||
return p
|
||||
}
|
||||
func getSpecialProcess(ctx context.Context, pid int, template *Process) *Process {
|
||||
p, _, _ := getSpecialProcessSingleInflight.Do(strconv.Itoa(pid), func() (interface{}, error) {
|
||||
// Check if we have already loaded the special process.
|
||||
process, ok := GetProcessFromStorage(pid)
|
||||
if ok {
|
||||
return process, nil
|
||||
}
|
||||
|
||||
// assign template
|
||||
p = template
|
||||
// Create new process from template
|
||||
process = template
|
||||
process.FirstSeen = time.Now().Unix()
|
||||
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
// Get profile.
|
||||
_, err := process.GetProfile(ctx)
|
||||
if err != nil {
|
||||
log.Tracer(ctx).Errorf("process: failed to get profile for process %s: %s", process, err)
|
||||
}
|
||||
|
||||
if p.FirstSeen == 0 {
|
||||
p.FirstSeen = time.Now().Unix()
|
||||
}
|
||||
|
||||
// only find profiles if not already done.
|
||||
if p.profile != nil {
|
||||
log.Tracer(ctx).Trace("process: special profile already loaded")
|
||||
// mark profile as used
|
||||
p.profile.MarkUsed()
|
||||
return p
|
||||
}
|
||||
log.Tracer(ctx).Trace("process: loading special profile")
|
||||
|
||||
// get profile
|
||||
localProfile := getProfile()
|
||||
|
||||
// mark profile as used
|
||||
localProfile.MarkUsed()
|
||||
|
||||
p.LocalProfileKey = localProfile.Key()
|
||||
p.profile = profile.NewLayeredProfile(localProfile)
|
||||
|
||||
go p.Save()
|
||||
return p
|
||||
// Save process to storage.
|
||||
process.Save()
|
||||
return process, nil
|
||||
})
|
||||
return p.(*Process)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user