mirror of
https://github.com/safing/portmaster
synced 2025-04-25 13:29:10 +00:00
Add experimental support to inherit profiles from parent processes
This commit is contained in:
parent
a13cd45a13
commit
dc68abc17d
4 changed files with 71 additions and 14 deletions
|
@ -307,3 +307,18 @@ func (md *MatchingData) MatchingPath() string { return md.p.MatchingPath }
|
|||
|
||||
// Cmdline returns the command line of the process.
|
||||
func (md *MatchingData) Cmdline() string { return md.p.CmdLine }
|
||||
|
||||
// Parent returns the matching data of the parent. Due to bad import cycles we cannot
|
||||
// use the correct interface type here ...
|
||||
func (md *MatchingData) Parent() interface{} {
|
||||
if md.p.ParentPid == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
parentProcess, err := loadProcess(module.Ctx, md.p.ParentPid)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return parentProcess.MatchingData()
|
||||
}
|
||||
|
|
|
@ -125,6 +125,9 @@ var (
|
|||
cfgOptionExitHubPolicyOrder = 146
|
||||
|
||||
// Setting "DNS Exit Node Rules" at order 147.
|
||||
|
||||
CfgOptionInheritProfileKey = "core/inheritProfiles"
|
||||
cfgOptionInhertiProfile config.BoolOption
|
||||
)
|
||||
|
||||
// A list of all security level settings.
|
||||
|
@ -721,5 +724,23 @@ By default, the Portmaster tries to choose the node closest to the destination a
|
|||
cfgOptionRoutingAlgorithm = config.Concurrent.GetAsString(CfgOptionRoutingAlgorithmKey, defaultRoutingAlg)
|
||||
cfgStringOptions[CfgOptionRoutingAlgorithmKey] = cfgOptionRoutingAlgorithm
|
||||
|
||||
err = config.Register(&config.Option{
|
||||
Name: "Inherit Process Profiles",
|
||||
Key: CfgOptionInheritProfileKey,
|
||||
Description: "Whether or not processes that do not have a dedicated profile should inherit the app profile from the parent process.",
|
||||
OptType: config.OptTypeBool,
|
||||
DefaultValue: false,
|
||||
ExpertiseLevel: config.ExpertiseLevelDeveloper,
|
||||
ReleaseLevel: config.ReleaseLevelExperimental,
|
||||
Annotations: config.Annotations{
|
||||
config.DisplayOrderAnnotation: 529,
|
||||
config.CategoryAnnotation: "Development",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfgOptionInhertiProfile = config.Concurrent.GetAsBool(CfgOptionInheritProfileKey, false)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -73,6 +73,10 @@ type (
|
|||
Path() string
|
||||
MatchingPath() string
|
||||
Cmdline() string
|
||||
Parent() interface{} // implementations should return MatchingData but we do
|
||||
// have import cycles here if we try to specify that.
|
||||
// TODO(ppacher): fix that and move the matching data def into
|
||||
// it's own package (where it belongs to because it's needed by process and profile)
|
||||
}
|
||||
|
||||
matchingFingerprint interface {
|
||||
|
|
|
@ -84,11 +84,30 @@ func GetLocalProfile(id string, md MatchingData, createProfileCallback func() *P
|
|||
}
|
||||
|
||||
// If we don't have a profile yet, find profile based on matching data.
|
||||
if profile == nil {
|
||||
profile, err = findProfile(SourceLocal, md)
|
||||
iter := md
|
||||
var highestScore int
|
||||
for iter != nil {
|
||||
iterProfile, score, err := findProfile(SourceLocal, iter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to search for profile: %w", err)
|
||||
}
|
||||
|
||||
if score > highestScore {
|
||||
profile = iterProfile
|
||||
highestScore = score
|
||||
}
|
||||
|
||||
if !cfgOptionInhertiProfile() {
|
||||
break
|
||||
}
|
||||
|
||||
// try to get the matching data of the parent
|
||||
parent := iter.Parent()
|
||||
if parent == nil {
|
||||
break
|
||||
}
|
||||
|
||||
iter, _ = parent.(MatchingData)
|
||||
}
|
||||
|
||||
// If we still don't have a profile, create a new one.
|
||||
|
@ -186,21 +205,19 @@ func getProfile(scopedID string) (profile *Profile, err error) {
|
|||
|
||||
// findProfile searches for a profile with the given linked path. If it cannot
|
||||
// find one, it will create a new profile for the given linked path.
|
||||
func findProfile(source profileSource, md MatchingData) (profile *Profile, err error) {
|
||||
func findProfile(source profileSource, md MatchingData) (profile *Profile, highestScore int, err error) {
|
||||
// TODO: Loading every profile from database and parsing it for every new
|
||||
// process might be quite expensive. Measure impact and possibly improve.
|
||||
|
||||
// Get iterator over all profiles.
|
||||
it, err := profileDB.Query(query.New(profilesDBPath + makeScopedID(source, "")))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query for profiles: %w", err)
|
||||
return nil, 0, fmt.Errorf("failed to query for profiles: %w", err)
|
||||
}
|
||||
|
||||
// Find best matching profile.
|
||||
var (
|
||||
highestScore int
|
||||
bestMatch record.Record
|
||||
)
|
||||
var bestMatch record.Record
|
||||
|
||||
profileFeed:
|
||||
for r := range it.Next {
|
||||
// Parse fingerprints.
|
||||
|
@ -232,27 +249,27 @@ profileFeed:
|
|||
|
||||
// Check if there was an error while iterating.
|
||||
if it.Err() != nil {
|
||||
return nil, fmt.Errorf("failed to iterate over profiles: %w", err)
|
||||
return nil, 0, fmt.Errorf("failed to iterate over profiles: %w", err)
|
||||
}
|
||||
|
||||
// Return nothing if no profile matched.
|
||||
if bestMatch == nil {
|
||||
return nil, nil
|
||||
return nil, 0, nil
|
||||
}
|
||||
|
||||
// If we have a match, parse and return the profile.
|
||||
profile, err = loadProfile(bestMatch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse selected profile %s: %w", bestMatch.Key(), err)
|
||||
return nil, 0, fmt.Errorf("failed to parse selected profile %s: %w", bestMatch.Key(), err)
|
||||
}
|
||||
|
||||
// Check if this profile is already active and return the active version instead.
|
||||
if activeProfile := getActiveProfile(profile.ScopedID()); activeProfile != nil && !activeProfile.IsOutdated() {
|
||||
return activeProfile, nil
|
||||
return activeProfile, highestScore, nil
|
||||
}
|
||||
|
||||
// Return nothing if no profile matched.
|
||||
return profile, nil
|
||||
// Return the freshly loaded profile since there's no active version available.
|
||||
return profile, highestScore, nil
|
||||
}
|
||||
|
||||
func loadProfileFingerprints(r record.Record) (parsed *parsedFingerprints, err error) {
|
||||
|
|
Loading…
Add table
Reference in a new issue