refractor(aa): move profile specific method to the profile struct.

This commit is contained in:
Alexandre Pujol 2024-04-23 21:32:58 +01:00
parent 120db93396
commit 2923df2a73
Failed to generate hash of commit
3 changed files with 89 additions and 63 deletions

View file

@ -5,12 +5,6 @@
package aa package aa
import ( import (
"bytes"
"reflect"
"slices"
"sort"
"strings"
"github.com/arduino/go-paths-helper" "github.com/arduino/go-paths-helper"
) )
@ -60,22 +54,7 @@ func (f *AppArmorProfileFile) GetDefaultProfile() *Profile {
// Follow: https://apparmor.pujol.io/development/guidelines/#guidelines // Follow: https://apparmor.pujol.io/development/guidelines/#guidelines
func (f *AppArmorProfileFile) Sort() { func (f *AppArmorProfileFile) Sort() {
for _, p := range f.Profiles { for _, p := range f.Profiles {
sort.Slice(p.Rules, func(i, j int) bool { p.Sort()
typeOfI := reflect.TypeOf(p.Rules[i])
typeOfJ := reflect.TypeOf(p.Rules[j])
if typeOfI != typeOfJ {
valueOfI := typeToValue(typeOfI)
valueOfJ := typeToValue(typeOfJ)
if typeOfI == reflect.TypeOf((*Include)(nil)) && p.Rules[i].(*Include).IfExists {
valueOfI = "include_if_exists"
}
if typeOfJ == reflect.TypeOf((*Include)(nil)) && p.Rules[j].(*Include).IfExists {
valueOfJ = "include_if_exists"
}
return ruleWeights[valueOfI] < ruleWeights[valueOfJ]
}
return p.Rules[i].Less(p.Rules[j])
})
} }
} }
@ -87,53 +66,14 @@ func (f *AppArmorProfileFile) Sort() {
// Note: logs.regCleanLogs helps a lot to do a first cleaning // Note: logs.regCleanLogs helps a lot to do a first cleaning
func (f *AppArmorProfileFile) MergeRules() { func (f *AppArmorProfileFile) MergeRules() {
for _, p := range f.Profiles { for _, p := range f.Profiles {
for i := 0; i < len(p.Rules); i++ { p.Merge()
for j := i + 1; j < len(p.Rules); j++ {
typeOfI := reflect.TypeOf(p.Rules[i])
typeOfJ := reflect.TypeOf(p.Rules[j])
if typeOfI != typeOfJ {
continue
}
// If rules are identical, merge them
if p.Rules[i].Equals(p.Rules[j]) {
p.Rules = append(p.Rules[:j], p.Rules[j+1:]...)
j--
}
}
}
} }
} }
// Format the profile for better readability before printing it. // Format the profile for better readability before printing it.
// Follow: https://apparmor.pujol.io/development/guidelines/#the-file-block // Follow: https://apparmor.pujol.io/development/guidelines/#the-file-block
func (f *AppArmorProfileFile) Format() { func (f *AppArmorProfileFile) Format() {
const prefixOwner = " "
for _, p := range f.Profiles { for _, p := range f.Profiles {
hasOwnerRule := false p.Format()
for i := len(p.Rules) - 1; i > 0; i-- {
j := i - 1
typeOfI := reflect.TypeOf(p.Rules[i])
typeOfJ := reflect.TypeOf(p.Rules[j])
// File rule
if typeOfI == reflect.TypeOf((*File)(nil)) && typeOfJ == reflect.TypeOf((*File)(nil)) {
letterI := getLetterIn(fileAlphabet, p.Rules[i].(*File).Path)
letterJ := getLetterIn(fileAlphabet, p.Rules[j].(*File).Path)
// Add prefix before rule path to align with other rule
if p.Rules[i].(*File).Owner {
hasOwnerRule = true
} else if hasOwnerRule {
p.Rules[i].(*File).Prefix = prefixOwner
}
if letterI != letterJ {
// Add a new empty line between Files rule of different type
hasOwnerRule = false
p.Rules = append(p.Rules[:i], append([]ApparmorRule{&Rule{}}, p.Rules[i:]...)...)
}
}
}
} }
} }

View file

@ -6,6 +6,7 @@ package aa
import ( import (
"maps" "maps"
"reflect"
"slices" "slices"
"strings" "strings"
) )
@ -50,6 +51,67 @@ func (p *Profile) String() string {
return renderTemplate(tokPROFILE, p) return renderTemplate(tokPROFILE, p)
} }
// Merge merge similar rules together.
// Steps:
// - Remove identical rules
// - Merge rule access. Eg: for same path, 'r' and 'w' becomes 'rw'
//
// Note: logs.regCleanLogs helps a lot to do a first cleaning
func (p *Profile) Merge() {
for i := 0; i < len(p.Rules); i++ {
for j := i + 1; j < len(p.Rules); j++ {
typeOfI := reflect.TypeOf(p.Rules[i])
typeOfJ := reflect.TypeOf(p.Rules[j])
if typeOfI != typeOfJ {
continue
}
// If rules are identical, merge them
if p.Rules[i].Equals(p.Rules[j]) {
p.Rules = append(p.Rules[:j], p.Rules[j+1:]...)
j--
}
}
}
}
// Sort the rules in a profile.
// Follow: https://apparmor.pujol.io/development/guidelines/#guidelines
func (p *Profile) Sort() {
p.Rules.Sort()
}
// Format the profile for better readability before printing it.
// Follow: https://apparmor.pujol.io/development/guidelines/#the-file-block
func (p *Profile) Format() {
const prefixOwner = " "
hasOwnerRule := false
for i := len(p.Rules) - 1; i > 0; i-- {
j := i - 1
typeOfI := reflect.TypeOf(p.Rules[i])
typeOfJ := reflect.TypeOf(p.Rules[j])
// File rule
if typeOfI == reflect.TypeOf((*File)(nil)) && typeOfJ == reflect.TypeOf((*File)(nil)) {
letterI := getLetterIn(fileAlphabet, p.Rules[i].(*File).Path)
letterJ := getLetterIn(fileAlphabet, p.Rules[j].(*File).Path)
// Add prefix before rule path to align with other rule
if p.Rules[i].(*File).Owner {
hasOwnerRule = true
} else if hasOwnerRule {
p.Rules[i].(*File).Prefix = prefixOwner
}
if letterI != letterJ {
// Add a new empty line between Files rule of different type
hasOwnerRule = false
p.Rules = append(p.Rules[:i], append([]Rule{&RuleBase{}}, p.Rules[i:]...)...)
}
}
}
}
// AddRule adds a new rule to the profile from a log map. // AddRule adds a new rule to the profile from a log map.
func (p *Profile) AddRule(log map[string]string) { func (p *Profile) AddRule(log map[string]string) {

View file

@ -5,6 +5,8 @@
package aa package aa
import ( import (
"reflect"
"sort"
"strings" "strings"
) )
@ -28,8 +30,29 @@ func (r Rules) String() string {
return renderTemplate("rules", r) return renderTemplate("rules", r)
} }
// Sort the rules in a profile.
// Follow: https://apparmor.pujol.io/development/guidelines/#guidelines
func (r Rules) Sort() {
sort.Slice(r, func(i, j int) bool {
typeOfI := reflect.TypeOf(r[i])
typeOfJ := reflect.TypeOf(r[j])
if typeOfI != typeOfJ {
valueOfI := typeToValue(typeOfI)
valueOfJ := typeToValue(typeOfJ)
if typeOfI == reflect.TypeOf((*Include)(nil)) && r[i].(*Include).IfExists {
valueOfI = "include_if_exists"
}
if typeOfJ == reflect.TypeOf((*Include)(nil)) && r[j].(*Include).IfExists {
valueOfJ = "include_if_exists"
}
return ruleWeights[valueOfI] < ruleWeights[valueOfJ]
}
return r[i].Less(r[j])
})
}
type RuleBase struct { type RuleBase struct {
IsLineRule bool
Comment string Comment string
NoNewPrivs bool NoNewPrivs bool
FileInherit bool FileInherit bool
@ -67,6 +90,7 @@ func newRuleFromLog(log map[string]string) RuleBase {
} }
return RuleBase{ return RuleBase{
IsLineRule: false,
Comment: msg, Comment: msg,
NoNewPrivs: noNewPrivs, NoNewPrivs: noNewPrivs,
FileInherit: fileInherit, FileInherit: fileInherit,