feat(aa): add the Kind struct to manage aa rules.
This commit is contained in:
parent
1333ec2025
commit
3b0944c615
23 changed files with 239 additions and 223 deletions
|
|
@ -24,7 +24,7 @@ func newRule(rule []string) RuleBase {
|
||||||
|
|
||||||
idx := 0
|
idx := 0
|
||||||
for idx < len(rule) {
|
for idx < len(rule) {
|
||||||
if rule[idx] == tokCOMMENT {
|
if rule[idx] == COMMENT.Tok() {
|
||||||
comment = " " + strings.Join(rule[idx+1:], " ")
|
comment = " " + strings.Join(rule[idx+1:], " ")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -85,15 +85,15 @@ func (r RuleBase) Equals(other any) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r RuleBase) String() string {
|
func (r RuleBase) String() string {
|
||||||
return renderTemplate("comment", r)
|
return renderTemplate(r.Kind(), r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r RuleBase) Constraint() constraint {
|
func (r RuleBase) Constraint() constraint {
|
||||||
return anyKind
|
return anyKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r RuleBase) Kind() string {
|
func (r RuleBase) Kind() Kind {
|
||||||
return "base"
|
return COMMENT
|
||||||
}
|
}
|
||||||
|
|
||||||
type Qualifier struct {
|
type Qualifier struct {
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tokHAT = "hat"
|
HAT Kind = "hat"
|
||||||
tokCARET = "^"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Hat represents a single AppArmor hat.
|
// Hat represents a single AppArmor hat.
|
||||||
|
|
@ -26,7 +25,7 @@ func (p *Hat) Less(other any) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Hat) Equals(other any) bool {
|
func (p *Hat) Equals(other any) bool {
|
||||||
o, _ := other.(*Profile)
|
o, _ := other.(*Hat)
|
||||||
return p.Name == o.Name
|
return p.Name == o.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,6 +37,6 @@ func (p *Hat) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Hat) Kind() string {
|
func (p *Hat) Kind() Kind {
|
||||||
return tokHAT
|
return HAT
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ import (
|
||||||
"slices"
|
"slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
const tokCAPABILITY = "capability"
|
const CAPABILITY Kind = "capability"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
requirements[tokCAPABILITY] = requirement{
|
requirements[CAPABILITY] = requirement{
|
||||||
"name": {
|
"name": {
|
||||||
"audit_control", "audit_read", "audit_write", "block_suspend", "bpf",
|
"audit_control", "audit_read", "audit_write", "block_suspend", "bpf",
|
||||||
"checkpoint_restore", "chown", "dac_override", "dac_read_search",
|
"checkpoint_restore", "chown", "dac_override", "dac_read_search",
|
||||||
|
|
@ -36,7 +36,7 @@ func newCapabilityFromLog(log map[string]string) Rule {
|
||||||
return &Capability{
|
return &Capability{
|
||||||
RuleBase: newRuleFromLog(log),
|
RuleBase: newRuleFromLog(log),
|
||||||
Qualifier: newQualifierFromLog(log),
|
Qualifier: newQualifierFromLog(log),
|
||||||
Names: Must(toValues(tokCAPABILITY, "name", log["capname"])),
|
Names: Must(toValues(CAPABILITY, "name", log["capname"])),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,6 +70,6 @@ func (r *Capability) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Capability) Kind() string {
|
func (r *Capability) Kind() Kind {
|
||||||
return tokCAPABILITY
|
return CAPABILITY
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@ package aa
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
const tokCHANGEPROFILE = "change_profile"
|
const CHANGEPROFILE Kind = "change_profile"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
requirements[tokCHANGEPROFILE] = requirement{
|
requirements[CHANGEPROFILE] = requirement{
|
||||||
"mode": []string{"safe", "unsafe"},
|
"mode": []string{"safe", "unsafe"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -67,6 +67,6 @@ func (r *ChangeProfile) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ChangeProfile) Kind() string {
|
func (r *ChangeProfile) Kind() Kind {
|
||||||
return tokCHANGEPROFILE
|
return CHANGEPROFILE
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ import (
|
||||||
"slices"
|
"slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
const tokDBUS = "dbus"
|
const DBUS Kind = "dbus"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
requirements[tokDBUS] = requirement{
|
requirements[DBUS] = requirement{
|
||||||
"access": []string{
|
"access": []string{
|
||||||
"send", "receive", "bind", "eavesdrop", "r", "read",
|
"send", "receive", "bind", "eavesdrop", "r", "read",
|
||||||
"w", "write", "rw",
|
"w", "write", "rw",
|
||||||
|
|
@ -110,6 +110,6 @@ func (r *Dbus) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Dbus) Kind() string {
|
func (r *Dbus) Kind() Kind {
|
||||||
return tokDBUS
|
return DBUS
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tokLINK = "link"
|
LINK Kind = "link"
|
||||||
tokFILE = "file"
|
FILE Kind = "file"
|
||||||
tokOWNER = "owner"
|
tokOWNER = "owner"
|
||||||
tokSUBSET = "subset"
|
tokSUBSET = "subset"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
requirements[tokFILE] = requirement{
|
requirements[FILE] = requirement{
|
||||||
"access": {"m", "r", "w", "l", "k"},
|
"access": {"m", "r", "w", "l", "k"},
|
||||||
"transition": {
|
"transition": {
|
||||||
"ix", "ux", "Ux", "px", "Px", "cx", "Cx", "pix", "Pix", "cix",
|
"ix", "ux", "Ux", "px", "Px", "cx", "Cx", "pix", "Pix", "cix",
|
||||||
|
|
@ -40,15 +40,15 @@ func isOwner(log map[string]string) bool {
|
||||||
// cmpFileAccess compares two access strings for file rules.
|
// cmpFileAccess compares two access strings for file rules.
|
||||||
// It is aimed to be used in slices.SortFunc.
|
// It is aimed to be used in slices.SortFunc.
|
||||||
func cmpFileAccess(i, j string) int {
|
func cmpFileAccess(i, j string) int {
|
||||||
if slices.Contains(requirements[tokFILE]["access"], i) &&
|
if slices.Contains(requirements[FILE]["access"], i) &&
|
||||||
slices.Contains(requirements[tokFILE]["access"], j) {
|
slices.Contains(requirements[FILE]["access"], j) {
|
||||||
return requirementsWeights[tokFILE]["access"][i] - requirementsWeights[tokFILE]["access"][j]
|
return requirementsWeights[FILE]["access"][i] - requirementsWeights[FILE]["access"][j]
|
||||||
}
|
}
|
||||||
if slices.Contains(requirements[tokFILE]["transition"], i) &&
|
if slices.Contains(requirements[FILE]["transition"], i) &&
|
||||||
slices.Contains(requirements[tokFILE]["transition"], j) {
|
slices.Contains(requirements[FILE]["transition"], j) {
|
||||||
return requirementsWeights[tokFILE]["transition"][i] - requirementsWeights[tokFILE]["transition"][j]
|
return requirementsWeights[FILE]["transition"][i] - requirementsWeights[FILE]["transition"][j]
|
||||||
}
|
}
|
||||||
if slices.Contains(requirements[tokFILE]["access"], i) {
|
if slices.Contains(requirements[FILE]["access"], i) {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
|
|
@ -121,8 +121,8 @@ func (r *File) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *File) Kind() string {
|
func (r *File) Kind() Kind {
|
||||||
return tokFILE
|
return FILE
|
||||||
}
|
}
|
||||||
|
|
||||||
type Link struct {
|
type Link struct {
|
||||||
|
|
@ -179,6 +179,6 @@ func (r *Link) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Link) Kind() string {
|
func (r *Link) Kind() Kind {
|
||||||
return tokLINK
|
return LINK
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ import (
|
||||||
"slices"
|
"slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
const tokIOURING = "io_uring"
|
const IOURING Kind = "io_uring"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
requirements[tokIOURING] = requirement{
|
requirements[IOURING] = requirement{
|
||||||
"access": []string{"sqpoll", "override_creds"},
|
"access": []string{"sqpoll", "override_creds"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -28,7 +28,7 @@ func newIOUringFromLog(log map[string]string) Rule {
|
||||||
return &IOUring{
|
return &IOUring{
|
||||||
RuleBase: newRuleFromLog(log),
|
RuleBase: newRuleFromLog(log),
|
||||||
Qualifier: newQualifierFromLog(log),
|
Qualifier: newQualifierFromLog(log),
|
||||||
Access: Must(toAccess(tokIOURING, log["requested"])),
|
Access: Must(toAccess(IOURING, log["requested"])),
|
||||||
Label: log["label"],
|
Label: log["label"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -64,6 +64,6 @@ func (r *IOUring) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IOUring) Kind() string {
|
func (r *IOUring) Kind() Kind {
|
||||||
return tokIOURING
|
return IOURING
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tokMOUNT = "mount"
|
MOUNT Kind = "mount"
|
||||||
tokREMOUNT = "remount"
|
REMOUNT Kind = "remount"
|
||||||
tokUMOUNT = "umount"
|
UMOUNT Kind = "umount"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
requirements[tokMOUNT] = requirement{
|
requirements[MOUNT] = requirement{
|
||||||
"flags": {
|
"flags": {
|
||||||
"acl", "async", "atime", "ro", "rw", "bind", "rbind", "dev",
|
"acl", "async", "atime", "ro", "rw", "bind", "rbind", "dev",
|
||||||
"diratime", "dirsync", "exec", "iversion", "loud", "mand", "move",
|
"diratime", "dirsync", "exec", "iversion", "loud", "mand", "move",
|
||||||
|
|
@ -38,14 +38,14 @@ func newMountConditionsFromLog(log map[string]string) MountConditions {
|
||||||
if _, present := log["flags"]; present {
|
if _, present := log["flags"]; present {
|
||||||
return MountConditions{
|
return MountConditions{
|
||||||
FsType: log["fstype"],
|
FsType: log["fstype"],
|
||||||
Options: Must(toValues(tokMOUNT, "flags", log["flags"])),
|
Options: Must(toValues(MOUNT, "flags", log["flags"])),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return MountConditions{FsType: log["fstype"]}
|
return MountConditions{FsType: log["fstype"]}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m MountConditions) Validate() error {
|
func (m MountConditions) Validate() error {
|
||||||
return validateValues(tokMOUNT, "flags", m.Options)
|
return validateValues(MOUNT, "flags", m.Options)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m MountConditions) Less(other MountConditions) bool {
|
func (m MountConditions) Less(other MountConditions) bool {
|
||||||
|
|
@ -113,8 +113,8 @@ func (r *Mount) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Mount) Kind() string {
|
func (r *Mount) Kind() Kind {
|
||||||
return tokMOUNT
|
return MOUNT
|
||||||
}
|
}
|
||||||
|
|
||||||
type Umount struct {
|
type Umount struct {
|
||||||
|
|
@ -166,8 +166,8 @@ func (r *Umount) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Umount) Kind() string {
|
func (r *Umount) Kind() Kind {
|
||||||
return tokUMOUNT
|
return UMOUNT
|
||||||
}
|
}
|
||||||
|
|
||||||
type Remount struct {
|
type Remount struct {
|
||||||
|
|
@ -219,6 +219,6 @@ func (r *Remount) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Remount) Kind() string {
|
func (r *Remount) Kind() Kind {
|
||||||
return tokREMOUNT
|
return REMOUNT
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const tokMQUEUE = "mqueue"
|
const MQUEUE Kind = "mqueue"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
requirements[tokMQUEUE] = requirement{
|
requirements[MQUEUE] = requirement{
|
||||||
"access": []string{
|
"access": []string{
|
||||||
"r", "w", "rw", "read", "write", "create", "open",
|
"r", "w", "rw", "read", "write", "create", "open",
|
||||||
"delete", "getattr", "setattr",
|
"delete", "getattr", "setattr",
|
||||||
|
|
@ -41,7 +41,7 @@ func newMqueueFromLog(log map[string]string) Rule {
|
||||||
return &Mqueue{
|
return &Mqueue{
|
||||||
RuleBase: newRuleFromLog(log),
|
RuleBase: newRuleFromLog(log),
|
||||||
Qualifier: newQualifierFromLog(log),
|
Qualifier: newQualifierFromLog(log),
|
||||||
Access: Must(toAccess(tokMQUEUE, log["requested"])),
|
Access: Must(toAccess(MQUEUE, log["requested"])),
|
||||||
Type: mqueueType,
|
Type: mqueueType,
|
||||||
Label: log["label"],
|
Label: log["label"],
|
||||||
Name: log["name"],
|
Name: log["name"],
|
||||||
|
|
@ -86,6 +86,6 @@ func (r *Mqueue) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Mqueue) Kind() string {
|
func (r *Mqueue) Kind() Kind {
|
||||||
return tokMQUEUE
|
return MQUEUE
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
const tokNETWORK = "network"
|
const NETWORK Kind = "network"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
requirements[tokNETWORK] = requirement{
|
requirements[NETWORK] = requirement{
|
||||||
"access": []string{
|
"access": []string{
|
||||||
"create", "bind", "listen", "accept", "connect", "shutdown",
|
"create", "bind", "listen", "accept", "connect", "shutdown",
|
||||||
"getattr", "setattr", "getopt", "setopt", "send", "receive",
|
"getattr", "setattr", "getopt", "setopt", "send", "receive",
|
||||||
|
|
@ -126,6 +126,6 @@ func (r *Network) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Network) Kind() string {
|
func (r *Network) Kind() Kind {
|
||||||
return tokNETWORK
|
return NETWORK
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,16 @@ const (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
newRuleMap = map[string]func([]string) (Rule, error){
|
newRuleMap = map[string]func([]string) (Rule, error){
|
||||||
tokCOMMENT: newComment,
|
COMMENT.Tok(): newComment,
|
||||||
tokABI: newAbi,
|
ABI.Tok(): newAbi,
|
||||||
tokALIAS: newAlias,
|
ALIAS.Tok(): newAlias,
|
||||||
tokINCLUDE: newInclude,
|
INCLUDE.Tok(): newInclude,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tok = map[Kind]string{
|
||||||
|
COMMENT: "#",
|
||||||
|
VARIABLE: "@{",
|
||||||
|
}
|
||||||
openBlocks = []rune{tokOPENPAREN, tokOPENBRACE, tokOPENBRACKET}
|
openBlocks = []rune{tokOPENPAREN, tokOPENBRACE, tokOPENBRACKET}
|
||||||
closeBlocks = []rune{tokCLOSEPAREN, tokCLOSEBRACE, tokCLOSEBRACKET}
|
closeBlocks = []rune{tokCLOSEPAREN, tokCLOSEBRACE, tokCLOSEBRACKET}
|
||||||
)
|
)
|
||||||
|
|
@ -53,7 +57,7 @@ func tokenize(str string) []string {
|
||||||
|
|
||||||
blockStack := []rune{}
|
blockStack := []rune{}
|
||||||
tokens := make([]string, 0, len(str)/2)
|
tokens := make([]string, 0, len(str)/2)
|
||||||
if len(str) > 2 && str[0:2] == tokVARIABLE {
|
if len(str) > 2 && str[0:2] == VARIABLE.Tok() {
|
||||||
isVariable = true
|
isVariable = true
|
||||||
}
|
}
|
||||||
for _, r := range str {
|
for _, r := range str {
|
||||||
|
|
@ -122,7 +126,7 @@ func tokenToSlice(token string) []string {
|
||||||
func tokensStripComment(tokens []string) []string {
|
func tokensStripComment(tokens []string) []string {
|
||||||
res := []string{}
|
res := []string{}
|
||||||
for _, v := range tokens {
|
for _, v := range tokens {
|
||||||
if v == tokCOMMENT {
|
if v == COMMENT.Tok() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
res = append(res, v)
|
res = append(res, v)
|
||||||
|
|
@ -147,7 +151,7 @@ func newRules(rules [][]string) (Rules, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
res = append(res, r)
|
res = append(res, r)
|
||||||
} else if strings.HasPrefix(rule[0], tokVARIABLE) {
|
} else if strings.HasPrefix(rule[0], VARIABLE.Tok()) {
|
||||||
r, err = newVariable(rule)
|
r, err = newVariable(rule)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -167,7 +171,7 @@ func (f *AppArmorProfileFile) parsePreamble(input []string) error {
|
||||||
|
|
||||||
tokenizedRules := [][]string{}
|
tokenizedRules := [][]string{}
|
||||||
for _, line := range input {
|
for _, line := range input {
|
||||||
if strings.HasPrefix(line, tokCOMMENT) {
|
if strings.HasPrefix(line, COMMENT.Tok()) {
|
||||||
r, err = newComment(strings.Split(line, " "))
|
r, err = newComment(strings.Split(line, " "))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -215,7 +219,7 @@ done:
|
||||||
switch {
|
switch {
|
||||||
case tmp == "":
|
case tmp == "":
|
||||||
continue
|
continue
|
||||||
case strings.HasPrefix(tmp, tokPROFILE):
|
case strings.HasPrefix(tmp, PROFILE.Tok()):
|
||||||
rawHeader = tmp
|
rawHeader = tmp
|
||||||
break done
|
break done
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
const tokPIVOTROOT = "pivot_root"
|
const PIVOTROOT = "pivot_root"
|
||||||
|
|
||||||
type PivotRoot struct {
|
type PivotRoot struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
|
|
@ -57,6 +57,6 @@ func (r *PivotRoot) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PivotRoot) Kind() string {
|
func (r *PivotRoot) Kind() Kind {
|
||||||
return tokPIVOTROOT
|
return PIVOTROOT
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tokABI = "abi"
|
ABI Kind = "abi"
|
||||||
tokALIAS = "alias"
|
ALIAS Kind = "alias"
|
||||||
tokINCLUDE = "include"
|
INCLUDE Kind = "include"
|
||||||
|
VARIABLE Kind = "variable"
|
||||||
|
COMMENT Kind = "comment"
|
||||||
|
|
||||||
tokIFEXISTS = "if exists"
|
tokIFEXISTS = "if exists"
|
||||||
tokVARIABLE = "@{"
|
|
||||||
tokCOMMENT = "#"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Comment struct {
|
type Comment struct {
|
||||||
|
|
@ -42,7 +43,7 @@ func (r *Comment) Equals(other any) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Comment) String() string {
|
func (r *Comment) String() string {
|
||||||
return renderTemplate("comment", r)
|
return renderTemplate(r.Kind(), r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Comment) IsPreamble() bool {
|
func (r *Comment) IsPreamble() bool {
|
||||||
|
|
@ -53,8 +54,8 @@ func (r *Comment) Constraint() constraint {
|
||||||
return anyKind
|
return anyKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Comment) Kind() string {
|
func (r *Comment) Kind() Kind {
|
||||||
return tokCOMMENT
|
return COMMENT
|
||||||
}
|
}
|
||||||
|
|
||||||
type Abi struct {
|
type Abi struct {
|
||||||
|
|
@ -65,7 +66,7 @@ type Abi struct {
|
||||||
|
|
||||||
func newAbi(rule []string) (Rule, error) {
|
func newAbi(rule []string) (Rule, error) {
|
||||||
var magic bool
|
var magic bool
|
||||||
if len(rule) > 0 && rule[0] == tokABI {
|
if len(rule) > 0 && rule[0] == ABI.Tok() {
|
||||||
rule = rule[1:]
|
rule = rule[1:]
|
||||||
}
|
}
|
||||||
if len(rule) != 1 {
|
if len(rule) != 1 {
|
||||||
|
|
@ -113,8 +114,8 @@ func (r *Abi) Constraint() constraint {
|
||||||
return preambleKind
|
return preambleKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Abi) Kind() string {
|
func (r *Abi) Kind() Kind {
|
||||||
return tokABI
|
return ABI
|
||||||
}
|
}
|
||||||
|
|
||||||
type Alias struct {
|
type Alias struct {
|
||||||
|
|
@ -124,7 +125,7 @@ type Alias struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAlias(rule []string) (Rule, error) {
|
func newAlias(rule []string) (Rule, error) {
|
||||||
if len(rule) > 0 && rule[0] == tokALIAS {
|
if len(rule) > 0 && rule[0] == ALIAS.Tok() {
|
||||||
rule = rule[1:]
|
rule = rule[1:]
|
||||||
}
|
}
|
||||||
if len(rule) != 3 {
|
if len(rule) != 3 {
|
||||||
|
|
@ -165,8 +166,8 @@ func (r *Alias) Constraint() constraint {
|
||||||
return preambleKind
|
return preambleKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Alias) Kind() string {
|
func (r *Alias) Kind() Kind {
|
||||||
return tokALIAS
|
return ALIAS
|
||||||
}
|
}
|
||||||
|
|
||||||
type Include struct {
|
type Include struct {
|
||||||
|
|
@ -180,7 +181,7 @@ func newInclude(rule []string) (Rule, error) {
|
||||||
var magic bool
|
var magic bool
|
||||||
var ifexists bool
|
var ifexists bool
|
||||||
|
|
||||||
if len(rule) > 0 && rule[0] == tokINCLUDE {
|
if len(rule) > 0 && rule[0] == INCLUDE.Tok() {
|
||||||
rule = rule[1:]
|
rule = rule[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -239,8 +240,8 @@ func (r *Include) Constraint() constraint {
|
||||||
return anyKind
|
return anyKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Include) Kind() string {
|
func (r *Include) Kind() Kind {
|
||||||
return tokINCLUDE
|
return INCLUDE
|
||||||
}
|
}
|
||||||
|
|
||||||
type Variable struct {
|
type Variable struct {
|
||||||
|
|
@ -257,7 +258,7 @@ func newVariable(rule []string) (Rule, error) {
|
||||||
return nil, fmt.Errorf("invalid variable format: %v", rule)
|
return nil, fmt.Errorf("invalid variable format: %v", rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
name := strings.Trim(rule[0], tokVARIABLE+"}")
|
name := strings.Trim(rule[0], VARIABLE.Tok()+"}")
|
||||||
switch rule[1] {
|
switch rule[1] {
|
||||||
case tokEQUAL:
|
case tokEQUAL:
|
||||||
define = true
|
define = true
|
||||||
|
|
@ -297,13 +298,13 @@ func (r *Variable) Equals(other any) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Variable) String() string {
|
func (r *Variable) String() string {
|
||||||
return renderTemplate("variable", r)
|
return renderTemplate(r.Kind(), r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Variable) Constraint() constraint {
|
func (r *Variable) Constraint() constraint {
|
||||||
return preambleKind
|
return preambleKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Variable) Kind() string {
|
func (r *Variable) Kind() Kind {
|
||||||
return tokVARIABLE
|
return VARIABLE
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
PROFILE Kind = "profile"
|
||||||
|
|
||||||
tokATTRIBUTES = "xattrs"
|
tokATTRIBUTES = "xattrs"
|
||||||
tokFLAGS = "flags"
|
tokFLAGS = "flags"
|
||||||
tokPROFILE = "profile"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
requirements[tokPROFILE] = requirement{
|
requirements[PROFILE] = requirement{
|
||||||
tokFLAGS: {
|
tokFLAGS: {
|
||||||
"enforce", "complain", "kill", "default_allow", "unconfined",
|
"enforce", "complain", "kill", "default_allow", "unconfined",
|
||||||
"prompt", "audit", "mediate_deleted", "attach_disconnected",
|
"prompt", "audit", "mediate_deleted", "attach_disconnected",
|
||||||
|
|
@ -52,7 +53,7 @@ func newHeader(rule []string) (Header, error) {
|
||||||
if rule[len(rule)-1] == "{" {
|
if rule[len(rule)-1] == "{" {
|
||||||
rule = rule[:len(rule)-1]
|
rule = rule[:len(rule)-1]
|
||||||
}
|
}
|
||||||
if rule[0] == tokPROFILE {
|
if rule[0] == PROFILE.Tok() {
|
||||||
rule = rule[1:]
|
rule = rule[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,8 +121,8 @@ func (p *Profile) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Profile) Kind() string {
|
func (p *Profile) Kind() Kind {
|
||||||
return tokPROFILE
|
return PROFILE
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge merge similar rules together.
|
// Merge merge similar rules together.
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ import (
|
||||||
"slices"
|
"slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
const tokPTRACE = "ptrace"
|
const PTRACE Kind = "ptrace"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
requirements[tokPTRACE] = requirement{
|
requirements[PTRACE] = requirement{
|
||||||
"access": []string{
|
"access": []string{
|
||||||
"r", "w", "rw", "read", "readby", "trace", "tracedby",
|
"r", "w", "rw", "read", "readby", "trace", "tracedby",
|
||||||
},
|
},
|
||||||
|
|
@ -30,7 +30,7 @@ func newPtraceFromLog(log map[string]string) Rule {
|
||||||
return &Ptrace{
|
return &Ptrace{
|
||||||
RuleBase: newRuleFromLog(log),
|
RuleBase: newRuleFromLog(log),
|
||||||
Qualifier: newQualifierFromLog(log),
|
Qualifier: newQualifierFromLog(log),
|
||||||
Access: Must(toAccess(tokPTRACE, log["requested_mask"])),
|
Access: Must(toAccess(PTRACE, log["requested_mask"])),
|
||||||
Peer: log["peer"],
|
Peer: log["peer"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -67,6 +67,6 @@ func (r *Ptrace) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Ptrace) Kind() string {
|
func (r *Ptrace) Kind() Kind {
|
||||||
return tokPTRACE
|
return PTRACE
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ func (f *AppArmorProfileFile) Resolve() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *AppArmorProfileFile) resolveValues(input string) ([]string, error) {
|
func (f *AppArmorProfileFile) resolveValues(input string) ([]string, error) {
|
||||||
if !strings.Contains(input, tokVARIABLE) {
|
if !strings.Contains(input, VARIABLE.Tok()) {
|
||||||
return []string{input}, nil
|
return []string{input}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,7 +76,7 @@ func (f *AppArmorProfileFile) resolveValues(input string) ([]string, error) {
|
||||||
if vrbl.Name == varname {
|
if vrbl.Name == varname {
|
||||||
found = true
|
found = true
|
||||||
for _, v := range vrbl.Values {
|
for _, v := range vrbl.Values {
|
||||||
if strings.Contains(v, tokVARIABLE+varname+"}") {
|
if strings.Contains(v, VARIABLE.Tok()+varname+"}") {
|
||||||
return nil, fmt.Errorf("recursive variable found in: %s", varname)
|
return nil, fmt.Errorf("recursive variable found in: %s", varname)
|
||||||
}
|
}
|
||||||
newValues := strings.ReplaceAll(input, variable, v)
|
newValues := strings.ReplaceAll(input, variable, v)
|
||||||
|
|
@ -152,7 +152,7 @@ func (f *AppArmorProfileFile) resolveInclude(include *Include) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all includes in iFile
|
// Remove all includes in iFile
|
||||||
iFile.Preamble = iFile.Preamble.DeleteKind(tokINCLUDE)
|
iFile.Preamble = iFile.Preamble.DeleteKind(INCLUDE)
|
||||||
|
|
||||||
// Cache the included file
|
// Cache the included file
|
||||||
includeCache[include] = iFile
|
includeCache[include] = iFile
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,11 @@ package aa
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tokRLIMIT = "rlimit"
|
RLIMIT Kind = "rlimit"
|
||||||
tokSET = "set"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
requirements[tokRLIMIT] = requirement{
|
requirements[RLIMIT] = requirement{
|
||||||
"keys": {
|
"keys": {
|
||||||
"cpu", "fsize", "data", "stack", "core", "rss", "nofile", "ofile",
|
"cpu", "fsize", "data", "stack", "core", "rss", "nofile", "ofile",
|
||||||
"as", "nproc", "memlock", "locks", "sigpending", "msgqueue", "nice",
|
"as", "nproc", "memlock", "locks", "sigpending", "msgqueue", "nice",
|
||||||
|
|
@ -68,6 +67,6 @@ func (r *Rlimit) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Rlimit) Kind() string {
|
func (r *Rlimit) Kind() Kind {
|
||||||
return tokRLIMIT
|
return RLIMIT
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,20 @@ const (
|
||||||
blockKind // The rule can only be found in a profile
|
blockKind // The rule can only be found in a profile
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Kind represents an AppArmor rule kind.
|
||||||
|
type Kind string
|
||||||
|
|
||||||
|
func (k Kind) String() string {
|
||||||
|
return string(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Kind) Tok() string {
|
||||||
|
if t, ok := tok[k]; ok {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
return string(k)
|
||||||
|
}
|
||||||
|
|
||||||
// Rule generic interface for all AppArmor rules
|
// Rule generic interface for all AppArmor rules
|
||||||
type Rule interface {
|
type Rule interface {
|
||||||
Validate() error
|
Validate() error
|
||||||
|
|
@ -33,7 +47,7 @@ type Rule interface {
|
||||||
Equals(other any) bool
|
Equals(other any) bool
|
||||||
String() string
|
String() string
|
||||||
Constraint() constraint
|
Constraint() constraint
|
||||||
Kind() string
|
Kind() Kind
|
||||||
}
|
}
|
||||||
|
|
||||||
type Rules []Rule
|
type Rules []Rule
|
||||||
|
|
@ -77,7 +91,7 @@ func (r Rules) Delete(i int) Rules {
|
||||||
return append(r[:i], r[i+1:]...)
|
return append(r[:i], r[i+1:]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Rules) DeleteKind(kind string) Rules {
|
func (r Rules) DeleteKind(kind Kind) Rules {
|
||||||
res := make(Rules, 0)
|
res := make(Rules, 0)
|
||||||
for _, rule := range r {
|
for _, rule := range r {
|
||||||
if rule.Kind() != kind {
|
if rule.Kind() != kind {
|
||||||
|
|
@ -87,7 +101,7 @@ func (r Rules) DeleteKind(kind string) Rules {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Rules) Filter(filter string) Rules {
|
func (r Rules) Filter(filter Kind) Rules {
|
||||||
res := make(Rules, 0)
|
res := make(Rules, 0)
|
||||||
for _, rule := range r {
|
for _, rule := range r {
|
||||||
if rule.Kind() != filter {
|
if rule.Kind() != filter {
|
||||||
|
|
@ -128,12 +142,12 @@ func Must[T any](v T, err error) T {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateValues(rule string, key string, values []string) error {
|
func validateValues(kind Kind, key string, values []string) error {
|
||||||
for _, v := range values {
|
for _, v := range values {
|
||||||
if v == "" {
|
if v == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !slices.Contains(requirements[rule][key], v) {
|
if !slices.Contains(requirements[kind][key], v) {
|
||||||
return fmt.Errorf("invalid mode '%s'", v)
|
return fmt.Errorf("invalid mode '%s'", v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -142,10 +156,10 @@ func validateValues(rule string, key string, values []string) error {
|
||||||
|
|
||||||
// Helper function to convert a string to a slice of rule values according to
|
// Helper function to convert a string to a slice of rule values according to
|
||||||
// the rule requirements as defined in the requirements map.
|
// the rule requirements as defined in the requirements map.
|
||||||
func toValues(rule string, key string, input string) ([]string, error) {
|
func toValues(kind Kind, key string, input string) ([]string, error) {
|
||||||
req, ok := requirements[rule][key]
|
req, ok := requirements[kind][key]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("unrecognized requirement '%s' for rule %s", key, rule)
|
return nil, fmt.Errorf("unrecognized requirement '%s' for rule %s", key, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
res := tokenToSlice(input)
|
res := tokenToSlice(input)
|
||||||
|
|
@ -156,22 +170,22 @@ func toValues(rule string, key string, input string) ([]string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
slices.SortFunc(res, func(i, j string) int {
|
slices.SortFunc(res, func(i, j string) int {
|
||||||
return requirementsWeights[rule][key][i] - requirementsWeights[rule][key][j]
|
return requirementsWeights[kind][key][i] - requirementsWeights[kind][key][j]
|
||||||
})
|
})
|
||||||
return slices.Compact(res), nil
|
return slices.Compact(res), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to convert an access string to a slice of access according to
|
// Helper function to convert an access string to a slice of access according to
|
||||||
// the rule requirements as defined in the requirements map.
|
// the rule requirements as defined in the requirements map.
|
||||||
func toAccess(rule string, input string) ([]string, error) {
|
func toAccess(kind Kind, input string) ([]string, error) {
|
||||||
var res []string
|
var res []string
|
||||||
|
|
||||||
switch rule {
|
switch kind {
|
||||||
case tokFILE:
|
case FILE:
|
||||||
raw := strings.Split(input, "")
|
raw := strings.Split(input, "")
|
||||||
trans := []string{}
|
trans := []string{}
|
||||||
for _, access := range raw {
|
for _, access := range raw {
|
||||||
if slices.Contains(requirements[tokFILE]["access"], access) {
|
if slices.Contains(requirements[FILE]["access"], access) {
|
||||||
res = append(res, access)
|
res = append(res, access)
|
||||||
} else {
|
} else {
|
||||||
trans = append(trans, access)
|
trans = append(trans, access)
|
||||||
|
|
@ -180,17 +194,17 @@ func toAccess(rule string, input string) ([]string, error) {
|
||||||
|
|
||||||
transition := strings.Join(trans, "")
|
transition := strings.Join(trans, "")
|
||||||
if len(transition) > 0 {
|
if len(transition) > 0 {
|
||||||
if slices.Contains(requirements[tokFILE]["transition"], transition) {
|
if slices.Contains(requirements[FILE]["transition"], transition) {
|
||||||
res = append(res, transition)
|
res = append(res, transition)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unrecognized transition: %s", transition)
|
return nil, fmt.Errorf("unrecognized transition: %s", transition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case tokFILE + "-log":
|
case FILE + "-log":
|
||||||
raw := strings.Split(input, "")
|
raw := strings.Split(input, "")
|
||||||
for _, access := range raw {
|
for _, access := range raw {
|
||||||
if slices.Contains(requirements[tokFILE]["access"], access) {
|
if slices.Contains(requirements[FILE]["access"], access) {
|
||||||
res = append(res, access)
|
res = append(res, access)
|
||||||
} else if maskToAccess[access] != "" {
|
} else if maskToAccess[access] != "" {
|
||||||
res = append(res, maskToAccess[access])
|
res = append(res, maskToAccess[access])
|
||||||
|
|
@ -200,7 +214,7 @@ func toAccess(rule string, input string) ([]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return toValues(rule, "access", input)
|
return toValues(kind, "access", input)
|
||||||
}
|
}
|
||||||
|
|
||||||
slices.SortFunc(res, cmpFileAccess)
|
slices.SortFunc(res, cmpFileAccess)
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ import (
|
||||||
"slices"
|
"slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
const tokSIGNAL = "signal"
|
const SIGNAL Kind = "signal"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
requirements[tokSIGNAL] = requirement{
|
requirements[SIGNAL] = requirement{
|
||||||
"access": {
|
"access": {
|
||||||
"r", "w", "rw", "read", "write", "send", "receive",
|
"r", "w", "rw", "read", "write", "send", "receive",
|
||||||
},
|
},
|
||||||
|
|
@ -44,7 +44,7 @@ func newSignalFromLog(log map[string]string) Rule {
|
||||||
return &Signal{
|
return &Signal{
|
||||||
RuleBase: newRuleFromLog(log),
|
RuleBase: newRuleFromLog(log),
|
||||||
Qualifier: newQualifierFromLog(log),
|
Qualifier: newQualifierFromLog(log),
|
||||||
Access: Must(toAccess(tokSIGNAL, log["requested_mask"])),
|
Access: Must(toAccess(SIGNAL, log["requested_mask"])),
|
||||||
Set: []string{log["signal"]},
|
Set: []string{log["signal"]},
|
||||||
Peer: log["peer"],
|
Peer: log["peer"],
|
||||||
}
|
}
|
||||||
|
|
@ -88,6 +88,6 @@ func (r *Signal) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Signal) Kind() string {
|
func (r *Signal) Kind() Kind {
|
||||||
return tokSIGNAL
|
return SIGNAL
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ var (
|
||||||
|
|
||||||
// The functions available in the template
|
// The functions available in the template
|
||||||
tmplFunctionMap = template.FuncMap{
|
tmplFunctionMap = template.FuncMap{
|
||||||
"typeof": typeOf,
|
"kindof": kindOf,
|
||||||
"join": join,
|
"join": join,
|
||||||
"cjoin": cjoin,
|
"cjoin": cjoin,
|
||||||
"indent": indent,
|
"indent": indent,
|
||||||
|
|
@ -34,24 +34,25 @@ var (
|
||||||
}
|
}
|
||||||
|
|
||||||
// The apparmor templates
|
// The apparmor templates
|
||||||
tmpl = generateTemplates([]string{
|
tmpl = generateTemplates([]Kind{
|
||||||
// Global templates
|
// Global templates
|
||||||
"apparmor",
|
"apparmor",
|
||||||
tokPROFILE,
|
PROFILE,
|
||||||
|
HAT,
|
||||||
"rules",
|
"rules",
|
||||||
|
|
||||||
// Preamble templates
|
// Preamble templates
|
||||||
tokABI,
|
ABI,
|
||||||
tokALIAS,
|
ALIAS,
|
||||||
tokINCLUDE,
|
INCLUDE,
|
||||||
"variable",
|
VARIABLE,
|
||||||
"comment",
|
COMMENT,
|
||||||
|
|
||||||
// Rules templates
|
// Rules templates
|
||||||
tokALL, tokRLIMIT, tokUSERNS, tokCAPABILITY, tokNETWORK,
|
ALL, RLIMIT, USERNS, CAPABILITY, NETWORK,
|
||||||
tokMOUNT, tokREMOUNT, tokUMOUNT, tokPIVOTROOT, tokCHANGEPROFILE,
|
MOUNT, REMOUNT, UMOUNT, PIVOTROOT, CHANGEPROFILE,
|
||||||
tokMQUEUE, tokIOURING, tokUNIX, tokPTRACE, tokSIGNAL, tokDBUS,
|
MQUEUE, IOURING, UNIX, PTRACE, SIGNAL, DBUS,
|
||||||
tokFILE, tokLINK,
|
FILE, LINK,
|
||||||
})
|
})
|
||||||
|
|
||||||
// convert apparmor requested mask to apparmor access mode
|
// convert apparmor requested mask to apparmor access mode
|
||||||
|
|
@ -64,27 +65,28 @@ var (
|
||||||
}
|
}
|
||||||
|
|
||||||
// The order the apparmor rules should be sorted
|
// The order the apparmor rules should be sorted
|
||||||
ruleAlphabet = []string{
|
ruleAlphabet = []Kind{
|
||||||
"include",
|
INCLUDE,
|
||||||
"all",
|
ALL,
|
||||||
"rlimit",
|
RLIMIT,
|
||||||
"userns",
|
USERNS,
|
||||||
"capability",
|
CAPABILITY,
|
||||||
"network",
|
NETWORK,
|
||||||
"mount",
|
MOUNT,
|
||||||
"remount",
|
REMOUNT,
|
||||||
"umount",
|
UMOUNT,
|
||||||
"pivotroot",
|
PIVOTROOT,
|
||||||
"changeprofile",
|
CHANGEPROFILE,
|
||||||
"mqueue",
|
MQUEUE,
|
||||||
"iouring",
|
IOURING,
|
||||||
"signal",
|
SIGNAL,
|
||||||
"ptrace",
|
PTRACE,
|
||||||
"unix",
|
UNIX,
|
||||||
"dbus",
|
DBUS,
|
||||||
"file",
|
FILE,
|
||||||
"link",
|
LINK,
|
||||||
"profile",
|
PROFILE,
|
||||||
|
HAT,
|
||||||
"include_if_exists",
|
"include_if_exists",
|
||||||
}
|
}
|
||||||
ruleWeights = generateWeights(ruleAlphabet)
|
ruleWeights = generateWeights(ruleAlphabet)
|
||||||
|
|
@ -117,16 +119,16 @@ var (
|
||||||
fileWeights = generateWeights(fileAlphabet)
|
fileWeights = generateWeights(fileAlphabet)
|
||||||
|
|
||||||
// The order the rule values (access, type, domains, etc) should be sorted
|
// The order the rule values (access, type, domains, etc) should be sorted
|
||||||
requirements = map[string]requirement{}
|
requirements = map[Kind]requirement{}
|
||||||
requirementsWeights map[string]map[string]map[string]int
|
requirementsWeights map[Kind]map[string]map[string]int
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
requirementsWeights = generateRequirementsWeights(requirements)
|
requirementsWeights = generateRequirementsWeights(requirements)
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateTemplates(names []string) map[string]*template.Template {
|
func generateTemplates(names []Kind) map[Kind]*template.Template {
|
||||||
res := make(map[string]*template.Template, len(names))
|
res := make(map[Kind]*template.Template, len(names))
|
||||||
base := template.New("").Funcs(tmplFunctionMap)
|
base := template.New("").Funcs(tmplFunctionMap)
|
||||||
base = template.Must(base.ParseFS(tmplFiles,
|
base = template.Must(base.ParseFS(tmplFiles,
|
||||||
"templates/*.j2", "templates/rule/*.j2",
|
"templates/*.j2", "templates/rule/*.j2",
|
||||||
|
|
@ -141,11 +143,11 @@ func generateTemplates(names []string) map[string]*template.Template {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderTemplate(name string, data any) string {
|
func renderTemplate(name Kind, data any) string {
|
||||||
var res strings.Builder
|
var res strings.Builder
|
||||||
template, ok := tmpl[name]
|
template, ok := tmpl[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("template '" + name + "' not found")
|
panic("template '" + name.String() + "' not found")
|
||||||
}
|
}
|
||||||
err := template.Execute(&res, data)
|
err := template.Execute(&res, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -154,16 +156,16 @@ func renderTemplate(name string, data any) string {
|
||||||
return res.String()
|
return res.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateWeights(alphabet []string) map[string]int {
|
func generateWeights[T Kind | string](alphabet []T) map[T]int {
|
||||||
res := make(map[string]int, len(alphabet))
|
res := make(map[T]int, len(alphabet))
|
||||||
for i, r := range alphabet {
|
for i, r := range alphabet {
|
||||||
res[r] = i
|
res[r] = i
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateRequirementsWeights(requirements map[string]requirement) map[string]map[string]map[string]int {
|
func generateRequirementsWeights(requirements map[Kind]requirement) map[Kind]map[string]map[string]int {
|
||||||
res := make(map[string]map[string]map[string]int, len(requirements))
|
res := make(map[Kind]map[string]map[string]int, len(requirements))
|
||||||
for rule, req := range requirements {
|
for rule, req := range requirements {
|
||||||
res[rule] = make(map[string]map[string]int, len(req))
|
res[rule] = make(map[string]map[string]int, len(req))
|
||||||
for key, values := range req {
|
for key, values := range req {
|
||||||
|
|
@ -207,15 +209,11 @@ func cjoin(i any) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func typeOf(i any) string {
|
func kindOf(i any) string {
|
||||||
if i == nil {
|
if i == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return strings.TrimPrefix(reflect.TypeOf(i).String(), "*aa.")
|
return i.(Rule).Kind().String()
|
||||||
}
|
|
||||||
|
|
||||||
func typeToValue(i reflect.Type) string {
|
|
||||||
return strings.ToLower(strings.TrimPrefix(i.String(), "*aa."))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setindent(i string) string {
|
func setindent(i string) string {
|
||||||
|
|
|
||||||
|
|
@ -4,118 +4,118 @@
|
||||||
|
|
||||||
{{- define "rules" -}}
|
{{- define "rules" -}}
|
||||||
|
|
||||||
{{- $oldtype := "" -}}
|
{{- $oldkind := "" -}}
|
||||||
{{- range . -}}
|
{{- range . -}}
|
||||||
{{- $type := typeof . -}}
|
{{- $kind := kindof . -}}
|
||||||
{{- if eq $type "" -}}
|
{{- if eq $kind "" -}}
|
||||||
{{- "\n" -}}
|
{{- "\n" -}}
|
||||||
{{- continue -}}
|
{{- continue -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if eq $type "Comment" -}}
|
{{- if eq $kind "comment" -}}
|
||||||
{{- template "comment" . -}}
|
{{- template "comment" . -}}
|
||||||
{{- "\n" -}}
|
{{- "\n" -}}
|
||||||
{{- continue -}}
|
{{- continue -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if and (ne $type $oldtype) (ne $oldtype "") -}}
|
{{- if and (ne $kind $oldkind) (ne $oldkind "") -}}
|
||||||
{{- "\n" -}}
|
{{- "\n" -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- indent "" -}}
|
{{- indent "" -}}
|
||||||
|
|
||||||
{{- if eq $type "Abi" -}}
|
{{- if eq $kind "abi" -}}
|
||||||
{{- template "abi" . -}}
|
{{- template "abi" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Alias" -}}
|
{{- if eq $kind "alias" -}}
|
||||||
{{- template "alias" . -}}
|
{{- template "alias" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Include" -}}
|
{{- if eq $kind "include" -}}
|
||||||
{{- template "include" . -}}
|
{{- template "include" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Variable" -}}
|
{{- if eq $kind "variable" -}}
|
||||||
{{- template "variable" . -}}
|
{{- template "variable" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "All" -}}
|
{{- if eq $kind "all" -}}
|
||||||
{{- template "all" . -}}
|
{{- template "all" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Rlimit" -}}
|
{{- if eq $kind "rlimit" -}}
|
||||||
{{- template "rlimit" . -}}
|
{{- template "rlimit" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Userns" -}}
|
{{- if eq $kind "userns" -}}
|
||||||
{{- template "userns" . -}}
|
{{- template "userns" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Capability" -}}
|
{{- if eq $kind "capability" -}}
|
||||||
{{- template "capability" . -}}
|
{{- template "capability" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Network" -}}
|
{{- if eq $kind "network" -}}
|
||||||
{{- template "network" . -}}
|
{{- template "network" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Mount" -}}
|
{{- if eq $kind "mount" -}}
|
||||||
{{- template "mount" . -}}
|
{{- template "mount" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Remount" -}}
|
{{- if eq $kind "remount" -}}
|
||||||
{{- template "remount" . -}}
|
{{- template "remount" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Umount" -}}
|
{{- if eq $kind "umount" -}}
|
||||||
{{- template "umount" . -}}
|
{{- template "umount" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "PivotRoot" -}}
|
{{- if eq $kind "pivot_root" -}}
|
||||||
{{- template "pivot_root" . -}}
|
{{- template "pivot_root" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "ChangeProfile" -}}
|
{{- if eq $kind "change_profile" -}}
|
||||||
{{- template "change_profile" . -}}
|
{{- template "change_profile" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Mqueue" -}}
|
{{- if eq $kind "mqueue" -}}
|
||||||
{{- template "mqueue" . -}}
|
{{- template "mqueue" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "IOUring" -}}
|
{{- if eq $kind "io_uring" -}}
|
||||||
{{- template "io_uring" . -}}
|
{{- template "io_uring" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Unix" -}}
|
{{- if eq $kind "unix" -}}
|
||||||
{{- template "unix" . -}}
|
{{- template "unix" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Ptrace" -}}
|
{{- if eq $kind "ptrace" -}}
|
||||||
{{- template "ptrace" . -}}
|
{{- template "ptrace" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Signal" -}}
|
{{- if eq $kind "signal" -}}
|
||||||
{{- template "signal" . -}}
|
{{- template "signal" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Dbus" -}}
|
{{- if eq $kind "dbus" -}}
|
||||||
{{- template "dbus" . -}}
|
{{- template "dbus" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "File" -}}
|
{{- if eq $kind "file" -}}
|
||||||
{{- template "file" . -}}
|
{{- template "file" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Link" -}}
|
{{- if eq $kind "link" -}}
|
||||||
{{- template "link" . -}}
|
{{- template "link" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Profile" -}}
|
{{- if eq $kind "profile" -}}
|
||||||
{{- template "profile" . -}}
|
{{- template "profile" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- "\n" -}}
|
{{- "\n" -}}
|
||||||
{{- $oldtype = $type -}}
|
{{- $oldkind = $kind -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ import (
|
||||||
"slices"
|
"slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
const tokUNIX = "unix"
|
const UNIX Kind = "unix"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
requirements[tokUNIX] = requirement{
|
requirements[UNIX] = requirement{
|
||||||
"access": []string{
|
"access": []string{
|
||||||
"create", "bind", "listen", "accept", "connect", "shutdown",
|
"create", "bind", "listen", "accept", "connect", "shutdown",
|
||||||
"getattr", "setattr", "getopt", "setopt", "send", "receive",
|
"getattr", "setattr", "getopt", "setopt", "send", "receive",
|
||||||
|
|
@ -39,7 +39,7 @@ func newUnixFromLog(log map[string]string) Rule {
|
||||||
return &Unix{
|
return &Unix{
|
||||||
RuleBase: newRuleFromLog(log),
|
RuleBase: newRuleFromLog(log),
|
||||||
Qualifier: newQualifierFromLog(log),
|
Qualifier: newQualifierFromLog(log),
|
||||||
Access: Must(toAccess(tokUNIX, log["requested_mask"])),
|
Access: Must(toAccess(UNIX, log["requested_mask"])),
|
||||||
Type: log["sock_type"],
|
Type: log["sock_type"],
|
||||||
Protocol: log["protocol"],
|
Protocol: log["protocol"],
|
||||||
Address: log["addr"],
|
Address: log["addr"],
|
||||||
|
|
@ -107,6 +107,6 @@ func (r *Unix) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Unix) Kind() string {
|
func (r *Unix) Kind() Kind {
|
||||||
return tokUNIX
|
return UNIX
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
const tokUSERNS = "userns"
|
const USERNS Kind = "userns"
|
||||||
|
|
||||||
type Userns struct {
|
type Userns struct {
|
||||||
RuleBase
|
RuleBase
|
||||||
|
|
@ -45,6 +45,6 @@ func (r *Userns) Constraint() constraint {
|
||||||
return blockKind
|
return blockKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Userns) Kind() string {
|
func (r *Userns) Kind() Kind {
|
||||||
return tokUSERNS
|
return USERNS
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue