Merge branch 'feat/aa'
Improve go apparmor lib. * aa: (62 commits) feat(aa): handle appending value to defined variables. chore(aa): cosmetic. fix: userspace prebuild test. chore: cleanup unit test. feat(aa): improve log conversion. feat(aa): move conversion function to its own file & add unit tests. fix: go linter issue & not defined variables. tests(aa): improve aa unit tests. tests(aa): improve rules unit tests. feat(aa): ensure the prebuild jobs are working. feat(aa): add more unit tests. chore(aa): cleanup. feat(aa): Move sort, merge and format methods to the rules interface. feat(aa): add the hat template. feat(aa): add the Kind struct to manage aa rules. feat(aa): cleanup rules methods. feat(aa): add function to resolve include preamble. feat(aa): updaqte mount flags order. feat(aa): update default tunable selection. feat(aa): parse apparmor preamble files. ...
This commit is contained in:
commit
89abbae6bd
90 changed files with 4995 additions and 2012 deletions
180
pkg/aa/resolve.go
Normal file
180
pkg/aa/resolve.go
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
// apparmor.d - Full set of apparmor profiles
|
||||
// Copyright (C) 2021-2024 Alexandre Pujol <alexandre@pujol.io>
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
package aa
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/roddhjav/apparmor.d/pkg/paths"
|
||||
"github.com/roddhjav/apparmor.d/pkg/util"
|
||||
)
|
||||
|
||||
var (
|
||||
includeCache map[*Include]*AppArmorProfileFile = make(map[*Include]*AppArmorProfileFile)
|
||||
|
||||
regVariableReference = regexp.MustCompile(`@{([^{}]+)}`)
|
||||
)
|
||||
|
||||
// Resolve resolves variables and includes definied in the profile preamble
|
||||
func (f *AppArmorProfileFile) Resolve() error {
|
||||
// Resolve preamble includes
|
||||
// for _, include := range f.Preamble.GetIncludes() {
|
||||
// err := f.resolveInclude(include)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
|
||||
// Append value to variable
|
||||
seen := map[string]*Variable{}
|
||||
for idx, variable := range f.Preamble.GetVariables() {
|
||||
if _, ok := seen[variable.Name]; ok {
|
||||
if variable.Define {
|
||||
return fmt.Errorf("variable %s already defined", variable.Name)
|
||||
}
|
||||
seen[variable.Name].Values = append(seen[variable.Name].Values, variable.Values...)
|
||||
f.Preamble = f.Preamble.Delete(idx)
|
||||
}
|
||||
if variable.Define {
|
||||
seen[variable.Name] = variable
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve variables
|
||||
for _, variable := range f.Preamble.GetVariables() {
|
||||
newValues := []string{}
|
||||
for _, value := range variable.Values {
|
||||
vars, err := f.resolveValues(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newValues = append(newValues, vars...)
|
||||
}
|
||||
variable.Values = newValues
|
||||
}
|
||||
|
||||
// Resolve variables in attachements
|
||||
for _, profile := range f.Profiles {
|
||||
attachments := []string{}
|
||||
for _, att := range profile.Attachments {
|
||||
vars, err := f.resolveValues(att)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attachments = append(attachments, vars...)
|
||||
}
|
||||
profile.Attachments = attachments
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *AppArmorProfileFile) resolveValues(input string) ([]string, error) {
|
||||
if !strings.Contains(input, VARIABLE.Tok()) {
|
||||
return []string{input}, nil
|
||||
}
|
||||
|
||||
values := []string{}
|
||||
match := regVariableReference.FindStringSubmatch(input)
|
||||
if len(match) == 0 {
|
||||
return nil, fmt.Errorf("Invalid variable reference: %s", input)
|
||||
}
|
||||
|
||||
variable := match[0]
|
||||
varname := match[1]
|
||||
found := false
|
||||
for _, vrbl := range f.Preamble.GetVariables() {
|
||||
if vrbl.Name == varname {
|
||||
found = true
|
||||
for _, v := range vrbl.Values {
|
||||
if strings.Contains(v, VARIABLE.Tok()+varname+"}") {
|
||||
return nil, fmt.Errorf("recursive variable found in: %s", varname)
|
||||
}
|
||||
newValues := strings.ReplaceAll(input, variable, v)
|
||||
newValues = strings.ReplaceAll(newValues, "//", "/")
|
||||
res, err := f.resolveValues(newValues)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
values = append(values, res...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return nil, fmt.Errorf("Variable %s not defined", varname)
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// resolveInclude resolves all includes defined in the profile preamble
|
||||
func (f *AppArmorProfileFile) resolveInclude(include *Include) error {
|
||||
if include == nil || include.Path == "" {
|
||||
return fmt.Errorf("Invalid include: %v", include)
|
||||
}
|
||||
|
||||
_, isCached := includeCache[include]
|
||||
if !isCached {
|
||||
var files paths.PathList
|
||||
var err error
|
||||
|
||||
path := MagicRoot.Join(include.Path)
|
||||
if !include.IsMagic {
|
||||
path = paths.New(include.Path)
|
||||
}
|
||||
|
||||
if path.IsDir() {
|
||||
files, err = path.ReadDir(paths.FilterOutDirectories())
|
||||
if err != nil {
|
||||
if include.IfExists {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("File %s not found: %v", path, err)
|
||||
}
|
||||
|
||||
} else if path.Exist() {
|
||||
files = append(files, path)
|
||||
|
||||
} else {
|
||||
if include.IfExists {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("File %s not found", path)
|
||||
|
||||
}
|
||||
|
||||
iFile := &AppArmorProfileFile{}
|
||||
for _, file := range files {
|
||||
raw, err := util.ReadFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := iFile.Parse(raw); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := iFile.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, inc := range iFile.Preamble.GetIncludes() {
|
||||
if err := iFile.resolveInclude(inc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all includes in iFile
|
||||
iFile.Preamble = iFile.Preamble.DeleteKind(INCLUDE)
|
||||
|
||||
// Cache the included file
|
||||
includeCache[include] = iFile
|
||||
}
|
||||
|
||||
// Insert iFile in the place of include in the current file
|
||||
index := f.Preamble.Index(include)
|
||||
f.Preamble = f.Preamble.Replace(index, includeCache[include].Preamble...)
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue