diff --git a/docs/development/directives.md b/docs/development/directives.md index 9cff8840..291b0b74 100644 --- a/docs/development/directives.md +++ b/docs/development/directives.md @@ -115,6 +115,10 @@ The `exec` directive is useful to allow executing transitions to a profile witho : List a profile **files** to stack at the end of the current profile. +**`[X]`** + +: If `X` is set, the directive will conserve the `x` file rules regardless of the transition. Not enabled by default as it may conflict with the parent profile. + **Example** diff --git a/pkg/prebuild/builder/complain.go b/pkg/prebuild/builder/complain.go index e0f9f26b..68dcc9f4 100644 --- a/pkg/prebuild/builder/complain.go +++ b/pkg/prebuild/builder/complain.go @@ -14,7 +14,7 @@ import ( var ( regFlags = regexp.MustCompile(`flags=\(([^)]+)\)`) - regProfileHeader = regexp.MustCompile(` {`) + regProfileHeader = regexp.MustCompile(` {\n`) ) type Complain struct { @@ -40,7 +40,7 @@ func (b Complain) Apply(opt *Option, profile string) (string, error) { } } flags = append(flags, "complain") - strFlags := " flags=(" + strings.Join(flags, ",") + ") {" + strFlags := " flags=(" + strings.Join(flags, ",") + ") {\n" // Remove all flags definition, then set manifest' flags profile = regFlags.ReplaceAllLiteralString(profile, "") diff --git a/pkg/prebuild/builder/enforce.go b/pkg/prebuild/builder/enforce.go index bc25e03d..d453da51 100644 --- a/pkg/prebuild/builder/enforce.go +++ b/pkg/prebuild/builder/enforce.go @@ -36,9 +36,9 @@ func (b Enforce) Apply(opt *Option, profile string) (string, error) { return profile, nil } flags = slices.Delete(flags, idx, idx+1) - strFlags := "{" + strFlags := "{\n" if len(flags) >= 1 { - strFlags = " flags=(" + strings.Join(flags, ",") + ") {" + strFlags = " flags=(" + strings.Join(flags, ",") + ") {\n" } // Remove all flags definition, then set new flags diff --git a/pkg/prebuild/directive/exec.go b/pkg/prebuild/directive/exec.go index dd0d2ed0..b77d80fa 100644 --- a/pkg/prebuild/directive/exec.go +++ b/pkg/prebuild/directive/exec.go @@ -7,6 +7,7 @@ package directive import ( + "fmt" "slices" "strings" @@ -30,6 +31,9 @@ func init() { } func (d Exec) Apply(opt *Option, profileRaw string) (string, error) { + if len(opt.ArgList) == 0 { + return "", fmt.Errorf("No profile to exec") + } transition := "Px" transitions := []string{"P", "U", "p", "u", "PU", "pu"} t := opt.ArgList[0] diff --git a/pkg/prebuild/directive/stack.go b/pkg/prebuild/directive/stack.go index e0ab9d84..a2079dfb 100644 --- a/pkg/prebuild/directive/stack.go +++ b/pkg/prebuild/directive/stack.go @@ -7,6 +7,7 @@ package directive import ( "fmt" "regexp" + "slices" "strings" "github.com/roddhjav/apparmor.d/pkg/prebuild/cfg" @@ -19,7 +20,6 @@ var ( regCleanStakedRules = util.ToRegexRepl([]string{ `(?m)^.*include .*$`, ``, // Remove mandatory base abstraction `(?m)^.*@{exec_path}.*$`, ``, // Remove entry point - `(?m)^.*(|P|p)(|U|u)(|i)x,.*$`, ``, // Remove transition rules `(?m)^(?:[\t ]*(?:\r?\n))+`, ``, // Remove empty lines }) ) @@ -33,12 +33,26 @@ func init() { Base: cfg.Base{ Keyword: "stack", Msg: "Stack directive applied", - Help: Keyword + `stack profiles...`, + Help: Keyword + `stack [X] profiles...`, }, }) } func (s Stack) Apply(opt *Option, profile string) (string, error) { + 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) + } + res := "" for name := range opt.ArgMap { stackedProfile := util.MustReadFile(cfg.RootApparmord.Join(name)) diff --git a/pkg/prebuild/prepare/flags.go b/pkg/prebuild/prepare/flags.go index cd6c2f54..4ef41ef5 100644 --- a/pkg/prebuild/prepare/flags.go +++ b/pkg/prebuild/prepare/flags.go @@ -15,7 +15,7 @@ import ( var ( regFlags = regexp.MustCompile(`flags=\(([^)]+)\)`) - regProfileHeader = regexp.MustCompile(` {`) + regProfileHeader = regexp.MustCompile(` {\n`) ) type SetFlags struct { @@ -43,7 +43,7 @@ func (p SetFlags) Apply() ([]string, error) { // Overwrite profile flags if len(flags) > 0 { - flagsStr := " flags=(" + strings.Join(flags, ",") + ") {" + flagsStr := " flags=(" + strings.Join(flags, ",") + ") {\n" out, err := util.ReadFile(file) if err != nil { return res, err