Continue with the new profile integration
This commit is contained in:
29
process/config.go
Normal file
29
process/config.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package process
|
||||
|
||||
import (
|
||||
"github.com/safing/portbase/config"
|
||||
)
|
||||
|
||||
var (
|
||||
CfgOptionEnableProcessDetectionKey = "core/enableProcessDetection"
|
||||
enableProcessDetection config.BoolOption
|
||||
)
|
||||
|
||||
func registerConfiguration() error {
|
||||
// Enable Process Detection
|
||||
// This should be always enabled. Provided as an option to disable in case there are severe problems on a system, or for debugging.
|
||||
err := config.Register(&config.Option{
|
||||
Name: "Enable Process Detection",
|
||||
Key: CfgOptionEnableProcessDetectionKey,
|
||||
Description: "This option enables the attribution of network traffic to processes. This should be always enabled, and effectively disables app profiles if disabled.",
|
||||
OptType: config.OptTypeBool,
|
||||
ExpertiseLevel: config.ExpertiseLevelDeveloper,
|
||||
DefaultValue: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
enableProcessDetection = config.Concurrent.GetAsBool(CfgOptionEnableProcessDetectionKey, true)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/safing/portbase/database"
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portmaster/profile"
|
||||
"github.com/tevino/abool"
|
||||
)
|
||||
|
||||
@@ -90,11 +89,7 @@ func (p *Process) Delete() {
|
||||
go dbController.PushUpdate(p)
|
||||
}
|
||||
|
||||
// deactivate profile
|
||||
// TODO: check if there is another process using the same profile set
|
||||
if p.profileSet != nil {
|
||||
profile.DeactivateProfileSet(p.profileSet)
|
||||
}
|
||||
// TODO: maybe mark the assigned profiles as no longer needed?
|
||||
}
|
||||
|
||||
// CleanProcessStorage cleans the storage from old processes.
|
||||
|
||||
@@ -56,6 +56,11 @@ func GetPidByPacket(pkt packet.Packet) (pid int, direction bool, err error) {
|
||||
|
||||
// GetProcessByPacket returns the process that owns the given packet.
|
||||
func GetProcessByPacket(pkt packet.Packet) (process *Process, direction bool, err error) {
|
||||
if !enableProcessDetection() {
|
||||
log.Tracer(pkt.Ctx()).Tracef("process: process detection disabled")
|
||||
return UnknownProcess, direction, nil
|
||||
}
|
||||
|
||||
log.Tracer(pkt.Ctx()).Tracef("process: getting process and profile by packet")
|
||||
|
||||
var pid int
|
||||
@@ -75,10 +80,9 @@ func GetProcessByPacket(pkt packet.Packet) (process *Process, direction bool, er
|
||||
return nil, direction, err
|
||||
}
|
||||
|
||||
err = process.FindProfiles(pkt.Ctx())
|
||||
err = process.GetProfile(pkt.Ctx())
|
||||
if err != nil {
|
||||
log.Tracer(pkt.Ctx()).Errorf("process: failed to find profiles for process %s: %s", process, err)
|
||||
log.Errorf("failed to find profiles for process %s: %s", process, err)
|
||||
log.Tracer(pkt.Ctx()).Errorf("process: failed to get profile for process %s: %s", process, err)
|
||||
}
|
||||
|
||||
return process, direction, nil
|
||||
@@ -110,6 +114,11 @@ func GetPidByEndpoints(localIP net.IP, localPort uint16, remoteIP net.IP, remote
|
||||
|
||||
// GetProcessByEndpoints returns the process that owns the described link.
|
||||
func GetProcessByEndpoints(ctx context.Context, localIP net.IP, localPort uint16, remoteIP net.IP, remotePort uint16, protocol packet.IPProtocol) (process *Process, err error) {
|
||||
if !enableProcessDetection() {
|
||||
log.Tracer(ctx).Tracef("process: process detection disabled")
|
||||
return UnknownProcess, nil
|
||||
}
|
||||
|
||||
log.Tracer(ctx).Tracef("process: getting process and profile by endpoints")
|
||||
|
||||
var pid int
|
||||
@@ -129,10 +138,9 @@ func GetProcessByEndpoints(ctx context.Context, localIP net.IP, localPort uint16
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = process.FindProfiles(ctx)
|
||||
err = process.GetProfile(ctx)
|
||||
if err != nil {
|
||||
log.Tracer(ctx).Errorf("process: failed to find profiles for process %s: %s", process, err)
|
||||
log.Errorf("process: failed to find profiles for process %s: %s", process, err)
|
||||
log.Tracer(ctx).Errorf("process: failed to get profile for process %s: %s", process, err)
|
||||
}
|
||||
|
||||
return process, nil
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
package process
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/safing/portbase/database"
|
||||
"github.com/safing/portbase/database/query"
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portmaster/profile"
|
||||
)
|
||||
|
||||
var (
|
||||
profileDB = database.NewInterface(nil)
|
||||
)
|
||||
|
||||
// FindProfiles finds and assigns a profile set to the process.
|
||||
func (p *Process) FindProfiles(ctx context.Context) error {
|
||||
log.Tracer(ctx).Trace("process: loading profile set")
|
||||
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
// only find profiles if not already done.
|
||||
if p.profileSet != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// User Profile
|
||||
it, err := profileDB.Query(query.New(profile.MakeProfileKey(profile.UserNamespace, "")).Where(query.Where("LinkedPath", query.SameAs, p.Path)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var userProfile *profile.Profile
|
||||
// get first result
|
||||
r := <-it.Next
|
||||
// cancel immediately
|
||||
it.Cancel()
|
||||
// ensure its a profile
|
||||
userProfile, err = profile.EnsureProfile(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create new profile if it does not exist.
|
||||
if userProfile == nil {
|
||||
// create new profile
|
||||
userProfile = profile.New()
|
||||
userProfile.Name = p.ExecName
|
||||
userProfile.LinkedPath = p.Path
|
||||
}
|
||||
|
||||
if userProfile.MarkUsed() {
|
||||
_ = userProfile.Save(profile.UserNamespace)
|
||||
}
|
||||
|
||||
// Stamp
|
||||
// Find/Re-evaluate Stamp profile
|
||||
// 1. check linked stamp profile
|
||||
// 2. if last check is was more than a week ago, fetch from stamp:
|
||||
// 3. send path identifier to stamp
|
||||
// 4. evaluate all returned profiles
|
||||
// 5. select best
|
||||
// 6. link stamp profile to user profile
|
||||
// FIXME: implement!
|
||||
|
||||
p.UserProfileKey = userProfile.Key()
|
||||
p.profileSet = profile.NewSet(ctx, fmt.Sprintf("%d-%s", p.Pid, p.Path), userProfile, nil)
|
||||
go p.Save()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:deadcode,unused // FIXME
|
||||
func matchProfile(p *Process, prof *profile.Profile) (score int) {
|
||||
for _, fp := range prof.Fingerprints {
|
||||
score += matchFingerprint(p, fp)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//nolint:deadcode,unused // FIXME
|
||||
func matchFingerprint(p *Process, fp *profile.Fingerprint) (score int) {
|
||||
if !fp.MatchesOS() {
|
||||
return 0
|
||||
}
|
||||
|
||||
switch fp.Type {
|
||||
case "full_path":
|
||||
if p.Path == fp.Value {
|
||||
return profile.GetFingerprintWeight(fp.Type)
|
||||
}
|
||||
case "partial_path":
|
||||
// FIXME: if full_path matches, do not match partial paths
|
||||
return profile.GetFingerprintWeight(fp.Type)
|
||||
case "md5_sum", "sha1_sum", "sha256_sum":
|
||||
// FIXME: one sum is enough, check sums in a grouped form, start with the best
|
||||
sum, err := p.GetExecHash(fp.Type)
|
||||
if err != nil {
|
||||
log.Errorf("process: failed to get hash of executable: %s", err)
|
||||
} else if sum == fp.Value {
|
||||
return profile.GetFingerprintWeight(fp.Type)
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
@@ -17,7 +17,7 @@ var (
|
||||
)
|
||||
|
||||
// GetPidOfInode returns the pid of the given uid and socket inode.
|
||||
func GetPidOfInode(uid, inode int) (int, bool) {
|
||||
func GetPidOfInode(uid, inode int) (int, bool) { //nolint:gocognit // TODO
|
||||
pidsByUserLock.Lock()
|
||||
defer pidsByUserLock.Unlock()
|
||||
|
||||
|
||||
@@ -40,10 +40,10 @@ type Process struct {
|
||||
// ExecOwner ...
|
||||
// ExecSignature ...
|
||||
|
||||
UserProfileKey string
|
||||
profileSet *profile.Set
|
||||
Name string
|
||||
Icon string
|
||||
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.
|
||||
|
||||
FirstCommEstablished int64
|
||||
@@ -53,12 +53,12 @@ type Process struct {
|
||||
Error string // If this is set, the process is invalid. This is used to cache failing or inexistent processes.
|
||||
}
|
||||
|
||||
// ProfileSet returns the assigned profile set.
|
||||
func (p *Process) ProfileSet() *profile.Set {
|
||||
// Profile returns the assigned layered profile.
|
||||
func (p *Process) Profile() *profile.LayeredProfile {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
return p.profileSet
|
||||
return p.profile
|
||||
}
|
||||
|
||||
// Strings returns a string representation of process.
|
||||
@@ -208,13 +208,14 @@ func GetOrFindProcess(ctx context.Context, pid int) (*Process, error) {
|
||||
|
||||
func deduplicateRequest(ctx context.Context, pid int) (finishRequest func()) {
|
||||
dupReqLock.Lock()
|
||||
defer dupReqLock.Unlock()
|
||||
|
||||
// get duplicate request waitgroup
|
||||
wg, requestActive := dupReqMap[pid]
|
||||
|
||||
// someone else is already on it!
|
||||
if requestActive {
|
||||
dupReqLock.Unlock()
|
||||
|
||||
// log that we are waiting
|
||||
log.Tracer(ctx).Tracef("intel: waiting for duplicate request for PID %d to complete", pid)
|
||||
// wait
|
||||
@@ -232,6 +233,8 @@ func deduplicateRequest(ctx context.Context, pid int) (finishRequest func()) {
|
||||
// add to registry
|
||||
dupReqMap[pid] = wg
|
||||
|
||||
dupReqLock.Unlock()
|
||||
|
||||
// return function to mark request as finished
|
||||
return func() {
|
||||
dupReqLock.Lock()
|
||||
|
||||
42
process/profile.go
Normal file
42
process/profile.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package process
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portmaster/profile"
|
||||
)
|
||||
|
||||
// GetProfile finds and assigns a profile set to the process.
|
||||
func (p *Process) GetProfile(ctx context.Context) 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")
|
||||
return nil
|
||||
}
|
||||
log.Tracer(ctx).Trace("process: loading profile")
|
||||
|
||||
// get profile
|
||||
localProfile, new, err := profile.FindOrCreateLocalProfileByPath(p.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// add more information if new
|
||||
if new {
|
||||
localProfile.Name = p.ExecName
|
||||
}
|
||||
|
||||
// mark as used and save
|
||||
if localProfile.MarkUsed() {
|
||||
_ = localProfile.Save()
|
||||
}
|
||||
|
||||
p.LocalProfileKey = localProfile.Key()
|
||||
p.profile = profile.NewLayeredProfile(localProfile)
|
||||
|
||||
go p.Save()
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user