diff --git a/pkg/aa/capability.go b/pkg/aa/capability.go index 46450e453..5fe214102 100644 --- a/pkg/aa/capability.go +++ b/pkg/aa/capability.go @@ -10,6 +10,21 @@ import ( const tokCAPABILITY = "capability" +func init() { + requirements[tokCAPABILITY] = requirement{ + "name": { + "audit_control", "audit_read", "audit_write", "block_suspend", "bpf", + "checkpoint_restore", "chown", "dac_override", "dac_read_search", + "fowner", "fsetid", "ipc_lock", "ipc_owner", "kill", "lease", + "linux_immutable", "mac_admin", "mac_override", "mknod", "net_admin", + "net_bind_service", "net_broadcast", "net_raw", "perfmon", "setfcap", + "setgid", "setpcap", "setuid", "sys_admin", "sys_boot", "sys_chroot", + "sys_module", "sys_nice", "sys_pacct", "sys_ptrace", "sys_rawio", + "sys_resource", "sys_time", "sys_tty_config", "syslog", "wake_alarm", + }, + } +} + type Capability struct { RuleBase Qualifier diff --git a/pkg/aa/change_profile.go b/pkg/aa/change_profile.go index 4d5ded150..7ba53d0d1 100644 --- a/pkg/aa/change_profile.go +++ b/pkg/aa/change_profile.go @@ -6,6 +6,12 @@ package aa const tokCHANGEPROFILE = "change_profile" +func init() { + requirements[tokCHANGEPROFILE] = requirement{ + "mode": []string{"safe", "unsafe"}, + } +} + type ChangeProfile struct { RuleBase Qualifier diff --git a/pkg/aa/dbus.go b/pkg/aa/dbus.go index ea88e5381..41863da99 100644 --- a/pkg/aa/dbus.go +++ b/pkg/aa/dbus.go @@ -10,6 +10,16 @@ import ( const tokDBUS = "dbus" +func init() { + requirements[tokDBUS] = requirement{ + "access": []string{ + "send", "receive", "bind", "eavesdrop", "r", "read", + "w", "write", "rw", + }, + "bus": []string{"system", "session", "accessibility"}, + } +} + type Dbus struct { RuleBase Qualifier diff --git a/pkg/aa/file.go b/pkg/aa/file.go index 330ec6a50..84450afec 100644 --- a/pkg/aa/file.go +++ b/pkg/aa/file.go @@ -16,6 +16,16 @@ const ( tokSUBSET = "subset" ) +func init() { + requirements[tokFILE] = requirement{ + "access": {"m", "r", "w", "l", "k"}, + "transition": { + "ix", "ux", "Ux", "px", "Px", "cx", "Cx", "pix", "Pix", "cix", + "Cix", "pux", "PUx", "cux", "CUx", "x", + }, + } +} + type File struct { RuleBase Qualifier diff --git a/pkg/aa/io_uring.go b/pkg/aa/io_uring.go index 9ad2829a8..effc898d5 100644 --- a/pkg/aa/io_uring.go +++ b/pkg/aa/io_uring.go @@ -8,6 +8,11 @@ import "slices" const tokIOURING = "io_uring" +func init() { + requirements[tokIOURING] = requirement{ + "access": []string{"sqpoll", "override_creds"}, + } +} type IOUring struct { RuleBase diff --git a/pkg/aa/mount.go b/pkg/aa/mount.go index 7d7fef3a2..7c3f3866b 100644 --- a/pkg/aa/mount.go +++ b/pkg/aa/mount.go @@ -15,7 +15,18 @@ const ( tokUMOUNT = "umount" ) -) +func init() { + requirements[tokMOUNT] = requirement{ + "flags": { + "acl", "async", "atime", "bind", "dev", "diratime", "dirsync", "exec", + "iversion", "loud", "mand", "move", "noacl", "noatime", "nodev", + "nodiratime", "noexec", "noiversion", "nomand", "norelatime", "nosuid", + "nouser", "private", "rbind", "relatime", "remount", "ro", "rprivate", + "rshared", "rslave", "runbindable", "rw", "shared", "silent", "slave", + "strictatime", "suid", "sync", "unbindable", "user", "verbose", + }, + } +} type MountConditions struct { FsType string diff --git a/pkg/aa/mqueue.go b/pkg/aa/mqueue.go index e00aedb7f..08bdc4d0b 100644 --- a/pkg/aa/mqueue.go +++ b/pkg/aa/mqueue.go @@ -11,6 +11,15 @@ import ( const tokMQUEUE = "mqueue" +func init() { + requirements[tokMQUEUE] = requirement{ + "access": []string{ + "r", "w", "rw", "read", "write", "create", "open", + "delete", "getattr", "setattr", + }, + "type": []string{"posix", "sysv"}, + } +} type Mqueue struct { RuleBase diff --git a/pkg/aa/network.go b/pkg/aa/network.go index f8a286e3c..554b77ab4 100644 --- a/pkg/aa/network.go +++ b/pkg/aa/network.go @@ -4,10 +4,29 @@ package aa -import "slices" - const tokNETWORK = "network" +func init() { + requirements[tokNETWORK] = requirement{ + "access": []string{ + "create", "bind", "listen", "accept", "connect", "shutdown", + "getattr", "setattr", "getopt", "setopt", "send", "receive", + "r", "w", "rw", + }, + "domains": []string{ + "unix", "inet", "ax25", "ipx", "appletalk", "netrom", "bridge", + "atmpvc", "x25", "inet6", "rose", "netbeui", "security", "key", + "netlink", "packet", "ash", "econet", "atmsvc", "rds", "sna", "irda", + "pppox", "wanpipe", "llc", "ib", "mpls", "can", "tipc", "bluetooth", + "iucv", "rxrpc", "isdn", "phonet", "ieee802154", "caif", "alg", + "nfc", "vsock", "kcm", "qipcrtr", "smc", "xdp", "mctp", + }, + "type": []string{ + "stream", "dgram", "seqpacket", "rdm", "raw", "packet", + }, + "protocol": []string{"tcp", "udp", "icmp"}, + } +} type AddressExpr struct { Source string diff --git a/pkg/aa/ptrace.go b/pkg/aa/ptrace.go index a8ac55fc5..85106b884 100644 --- a/pkg/aa/ptrace.go +++ b/pkg/aa/ptrace.go @@ -8,6 +8,14 @@ import "slices" const tokPTRACE = "ptrace" +func init() { + requirements[tokPTRACE] = requirement{ + "access": []string{ + "r", "w", "rw", "read", "readby", "trace", "tracedby", + }, + } +} + type Ptrace struct { RuleBase Qualifier diff --git a/pkg/aa/rlimit.go b/pkg/aa/rlimit.go index 4005cd220..fc9ebf281 100644 --- a/pkg/aa/rlimit.go +++ b/pkg/aa/rlimit.go @@ -9,6 +9,15 @@ const ( tokSET = "set" ) +func init() { + requirements[tokRLIMIT] = requirement{ + "keys": { + "cpu", "fsize", "data", "stack", "core", "rss", "nofile", "ofile", + "as", "nproc", "memlock", "locks", "sigpending", "msgqueue", "nice", + "rtprio", "rttime", + }, + } +} type Rlimit struct { RuleBase diff --git a/pkg/aa/rules.go b/pkg/aa/rules.go index 7cb6dc1a8..26d90ba35 100644 --- a/pkg/aa/rules.go +++ b/pkg/aa/rules.go @@ -10,6 +10,8 @@ const ( tokDENY = "deny" ) +type requirement map[string][]string + type constraint uint const ( diff --git a/pkg/aa/signal.go b/pkg/aa/signal.go index 7daaa9a89..c1dc6803c 100644 --- a/pkg/aa/signal.go +++ b/pkg/aa/signal.go @@ -8,6 +8,27 @@ import "slices" const tokSIGNAL = "signal" +func init() { + requirements[tokSIGNAL] = requirement{ + "access": { + "r", "w", "rw", "read", "write", "send", "receive", + }, + "set": { + "hup", "int", "quit", "ill", "trap", "abrt", "bus", "fpe", + "kill", "usr1", "segv", "usr2", "pipe", "alrm", "term", "stkflt", + "chld", "cont", "stop", "stp", "ttin", "ttou", "urg", "xcpu", + "xfsz", "vtalrm", "prof", "winch", "io", "pwr", "sys", "emt", + "exists", "rtmin+0", "rtmin+1", "rtmin+2", "rtmin+3", "rtmin+4", + "rtmin+5", "rtmin+6", "rtmin+7", "rtmin+8", "rtmin+9", "rtmin+10", + "rtmin+11", "rtmin+12", "rtmin+13", "rtmin+14", "rtmin+15", + "rtmin+16", "rtmin+17", "rtmin+18", "rtmin+19", "rtmin+20", + "rtmin+21", "rtmin+22", "rtmin+23", "rtmin+24", "rtmin+25", + "rtmin+26", "rtmin+27", "rtmin+28", "rtmin+29", "rtmin+30", + "rtmin+31", "rtmin+32", + }, + } +} + type Signal struct { RuleBase Qualifier diff --git a/pkg/aa/template.go b/pkg/aa/template.go index c0b741480..0d81a7294 100644 --- a/pkg/aa/template.go +++ b/pkg/aa/template.go @@ -73,7 +73,7 @@ var ( "profile", "include_if_exists", } - ruleWeights = make(map[string]int, len(ruleAlphabet)) + ruleWeights = generateWeights(ruleAlphabet) // The order the apparmor file rules should be sorted fileAlphabet = []string{ @@ -100,9 +100,17 @@ var ( "deny", // 12. Deny rules "profile", // 13. Subprofiles } - fileWeights = make(map[string]int, len(fileAlphabet)) + fileWeights = generateWeights(fileAlphabet) + + // The order the rule values (access, type, domains, etc) should be sorted + requirements = map[string]requirement{} + requirementsWeights map[string]map[string]map[string]int ) +func init() { + requirementsWeights = generateRequirementsWeights(requirements) +} + func generateTemplates(names []string) map[string]*template.Template { res := make(map[string]*template.Template, len(names)) base := template.New("").Funcs(tmplFunctionMap) @@ -132,13 +140,23 @@ func renderTemplate(name string, data any) string { return res.String() } -func init() { - for i, r := range fileAlphabet { - fileWeights[r] = i +func generateWeights(alphabet []string) map[string]int { + res := make(map[string]int, len(alphabet)) + for i, r := range alphabet { + res[r] = i } - for i, r := range ruleAlphabet { - ruleWeights[r] = i + return res +} + +func generateRequirementsWeights(requirements map[string]requirement) map[string]map[string]map[string]int { + res := make(map[string]map[string]map[string]int, len(requirements)) + for rule, req := range requirements { + res[rule] = make(map[string]map[string]int, len(req)) + for key, values := range req { + res[rule][key] = generateWeights(values) + } } + return res } func join(i any) string { diff --git a/pkg/aa/unix.go b/pkg/aa/unix.go index f5915f018..3207f571e 100644 --- a/pkg/aa/unix.go +++ b/pkg/aa/unix.go @@ -8,6 +8,16 @@ import "slices" const tokUNIX = "unix" +func init() { + requirements[tokUNIX] = requirement{ + "access": []string{ + "create", "bind", "listen", "accept", "connect", "shutdown", + "getattr", "setattr", "getopt", "setopt", "send", "receive", + "r", "w", "rw", + }, + } +} + type Unix struct { RuleBase Qualifier