Improve profile metadata handling

This commit is contained in:
Daniel
2022-10-06 10:33:25 +02:00
parent c4943a96b1
commit 595f4c0106
9 changed files with 165 additions and 137 deletions

View File

@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"path/filepath"
"strings"
"sync"
"sync/atomic"
@@ -89,6 +88,10 @@ type Profile struct { //nolint:maligned // not worth the effort
// Is automatically removed when the path does not exist.
// Is automatically populated with the next match when empty.
PresentationPath string
// UsePresentationPath can be used to enable/disable fetching information
// from the executable at PresentationPath. In some cases, this is not
// desirable.
UsePresentationPath bool
// Fingerprints holds process matching information.
Fingerprints []Fingerprint
// SecurityLevel is the mininum security level to apply to
@@ -419,48 +422,54 @@ func EnsureProfile(r record.Record) (*Profile, error) {
return newProfile, nil
}
// UpdateMetadata updates meta data fields on the profile and returns whether
// 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
// the profile afterwards.
func (profile *Profile) UpdateMetadata(binaryPath string) (changed bool) {
// updateMetadata updates meta data fields on the profile and returns whether
// the profile was changed.
func (profile *Profile) updateMetadata(binaryPath string) (changed bool) {
// Check if this is a local profile, else warn and return.
if profile.Source != SourceLocal {
log.Warningf("tried to update metadata for non-local profile %s", profile.ScopedID())
return false
}
profile.Lock()
defer profile.Unlock()
// Update special profile and return if it was one.
if ok, changed := updateSpecialProfileMetadata(profile, binaryPath); ok {
return changed
// Set PresentationPath if unset.
if profile.PresentationPath == "" && binaryPath != "" {
profile.PresentationPath = binaryPath
changed = true
}
var needsUpdateFromSystem bool
// Migrate LinkedPath to PresentationPath.
// TODO: Remove in v1.5
if profile.PresentationPath == "" && profile.LinkedPath != "" {
profile.PresentationPath = profile.LinkedPath
changed = true
}
// Check profile name.
filename := filepath.Base(profile.PresentationPath)
// Update profile name if it is empty or equals the filename, which is the
// case for older profiles.
if strings.TrimSpace(profile.Name) == "" || profile.Name == filename {
// Generate a default profile name if does not exist.
// Set Name if unset.
if profile.Name == "" && profile.PresentationPath != "" {
// Generate a default profile name from path.
profile.Name = osdetail.GenerateBinaryNameFromPath(profile.PresentationPath)
if profile.Name == filename {
// TODO: Theoretically, the generated name could be identical to the
// filename.
// As a quick fix, append a space to the name.
profile.Name += " "
changed = true
}
// Migrato to Fingerprints.
// TODO: Remove in v1.5
if len(profile.Fingerprints) == 0 && profile.LinkedPath != "" {
profile.Fingerprints = []Fingerprint{
{
Type: FingerprintTypePathID,
Operation: FingerprintOperationEqualsID,
Value: profile.LinkedPath,
},
}
changed = true
needsUpdateFromSystem = true
}
// If needed, get more/better data from the operating system.
if needsUpdateFromSystem {
module.StartWorker("get profile metadata", profile.updateMetadataFromSystem)
// UI Backward Compatibility:
// Fill LinkedPath with PresentationPath
// TODO: Remove in v1.1
if profile.LinkedPath == "" && profile.PresentationPath != "" {
profile.LinkedPath = profile.PresentationPath
changed = true
}
return changed
@@ -469,23 +478,14 @@ func (profile *Profile) UpdateMetadata(binaryPath string) (changed bool) {
// updateMetadataFromSystem updates the profile metadata with data from the
// operating system and saves it afterwards.
func (profile *Profile) updateMetadataFromSystem(ctx context.Context) error {
var changed bool
// This function is only valid for local profiles.
if profile.Source != SourceLocal || profile.PresentationPath == "" {
return fmt.Errorf("tried to update metadata for non-local or non-path profile %s", profile.ScopedID())
}
// Save the profile when finished, if needed.
save := false
defer func() {
if save {
err := profile.Save()
if err != nil {
log.Warningf("profile: failed to save %s after metadata update: %s", profile.ScopedID(), err)
}
}
}()
// Get binary name from linked path.
// Get binary name from PresentationPath.
newName, err := osdetail.GetBinaryNameFromSystem(profile.PresentationPath)
if err != nil {
switch {
@@ -503,25 +503,26 @@ func (profile *Profile) updateMetadataFromSystem(ctx context.Context) error {
return nil
}
// Get filename of linked path for comparison.
filename := filepath.Base(profile.PresentationPath)
// Apply new data to profile.
func() {
// Lock profile for applying metadata.
profile.Lock()
defer profile.Unlock()
// TODO: Theoretically, the generated name from the system could be identical
// to the filename. This would mean that the worker is triggered every time
// the profile is freshly loaded.
if newName == filename {
// As a quick fix, append a space to the name.
newName += " "
}
// Apply new name if it changed.
if profile.Name != newName {
profile.Name = newName
changed = true
}
}()
// Lock profile for applying metadata.
profile.Lock()
defer profile.Unlock()
// Apply new name if it changed.
if profile.Name != newName {
profile.Name = newName
save = true
// If anything changed, save the profile.
// profile.Lock must not be held!
if changed {
err := profile.Save()
if err != nil {
log.Warningf("profile: failed to save %s after metadata update: %s", profile.ScopedID(), err)
}
}
return nil