2024-03-21 22:09:46 +01:00
|
|
|
// apparmor.d - Full set of apparmor profiles
|
|
|
|
// Copyright (C) 2021-2024 Alexandre Pujol <alexandre@pujol.io>
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
|
|
|
|
|
|
|
package directive
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"regexp"
|
2024-09-10 19:13:48 +02:00
|
|
|
"slices"
|
2024-03-21 22:09:46 +01:00
|
|
|
"strings"
|
|
|
|
|
2024-10-02 17:22:46 +02:00
|
|
|
"github.com/roddhjav/apparmor.d/pkg/prebuild"
|
2024-03-21 22:09:46 +01:00
|
|
|
"github.com/roddhjav/apparmor.d/pkg/util"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
regRules = regexp.MustCompile(`(?m)^profile.*{$((.|\n)*)}`)
|
|
|
|
regEndOfRules = regexp.MustCompile(`(?m)([\t ]*include if exists <.*>\n)+}`)
|
|
|
|
regCleanStakedRules = util.ToRegexRepl([]string{
|
|
|
|
`(?m)^.*include <abstractions/base>.*$`, ``, // Remove mandatory base abstraction
|
|
|
|
`(?m)^.*@{exec_path}.*$`, ``, // Remove entry point
|
|
|
|
`(?m)^(?:[\t ]*(?:\r?\n))+`, ``, // Remove empty lines
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
|
|
|
type Stack struct {
|
2024-10-02 17:22:46 +02:00
|
|
|
prebuild.Base
|
2024-03-21 22:09:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
2024-03-25 23:40:25 +01:00
|
|
|
RegisterDirective(&Stack{
|
2024-10-02 17:22:46 +02:00
|
|
|
Base: prebuild.Base{
|
2024-03-25 23:40:25 +01:00
|
|
|
Keyword: "stack",
|
|
|
|
Msg: "Stack directive applied",
|
2024-09-26 23:05:47 +02:00
|
|
|
Help: []string{"[X] profiles..."},
|
2024-03-21 22:09:46 +01:00
|
|
|
},
|
2024-03-25 23:40:25 +01:00
|
|
|
})
|
2024-03-21 22:09:46 +01:00
|
|
|
}
|
|
|
|
|
2024-05-25 23:30:20 +02:00
|
|
|
func (s Stack) Apply(opt *Option, profile string) (string, error) {
|
2024-09-10 19:13:48 +02:00
|
|
|
if len(opt.ArgList) == 0 {
|
|
|
|
return "", fmt.Errorf("No profile to stack")
|
|
|
|
}
|
|
|
|
t := opt.ArgList[0]
|
|
|
|
if t != "X" {
|
|
|
|
regCleanStakedRules = slices.Insert(regCleanStakedRules, 0,
|
|
|
|
util.ToRegexRepl([]string{
|
|
|
|
`(?m)^.*(|P|p)(|U|u)(|i)x,.*$`, ``, // Remove X transition rules
|
|
|
|
})...,
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
delete(opt.ArgMap, t)
|
|
|
|
}
|
|
|
|
|
2024-03-21 22:09:46 +01:00
|
|
|
res := ""
|
2024-03-23 18:41:10 +01:00
|
|
|
for name := range opt.ArgMap {
|
2024-10-02 17:22:46 +02:00
|
|
|
stackedProfile := util.MustReadFile(prebuild.RootApparmord.Join(name))
|
2024-03-21 22:09:46 +01:00
|
|
|
m := regRules.FindStringSubmatch(stackedProfile)
|
|
|
|
if len(m) < 2 {
|
2024-05-25 23:30:20 +02:00
|
|
|
return "", fmt.Errorf("No profile found in %s", name)
|
2024-03-21 22:09:46 +01:00
|
|
|
}
|
|
|
|
stackedRules := m[1]
|
|
|
|
stackedRules = regCleanStakedRules.Replace(stackedRules)
|
|
|
|
res += " # Stacked profile: " + name + "\n" + stackedRules + "\n"
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert the stacked profile at the end of the current profile, remove the stack directive
|
|
|
|
m := regEndOfRules.FindStringSubmatch(profile)
|
|
|
|
if len(m) <= 1 {
|
2024-05-25 23:30:20 +02:00
|
|
|
return "", fmt.Errorf("No end of rules found in %s", opt.File)
|
2024-03-21 22:09:46 +01:00
|
|
|
}
|
|
|
|
profile = strings.Replace(profile, m[0], res+m[0], -1)
|
|
|
|
profile = strings.Replace(profile, opt.Raw, "", -1)
|
2024-05-25 23:30:20 +02:00
|
|
|
return profile, nil
|
2024-03-21 22:09:46 +01:00
|
|
|
}
|