mirror of
https://github.com/roddhjav/apparmor.d.git
synced 2025-01-18 00:48:10 +01:00
feat(aa-log): add a new apparmor profile struct
Also rewrite variables resolution to this new struct.
This commit is contained in:
parent
b2d093e125
commit
a8470dfa38
5 changed files with 379 additions and 156 deletions
|
@ -2,104 +2,19 @@
|
||||||
// Copyright (C) 2023 Alexandre Pujol <alexandre@pujol.io>
|
// Copyright (C) 2023 Alexandre Pujol <alexandre@pujol.io>
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
// Warning: this is purposely not using a Yacc parser. Its only aim is to
|
|
||||||
// extract variables and attachments for apparmor.d profile
|
|
||||||
|
|
||||||
package aa
|
package aa
|
||||||
|
// AppArmorProfiles represents a full set of apparmor profiles
|
||||||
|
type AppArmorProfiles map[string]*AppArmorProfile
|
||||||
|
|
||||||
import (
|
// ApparmorProfile represents a full apparmor profile.
|
||||||
"regexp"
|
// Warning: close to the BNF grammar of apparmor profile but not exactly the same (yet):
|
||||||
"strings"
|
// - Some rules are not supported yet (subprofile, hat...)
|
||||||
|
// - The structure is simplified as it only aims at writting profile, not parsing it.
|
||||||
"golang.org/x/exp/maps"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
regVariablesDef = regexp.MustCompile(`@{(.*)}\s*[+=]+\s*(.*)`)
|
|
||||||
regVariablesRef = regexp.MustCompile(`@{([^{}]+)}`)
|
|
||||||
|
|
||||||
// Tunables
|
|
||||||
Tunables = map[string][]string{
|
|
||||||
"bin": {"/{usr/,}{s,}bin"},
|
|
||||||
"lib": {"/{usr/,}lib{,exec,32,64}"},
|
|
||||||
"multiarch": {"*-linux-gnu*"},
|
|
||||||
"user_share_dirs": {"/home/*/.local/share"},
|
|
||||||
"etc_ro": {"/{usr/,}etc/"},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
type AppArmorProfile struct {
|
type AppArmorProfile struct {
|
||||||
Variables map[string][]string
|
Preamble
|
||||||
Attachments []string
|
Profile
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAppArmorProfile() *AppArmorProfile {
|
func NewAppArmorProfile() *AppArmorProfile {
|
||||||
variables := make(map[string][]string)
|
return &AppArmorProfile{}
|
||||||
maps.Copy(variables, Tunables)
|
|
||||||
return &AppArmorProfile{
|
|
||||||
Variables: variables,
|
|
||||||
Attachments: []string{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseVariables extract all variables from the profile
|
|
||||||
func (p *AppArmorProfile) ParseVariables(content string) {
|
|
||||||
matches := regVariablesDef.FindAllStringSubmatch(content, -1)
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) > 2 {
|
|
||||||
key := match[1]
|
|
||||||
values := match[2]
|
|
||||||
if _, ok := p.Variables[key]; ok {
|
|
||||||
p.Variables[key] = append(p.Variables[key], strings.Split(values, " ")...)
|
|
||||||
} else {
|
|
||||||
p.Variables[key] = strings.Split(values, " ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolve recursively resolves all variables references
|
|
||||||
func (p *AppArmorProfile) resolve(str string) []string {
|
|
||||||
if strings.Contains(str, "@{") {
|
|
||||||
vars := []string{}
|
|
||||||
match := regVariablesRef.FindStringSubmatch(str)
|
|
||||||
if len(match) > 1 {
|
|
||||||
variable := match[0]
|
|
||||||
varname := match[1]
|
|
||||||
for _, value := range p.Variables[varname] {
|
|
||||||
newVar := strings.ReplaceAll(str, variable, value)
|
|
||||||
vars = append(vars, p.resolve(newVar)...)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
vars = append(vars, str)
|
|
||||||
}
|
|
||||||
return vars
|
|
||||||
}
|
|
||||||
return []string{str}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResolveAttachments resolve profile attachments defined in exec_path
|
|
||||||
func (p *AppArmorProfile) ResolveAttachments() {
|
|
||||||
for _, exec := range p.Variables["exec_path"] {
|
|
||||||
p.Attachments = append(p.Attachments, p.resolve(exec)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NestAttachments return a nested attachment string
|
|
||||||
func (p *AppArmorProfile) NestAttachments() string {
|
|
||||||
if len(p.Attachments) == 0 {
|
|
||||||
return ""
|
|
||||||
} else if len(p.Attachments) == 1 {
|
|
||||||
return p.Attachments[0]
|
|
||||||
} else {
|
|
||||||
res := []string{}
|
|
||||||
for _, attachment := range p.Attachments {
|
|
||||||
if strings.HasPrefix(attachment, "/") {
|
|
||||||
res = append(res, attachment[1:])
|
|
||||||
} else {
|
|
||||||
res = append(res, attachment)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "/{" + strings.Join(res, ",") + "}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
202
pkg/aa/rules.go
Normal file
202
pkg/aa/rules.go
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
// apparmor.d - Full set of apparmor profiles
|
||||||
|
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
package aa
|
||||||
|
|
||||||
|
// Preamble section of a profile
|
||||||
|
type Preamble struct {
|
||||||
|
Abi []Abi
|
||||||
|
PreambleIncludes []Include
|
||||||
|
Aliases []Alias
|
||||||
|
Variables []Variable
|
||||||
|
}
|
||||||
|
|
||||||
|
// Profile section of a profile
|
||||||
|
type Profile struct {
|
||||||
|
Name string
|
||||||
|
Attachments []string
|
||||||
|
Attributes []string
|
||||||
|
Flags []string
|
||||||
|
Rules
|
||||||
|
}
|
||||||
|
|
||||||
|
type Rules struct {
|
||||||
|
Includes []Include
|
||||||
|
Rlimit []Rlimit
|
||||||
|
Userns Userns
|
||||||
|
Capability []Capability
|
||||||
|
Network []Network
|
||||||
|
Mount []Mount
|
||||||
|
Umount []Umount
|
||||||
|
Remount []Remount
|
||||||
|
PivotRoot []PivotRoot
|
||||||
|
ChangeProfile []ChangeProfile
|
||||||
|
Unix []Unix
|
||||||
|
Ptrace []Ptrace
|
||||||
|
Signal []Signal
|
||||||
|
Dbus []Dbus
|
||||||
|
File []File
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Qualifier to apply extra settings to a rule
|
||||||
|
type Qualifier struct {
|
||||||
|
Audit bool
|
||||||
|
AccessType string
|
||||||
|
Owner bool
|
||||||
|
NoNewPrivs bool
|
||||||
|
FileInherit bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preamble rules
|
||||||
|
|
||||||
|
type Abi struct {
|
||||||
|
AbsPath string
|
||||||
|
MagicPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Alias struct {
|
||||||
|
Path string
|
||||||
|
RewrittenPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Include struct {
|
||||||
|
IfExists bool
|
||||||
|
AbsPath string
|
||||||
|
MagicPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Variable struct {
|
||||||
|
Name string
|
||||||
|
Values []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Profile rules
|
||||||
|
|
||||||
|
type Rlimit struct {
|
||||||
|
Key string
|
||||||
|
Op string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Userns struct {
|
||||||
|
Qualifier
|
||||||
|
Create bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Capability struct {
|
||||||
|
Qualifier
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddressExpr struct {
|
||||||
|
Source string
|
||||||
|
Destination string
|
||||||
|
Port string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Network struct {
|
||||||
|
Qualifier
|
||||||
|
Domain string
|
||||||
|
Type string
|
||||||
|
Protocol string
|
||||||
|
AddressExpr
|
||||||
|
}
|
||||||
|
|
||||||
|
type MountConditions struct {
|
||||||
|
Fs string
|
||||||
|
Op string
|
||||||
|
FsType string
|
||||||
|
Options []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mount struct {
|
||||||
|
Qualifier
|
||||||
|
MountConditions
|
||||||
|
Source string
|
||||||
|
MountPoint string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Umount struct {
|
||||||
|
Qualifier
|
||||||
|
MountConditions
|
||||||
|
MountPoint string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Remount struct {
|
||||||
|
Qualifier
|
||||||
|
MountConditions
|
||||||
|
MountPoint string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PivotRoot struct {
|
||||||
|
Qualifier
|
||||||
|
OldRoot string
|
||||||
|
NewRoot string
|
||||||
|
TargetProfile string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChangeProfile struct {
|
||||||
|
ExecMode string
|
||||||
|
Exec string
|
||||||
|
ProfileName string
|
||||||
|
}
|
||||||
|
|
||||||
|
type IOUring struct {
|
||||||
|
Qualifier
|
||||||
|
Access string
|
||||||
|
Label string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Signal struct {
|
||||||
|
Qualifier
|
||||||
|
Access string
|
||||||
|
Set string
|
||||||
|
Peer string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Ptrace struct {
|
||||||
|
Qualifier
|
||||||
|
Access string
|
||||||
|
Peer string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Unix struct {
|
||||||
|
Qualifier
|
||||||
|
Access string
|
||||||
|
Type string
|
||||||
|
Protocol string
|
||||||
|
Address string
|
||||||
|
Label string
|
||||||
|
Attr string
|
||||||
|
Opt string
|
||||||
|
Peer string
|
||||||
|
PeerAddr string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mqueue struct {
|
||||||
|
Qualifier
|
||||||
|
Access string
|
||||||
|
Type string
|
||||||
|
Label string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Dbus struct {
|
||||||
|
Qualifier
|
||||||
|
Access string
|
||||||
|
Bus string
|
||||||
|
Name string
|
||||||
|
Path string
|
||||||
|
Interface string
|
||||||
|
Member string
|
||||||
|
Label string
|
||||||
|
}
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
Qualifier
|
||||||
|
Path string
|
||||||
|
Access string
|
||||||
|
Target string
|
||||||
|
}
|
||||||
|
|
117
pkg/aa/variables.go
Normal file
117
pkg/aa/variables.go
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
// apparmor.d - Full set of apparmor profiles
|
||||||
|
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
// Warning: this is purposely not using a Yacc parser. Its only aim is to
|
||||||
|
// extract variables and attachments for apparmor.d profile
|
||||||
|
|
||||||
|
package aa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/arduino/go-paths-helper"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
regVariablesDef = regexp.MustCompile(`@{(.*)}\s*[+=]+\s*(.*)`)
|
||||||
|
regVariablesRef = regexp.MustCompile(`@{([^{}]+)}`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Default Apparmor magic directory: /etc/apparmor.d/.
|
||||||
|
var MagicRoot = paths.New("/etc/apparmor.d")
|
||||||
|
|
||||||
|
// DefaultTunables return a minimal working profile to build the profile
|
||||||
|
// It should not be used when loading file from /etc/apparmor.d
|
||||||
|
func DefaultTunables() *AppArmorProfile {
|
||||||
|
return &AppArmorProfile{
|
||||||
|
Preamble: Preamble{
|
||||||
|
Variables: []Variable{
|
||||||
|
{"bin", []string{"/{usr/,}{s,}bin"}},
|
||||||
|
{"lib", []string{"/{usr/,}lib{,exec,32,64}"}},
|
||||||
|
{"multiarch", []string{"*-linux-gnu*"}},
|
||||||
|
{"user_share_dirs", []string{"/home/*/.local/share"}},
|
||||||
|
{"etc_ro", []string{"/{usr/,}etc/"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseVariables extract all variables from the profile
|
||||||
|
func (p *AppArmorProfile) ParseVariables(content string) {
|
||||||
|
matches := regVariablesDef.FindAllStringSubmatch(content, -1)
|
||||||
|
for _, match := range matches {
|
||||||
|
if len(match) > 2 {
|
||||||
|
key := match[1]
|
||||||
|
values := strings.Split(match[2], " ")
|
||||||
|
found := false
|
||||||
|
for idx, variable := range p.Variables {
|
||||||
|
if variable.Name == key {
|
||||||
|
p.Variables[idx].Values = append(p.Variables[idx].Values, values...)
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
variable := Variable{Name: key, Values: values}
|
||||||
|
p.Variables = append(p.Variables, variable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve recursively resolves all variables references
|
||||||
|
func (p *AppArmorProfile) resolve(str string) []string {
|
||||||
|
if strings.Contains(str, "@{") {
|
||||||
|
vars := []string{}
|
||||||
|
match := regVariablesRef.FindStringSubmatch(str)
|
||||||
|
if len(match) > 1 {
|
||||||
|
variable := match[0]
|
||||||
|
varname := match[1]
|
||||||
|
for _, vrbl := range p.Variables {
|
||||||
|
if vrbl.Name == varname {
|
||||||
|
for _, value := range vrbl.Values {
|
||||||
|
newVar := strings.ReplaceAll(str, variable, value)
|
||||||
|
vars = append(vars, p.resolve(newVar)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vars = append(vars, str)
|
||||||
|
}
|
||||||
|
return vars
|
||||||
|
}
|
||||||
|
return []string{str}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveAttachments resolve profile attachments defined in exec_path
|
||||||
|
func (p *AppArmorProfile) ResolveAttachments() {
|
||||||
|
for _, variable := range p.Variables {
|
||||||
|
if variable.Name == "exec_path" {
|
||||||
|
for _, value := range variable.Values {
|
||||||
|
p.Attachments = append(p.Attachments, p.resolve(value)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NestAttachments return a nested attachment string
|
||||||
|
func (p *AppArmorProfile) NestAttachments() string {
|
||||||
|
if len(p.Attachments) == 0 {
|
||||||
|
return ""
|
||||||
|
} else if len(p.Attachments) == 1 {
|
||||||
|
return p.Attachments[0]
|
||||||
|
} else {
|
||||||
|
res := []string{}
|
||||||
|
for _, attachment := range p.Attachments {
|
||||||
|
if strings.HasPrefix(attachment, "/") {
|
||||||
|
res = append(res, attachment[1:])
|
||||||
|
} else {
|
||||||
|
res = append(res, attachment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "/{" + strings.Join(res, ",") + "}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewAppArmorProfile(t *testing.T) {
|
func TestDefaultTunables(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
want *AppArmorProfile
|
want *AppArmorProfile
|
||||||
|
@ -17,20 +17,21 @@ func TestNewAppArmorProfile(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "aa",
|
name: "aa",
|
||||||
want: &AppArmorProfile{
|
want: &AppArmorProfile{
|
||||||
Variables: map[string][]string{
|
Preamble: Preamble{
|
||||||
"bin": {"/{usr/,}{s,}bin"},
|
Variables: []Variable{
|
||||||
"lib": {"/{usr/,}lib{,exec,32,64}"},
|
{"bin", []string{"/{usr/,}{s,}bin"}},
|
||||||
"multiarch": {"*-linux-gnu*"},
|
{"lib", []string{"/{usr/,}lib{,exec,32,64}"}},
|
||||||
"user_share_dirs": {"/home/*/.local/share"},
|
{"multiarch", []string{"*-linux-gnu*"}},
|
||||||
"etc_ro": {"/{usr/,}etc/"},
|
{"user_share_dirs", []string{"/home/*/.local/share"}},
|
||||||
|
{"etc_ro", []string{"/{usr/,}etc/"}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Attachments: []string{},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if got := NewAppArmorProfile(); !reflect.DeepEqual(got, tt.want) {
|
if got := DefaultTunables(); !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("NewAppArmorProfile() = %v, want %v", got, tt.want)
|
t.Errorf("NewAppArmorProfile() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -41,7 +42,7 @@ func TestAppArmorProfile_ParseVariables(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
content string
|
content string
|
||||||
want map[string][]string
|
want []Variable
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "firefox",
|
name: "firefox",
|
||||||
|
@ -51,12 +52,12 @@ func TestAppArmorProfile_ParseVariables(t *testing.T) {
|
||||||
@{firefox_cache_dirs} = @{user_cache_dirs}/mozilla/
|
@{firefox_cache_dirs} = @{user_cache_dirs}/mozilla/
|
||||||
@{exec_path} = /{usr/,}bin/@{firefox_name} @{firefox_lib_dirs}/@{firefox_name}
|
@{exec_path} = /{usr/,}bin/@{firefox_name} @{firefox_lib_dirs}/@{firefox_name}
|
||||||
`,
|
`,
|
||||||
want: map[string][]string{
|
want: []Variable{
|
||||||
"firefox_name": {"firefox{,-esr,-bin}"},
|
{"firefox_name", []string{"firefox{,-esr,-bin}"}},
|
||||||
"firefox_config_dirs": {"@{HOME}/.mozilla/"},
|
{"firefox_lib_dirs", []string{"/{usr/,}lib{,32,64}/@{firefox_name}", "/opt/@{firefox_name}"}},
|
||||||
"firefox_lib_dirs": {"/{usr/,}lib{,32,64}/@{firefox_name}", "/opt/@{firefox_name}"},
|
{"firefox_config_dirs", []string{"@{HOME}/.mozilla/"}},
|
||||||
"firefox_cache_dirs": {"@{user_cache_dirs}/mozilla/"},
|
{"firefox_cache_dirs", []string{"@{user_cache_dirs}/mozilla/"}},
|
||||||
"exec_path": {"/{usr/,}bin/@{firefox_name}", "@{firefox_lib_dirs}/@{firefox_name}"},
|
{"exec_path", []string{"/{usr/,}bin/@{firefox_name}", "@{firefox_lib_dirs}/@{firefox_name}"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -65,23 +66,19 @@ func TestAppArmorProfile_ParseVariables(t *testing.T) {
|
||||||
@{exec_path} += /{usr/,}bin/Xorg{,.bin}
|
@{exec_path} += /{usr/,}bin/Xorg{,.bin}
|
||||||
@{exec_path} += /{usr/,}lib/Xorg{,.wrap}
|
@{exec_path} += /{usr/,}lib/Xorg{,.wrap}
|
||||||
@{exec_path} += /{usr/,}lib/xorg/Xorg{,.wrap}`,
|
@{exec_path} += /{usr/,}lib/xorg/Xorg{,.wrap}`,
|
||||||
want: map[string][]string{
|
want: []Variable{
|
||||||
"exec_path": {
|
{"exec_path", []string{
|
||||||
"/{usr/,}bin/X",
|
"/{usr/,}bin/X",
|
||||||
"/{usr/,}bin/Xorg{,.bin}",
|
"/{usr/,}bin/Xorg{,.bin}",
|
||||||
"/{usr/,}lib/Xorg{,.wrap}",
|
"/{usr/,}lib/Xorg{,.wrap}",
|
||||||
"/{usr/,}lib/xorg/Xorg{,.wrap}",
|
"/{usr/,}lib/xorg/Xorg{,.wrap}"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
p := &AppArmorProfile{
|
p := NewAppArmorProfile()
|
||||||
Variables: map[string][]string{},
|
|
||||||
Attachments: []string{},
|
|
||||||
}
|
|
||||||
|
|
||||||
p.ParseVariables(tt.content)
|
p.ParseVariables(tt.content)
|
||||||
if !reflect.DeepEqual(p.Variables, tt.want) {
|
if !reflect.DeepEqual(p.Variables, tt.want) {
|
||||||
t.Errorf("AppArmorProfile.ParseVariables() = %v, want %v", p.Variables, tt.want)
|
t.Errorf("AppArmorProfile.ParseVariables() = %v, want %v", p.Variables, tt.want)
|
||||||
|
@ -92,24 +89,19 @@ func TestAppArmorProfile_ParseVariables(t *testing.T) {
|
||||||
|
|
||||||
func TestAppArmorProfile_resolve(t *testing.T) {
|
func TestAppArmorProfile_resolve(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
variables map[string][]string
|
input string
|
||||||
input string
|
want []string
|
||||||
want []string
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty",
|
name: "empty",
|
||||||
variables: Tunables,
|
input: "@{}",
|
||||||
input: "@{}",
|
want: []string{"@{}"},
|
||||||
want: []string{"@{}"},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
p := &AppArmorProfile{
|
p := DefaultTunables()
|
||||||
Variables: tt.variables,
|
|
||||||
Attachments: []string{},
|
|
||||||
}
|
|
||||||
if got := p.resolve(tt.input); !reflect.DeepEqual(got, tt.want) {
|
if got := p.resolve(tt.input); !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("AppArmorProfile.resolve() = %v, want %v", got, tt.want)
|
t.Errorf("AppArmorProfile.resolve() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
|
@ -120,15 +112,15 @@ func TestAppArmorProfile_resolve(t *testing.T) {
|
||||||
func TestAppArmorProfile_ResolveAttachments(t *testing.T) {
|
func TestAppArmorProfile_ResolveAttachments(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
variables map[string][]string
|
variables []Variable
|
||||||
want []string
|
want []string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "firefox",
|
name: "firefox",
|
||||||
variables: map[string][]string{
|
variables: []Variable{
|
||||||
"firefox_name": {"firefox{,-esr,-bin}"},
|
{"firefox_name", []string{"firefox{,-esr,-bin}"}},
|
||||||
"firefox_lib_dirs": {"/{usr/,}/lib{,32,64}/@{firefox_name}", "/opt/@{firefox_name}"},
|
{"firefox_lib_dirs", []string{"/{usr/,}/lib{,32,64}/@{firefox_name}", "/opt/@{firefox_name}"}},
|
||||||
"exec_path": {"/{usr/,}bin/@{firefox_name}", "@{firefox_lib_dirs}/@{firefox_name}"},
|
{"exec_path", []string{"/{usr/,}bin/@{firefox_name}", "@{firefox_lib_dirs}/@{firefox_name}"}},
|
||||||
},
|
},
|
||||||
want: []string{
|
want: []string{
|
||||||
"/{usr/,}bin/firefox{,-esr,-bin}",
|
"/{usr/,}bin/firefox{,-esr,-bin}",
|
||||||
|
@ -138,10 +130,10 @@ func TestAppArmorProfile_ResolveAttachments(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "chromium",
|
name: "chromium",
|
||||||
variables: map[string][]string{
|
variables: []Variable{
|
||||||
"chromium_name": {"chromium"},
|
{"chromium_name", []string{"chromium"}},
|
||||||
"chromium_lib_dirs": {"/{usr/,}lib/@{chromium_name}"},
|
{"chromium_lib_dirs", []string{"/{usr/,}lib/@{chromium_name}"}},
|
||||||
"exec_path": {"@{chromium_lib_dirs}/@{chromium_name}"},
|
{"exec_path", []string{"@{chromium_lib_dirs}/@{chromium_name}"}},
|
||||||
},
|
},
|
||||||
want: []string{
|
want: []string{
|
||||||
"/{usr/,}lib/chromium/chromium",
|
"/{usr/,}lib/chromium/chromium",
|
||||||
|
@ -149,9 +141,9 @@ func TestAppArmorProfile_ResolveAttachments(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "geoclue",
|
name: "geoclue",
|
||||||
variables: map[string][]string{
|
variables: []Variable{
|
||||||
"libexec": {"/{usr/,}libexec"},
|
{"libexec", []string{"/{usr/,}libexec"}},
|
||||||
"exec_path": {"@{libexec}/geoclue", "@{libexec}/geoclue-2.0/demos/agent"},
|
{"exec_path", []string{"@{libexec}/geoclue", "@{libexec}/geoclue-2.0/demos/agent"}},
|
||||||
},
|
},
|
||||||
want: []string{
|
want: []string{
|
||||||
"/{usr/,}libexec/geoclue",
|
"/{usr/,}libexec/geoclue",
|
||||||
|
@ -160,11 +152,11 @@ func TestAppArmorProfile_ResolveAttachments(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "opera",
|
name: "opera",
|
||||||
variables: map[string][]string{
|
variables: []Variable{
|
||||||
"multiarch": {"*-linux-gnu*"},
|
{"multiarch", []string{"*-linux-gnu*"}},
|
||||||
"chromium_name": {"opera{,-beta,-developer}"},
|
{"chromium_name", []string{"opera{,-beta,-developer}"}},
|
||||||
"chromium_lib_dirs": {"/{usr/,}lib/@{multiarch}/@{chromium_name}"},
|
{"chromium_lib_dirs", []string{"/{usr/,}lib/@{multiarch}/@{chromium_name}"}},
|
||||||
"exec_path": {"@{chromium_lib_dirs}/@{chromium_name}"},
|
{"exec_path", []string{"@{chromium_lib_dirs}/@{chromium_name}"}},
|
||||||
},
|
},
|
||||||
want: []string{
|
want: []string{
|
||||||
"/{usr/,}lib/*-linux-gnu*/opera{,-beta,-developer}/opera{,-beta,-developer}",
|
"/{usr/,}lib/*-linux-gnu*/opera{,-beta,-developer}/opera{,-beta,-developer}",
|
||||||
|
@ -173,10 +165,8 @@ func TestAppArmorProfile_ResolveAttachments(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
p := &AppArmorProfile{
|
p := NewAppArmorProfile()
|
||||||
Variables: tt.variables,
|
p.Variables = tt.variables
|
||||||
Attachments: []string{},
|
|
||||||
}
|
|
||||||
p.ResolveAttachments()
|
p.ResolveAttachments()
|
||||||
if !reflect.DeepEqual(p.Attachments, tt.want) {
|
if !reflect.DeepEqual(p.Attachments, tt.want) {
|
||||||
t.Errorf("AppArmorProfile.ResolveAttachments() = %v, want %v", p.Attachments, tt.want)
|
t.Errorf("AppArmorProfile.ResolveAttachments() = %v, want %v", p.Attachments, tt.want)
|
||||||
|
@ -226,13 +216,12 @@ func TestAppArmorProfile_NestAttachments(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
p := &AppArmorProfile{
|
p := NewAppArmorProfile()
|
||||||
Variables: map[string][]string{},
|
p.Attachments = tt.Attachments
|
||||||
Attachments: tt.Attachments,
|
|
||||||
}
|
|
||||||
if got := p.NestAttachments(); got != tt.want {
|
if got := p.NestAttachments(); got != tt.want {
|
||||||
t.Errorf("AppArmorProfile.NestAttachments() = %v, want %v", got, tt.want)
|
t.Errorf("AppArmorProfile.NestAttachments() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ func BuildComplain(profile string) string {
|
||||||
|
|
||||||
// Bypass userspace tools restriction
|
// Bypass userspace tools restriction
|
||||||
func BuildUserspace(profile string) string {
|
func BuildUserspace(profile string) string {
|
||||||
p := aa.NewAppArmorProfile()
|
p := aa.DefaultTunables()
|
||||||
p.ParseVariables(profile)
|
p.ParseVariables(profile)
|
||||||
p.ResolveAttachments()
|
p.ResolveAttachments()
|
||||||
att := p.NestAttachments()
|
att := p.NestAttachments()
|
||||||
|
|
Loading…
Reference in a new issue