Improve metadata handling of profiles

Also, improve OS profile handling
This commit is contained in:
Daniel 2020-11-24 16:39:01 +01:00
parent 4b694c5f84
commit 5a88fc2fce
8 changed files with 133 additions and 130 deletions

View file

@ -165,15 +165,26 @@ type Reason struct {
Context interface{} Context interface{}
} }
func getProcessContext(proc *process.Process) ProcessContext { func getProcessContext(ctx context.Context, proc *process.Process) ProcessContext {
return ProcessContext{ // Gather process information.
pCtx := ProcessContext{
BinaryPath: proc.Path, BinaryPath: proc.Path,
ProcessName: proc.Name, ProcessName: proc.Name,
ProfileName: proc.Profile().LocalProfile().Name,
PID: proc.Pid, PID: proc.Pid,
Profile: proc.Profile().LocalProfile().ID,
Source: string(proc.Profile().LocalProfile().Source),
} }
// Get local profile.
localProfile := proc.Profile().LocalProfile()
if localProfile == nil {
log.Tracer(ctx).Warningf("network: process %s has no profile", proc)
return pCtx
}
// Add profile information and return.
pCtx.ProfileName = localProfile.Name
pCtx.Profile = localProfile.ID
pCtx.Source = string(localProfile.Source)
return pCtx
} }
// NewConnectionFromDNSRequest returns a new connection based on the given dns request. // NewConnectionFromDNSRequest returns a new connection based on the given dns request.
@ -204,7 +215,7 @@ func NewConnectionFromDNSRequest(ctx context.Context, fqdn string, cnames []stri
CNAME: cnames, CNAME: cnames,
}, },
process: proc, process: proc,
ProcessContext: getProcessContext(proc), ProcessContext: getProcessContext(ctx, proc),
Started: timestamp, Started: timestamp,
Ended: timestamp, Ended: timestamp,
} }
@ -304,7 +315,7 @@ func NewConnectionFromFirstPacket(pkt packet.Packet) *Connection {
IPProtocol: pkt.Info().Protocol, IPProtocol: pkt.Info().Protocol,
LocalIP: pkt.Info().LocalIP(), LocalIP: pkt.Info().LocalIP(),
LocalPort: pkt.Info().LocalPort(), LocalPort: pkt.Info().LocalPort(),
ProcessContext: getProcessContext(proc), ProcessContext: getProcessContext(pkt.Ctx(), proc),
process: proc, process: proc,
// remote endpoint // remote endpoint
Entity: entity, Entity: entity,

View file

@ -232,19 +232,14 @@ func loadProcess(ctx context.Context, pid int) (*Process, error) {
defer markRequestFinished() defer markRequestFinished()
} }
// create new process // Create new a process object.
new := &Process{ new := &Process{
Pid: pid, Pid: pid,
Virtual: true, // caller must decide to actually use the process - we need to save now. Virtual: true, // caller must decide to actually use the process - we need to save now.
FirstSeen: time.Now().Unix(), FirstSeen: time.Now().Unix(),
} }
switch { // Get process information from the system.
case new.IsKernel():
new.UserName = "Kernel"
new.Name = "Operating System"
default:
pInfo, err := processInfo.NewProcess(int32(pid)) pInfo, err := processInfo.NewProcess(int32(pid))
if err != nil { if err != nil {
return nil, err return nil, err
@ -313,7 +308,6 @@ func loadProcess(ctx context.Context, pid int) (*Process, error) {
// OS specifics // OS specifics
new.specialOSInit() new.specialOSInit()
}
new.Save() new.Save()
return new, nil return new, nil

View file

@ -2,10 +2,8 @@
package process package process
// IsKernel returns whether the process is the Kernel. // SystemProcessID is the PID of the System/Kernel itself.
func (p *Process) IsKernel() bool { const SystemProcessID = 0
return p.Pid == 0
}
// specialOSInit does special OS specific Process initialization. // specialOSInit does special OS specific Process initialization.
func (p *Process) specialOSInit() { func (p *Process) specialOSInit() {

View file

@ -1,9 +1,7 @@
package process package process
// IsKernel returns whether the process is the Kernel. // SystemProcessID is the PID of the System/Kernel itself.
func (p *Process) IsKernel() bool { const SystemProcessID = 0
return p.Pid == 0
}
// specialOSInit does special OS specific Process initialization. // specialOSInit does special OS specific Process initialization.
func (p *Process) specialOSInit() { func (p *Process) specialOSInit() {

View file

@ -7,10 +7,8 @@ import (
"github.com/safing/portbase/utils/osdetail" "github.com/safing/portbase/utils/osdetail"
) )
// IsKernel returns whether the process is the Kernel. // SystemProcessID is the PID of the System/Kernel itself.
func (p *Process) IsKernel() bool { const SystemProcessID = 4
return p.Pid == 4
}
// specialOSInit does special OS specific Process initialization. // specialOSInit does special OS specific Process initialization.
func (p *Process) specialOSInit() { func (p *Process) specialOSInit() {

View file

@ -9,11 +9,9 @@ import (
"golang.org/x/sync/singleflight" "golang.org/x/sync/singleflight"
) )
// Special Process IDs // UnidentifiedProcessID is the PID used for anything that could not be
const ( // attributed to a PID for any reason.
UnidentifiedProcessID = -1 const UnidentifiedProcessID = -1
SystemProcessID = 0
)
var ( var (
// unidentifiedProcess is used when a process cannot be found. // unidentifiedProcess is used when a process cannot be found.
@ -39,18 +37,18 @@ var (
// GetUnidentifiedProcess returns the special process assigned to unidentified processes. // GetUnidentifiedProcess returns the special process assigned to unidentified processes.
func GetUnidentifiedProcess(ctx context.Context) *Process { func GetUnidentifiedProcess(ctx context.Context) *Process {
return getSpecialProcess(ctx, UnidentifiedProcessID, unidentifiedProcess) return getSpecialProcess(ctx, unidentifiedProcess)
} }
// GetSystemProcess returns the special process used for the Kernel. // GetSystemProcess returns the special process used for the Kernel.
func GetSystemProcess(ctx context.Context) *Process { func GetSystemProcess(ctx context.Context) *Process {
return getSpecialProcess(ctx, SystemProcessID, systemProcess) return getSpecialProcess(ctx, systemProcess)
} }
func getSpecialProcess(ctx context.Context, pid int, template *Process) *Process { func getSpecialProcess(ctx context.Context, template *Process) *Process {
p, _, _ := getSpecialProcessSingleInflight.Do(strconv.Itoa(pid), func() (interface{}, error) { p, _, _ := getSpecialProcessSingleInflight.Do(strconv.Itoa(template.Pid), func() (interface{}, error) {
// Check if we have already loaded the special process. // Check if we have already loaded the special process.
process, ok := GetProcessFromStorage(pid) process, ok := GetProcessFromStorage(template.Pid)
if ok { if ok {
return process, nil return process, nil
} }

View file

@ -154,6 +154,10 @@ func (lp *LayeredProfile) UnlockForUsage() {
// LocalProfile returns the local profile associated with this layered profile. // LocalProfile returns the local profile associated with this layered profile.
func (lp *LayeredProfile) LocalProfile() *Profile { func (lp *LayeredProfile) LocalProfile() *Profile {
if lp == nil {
return nil
}
lp.RLock() lp.RLock()
defer lp.RUnlock() defer lp.RUnlock()

View file

@ -386,22 +386,22 @@ func EnsureProfile(r record.Record) (*Profile, error) {
// the profile was changed. If there is data that needs to be fetched from the // the profile was changed. If there is data that needs to be fetched from the
// operating system, it will start an async worker to fetch that data and save // operating system, it will start an async worker to fetch that data and save
// the profile afterwards. // the profile afterwards.
func (p *Profile) UpdateMetadata(processName string) (changed bool) { func (profile *Profile) UpdateMetadata(processName string) (changed bool) {
// Check if this is a local profile, else warn and return. // Check if this is a local profile, else warn and return.
if p.Source != SourceLocal { if profile.Source != SourceLocal {
log.Warningf("tried to update metadata for non-local profile %s", p.ScopedID()) log.Warningf("tried to update metadata for non-local profile %s", profile.ScopedID())
return false return false
} }
p.Lock() profile.Lock()
defer p.Unlock() defer profile.Unlock()
// Check if this is a special profile. // Check if this is a special profile.
if p.LinkedPath == "" { if profile.LinkedPath == "" {
// This is a special profile, just assign the processName, if needed, and // This is a special profile, just assign the processName, if needed, and
// return. // return.
if p.Name != processName { if profile.Name != processName {
p.Name = processName profile.Name = processName
return true return true
} }
return false return false
@ -410,18 +410,18 @@ func (p *Profile) UpdateMetadata(processName string) (changed bool) {
var needsUpdateFromSystem bool var needsUpdateFromSystem bool
// Check profile name. // Check profile name.
_, filename := filepath.Split(p.LinkedPath) _, filename := filepath.Split(profile.LinkedPath)
// Update profile name if it is empty or equals the filename, which is the // Update profile name if it is empty or equals the filename, which is the
// case for older profiles. // case for older profiles.
if p.Name == "" || p.Name == filename { if profile.Name == "" || profile.Name == filename {
// Generate a default profile name if does not exist. // Generate a default profile name if does not exist.
p.Name = osdetail.GenerateBinaryNameFromPath(p.LinkedPath) profile.Name = osdetail.GenerateBinaryNameFromPath(profile.LinkedPath)
if p.Name == filename { if profile.Name == filename {
// TODO: Theoretically, the generated name could be identical to the // TODO: Theoretically, the generated name could be identical to the
// filename. // filename.
// As a quick fix, append a space to the name. // As a quick fix, append a space to the name.
p.Name += " " profile.Name += " "
} }
changed = true changed = true
needsUpdateFromSystem = true needsUpdateFromSystem = true
@ -429,7 +429,7 @@ func (p *Profile) UpdateMetadata(processName string) (changed bool) {
// If needed, get more/better data from the operating system. // If needed, get more/better data from the operating system.
if needsUpdateFromSystem { if needsUpdateFromSystem {
module.StartWorker("get profile metadata", p.updateMetadataFromSystem) module.StartWorker("get profile metadata", profile.updateMetadataFromSystem)
} }
return changed return changed
@ -437,32 +437,34 @@ func (p *Profile) UpdateMetadata(processName string) (changed bool) {
// updateMetadataFromSystem updates the profile metadata with data from the // updateMetadataFromSystem updates the profile metadata with data from the
// operating system and saves it afterwards. // operating system and saves it afterwards.
func (p *Profile) updateMetadataFromSystem(ctx context.Context) error { func (profile *Profile) updateMetadataFromSystem(ctx context.Context) error {
// This function is only valid for local profiles. // This function is only valid for local profiles.
if p.Source != SourceLocal || p.LinkedPath == "" { if profile.Source != SourceLocal || profile.LinkedPath == "" {
return fmt.Errorf("tried to update metadata for non-local / non-linked profile %s", p.ScopedID()) return fmt.Errorf("tried to update metadata for non-local / non-linked profile %s", profile.ScopedID())
} }
// Save the profile when finished, if needed. // Save the profile when finished, if needed.
save := false save := false
defer func() { defer func() {
if save { if save {
err := p.Save() err := profile.Save()
if err != nil { if err != nil {
log.Warningf("profile: failed to save %s after metadata update: %s", p.ScopedID(), err) log.Warningf("profile: failed to save %s after metadata update: %s", profile.ScopedID(), err)
} }
} }
}() }()
// Get binary name from linked path. // Get binary name from linked path.
newName, err := osdetail.GetBinaryNameFromSystem(p.LinkedPath) newName, err := osdetail.GetBinaryNameFromSystem(profile.LinkedPath)
if err != nil { if err != nil {
log.Warningf("profile: error while getting binary name for %s: %s", p.LinkedPath, err) if !errors.Is(err, osdetail.ErrNotSupported) {
log.Warningf("profile: error while getting binary name for %s: %s", profile.LinkedPath, err)
}
return nil return nil
} }
// Get filename of linked path for comparison. // Get filename of linked path for comparison.
_, filename := filepath.Split(p.LinkedPath) _, filename := filepath.Split(profile.LinkedPath)
// TODO: Theoretically, the generated name from the system could be identical // TODO: Theoretically, the generated name from the system could be identical
// to the filename. This would mean that the worker is triggered every time // to the filename. This would mean that the worker is triggered every time
@ -473,12 +475,12 @@ func (p *Profile) updateMetadataFromSystem(ctx context.Context) error {
} }
// Lock profile for applying metadata. // Lock profile for applying metadata.
p.Lock() profile.Lock()
defer p.Unlock() defer profile.Unlock()
// Apply new name if it changed. // Apply new name if it changed.
if p.Name != newName { if profile.Name != newName {
p.Name = newName profile.Name = newName
save = true save = true
} }