mirror of
https://github.com/roddhjav/apparmor.d.git
synced 2025-01-18 17:08:09 +01:00
feat(aa): rename the main profile struct.
This commit is contained in:
parent
4b753210e7
commit
890275fb22
11 changed files with 287 additions and 274 deletions
214
pkg/aa/apparmor.go
Normal file
214
pkg/aa/apparmor.go
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"reflect"
|
||||||
|
"slices"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/arduino/go-paths-helper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Default Apparmor magic directory: /etc/apparmor.d/.
|
||||||
|
var MagicRoot = paths.New("/etc/apparmor.d")
|
||||||
|
|
||||||
|
// AppArmorProfileFiles represents a full set of apparmor profiles
|
||||||
|
type AppArmorProfileFiles map[string]*AppArmorProfileFile
|
||||||
|
|
||||||
|
// AppArmorProfileFile represents a full apparmor profile file.
|
||||||
|
// Warning: close to the BNF grammar of apparmor profile but not exactly the same (yet):
|
||||||
|
// - Some rules are not supported yet (subprofile, hat...)
|
||||||
|
// - The structure is simplified as it only aims at writing profile, not parsing it.
|
||||||
|
type AppArmorProfileFile struct {
|
||||||
|
Preamble
|
||||||
|
Profiles []*Profile
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preamble section of a profile file,
|
||||||
|
type Preamble struct {
|
||||||
|
Abi []*Abi
|
||||||
|
Includes []*Include
|
||||||
|
Aliases []*Alias
|
||||||
|
Variables []*Variable
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAppArmorProfile() *AppArmorProfileFile {
|
||||||
|
return &AppArmorProfileFile{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the formatted representation of a profile as a string
|
||||||
|
func (f *AppArmorProfileFile) String() string {
|
||||||
|
var res bytes.Buffer
|
||||||
|
err := tmplAppArmorProfile.Execute(&res, f)
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
return res.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultProfile ensure a profile is always present in the profile file and
|
||||||
|
// return it, as a default profile.
|
||||||
|
func (f *AppArmorProfileFile) GetDefaultProfile() *Profile {
|
||||||
|
if len(f.Profiles) == 0 {
|
||||||
|
f.Profiles = append(f.Profiles, &Profile{})
|
||||||
|
}
|
||||||
|
return f.Profiles[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRule adds a new rule to the profile from a log map
|
||||||
|
// See utils/apparmor/logparser.py for the format of the log map
|
||||||
|
func (f *AppArmorProfileFile) AddRule(log map[string]string) {
|
||||||
|
p := f.GetDefaultProfile()
|
||||||
|
|
||||||
|
// Generate profile flags and extra rules
|
||||||
|
switch log["error"] {
|
||||||
|
case "-2":
|
||||||
|
if !slices.Contains(p.Flags, "mediate_deleted") {
|
||||||
|
p.Flags = append(p.Flags, "mediate_deleted")
|
||||||
|
}
|
||||||
|
case "-13":
|
||||||
|
if strings.Contains(log["info"], "namespace creation restricted") {
|
||||||
|
p.Rules = append(p.Rules, newUsernsFromLog(log))
|
||||||
|
} else if strings.Contains(log["info"], "disconnected path") && !slices.Contains(p.Flags, "attach_disconnected") {
|
||||||
|
p.Flags = append(p.Flags, "attach_disconnected")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
switch log["class"] {
|
||||||
|
case "cap":
|
||||||
|
p.Rules = append(p.Rules, newCapabilityFromLog(log))
|
||||||
|
case "net":
|
||||||
|
if log["family"] == "unix" {
|
||||||
|
p.Rules = append(p.Rules, newUnixFromLog(log))
|
||||||
|
} else {
|
||||||
|
p.Rules = append(p.Rules, newNetworkFromLog(log))
|
||||||
|
}
|
||||||
|
case "mount":
|
||||||
|
if strings.Contains(log["flags"], "remount") {
|
||||||
|
p.Rules = append(p.Rules, newRemountFromLog(log))
|
||||||
|
} else {
|
||||||
|
switch log["operation"] {
|
||||||
|
case "mount":
|
||||||
|
p.Rules = append(p.Rules, newMountFromLog(log))
|
||||||
|
case "umount":
|
||||||
|
p.Rules = append(p.Rules, newUmountFromLog(log))
|
||||||
|
case "remount":
|
||||||
|
p.Rules = append(p.Rules, newRemountFromLog(log))
|
||||||
|
case "pivotroot":
|
||||||
|
p.Rules = append(p.Rules, newPivotRootFromLog(log))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "posix_mqueue", "sysv_mqueue":
|
||||||
|
p.Rules = append(p.Rules, newMqueueFromLog(log))
|
||||||
|
case "signal":
|
||||||
|
p.Rules = append(p.Rules, newSignalFromLog(log))
|
||||||
|
case "ptrace":
|
||||||
|
p.Rules = append(p.Rules, newPtraceFromLog(log))
|
||||||
|
case "namespace":
|
||||||
|
p.Rules = append(p.Rules, newUsernsFromLog(log))
|
||||||
|
case "unix":
|
||||||
|
p.Rules = append(p.Rules, newUnixFromLog(log))
|
||||||
|
case "dbus":
|
||||||
|
p.Rules = append(p.Rules, newDbusFromLog(log))
|
||||||
|
case "file":
|
||||||
|
if log["operation"] == "change_onexec" {
|
||||||
|
p.Rules = append(p.Rules, newChangeProfileFromLog(log))
|
||||||
|
} else {
|
||||||
|
p.Rules = append(p.Rules, newFileFromLog(log))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if strings.Contains(log["operation"], "dbus") {
|
||||||
|
p.Rules = append(p.Rules, newDbusFromLog(log))
|
||||||
|
} else if log["family"] == "unix" {
|
||||||
|
p.Rules = append(p.Rules, newUnixFromLog(log))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort the rules in the profile
|
||||||
|
// Follow: https://apparmor.pujol.io/development/guidelines/#guidelines
|
||||||
|
func (f *AppArmorProfileFile) Sort() {
|
||||||
|
for _, p := range f.Profiles {
|
||||||
|
sort.Slice(p.Rules, func(i, j int) bool {
|
||||||
|
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])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeRules 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 (f *AppArmorProfileFile) MergeRules() {
|
||||||
|
for _, p := range f.Profiles {
|
||||||
|
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--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the profile for better readability before printing it.
|
||||||
|
// Follow: https://apparmor.pujol.io/development/guidelines/#the-file-block
|
||||||
|
func (f *AppArmorProfileFile) Format() {
|
||||||
|
const prefixOwner = " "
|
||||||
|
for _, p := range f.Profiles {
|
||||||
|
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([]ApparmorRule{&Rule{}}, p.Rules[i:]...)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,17 +31,17 @@ func readprofile(path string) string {
|
||||||
func TestAppArmorProfile_String(t *testing.T) {
|
func TestAppArmorProfile_String(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
p *AppArmorProfile
|
f *AppArmorProfileFile
|
||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty",
|
name: "empty",
|
||||||
p: &AppArmorProfile{},
|
f: &AppArmorProfileFile{},
|
||||||
want: ``,
|
want: ``,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "foo",
|
name: "foo",
|
||||||
p: &AppArmorProfile{
|
f: &AppArmorProfileFile{
|
||||||
Preamble: Preamble{
|
Preamble: Preamble{
|
||||||
Abi: []*Abi{{IsMagic: true, Path: "abi/4.0"}},
|
Abi: []*Abi{{IsMagic: true, Path: "abi/4.0"}},
|
||||||
Includes: []*Include{{IsMagic: true, Path: "tunables/global"}},
|
Includes: []*Include{{IsMagic: true, Path: "tunables/global"}},
|
||||||
|
@ -117,7 +117,7 @@ func TestAppArmorProfile_String(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) {
|
||||||
if got := tt.p.String(); got != tt.want {
|
if got := tt.f.String(); got != tt.want {
|
||||||
t.Errorf("AppArmorProfile.String() = |%v|, want |%v|", got, tt.want)
|
t.Errorf("AppArmorProfile.String() = |%v|, want |%v|", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -128,12 +128,12 @@ func TestAppArmorProfile_AddRule(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
log map[string]string
|
log map[string]string
|
||||||
want *AppArmorProfile
|
want *AppArmorProfileFile
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "capability",
|
name: "capability",
|
||||||
log: capability1Log,
|
log: capability1Log,
|
||||||
want: &AppArmorProfile{
|
want: &AppArmorProfileFile{
|
||||||
Profiles: []*Profile{{
|
Profiles: []*Profile{{
|
||||||
Rules: []ApparmorRule{capability1},
|
Rules: []ApparmorRule{capability1},
|
||||||
}},
|
}},
|
||||||
|
@ -142,7 +142,7 @@ func TestAppArmorProfile_AddRule(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "network",
|
name: "network",
|
||||||
log: network1Log,
|
log: network1Log,
|
||||||
want: &AppArmorProfile{
|
want: &AppArmorProfileFile{
|
||||||
Profiles: []*Profile{{
|
Profiles: []*Profile{{
|
||||||
Rules: []ApparmorRule{network1},
|
Rules: []ApparmorRule{network1},
|
||||||
}},
|
}},
|
||||||
|
@ -151,7 +151,7 @@ func TestAppArmorProfile_AddRule(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "mount",
|
name: "mount",
|
||||||
log: mount2Log,
|
log: mount2Log,
|
||||||
want: &AppArmorProfile{
|
want: &AppArmorProfileFile{
|
||||||
Profiles: []*Profile{{
|
Profiles: []*Profile{{
|
||||||
Rules: []ApparmorRule{mount2},
|
Rules: []ApparmorRule{mount2},
|
||||||
}},
|
}},
|
||||||
|
@ -160,7 +160,7 @@ func TestAppArmorProfile_AddRule(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "signal",
|
name: "signal",
|
||||||
log: signal1Log,
|
log: signal1Log,
|
||||||
want: &AppArmorProfile{
|
want: &AppArmorProfileFile{
|
||||||
Profiles: []*Profile{{
|
Profiles: []*Profile{{
|
||||||
Rules: []ApparmorRule{signal1},
|
Rules: []ApparmorRule{signal1},
|
||||||
}},
|
}},
|
||||||
|
@ -169,7 +169,7 @@ func TestAppArmorProfile_AddRule(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "ptrace",
|
name: "ptrace",
|
||||||
log: ptrace2Log,
|
log: ptrace2Log,
|
||||||
want: &AppArmorProfile{
|
want: &AppArmorProfileFile{
|
||||||
Profiles: []*Profile{{
|
Profiles: []*Profile{{
|
||||||
Rules: []ApparmorRule{ptrace2},
|
Rules: []ApparmorRule{ptrace2},
|
||||||
}},
|
}},
|
||||||
|
@ -178,7 +178,7 @@ func TestAppArmorProfile_AddRule(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "unix",
|
name: "unix",
|
||||||
log: unix1Log,
|
log: unix1Log,
|
||||||
want: &AppArmorProfile{
|
want: &AppArmorProfileFile{
|
||||||
Profiles: []*Profile{{
|
Profiles: []*Profile{{
|
||||||
Rules: []ApparmorRule{unix1},
|
Rules: []ApparmorRule{unix1},
|
||||||
}},
|
}},
|
||||||
|
@ -187,7 +187,7 @@ func TestAppArmorProfile_AddRule(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "dbus",
|
name: "dbus",
|
||||||
log: dbus2Log,
|
log: dbus2Log,
|
||||||
want: &AppArmorProfile{
|
want: &AppArmorProfileFile{
|
||||||
Profiles: []*Profile{{
|
Profiles: []*Profile{{
|
||||||
Rules: []ApparmorRule{dbus2},
|
Rules: []ApparmorRule{dbus2},
|
||||||
}},
|
}},
|
||||||
|
@ -196,7 +196,7 @@ func TestAppArmorProfile_AddRule(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "file",
|
name: "file",
|
||||||
log: file2Log,
|
log: file2Log,
|
||||||
want: &AppArmorProfile{
|
want: &AppArmorProfileFile{
|
||||||
Profiles: []*Profile{{
|
Profiles: []*Profile{{
|
||||||
Rules: []ApparmorRule{file2},
|
Rules: []ApparmorRule{file2},
|
||||||
}},
|
}},
|
||||||
|
@ -217,12 +217,12 @@ func TestAppArmorProfile_AddRule(t *testing.T) {
|
||||||
func TestAppArmorProfile_Sort(t *testing.T) {
|
func TestAppArmorProfile_Sort(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
origin *AppArmorProfile
|
origin *AppArmorProfileFile
|
||||||
want *AppArmorProfile
|
want *AppArmorProfileFile
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "all",
|
name: "all",
|
||||||
origin: &AppArmorProfile{
|
origin: &AppArmorProfileFile{
|
||||||
Profiles: []*Profile{{
|
Profiles: []*Profile{{
|
||||||
Rules: []ApparmorRule{
|
Rules: []ApparmorRule{
|
||||||
file2, network1, includeLocal1, dbus2, signal1, ptrace1,
|
file2, network1, includeLocal1, dbus2, signal1, ptrace1,
|
||||||
|
@ -230,7 +230,7 @@ func TestAppArmorProfile_Sort(t *testing.T) {
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
want: &AppArmorProfile{
|
want: &AppArmorProfileFile{
|
||||||
Profiles: []*Profile{{
|
Profiles: []*Profile{{
|
||||||
Rules: []ApparmorRule{
|
Rules: []ApparmorRule{
|
||||||
capability2, network1, mount2, signal1, signal2, ptrace1,
|
capability2, network1, mount2, signal1, signal2, ptrace1,
|
||||||
|
@ -254,17 +254,17 @@ func TestAppArmorProfile_Sort(t *testing.T) {
|
||||||
func TestAppArmorProfile_MergeRules(t *testing.T) {
|
func TestAppArmorProfile_MergeRules(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
origin *AppArmorProfile
|
origin *AppArmorProfileFile
|
||||||
want *AppArmorProfile
|
want *AppArmorProfileFile
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "all",
|
name: "all",
|
||||||
origin: &AppArmorProfile{
|
origin: &AppArmorProfileFile{
|
||||||
Profiles: []*Profile{{
|
Profiles: []*Profile{{
|
||||||
Rules: []ApparmorRule{capability1, capability1, network1, network1, file1, file1},
|
Rules: []ApparmorRule{capability1, capability1, network1, network1, file1, file1},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
want: &AppArmorProfile{
|
want: &AppArmorProfileFile{
|
||||||
Profiles: []*Profile{{
|
Profiles: []*Profile{{
|
||||||
Rules: []ApparmorRule{capability1, network1, file1},
|
Rules: []ApparmorRule{capability1, network1, file1},
|
||||||
}},
|
}},
|
||||||
|
@ -285,12 +285,12 @@ func TestAppArmorProfile_MergeRules(t *testing.T) {
|
||||||
func TestAppArmorProfile_Integration(t *testing.T) {
|
func TestAppArmorProfile_Integration(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
p *AppArmorProfile
|
f *AppArmorProfileFile
|
||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "aa-status",
|
name: "aa-status",
|
||||||
p: &AppArmorProfile{
|
f: &AppArmorProfileFile{
|
||||||
Preamble: Preamble{
|
Preamble: Preamble{
|
||||||
Abi: []*Abi{{IsMagic: true, Path: "abi/3.0"}},
|
Abi: []*Abi{{IsMagic: true, Path: "abi/3.0"}},
|
||||||
Includes: []*Include{{IsMagic: true, Path: "tunables/global"}},
|
Includes: []*Include{{IsMagic: true, Path: "tunables/global"}},
|
||||||
|
@ -327,10 +327,10 @@ func TestAppArmorProfile_Integration(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) {
|
||||||
tt.p.Sort()
|
tt.f.Sort()
|
||||||
tt.p.MergeRules()
|
tt.f.MergeRules()
|
||||||
tt.p.Format()
|
tt.f.Format()
|
||||||
if got := tt.p.String(); "\n"+got != tt.want {
|
if got := tt.f.String(); "\n"+got != tt.want {
|
||||||
t.Errorf("AppArmorProfile = |%v|, want |%v|", "\n"+got, tt.want)
|
t.Errorf("AppArmorProfile = |%v|, want |%v|", "\n"+got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
|
@ -5,46 +5,19 @@
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"maps"
|
"maps"
|
||||||
"reflect"
|
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/arduino/go-paths-helper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default Apparmor magic directory: /etc/apparmor.d/.
|
// Profile represents a single AppArmor profile.
|
||||||
var MagicRoot = paths.New("/etc/apparmor.d")
|
|
||||||
|
|
||||||
// AppArmorProfiles represents a full set of apparmor profiles
|
|
||||||
type AppArmorProfiles map[string]*AppArmorProfile
|
|
||||||
|
|
||||||
// ApparmorProfile represents a full apparmor profile file.
|
|
||||||
// Warning: close to the BNF grammar of apparmor profile but not exactly the same (yet):
|
|
||||||
// - Some rules are not supported yet (subprofile, hat...)
|
|
||||||
// - The structure is simplified as it only aims at writing profile, not parsing it.
|
|
||||||
type AppArmorProfile struct {
|
|
||||||
Preamble
|
|
||||||
Profiles []*Profile
|
|
||||||
}
|
|
||||||
|
|
||||||
// Preamble section of a profile file,
|
|
||||||
type Preamble struct {
|
|
||||||
Abi []*Abi
|
|
||||||
Includes []*Include
|
|
||||||
Aliases []*Alias
|
|
||||||
Variables []*Variable
|
|
||||||
}
|
|
||||||
|
|
||||||
// Profile represent a single AppArmor profile.
|
|
||||||
type Profile struct {
|
type Profile struct {
|
||||||
Rule
|
Rule
|
||||||
Header
|
Header
|
||||||
Rules Rules
|
Rules Rules
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Header represents the header of a profile.
|
||||||
type Header struct {
|
type Header struct {
|
||||||
Name string
|
Name string
|
||||||
Attachments []string
|
Attachments []string
|
||||||
|
@ -53,7 +26,11 @@ type Header struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Profile) Less(other any) bool {
|
func (r *Profile) Less(other any) bool {
|
||||||
return false // TBD
|
o, _ := other.(*Profile)
|
||||||
|
if r.Name != o.Name {
|
||||||
|
return r.Name < o.Name
|
||||||
|
}
|
||||||
|
return len(r.Attachments) < len(o.Attachments)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Profile) Equals(other any) bool {
|
func (r *Profile) Equals(other any) bool {
|
||||||
|
@ -62,187 +39,3 @@ func (r *Profile) Equals(other any) bool {
|
||||||
maps.Equal(r.Attributes, o.Attributes) &&
|
maps.Equal(r.Attributes, o.Attributes) &&
|
||||||
slices.Equal(r.Flags, o.Flags)
|
slices.Equal(r.Flags, o.Flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApparmorRule generic interface
|
|
||||||
type ApparmorRule interface {
|
|
||||||
Less(other any) bool
|
|
||||||
Equals(other any) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type Rules []ApparmorRule
|
|
||||||
|
|
||||||
func NewAppArmorProfile() *AppArmorProfile {
|
|
||||||
return &AppArmorProfile{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the formatted representation of a profile as a string
|
|
||||||
func (p *AppArmorProfile) String() string {
|
|
||||||
var res bytes.Buffer
|
|
||||||
err := tmplAppArmorProfile.Execute(&res, p)
|
|
||||||
if err != nil {
|
|
||||||
return err.Error()
|
|
||||||
}
|
|
||||||
return res.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDefaultProfile ensure a profile is always present in the profile file and
|
|
||||||
// return it, as a default profile.
|
|
||||||
func (p *AppArmorProfile) GetDefaultProfile() *Profile {
|
|
||||||
if len(p.Profiles) == 0 {
|
|
||||||
p.Profiles = append(p.Profiles, &Profile{})
|
|
||||||
}
|
|
||||||
return p.Profiles[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddRule adds a new rule to the profile from a log map
|
|
||||||
// See utils/apparmor/logparser.py for the format of the log map
|
|
||||||
func (profile *AppArmorProfile) AddRule(log map[string]string) {
|
|
||||||
p := profile.GetDefaultProfile()
|
|
||||||
|
|
||||||
// Generate profile flags and extra rules
|
|
||||||
switch log["error"] {
|
|
||||||
case "-2":
|
|
||||||
if !slices.Contains(p.Flags, "mediate_deleted") {
|
|
||||||
p.Flags = append(p.Flags, "mediate_deleted")
|
|
||||||
}
|
|
||||||
case "-13":
|
|
||||||
if strings.Contains(log["info"], "namespace creation restricted") {
|
|
||||||
p.Rules = append(p.Rules, newUsernsFromLog(log))
|
|
||||||
} else if strings.Contains(log["info"], "disconnected path") && !slices.Contains(p.Flags, "attach_disconnected") {
|
|
||||||
p.Flags = append(p.Flags, "attach_disconnected")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
switch log["class"] {
|
|
||||||
case "cap":
|
|
||||||
p.Rules = append(p.Rules, newCapabilityFromLog(log))
|
|
||||||
case "net":
|
|
||||||
if log["family"] == "unix" {
|
|
||||||
p.Rules = append(p.Rules, newUnixFromLog(log))
|
|
||||||
} else {
|
|
||||||
p.Rules = append(p.Rules, newNetworkFromLog(log))
|
|
||||||
}
|
|
||||||
case "mount":
|
|
||||||
if strings.Contains(log["flags"], "remount") {
|
|
||||||
p.Rules = append(p.Rules, newRemountFromLog(log))
|
|
||||||
} else {
|
|
||||||
switch log["operation"] {
|
|
||||||
case "mount":
|
|
||||||
p.Rules = append(p.Rules, newMountFromLog(log))
|
|
||||||
case "umount":
|
|
||||||
p.Rules = append(p.Rules, newUmountFromLog(log))
|
|
||||||
case "remount":
|
|
||||||
p.Rules = append(p.Rules, newRemountFromLog(log))
|
|
||||||
case "pivotroot":
|
|
||||||
p.Rules = append(p.Rules, newPivotRootFromLog(log))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "posix_mqueue", "sysv_mqueue":
|
|
||||||
p.Rules = append(p.Rules, newMqueueFromLog(log))
|
|
||||||
case "signal":
|
|
||||||
p.Rules = append(p.Rules, newSignalFromLog(log))
|
|
||||||
case "ptrace":
|
|
||||||
p.Rules = append(p.Rules, newPtraceFromLog(log))
|
|
||||||
case "namespace":
|
|
||||||
p.Rules = append(p.Rules, newUsernsFromLog(log))
|
|
||||||
case "unix":
|
|
||||||
p.Rules = append(p.Rules, newUnixFromLog(log))
|
|
||||||
case "dbus":
|
|
||||||
p.Rules = append(p.Rules, newDbusFromLog(log))
|
|
||||||
case "file":
|
|
||||||
if log["operation"] == "change_onexec" {
|
|
||||||
p.Rules = append(p.Rules, newChangeProfileFromLog(log))
|
|
||||||
} else {
|
|
||||||
p.Rules = append(p.Rules, newFileFromLog(log))
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if strings.Contains(log["operation"], "dbus") {
|
|
||||||
p.Rules = append(p.Rules, newDbusFromLog(log))
|
|
||||||
} else if log["family"] == "unix" {
|
|
||||||
p.Rules = append(p.Rules, newUnixFromLog(log))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort the rules in the profile
|
|
||||||
// Follow: https://apparmor.pujol.io/development/guidelines/#guidelines
|
|
||||||
func (profile *AppArmorProfile) Sort() {
|
|
||||||
for _, p := range profile.Profiles {
|
|
||||||
sort.Slice(p.Rules, func(i, j int) bool {
|
|
||||||
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])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MergeRules 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 (profile *AppArmorProfile) MergeRules() {
|
|
||||||
for _, p := range profile.Profiles {
|
|
||||||
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--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format the profile for better readability before printing it.
|
|
||||||
// Follow: https://apparmor.pujol.io/development/guidelines/#the-file-block
|
|
||||||
func (profile *AppArmorProfile) Format() {
|
|
||||||
const prefixOwner = " "
|
|
||||||
for _, p := range profile.Profiles {
|
|
||||||
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([]ApparmorRule{&Rule{}}, p.Rules[i:]...)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,6 +9,14 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ApparmorRule generic interface
|
||||||
|
type ApparmorRule interface {
|
||||||
|
Less(other any) bool
|
||||||
|
Equals(other any) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Rules []ApparmorRule
|
||||||
|
|
||||||
type Rule struct {
|
type Rule struct {
|
||||||
Comment string
|
Comment string
|
||||||
NoNewPrivs bool
|
NoNewPrivs bool
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
{{- define "profile" -}}
|
{{- define "profile" -}}
|
||||||
|
|
||||||
{{- if or .Name .Attachments .Attributes .Flags -}}
|
{{- with .Header -}}
|
||||||
{{- "profile" -}}
|
{{- "profile" -}}
|
||||||
{{- with .Name -}}
|
{{- with .Name -}}
|
||||||
{{ " " }}{{ . }}
|
{{ " " }}{{ . }}
|
||||||
|
@ -18,9 +18,7 @@
|
||||||
{{- with .Flags -}}
|
{{- with .Flags -}}
|
||||||
{{ " flags=(" }}{{ join . }}{{ ")" }}
|
{{ " flags=(" }}{{ join . }}{{ ")" }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{ " {" }}
|
{{- "{\n" -}}
|
||||||
{{- template "comment" . -}}
|
|
||||||
{{- "\n" -}}
|
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- $oldtype := "" -}}
|
{{- $oldtype := "" -}}
|
||||||
|
@ -296,7 +294,7 @@
|
||||||
{{- $oldtype = $type -}}
|
{{- $oldtype = $type -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if or .Name .Attachments .Attributes .Flags -}}
|
{{- with .Header -}}
|
||||||
{{- "}\n" -}}
|
{{- "}\n" -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,8 @@ var (
|
||||||
|
|
||||||
// DefaultTunables return a minimal working profile to build the profile
|
// DefaultTunables return a minimal working profile to build the profile
|
||||||
// It should not be used when loading file from /etc/apparmor.d
|
// It should not be used when loading file from /etc/apparmor.d
|
||||||
func DefaultTunables() *AppArmorProfile {
|
func DefaultTunables() *AppArmorProfileFile {
|
||||||
return &AppArmorProfile{
|
return &AppArmorProfileFile{
|
||||||
Preamble: Preamble{
|
Preamble: Preamble{
|
||||||
Variables: []*Variable{
|
Variables: []*Variable{
|
||||||
{Name: "bin", Values: []string{"/{,usr/}{,s}bin"}},
|
{Name: "bin", Values: []string{"/{,usr/}{,s}bin"}},
|
||||||
|
@ -36,41 +36,41 @@ func DefaultTunables() *AppArmorProfile {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseVariables extract all variables from the profile
|
// ParseVariables extract all variables from the profile
|
||||||
func (p *AppArmorProfile) ParseVariables(content string) {
|
func (f *AppArmorProfileFile) ParseVariables(content string) {
|
||||||
matches := regVariablesDef.FindAllStringSubmatch(content, -1)
|
matches := regVariablesDef.FindAllStringSubmatch(content, -1)
|
||||||
for _, match := range matches {
|
for _, match := range matches {
|
||||||
if len(match) > 2 {
|
if len(match) > 2 {
|
||||||
key := match[1]
|
key := match[1]
|
||||||
values := strings.Split(match[2], " ")
|
values := strings.Split(match[2], " ")
|
||||||
found := false
|
found := false
|
||||||
for idx, variable := range p.Variables {
|
for idx, variable := range f.Variables {
|
||||||
if variable.Name == key {
|
if variable.Name == key {
|
||||||
p.Variables[idx].Values = append(p.Variables[idx].Values, values...)
|
f.Variables[idx].Values = append(f.Variables[idx].Values, values...)
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
variable := &Variable{Name: key, Values: values}
|
variable := &Variable{Name: key, Values: values}
|
||||||
p.Variables = append(p.Variables, variable)
|
f.Variables = append(f.Variables, variable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve recursively resolves all variables references
|
// resolve recursively resolves all variables references
|
||||||
func (p *AppArmorProfile) resolve(str string) []string {
|
func (f *AppArmorProfileFile) resolve(str string) []string {
|
||||||
if strings.Contains(str, "@{") {
|
if strings.Contains(str, "@{") {
|
||||||
vars := []string{}
|
vars := []string{}
|
||||||
match := regVariablesRef.FindStringSubmatch(str)
|
match := regVariablesRef.FindStringSubmatch(str)
|
||||||
if len(match) > 1 {
|
if len(match) > 1 {
|
||||||
variable := match[0]
|
variable := match[0]
|
||||||
varname := match[1]
|
varname := match[1]
|
||||||
for _, vrbl := range p.Variables {
|
for _, vrbl := range f.Variables {
|
||||||
if vrbl.Name == varname {
|
if vrbl.Name == varname {
|
||||||
for _, value := range vrbl.Values {
|
for _, value := range vrbl.Values {
|
||||||
newVar := strings.ReplaceAll(str, variable, value)
|
newVar := strings.ReplaceAll(str, variable, value)
|
||||||
vars = append(vars, p.resolve(newVar)...)
|
vars = append(vars, f.resolve(newVar)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,8 +83,8 @@ func (p *AppArmorProfile) resolve(str string) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResolveAttachments resolve profile attachments defined in exec_path
|
// ResolveAttachments resolve profile attachments defined in exec_path
|
||||||
func (profile *AppArmorProfile) ResolveAttachments() {
|
func (f *AppArmorProfileFile) ResolveAttachments() {
|
||||||
p := profile.GetDefaultProfile()
|
p := f.GetDefaultProfile()
|
||||||
|
|
||||||
for _, variable := range profile.Variables {
|
for _, variable := range profile.Variables {
|
||||||
if variable.Name == "exec_path" {
|
if variable.Name == "exec_path" {
|
||||||
|
@ -100,8 +100,8 @@ func (profile *AppArmorProfile) ResolveAttachments() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NestAttachments return a nested attachment string
|
// NestAttachments return a nested attachment string
|
||||||
func (profile *AppArmorProfile) NestAttachments() string {
|
func (f *AppArmorProfileFile) NestAttachments() string {
|
||||||
p := profile.GetDefaultProfile()
|
p := f.GetDefaultProfile()
|
||||||
if len(p.Attachments) == 0 {
|
if len(p.Attachments) == 0 {
|
||||||
return ""
|
return ""
|
||||||
} else if len(p.Attachments) == 1 {
|
} else if len(p.Attachments) == 1 {
|
||||||
|
|
|
@ -16,11 +16,11 @@ import (
|
||||||
func TestDefaultTunables(t *testing.T) {
|
func TestDefaultTunables(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
want *AppArmorProfile
|
want *AppArmorProfileFile
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "aa",
|
name: "aa",
|
||||||
want: &AppArmorProfile{
|
want: &AppArmorProfileFile{
|
||||||
Preamble: Preamble{
|
Preamble: Preamble{
|
||||||
Variables: []*Variable{
|
Variables: []*Variable{
|
||||||
{Name: "bin", Values: []string{"/{,usr/}{,s}bin"}},
|
{Name: "bin", Values: []string{"/{,usr/}{,s}bin"}},
|
||||||
|
|
|
@ -197,8 +197,8 @@ func (aaLogs AppArmorLogs) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseToProfiles convert the log data into a new AppArmorProfiles
|
// ParseToProfiles convert the log data into a new AppArmorProfiles
|
||||||
func (aaLogs AppArmorLogs) ParseToProfiles() aa.AppArmorProfiles {
|
func (aaLogs AppArmorLogs) ParseToProfiles() aa.AppArmorProfileFiles {
|
||||||
profiles := make(aa.AppArmorProfiles, 0)
|
profiles := make(aa.AppArmorProfileFiles, 0)
|
||||||
for _, log := range aaLogs {
|
for _, log := range aaLogs {
|
||||||
name := ""
|
name := ""
|
||||||
if strings.Contains(log["operation"], "dbus") {
|
if strings.Contains(log["operation"], "dbus") {
|
||||||
|
@ -208,7 +208,7 @@ func (aaLogs AppArmorLogs) ParseToProfiles() aa.AppArmorProfiles {
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := profiles[name]; !ok {
|
if _, ok := profiles[name]; !ok {
|
||||||
profile := &aa.AppArmorProfile{
|
profile := &aa.AppArmorProfileFile{
|
||||||
Profiles: []*aa.Profile{{Header: aa.Header{Name: name}}},
|
Profiles: []*aa.Profile{{Header: aa.Header{Name: name}}},
|
||||||
}
|
}
|
||||||
profile.AddRule(log)
|
profile.AddRule(log)
|
||||||
|
|
|
@ -292,13 +292,13 @@ func TestAppArmorLogs_ParseToProfiles(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
aaLogs AppArmorLogs
|
aaLogs AppArmorLogs
|
||||||
want aa.AppArmorProfiles
|
want aa.AppArmorProfileFiles
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "",
|
name: "",
|
||||||
aaLogs: append(append(refKmod, refPowerProfiles...), refKmod...),
|
aaLogs: append(append(refKmod, refPowerProfiles...), refKmod...),
|
||||||
want: aa.AppArmorProfiles{
|
want: aa.AppArmorProfileFiles{
|
||||||
"kmod": &aa.AppArmorProfile{
|
"kmod": &aa.AppArmorProfileFile{
|
||||||
Profiles: []*aa.Profile{{
|
Profiles: []*aa.Profile{{
|
||||||
Header: aa.Header{Name: "kmod"},
|
Header: aa.Header{Name: "kmod"},
|
||||||
Rules: aa.Rules{
|
Rules: aa.Rules{
|
||||||
|
@ -317,7 +317,7 @@ func TestAppArmorLogs_ParseToProfiles(t *testing.T) {
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
"power-profiles-daemon": &aa.AppArmorProfile{
|
"power-profiles-daemon": &aa.AppArmorProfileFile{
|
||||||
Profiles: []*aa.Profile{{
|
Profiles: []*aa.Profile{{
|
||||||
Header: aa.Header{Name: "power-profiles-daemon"},
|
Header: aa.Header{Name: "power-profiles-daemon"},
|
||||||
Rules: aa.Rules{
|
Rules: aa.Rules{
|
||||||
|
|
|
@ -51,7 +51,7 @@ func setInterfaces(rules map[string]string) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d Dbus) Apply(opt *Option, profile string) string {
|
func (d Dbus) Apply(opt *Option, profile string) string {
|
||||||
var p *aa.AppArmorProfile
|
var p *aa.AppArmorProfileFile
|
||||||
|
|
||||||
action := d.sanityCheck(opt)
|
action := d.sanityCheck(opt)
|
||||||
switch action {
|
switch action {
|
||||||
|
@ -95,9 +95,9 @@ func (d Dbus) sanityCheck(opt *Option) string {
|
||||||
return action
|
return action
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d Dbus) own(rules map[string]string) *aa.AppArmorProfile {
|
func (d Dbus) own(rules map[string]string) *aa.AppArmorProfileFile {
|
||||||
interfaces := setInterfaces(rules)
|
interfaces := setInterfaces(rules)
|
||||||
profile := &aa.AppArmorProfile{}
|
profile := &aa.AppArmorProfileFile{}
|
||||||
p := profile.GetDefaultProfile()
|
p := profile.GetDefaultProfile()
|
||||||
p.Rules = append(p.Rules, &aa.Dbus{
|
p.Rules = append(p.Rules, &aa.Dbus{
|
||||||
Access: "bind", Bus: rules["bus"], Name: rules["name"],
|
Access: "bind", Bus: rules["bus"], Name: rules["name"],
|
||||||
|
@ -131,9 +131,9 @@ func (d Dbus) own(rules map[string]string) *aa.AppArmorProfile {
|
||||||
return profile
|
return profile
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d Dbus) talk(rules map[string]string) *aa.AppArmorProfile {
|
func (d Dbus) talk(rules map[string]string) *aa.AppArmorProfileFile {
|
||||||
interfaces := setInterfaces(rules)
|
interfaces := setInterfaces(rules)
|
||||||
profile := &aa.AppArmorProfile{}
|
profile := &aa.AppArmorProfileFile{}
|
||||||
p := profile.GetDefaultProfile()
|
p := profile.GetDefaultProfile()
|
||||||
for _, iface := range interfaces {
|
for _, iface := range interfaces {
|
||||||
p.Rules = append(p.Rules, &aa.Dbus{
|
p.Rules = append(p.Rules, &aa.Dbus{
|
||||||
|
|
|
@ -36,7 +36,7 @@ func (d Exec) Apply(opt *Option, profileRaw string) string {
|
||||||
delete(opt.ArgMap, t)
|
delete(opt.ArgMap, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
profile := &aa.AppArmorProfile{}
|
profile := &aa.AppArmorProfileFile{}
|
||||||
p := profile.GetDefaultProfile()
|
p := profile.GetDefaultProfile()
|
||||||
for name := range opt.ArgMap {
|
for name := range opt.ArgMap {
|
||||||
profiletoTransition := util.MustReadFile(cfg.RootApparmord.Join(name))
|
profiletoTransition := util.MustReadFile(cfg.RootApparmord.Join(name))
|
||||||
|
|
Loading…
Reference in a new issue