feat(aa): add a string method to all rule struct.
This commit is contained in:
parent
e9fa0660f8
commit
5483668574
20 changed files with 337 additions and 34 deletions
|
|
@ -42,14 +42,9 @@ func NewAppArmorProfile() *AppArmorProfileFile {
|
||||||
return &AppArmorProfileFile{}
|
return &AppArmorProfileFile{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the formatted representation of a profile as a string
|
// String returns the formatted representation of a profile file as a string
|
||||||
func (f *AppArmorProfileFile) String() string {
|
func (f *AppArmorProfileFile) String() string {
|
||||||
var res bytes.Buffer
|
return renderTemplate("apparmor", f)
|
||||||
err := tmpl["apparmor"].Execute(&res, f)
|
|
||||||
if err != nil {
|
|
||||||
return err.Error()
|
|
||||||
}
|
|
||||||
return res.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDefaultProfile ensure a profile is always present in the profile file and
|
// GetDefaultProfile ensure a profile is always present in the profile file and
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
|
|
||||||
|
const tokCAPABILITY = "capability"
|
||||||
|
|
||||||
type Capability struct {
|
type Capability struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
Qualifier
|
Qualifier
|
||||||
|
|
@ -36,4 +38,6 @@ func (r *Capability) Equals(other any) bool {
|
||||||
return slices.Equal(r.Names, o.Names) && r.Qualifier.Equals(o.Qualifier)
|
return slices.Equal(r.Names, o.Names) && r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Capability) String() string {
|
||||||
|
return renderTemplate(tokCAPABILITY, r)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
|
const tokCHANGEPROFILE = "change_profile"
|
||||||
|
|
||||||
type ChangeProfile struct {
|
type ChangeProfile struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
Qualifier
|
Qualifier
|
||||||
|
|
@ -41,3 +43,7 @@ func (r *ChangeProfile) Equals(other any) bool {
|
||||||
return r.ExecMode == o.ExecMode && r.Exec == o.Exec &&
|
return r.ExecMode == o.ExecMode && r.Exec == o.Exec &&
|
||||||
r.ProfileName == o.ProfileName && r.Qualifier.Equals(o.Qualifier)
|
r.ProfileName == o.ProfileName && r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ChangeProfile) String() string {
|
||||||
|
return renderTemplate(tokCHANGEPROFILE, r)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
|
const tokDBUS = "dbus"
|
||||||
|
|
||||||
type Dbus struct {
|
type Dbus struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
Qualifier
|
Qualifier
|
||||||
|
|
@ -77,3 +79,7 @@ func (r *Dbus) Equals(other any) bool {
|
||||||
r.Member == o.Member && r.PeerName == o.PeerName &&
|
r.Member == o.Member && r.PeerName == o.PeerName &&
|
||||||
r.PeerLabel == o.PeerLabel && r.Qualifier.Equals(o.Qualifier)
|
r.PeerLabel == o.PeerLabel && r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Dbus) String() string {
|
||||||
|
return renderTemplate(tokDBUS, r)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,5 +59,9 @@ func (r *File) Equals(other any) bool {
|
||||||
r.Target == o.Target && r.Qualifier.Equals(o.Qualifier)
|
r.Target == o.Target && r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *File) String() string {
|
||||||
|
return renderTemplate("file", r)
|
||||||
|
}
|
||||||
|
|
||||||
r.Target == o.Target && r.Qualifier.Equals(o.Qualifier)
|
r.Target == o.Target && r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@
|
||||||
|
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
|
const tokIOURING = "io_uring"
|
||||||
|
|
||||||
|
|
||||||
type IOUring struct {
|
type IOUring struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
Qualifier
|
Qualifier
|
||||||
|
|
@ -36,4 +39,6 @@ func (r *IOUring) Equals(other any) bool {
|
||||||
return slices.Equal(r.Access, o.Access) && r.Label == o.Label && r.Qualifier.Equals(o.Qualifier)
|
return slices.Equal(r.Access, o.Access) && r.Label == o.Label && r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *IOUring) String() string {
|
||||||
|
return renderTemplate(tokIOURING, r)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,13 @@ import (
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
tokMOUNT = "mount"
|
||||||
|
tokREMOUNT = "remount"
|
||||||
|
tokUMOUNT = "umount"
|
||||||
|
)
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type MountConditions struct {
|
type MountConditions struct {
|
||||||
|
|
@ -75,6 +82,10 @@ func (r *Mount) Equals(other any) bool {
|
||||||
r.Qualifier.Equals(o.Qualifier)
|
r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Mount) String() string {
|
||||||
|
return renderTemplate(tokMOUNT, r)
|
||||||
|
}
|
||||||
|
|
||||||
type Umount struct {
|
type Umount struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
Qualifier
|
Qualifier
|
||||||
|
|
@ -109,6 +120,10 @@ func (r *Umount) Equals(other any) bool {
|
||||||
r.Qualifier.Equals(o.Qualifier)
|
r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Umount) String() string {
|
||||||
|
return renderTemplate(tokUMOUNT, r)
|
||||||
|
}
|
||||||
|
|
||||||
type Remount struct {
|
type Remount struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
Qualifier
|
Qualifier
|
||||||
|
|
@ -142,3 +157,7 @@ func (r *Remount) Equals(other any) bool {
|
||||||
r.MountConditions.Equals(o.MountConditions) &&
|
r.MountConditions.Equals(o.MountConditions) &&
|
||||||
r.Qualifier.Equals(o.Qualifier)
|
r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Remount) String() string {
|
||||||
|
return renderTemplate(tokREMOUNT, r)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const tokMQUEUE = "mqueue"
|
||||||
|
|
||||||
|
|
||||||
type Mqueue struct {
|
type Mqueue struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
Qualifier
|
Qualifier
|
||||||
|
|
@ -53,3 +56,7 @@ func (r *Mqueue) Equals(other any) bool {
|
||||||
return slices.Equal(r.Access, o.Access) && r.Type == o.Type && r.Label == o.Label &&
|
return slices.Equal(r.Access, o.Access) && r.Type == o.Type && r.Label == o.Label &&
|
||||||
r.Name == o.Name && r.Qualifier.Equals(o.Qualifier)
|
r.Name == o.Name && r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Mqueue) String() string {
|
||||||
|
return renderTemplate(tokMQUEUE, r)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@
|
||||||
|
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
|
const tokNETWORK = "network"
|
||||||
|
|
||||||
|
|
||||||
type AddressExpr struct {
|
type AddressExpr struct {
|
||||||
Source string
|
Source string
|
||||||
Destination string
|
Destination string
|
||||||
|
|
@ -76,3 +79,7 @@ func (r *Network) Equals(other any) bool {
|
||||||
r.Protocol == o.Protocol && r.AddressExpr.Equals(o.AddressExpr) &&
|
r.Protocol == o.Protocol && r.AddressExpr.Equals(o.AddressExpr) &&
|
||||||
r.Qualifier.Equals(o.Qualifier)
|
r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Network) String() string {
|
||||||
|
return renderTemplate(tokNETWORK, r)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
|
const tokPIVOTROOT = "pivot_root"
|
||||||
|
|
||||||
type PivotRoot struct {
|
type PivotRoot struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
Qualifier
|
Qualifier
|
||||||
|
|
@ -42,3 +44,7 @@ func (r *PivotRoot) Equals(other any) bool {
|
||||||
r.TargetProfile == o.TargetProfile &&
|
r.TargetProfile == o.TargetProfile &&
|
||||||
r.Qualifier.Equals(o.Qualifier)
|
r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *PivotRoot) String() string {
|
||||||
|
return renderTemplate(tokPIVOTROOT, r)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,12 @@ package aa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
|
const (
|
||||||
|
tokABI = "abi"
|
||||||
|
tokALIAS = "alias"
|
||||||
|
tokINCLUDE = "include"
|
||||||
|
tokIFEXISTS = "if exists"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Abi struct {
|
type Abi struct {
|
||||||
|
|
@ -27,6 +33,10 @@ func (r *Abi) Equals(other any) bool {
|
||||||
return r.Path == o.Path && r.IsMagic == o.IsMagic
|
return r.Path == o.Path && r.IsMagic == o.IsMagic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Abi) String() string {
|
||||||
|
return renderTemplate(tokABI, r)
|
||||||
|
}
|
||||||
|
|
||||||
type Alias struct {
|
type Alias struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
Path string
|
Path string
|
||||||
|
|
@ -46,6 +56,10 @@ func (r Alias) Equals(other any) bool {
|
||||||
return r.Path == o.Path && r.RewrittenPath == o.RewrittenPath
|
return r.Path == o.Path && r.RewrittenPath == o.RewrittenPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Alias) String() string {
|
||||||
|
return renderTemplate(tokALIAS, r)
|
||||||
|
}
|
||||||
|
|
||||||
type Include struct {
|
type Include struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
IfExists bool
|
IfExists bool
|
||||||
|
|
@ -69,6 +83,10 @@ func (r *Include) Equals(other any) bool {
|
||||||
return r.Path == o.Path && r.IsMagic == o.IsMagic && r.IfExists == o.IfExists
|
return r.Path == o.Path && r.IsMagic == o.IsMagic && r.IfExists == o.IfExists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Include) String() string {
|
||||||
|
return renderTemplate(tokINCLUDE, r)
|
||||||
|
}
|
||||||
|
|
||||||
type Variable struct {
|
type Variable struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
Name string
|
Name string
|
||||||
|
|
@ -90,3 +108,7 @@ func (r *Variable) Equals(other any) bool {
|
||||||
o, _ := other.(*Variable)
|
o, _ := other.(*Variable)
|
||||||
return r.Name == o.Name && slices.Equal(r.Values, o.Values)
|
return r.Name == o.Name && slices.Equal(r.Values, o.Values)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Variable) String() string {
|
||||||
|
return renderTemplate("variable", r)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,12 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
tokATTRIBUTES = "xattrs"
|
||||||
|
tokFLAGS = "flags"
|
||||||
|
tokPROFILE = "profile"
|
||||||
|
)
|
||||||
|
|
||||||
// Profile represents a single AppArmor profile.
|
// Profile represents a single AppArmor profile.
|
||||||
type Profile struct {
|
type Profile struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
|
|
@ -40,6 +46,11 @@ func (p *Profile) Equals(other any) bool {
|
||||||
slices.Equal(p.Flags, o.Flags)
|
slices.Equal(p.Flags, o.Flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Profile) String() string {
|
||||||
|
return renderTemplate(tokPROFILE, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// AddRule adds a new rule to the profile from a log map.
|
// AddRule adds a new rule to the profile from a log map.
|
||||||
func (p *Profile) AddRule(log map[string]string) {
|
func (p *Profile) AddRule(log map[string]string) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
|
const tokPTRACE = "ptrace"
|
||||||
|
|
||||||
type Ptrace struct {
|
type Ptrace struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
Qualifier
|
Qualifier
|
||||||
|
|
@ -36,3 +38,7 @@ func (r *Ptrace) Equals(other any) bool {
|
||||||
return slices.Equal(r.Access, o.Access) && r.Peer == o.Peer &&
|
return slices.Equal(r.Access, o.Access) && r.Peer == o.Peer &&
|
||||||
r.Qualifier.Equals(o.Qualifier)
|
r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Ptrace) String() string {
|
||||||
|
return renderTemplate(tokPTRACE, r)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,12 @@
|
||||||
|
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
|
const (
|
||||||
|
tokRLIMIT = "rlimit"
|
||||||
|
tokSET = "set"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
type Rlimit struct {
|
type Rlimit struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
Key string
|
Key string
|
||||||
|
|
@ -35,3 +41,7 @@ func (r *Rlimit) Equals(other any) bool {
|
||||||
o, _ := other.(*Rlimit)
|
o, _ := other.(*Rlimit)
|
||||||
return r.Key == o.Key && r.Op == o.Op && r.Value == o.Value
|
return r.Key == o.Key && r.Op == o.Op && r.Value == o.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Rlimit) String() string {
|
||||||
|
return renderTemplate(tokRLIMIT, r)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,27 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
tokALL = "all"
|
||||||
|
tokALLOW = "allow"
|
||||||
|
tokAUDIT = "audit"
|
||||||
|
tokDENY = "deny"
|
||||||
|
)
|
||||||
|
|
||||||
// Rule generic interface for all AppArmor rules
|
// Rule generic interface for all AppArmor rules
|
||||||
type Rule interface {
|
type Rule interface {
|
||||||
Less(other any) bool
|
Less(other any) bool
|
||||||
Equals(other any) bool
|
Equals(other any) bool
|
||||||
|
String() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Rules []Rule
|
type Rules []Rule
|
||||||
|
|
||||||
|
func (r Rules) String() string {
|
||||||
|
return renderTemplate("rules", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
type RuleBase struct {
|
type RuleBase struct {
|
||||||
Comment string
|
Comment string
|
||||||
NoNewPrivs bool
|
NoNewPrivs bool
|
||||||
|
|
@ -69,6 +82,10 @@ func (r RuleBase) Equals(other any) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r RuleBase) String() string {
|
||||||
|
return renderTemplate("comment", r)
|
||||||
|
}
|
||||||
|
|
||||||
type Qualifier struct {
|
type Qualifier struct {
|
||||||
Audit bool
|
Audit bool
|
||||||
AccessType string
|
AccessType string
|
||||||
|
|
@ -104,3 +121,7 @@ func (r *All) Less(other any) bool {
|
||||||
func (r *All) Equals(other any) bool {
|
func (r *All) Equals(other any) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *All) String() string {
|
||||||
|
return renderTemplate(tokALL, r)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -367,3 +367,113 @@ func TestRule_Equals(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRule_String(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
rule Rule
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "include1",
|
||||||
|
rule: include1,
|
||||||
|
want: "include <abstraction/base>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "include-local",
|
||||||
|
rule: includeLocal1,
|
||||||
|
want: "include if exists <local/foo>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "include-abs",
|
||||||
|
rule: &Include{Path: "/usr/share/apparmor.d/", IsMagic: false},
|
||||||
|
want: `include "/usr/share/apparmor.d/"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rlimit",
|
||||||
|
rule: rlimit1,
|
||||||
|
want: "set rlimit nproc <= 200,",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "capability",
|
||||||
|
rule: capability1,
|
||||||
|
want: "capability net_admin,",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "capability/multi",
|
||||||
|
rule: &Capability{Names: []string{"dac_override", "dac_read_search"}},
|
||||||
|
want: "capability dac_override dac_read_search,",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "capability/all",
|
||||||
|
rule: &Capability{},
|
||||||
|
want: "capability,",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "network",
|
||||||
|
rule: network1,
|
||||||
|
want: "network netlink raw,",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mount",
|
||||||
|
rule: mount1,
|
||||||
|
want: "mount fstype=overlay overlay -> /var/lib/docker/overlay2/opaque-bug-check1209538631/merged/, # failed perms check",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pivot_root",
|
||||||
|
rule: pivotroot1,
|
||||||
|
want: "pivot_root oldroot=@{run}/systemd/mount-rootfs/ @{run}/systemd/mount-rootfs/,",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "change_profile",
|
||||||
|
rule: changeprofile1,
|
||||||
|
want: "change_profile -> systemd-user,",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "signal",
|
||||||
|
rule: signal1,
|
||||||
|
want: "signal receive set=kill peer=firefox//&firejail-default,",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ptrace",
|
||||||
|
rule: ptrace1,
|
||||||
|
want: "ptrace read peer=nautilus,",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unix",
|
||||||
|
rule: unix1,
|
||||||
|
want: "unix (receive send) type=stream protocol=0 addr=none peer=(label=dbus-daemon, addr=@/tmp/dbus-AaKMpxzC4k),",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dbus",
|
||||||
|
rule: dbus1,
|
||||||
|
want: `dbus receive bus=session path=/org/gtk/vfs/metadata
|
||||||
|
interface=org.gtk.vfs.Metadata
|
||||||
|
member=Remove
|
||||||
|
peer=(name=:1.15, label=tracker-extract),`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dbus-bind",
|
||||||
|
rule: &Dbus{Access: []string{"bind"}, Bus: "session", Name: "org.gnome.*"},
|
||||||
|
want: `dbus bind bus=session name=org.gnome.*,`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dbus-full",
|
||||||
|
rule: &Dbus{Bus: "accessibility"},
|
||||||
|
want: `dbus bus=accessibility,`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "file",
|
||||||
|
rule: file1,
|
||||||
|
want: "/usr/share/poppler/cMap/Identity-H r,",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
r := tt.rule
|
||||||
|
if got := r.String(); got != tt.want {
|
||||||
|
t.Errorf("Rule.String() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@
|
||||||
|
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
|
|
||||||
|
const tokSIGNAL = "signal"
|
||||||
|
|
||||||
type Signal struct {
|
type Signal struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
Qualifier
|
Qualifier
|
||||||
|
|
@ -41,3 +44,7 @@ func (r *Signal) Equals(other any) bool {
|
||||||
return slices.Equal(r.Access, o.Access) && slices.Equal(r.Set, o.Set) &&
|
return slices.Equal(r.Access, o.Access) && slices.Equal(r.Set, o.Set) &&
|
||||||
r.Peer == o.Peer && r.Qualifier.Equals(o.Qualifier)
|
r.Peer == o.Peer && r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Signal) String() string {
|
||||||
|
return renderTemplate(tokSIGNAL, r)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,29 +8,40 @@ import (
|
||||||
"embed"
|
"embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default indentation for apparmor profile (2 spaces)
|
|
||||||
const indentation = " "
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// Default indentation for apparmor profile (2 spaces)
|
||||||
|
TemplateIndentation = " "
|
||||||
|
|
||||||
|
// The current indentation level
|
||||||
|
TemplateIndentationLevel = 0
|
||||||
|
|
||||||
//go:embed templates/*.j2
|
//go:embed templates/*.j2
|
||||||
|
//go:embed templates/rule/*.j2
|
||||||
tmplFiles embed.FS
|
tmplFiles embed.FS
|
||||||
|
|
||||||
// The functions available in the template
|
// The functions available in the template
|
||||||
tmplFunctionMap = template.FuncMap{
|
tmplFunctionMap = template.FuncMap{
|
||||||
"typeof": typeOf,
|
"typeof": typeOf,
|
||||||
"join": join,
|
"join": join,
|
||||||
|
"cjoin": cjoin,
|
||||||
"indent": indent,
|
"indent": indent,
|
||||||
"overindent": indentDbus,
|
"overindent": indentDbus,
|
||||||
|
"setindent": setindent,
|
||||||
}
|
}
|
||||||
|
|
||||||
// The apparmor templates
|
// The apparmor templates
|
||||||
tmpl = map[string]*template.Template{
|
tmpl = generateTemplates([]string{
|
||||||
"apparmor": generateTemplate("apparmor.j2"),
|
"apparmor", tokPROFILE, "rules", // Global templates
|
||||||
}
|
tokINCLUDE, tokRLIMIT, tokCAPABILITY, tokNETWORK,
|
||||||
|
tokMOUNT, tokPIVOTROOT, tokCHANGEPROFILE, tokSIGNAL,
|
||||||
|
tokPTRACE, tokUNIX, tokUSERNS, tokIOURING,
|
||||||
|
tokDBUS, "file",
|
||||||
|
})
|
||||||
|
|
||||||
// convert apparmor requested mask to apparmor access mode
|
// convert apparmor requested mask to apparmor access mode
|
||||||
maskToAccess = map[string]string{
|
maskToAccess = map[string]string{
|
||||||
|
|
@ -90,30 +101,35 @@ var (
|
||||||
fileWeights = map[string]int{}
|
fileWeights = map[string]int{}
|
||||||
)
|
)
|
||||||
|
|
||||||
func generateTemplate(name string) *template.Template {
|
func generateTemplates(names []string) map[string]*template.Template {
|
||||||
res := template.New(name).Funcs(tmplFunctionMap)
|
res := make(map[string]*template.Template, len(names))
|
||||||
switch name {
|
base := template.New("").Funcs(tmplFunctionMap)
|
||||||
case "apparmor.j2":
|
base = template.Must(base.ParseFS(tmplFiles,
|
||||||
res = template.Must(res.ParseFS(tmplFiles,
|
|
||||||
"templates/*.j2", "templates/rule/*.j2",
|
"templates/*.j2", "templates/rule/*.j2",
|
||||||
))
|
))
|
||||||
case "profile.j2":
|
for _, name := range names {
|
||||||
res = template.Must(res.Parse("{{ template \"profile\" . }}"))
|
t := template.Must(base.Clone())
|
||||||
res = template.Must(res.ParseFS(tmplFiles,
|
t = template.Must(t.Parse(
|
||||||
"templates/profile.j2", "templates/rule/*.j2",
|
fmt.Sprintf(`{{- template "%s" . -}}`, name),
|
||||||
))
|
|
||||||
default:
|
|
||||||
res = template.Must(res.Parse(
|
|
||||||
fmt.Sprintf("{{ template \"%s\" . }}", name),
|
|
||||||
))
|
|
||||||
res = template.Must(res.ParseFS(tmplFiles,
|
|
||||||
fmt.Sprintf("templates/rule/%s.j2", name),
|
|
||||||
"templates/rule/qualifier.j2", "templates/rule/comment.j2",
|
|
||||||
))
|
))
|
||||||
|
res[name] = t
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func renderTemplate(name string, data any) string {
|
||||||
|
var res strings.Builder
|
||||||
|
template, ok := tmpl[name]
|
||||||
|
if !ok {
|
||||||
|
panic("template not found")
|
||||||
|
}
|
||||||
|
err := template.Execute(&res, data)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return res.String()
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
for i, r := range fileAlphabet {
|
for i, r := range fileAlphabet {
|
||||||
fileWeights[r] = i
|
fileWeights[r] = i
|
||||||
|
|
@ -138,6 +154,25 @@ func join(i any) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cjoin(i any) string {
|
||||||
|
switch reflect.TypeOf(i).Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
s := i.([]string)
|
||||||
|
if len(s) == 1 {
|
||||||
|
return s[0]
|
||||||
|
}
|
||||||
|
return "(" + strings.Join(s, " ") + ")"
|
||||||
|
case reflect.Map:
|
||||||
|
res := []string{}
|
||||||
|
for k, v := range i.(map[string]string) {
|
||||||
|
res = append(res, k+"="+v)
|
||||||
|
}
|
||||||
|
return "(" + strings.Join(res, " ") + ")"
|
||||||
|
default:
|
||||||
|
return i.(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func typeOf(i any) string {
|
func typeOf(i any) string {
|
||||||
return strings.TrimPrefix(reflect.TypeOf(i).String(), "*aa.")
|
return strings.TrimPrefix(reflect.TypeOf(i).String(), "*aa.")
|
||||||
}
|
}
|
||||||
|
|
@ -146,12 +181,22 @@ func typeToValue(i reflect.Type) string {
|
||||||
return strings.ToLower(strings.TrimPrefix(i.String(), "*aa."))
|
return strings.ToLower(strings.TrimPrefix(i.String(), "*aa."))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setindent(i string) string {
|
||||||
|
switch i {
|
||||||
|
case "++":
|
||||||
|
TemplateIndentationLevel++
|
||||||
|
case "--":
|
||||||
|
TemplateIndentationLevel--
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func indent(s string) string {
|
func indent(s string) string {
|
||||||
return indentation + s
|
return strings.Repeat(TemplateIndentation, TemplateIndentationLevel) + s
|
||||||
}
|
}
|
||||||
|
|
||||||
func indentDbus(s string) string {
|
func indentDbus(s string) string {
|
||||||
return indentation + " " + s
|
return strings.Join([]string{TemplateIndentation, s}, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLetterIn(alphabet []string, in string) string {
|
func getLetterIn(alphabet []string, in string) string {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
|
const tokUNIX = "unix"
|
||||||
|
|
||||||
type Unix struct {
|
type Unix struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
Qualifier
|
Qualifier
|
||||||
|
|
@ -74,3 +76,7 @@ func (r *Unix) Equals(other any) bool {
|
||||||
r.PeerLabel == o.PeerLabel && r.PeerAddr == o.PeerAddr &&
|
r.PeerLabel == o.PeerLabel && r.PeerAddr == o.PeerAddr &&
|
||||||
r.Qualifier.Equals(o.Qualifier)
|
r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Unix) String() string {
|
||||||
|
return renderTemplate(tokUNIX, r)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
|
const tokUSERNS = "userns"
|
||||||
|
|
||||||
type Userns struct {
|
type Userns struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
Qualifier
|
Qualifier
|
||||||
|
|
@ -30,3 +32,7 @@ func (r *Userns) Equals(other any) bool {
|
||||||
o, _ := other.(*Userns)
|
o, _ := other.(*Userns)
|
||||||
return r.Create == o.Create && r.Qualifier.Equals(o.Qualifier)
|
return r.Create == o.Create && r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Userns) String() string {
|
||||||
|
return renderTemplate(tokUSERNS, r)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue