feat(aa): improve apparmor struct.
This commit is contained in:
parent
ea1736083a
commit
ab4feda5ba
28 changed files with 638 additions and 496 deletions
|
|
@ -5,23 +5,25 @@
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
type Capability struct {
|
type Capability struct {
|
||||||
|
Rule
|
||||||
Qualifier
|
Qualifier
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func CapabilityFromLog(log map[string]string) ApparmorRule {
|
func newCapabilityFromLog(log map[string]string) *Capability {
|
||||||
return &Capability{
|
return &Capability{
|
||||||
Qualifier: NewQualifierFromLog(log),
|
Rule: newRuleFromLog(log),
|
||||||
|
Qualifier: newQualifierFromLog(log),
|
||||||
Name: log["capname"],
|
Name: log["capname"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Capability) Less(other any) bool {
|
func (r *Capability) Less(other any) bool {
|
||||||
o, _ := other.(*Capability)
|
o, _ := other.(*Capability)
|
||||||
if r.Name == o.Name {
|
if r.Name != o.Name {
|
||||||
return r.Qualifier.Less(o.Qualifier)
|
return r.Name < o.Name
|
||||||
}
|
}
|
||||||
return r.Name < o.Name
|
return r.Qualifier.Less(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Capability) Equals(other any) bool {
|
func (r *Capability) Equals(other any) bool {
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,17 @@
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
type ChangeProfile struct {
|
type ChangeProfile struct {
|
||||||
|
Rule
|
||||||
Qualifier
|
Qualifier
|
||||||
ExecMode string
|
ExecMode string
|
||||||
Exec string
|
Exec string
|
||||||
ProfileName string
|
ProfileName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChangeProfileFromLog(log map[string]string) ApparmorRule {
|
func newChangeProfileFromLog(log map[string]string) *ChangeProfile {
|
||||||
return &ChangeProfile{
|
return &ChangeProfile{
|
||||||
Qualifier: NewQualifierFromLog(log),
|
Rule: newRuleFromLog(log),
|
||||||
|
Qualifier: newQualifierFromLog(log),
|
||||||
ExecMode: log["mode"],
|
ExecMode: log["mode"],
|
||||||
Exec: log["exec"],
|
Exec: log["exec"],
|
||||||
ProfileName: log["target"],
|
ProfileName: log["target"],
|
||||||
|
|
@ -22,16 +24,20 @@ func ChangeProfileFromLog(log map[string]string) ApparmorRule {
|
||||||
|
|
||||||
func (r *ChangeProfile) Less(other any) bool {
|
func (r *ChangeProfile) Less(other any) bool {
|
||||||
o, _ := other.(*ChangeProfile)
|
o, _ := other.(*ChangeProfile)
|
||||||
if r.ExecMode == o.ExecMode {
|
if r.ExecMode != o.ExecMode {
|
||||||
if r.Exec == o.Exec {
|
return r.ExecMode < o.ExecMode
|
||||||
return r.ProfileName < o.ProfileName
|
}
|
||||||
}
|
if r.Exec != o.Exec {
|
||||||
return r.Exec < o.Exec
|
return r.Exec < o.Exec
|
||||||
}
|
}
|
||||||
return r.ExecMode < o.ExecMode
|
if r.ProfileName != o.ProfileName {
|
||||||
|
return r.ProfileName < o.ProfileName
|
||||||
|
}
|
||||||
|
return r.Qualifier.Less(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ChangeProfile) Equals(other any) bool {
|
func (r *ChangeProfile) Equals(other any) bool {
|
||||||
o, _ := other.(*ChangeProfile)
|
o, _ := other.(*ChangeProfile)
|
||||||
return r.ExecMode == o.ExecMode && r.Exec == o.Exec && r.ProfileName == o.ProfileName
|
return r.ExecMode == o.ExecMode && r.Exec == o.Exec &&
|
||||||
|
r.ProfileName == o.ProfileName && r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,13 +71,13 @@ var (
|
||||||
"flags": "rw, rbind",
|
"flags": "rw, rbind",
|
||||||
}
|
}
|
||||||
mount1 = &Mount{
|
mount1 = &Mount{
|
||||||
Qualifier: Qualifier{Comment: "failed perms check"},
|
Rule: Rule{Comment: "failed perms check"},
|
||||||
MountConditions: MountConditions{FsType: "overlay"},
|
MountConditions: MountConditions{FsType: "overlay"},
|
||||||
Source: "overlay",
|
Source: "overlay",
|
||||||
MountPoint: "/var/lib/docker/overlay2/opaque-bug-check1209538631/merged/",
|
MountPoint: "/var/lib/docker/overlay2/opaque-bug-check1209538631/merged/",
|
||||||
}
|
}
|
||||||
mount2 = &Mount{
|
mount2 = &Mount{
|
||||||
Qualifier: Qualifier{Comment: "failed perms check"},
|
Rule: Rule{Comment: "failed perms check"},
|
||||||
MountConditions: MountConditions{Options: []string{"rw", "rbind"}},
|
MountConditions: MountConditions{Options: []string{"rw", "rbind"}},
|
||||||
Source: "/oldroot/dev/tty",
|
Source: "/oldroot/dev/tty",
|
||||||
MountPoint: "/newroot/dev/tty",
|
MountPoint: "/newroot/dev/tty",
|
||||||
|
|
@ -197,17 +197,17 @@ var (
|
||||||
"protocol": "0",
|
"protocol": "0",
|
||||||
}
|
}
|
||||||
unix1 = &Unix{
|
unix1 = &Unix{
|
||||||
Access: "send receive",
|
Access: "send receive",
|
||||||
Type: "stream",
|
Type: "stream",
|
||||||
Protocol: "0",
|
Protocol: "0",
|
||||||
Address: "none",
|
Address: "none",
|
||||||
Peer: "dbus-daemon",
|
PeerAddr: "@/tmp/dbus-AaKMpxzC4k",
|
||||||
PeerAddr: "@/tmp/dbus-AaKMpxzC4k",
|
PeerLabel: "dbus-daemon",
|
||||||
}
|
}
|
||||||
unix2 = &Unix{
|
unix2 = &Unix{
|
||||||
Qualifier: Qualifier{FileInherit: true},
|
Rule: Rule{FileInherit: true},
|
||||||
Access: "receive",
|
Access: "receive",
|
||||||
Type: "stream",
|
Type: "stream",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dbus
|
// Dbus
|
||||||
|
|
@ -236,11 +236,11 @@ var (
|
||||||
dbus1 = &Dbus{
|
dbus1 = &Dbus{
|
||||||
Access: "receive",
|
Access: "receive",
|
||||||
Bus: "session",
|
Bus: "session",
|
||||||
Name: ":1.15",
|
|
||||||
Path: "/org/gtk/vfs/metadata",
|
Path: "/org/gtk/vfs/metadata",
|
||||||
Interface: "org.gtk.vfs.Metadata",
|
Interface: "org.gtk.vfs.Metadata",
|
||||||
Member: "Remove",
|
Member: "Remove",
|
||||||
Label: "tracker-extract",
|
PeerName: ":1.15",
|
||||||
|
PeerLabel: "tracker-extract",
|
||||||
}
|
}
|
||||||
dbus2 = &Dbus{
|
dbus2 = &Dbus{
|
||||||
Access: "bind",
|
Access: "bind",
|
||||||
|
|
@ -285,8 +285,9 @@ var (
|
||||||
}
|
}
|
||||||
file1 = &File{Path: "/usr/share/poppler/cMap/Identity-H", Access: "r"}
|
file1 = &File{Path: "/usr/share/poppler/cMap/Identity-H", Access: "r"}
|
||||||
file2 = &File{
|
file2 = &File{
|
||||||
Qualifier: Qualifier{Owner: true, NoNewPrivs: true},
|
Rule: Rule{NoNewPrivs: true},
|
||||||
Path: "@{PROC}/4163/cgroup",
|
Owner: true,
|
||||||
Access: "r",
|
Path: "@{PROC}/4163/cgroup",
|
||||||
|
Access: "r",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
type Dbus struct {
|
type Dbus struct {
|
||||||
|
Rule
|
||||||
Qualifier
|
Qualifier
|
||||||
Access string
|
Access string
|
||||||
Bus string
|
Bus string
|
||||||
|
|
@ -12,45 +13,58 @@ type Dbus struct {
|
||||||
Path string
|
Path string
|
||||||
Interface string
|
Interface string
|
||||||
Member string
|
Member string
|
||||||
Label string
|
PeerName string
|
||||||
|
PeerLabel string
|
||||||
}
|
}
|
||||||
|
|
||||||
func DbusFromLog(log map[string]string) ApparmorRule {
|
func newDbusFromLog(log map[string]string) *Dbus {
|
||||||
|
name := ""
|
||||||
|
peerName := ""
|
||||||
|
if log["mask"] == "bind" {
|
||||||
|
name = log["name"]
|
||||||
|
} else {
|
||||||
|
peerName = log["name"]
|
||||||
|
}
|
||||||
return &Dbus{
|
return &Dbus{
|
||||||
Qualifier: NewQualifierFromLog(log),
|
Rule: newRuleFromLog(log),
|
||||||
|
Qualifier: newQualifierFromLog(log),
|
||||||
Access: log["mask"],
|
Access: log["mask"],
|
||||||
Bus: log["bus"],
|
Bus: log["bus"],
|
||||||
Name: log["name"],
|
Name: name,
|
||||||
Path: log["path"],
|
Path: log["path"],
|
||||||
Interface: log["interface"],
|
Interface: log["interface"],
|
||||||
Member: log["member"],
|
Member: log["member"],
|
||||||
Label: log["peer_label"],
|
PeerName: peerName,
|
||||||
|
PeerLabel: log["peer_label"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Dbus) Less(other any) bool {
|
func (r *Dbus) Less(other any) bool {
|
||||||
o, _ := other.(*Dbus)
|
o, _ := other.(*Dbus)
|
||||||
if r.Qualifier.Equals(o.Qualifier) {
|
if r.Access != o.Access {
|
||||||
if r.Access == o.Access {
|
|
||||||
if r.Bus == o.Bus {
|
|
||||||
if r.Name == o.Name {
|
|
||||||
if r.Path == o.Path {
|
|
||||||
if r.Interface == o.Interface {
|
|
||||||
if r.Member == o.Member {
|
|
||||||
return r.Label < o.Label
|
|
||||||
}
|
|
||||||
return r.Member < o.Member
|
|
||||||
}
|
|
||||||
return r.Interface < o.Interface
|
|
||||||
}
|
|
||||||
return r.Path < o.Path
|
|
||||||
}
|
|
||||||
return r.Name < o.Name
|
|
||||||
}
|
|
||||||
return r.Bus < o.Bus
|
|
||||||
}
|
|
||||||
return r.Access < o.Access
|
return r.Access < o.Access
|
||||||
}
|
}
|
||||||
|
if r.Bus != o.Bus {
|
||||||
|
return r.Bus < o.Bus
|
||||||
|
}
|
||||||
|
if r.Name != o.Name {
|
||||||
|
return r.Name < o.Name
|
||||||
|
}
|
||||||
|
if r.Path != o.Path {
|
||||||
|
return r.Path < o.Path
|
||||||
|
}
|
||||||
|
if r.Interface != o.Interface {
|
||||||
|
return r.Interface < o.Interface
|
||||||
|
}
|
||||||
|
if r.Member != o.Member {
|
||||||
|
return r.Member < o.Member
|
||||||
|
}
|
||||||
|
if r.PeerName != o.PeerName {
|
||||||
|
return r.PeerName < o.PeerName
|
||||||
|
}
|
||||||
|
if r.PeerLabel != o.PeerLabel {
|
||||||
|
return r.PeerLabel < o.PeerLabel
|
||||||
|
}
|
||||||
return r.Qualifier.Less(o.Qualifier)
|
return r.Qualifier.Less(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,5 +72,6 @@ func (r *Dbus) Equals(other any) bool {
|
||||||
o, _ := other.(*Dbus)
|
o, _ := other.(*Dbus)
|
||||||
return r.Access == o.Access && r.Bus == o.Bus && r.Name == o.Name &&
|
return r.Access == o.Access && r.Bus == o.Bus && r.Name == o.Name &&
|
||||||
r.Path == o.Path && r.Interface == o.Interface &&
|
r.Path == o.Path && r.Interface == o.Interface &&
|
||||||
r.Member == o.Member && r.Label == o.Label && r.Qualifier.Equals(o.Qualifier)
|
r.Member == o.Member && r.PeerName == o.PeerName &&
|
||||||
|
r.PeerLabel == o.PeerLabel && r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,26 @@
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
type File struct {
|
type File struct {
|
||||||
|
Rule
|
||||||
Qualifier
|
Qualifier
|
||||||
|
Owner bool
|
||||||
Path string
|
Path string
|
||||||
Access string
|
Access string
|
||||||
Target string
|
Target string
|
||||||
}
|
}
|
||||||
|
|
||||||
func FileFromLog(log map[string]string) ApparmorRule {
|
func newFileFromLog(log map[string]string) *File {
|
||||||
|
owner := false
|
||||||
|
fsuid, hasFsUID := log["fsuid"]
|
||||||
|
ouid, hasOuUID := log["ouid"]
|
||||||
|
isDbus := strings.Contains(log["operation"], "dbus")
|
||||||
|
if hasFsUID && hasOuUID && fsuid == ouid && ouid != "0" && !isDbus {
|
||||||
|
owner = true
|
||||||
|
}
|
||||||
return &File{
|
return &File{
|
||||||
Qualifier: NewQualifierFromLog(log),
|
Rule: newRuleFromLog(log),
|
||||||
|
Qualifier: newQualifierFromLog(log),
|
||||||
|
Owner: owner,
|
||||||
Path: log["name"],
|
Path: log["name"],
|
||||||
Access: toAccess(log["requested_mask"]),
|
Access: toAccess(log["requested_mask"]),
|
||||||
Target: log["target"],
|
Target: log["target"],
|
||||||
|
|
@ -24,23 +35,26 @@ func (r *File) Less(other any) bool {
|
||||||
o, _ := other.(*File)
|
o, _ := other.(*File)
|
||||||
letterR := getLetterIn(fileAlphabet, r.Path)
|
letterR := getLetterIn(fileAlphabet, r.Path)
|
||||||
letterO := getLetterIn(fileAlphabet, o.Path)
|
letterO := getLetterIn(fileAlphabet, o.Path)
|
||||||
if fileWeights[letterR] == fileWeights[letterO] || letterR == "" || letterO == "" {
|
if fileWeights[letterR] != fileWeights[letterO] && letterR != "" && letterO != "" {
|
||||||
if r.Qualifier.Equals(o.Qualifier) {
|
return fileWeights[letterR] < fileWeights[letterO]
|
||||||
if r.Path == o.Path {
|
|
||||||
if r.Access == o.Access {
|
|
||||||
return r.Target < o.Target
|
|
||||||
}
|
|
||||||
return r.Access < o.Access
|
|
||||||
}
|
|
||||||
return r.Path < o.Path
|
|
||||||
}
|
|
||||||
return r.Qualifier.Less(o.Qualifier)
|
|
||||||
}
|
}
|
||||||
return fileWeights[letterR] < fileWeights[letterO]
|
if r.Path != o.Path {
|
||||||
|
return r.Path < o.Path
|
||||||
|
}
|
||||||
|
if r.Access != o.Access {
|
||||||
|
return r.Access < o.Access
|
||||||
|
}
|
||||||
|
if r.Target != o.Target {
|
||||||
|
return r.Target < o.Target
|
||||||
|
}
|
||||||
|
if o.Owner != r.Owner {
|
||||||
|
return r.Owner
|
||||||
|
}
|
||||||
|
return r.Qualifier.Less(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *File) Equals(other any) bool {
|
func (r *File) Equals(other any) bool {
|
||||||
o, _ := other.(*File)
|
o, _ := other.(*File)
|
||||||
return r.Path == o.Path && r.Access == o.Access &&
|
return r.Path == o.Path && r.Access == o.Access && r.Owner == o.Owner &&
|
||||||
r.Target == o.Target && r.Qualifier.Equals(o.Qualifier)
|
r.Target == o.Target && r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
// apparmor.d - Full set of apparmor profiles
|
|
||||||
// Copyright (C) 2021-2024 Alexandre Pujol <alexandre@pujol.io>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
|
|
||||||
package aa
|
|
||||||
|
|
||||||
type Include struct {
|
|
||||||
IfExists bool
|
|
||||||
Path string
|
|
||||||
IsMagic bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Include) Less(other any) bool {
|
|
||||||
o, _ := other.(*Include)
|
|
||||||
if r.Path == o.Path {
|
|
||||||
if r.IsMagic == o.IsMagic {
|
|
||||||
return r.IfExists
|
|
||||||
}
|
|
||||||
return r.IsMagic
|
|
||||||
}
|
|
||||||
return r.Path < o.Path
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Include) Equals(other any) bool {
|
|
||||||
o, _ := other.(*Include)
|
|
||||||
return r.Path == o.Path && r.IsMagic == o.IsMagic &&
|
|
||||||
r.IfExists == o.IfExists
|
|
||||||
}
|
|
||||||
|
|
@ -5,19 +5,29 @@
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
type IOUring struct {
|
type IOUring struct {
|
||||||
|
Rule
|
||||||
Qualifier
|
Qualifier
|
||||||
Access string
|
Access string
|
||||||
Label string
|
Label string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newIOUringFromLog(log map[string]string) *IOUring {
|
||||||
|
return &IOUring{
|
||||||
|
Rule: newRuleFromLog(log),
|
||||||
|
Qualifier: newQualifierFromLog(log),
|
||||||
|
Access: toAccess(log["requested"]),
|
||||||
|
Label: log["label"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (r *IOUring) Less(other any) bool {
|
func (r *IOUring) Less(other any) bool {
|
||||||
o, _ := other.(*IOUring)
|
o, _ := other.(*IOUring)
|
||||||
if r.Qualifier.Equals(o.Qualifier) {
|
if r.Access != o.Access {
|
||||||
if r.Access == o.Access {
|
|
||||||
return r.Label < o.Label
|
|
||||||
}
|
|
||||||
return r.Access < o.Access
|
return r.Access < o.Access
|
||||||
}
|
}
|
||||||
|
if r.Label != o.Label {
|
||||||
|
return r.Label < o.Label
|
||||||
|
}
|
||||||
return r.Qualifier.Less(o.Qualifier)
|
return r.Qualifier.Less(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ type MountConditions struct {
|
||||||
Options []string
|
Options []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func MountConditionsFromLog(log map[string]string) MountConditions {
|
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"],
|
||||||
|
|
@ -26,10 +26,10 @@ func MountConditionsFromLog(log map[string]string) MountConditions {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m MountConditions) Less(other MountConditions) bool {
|
func (m MountConditions) Less(other MountConditions) bool {
|
||||||
if m.FsType == other.FsType {
|
if m.FsType != other.FsType {
|
||||||
return len(m.Options) < len(other.Options)
|
return m.FsType < other.FsType
|
||||||
}
|
}
|
||||||
return m.FsType < other.FsType
|
return len(m.Options) < len(other.Options)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m MountConditions) Equals(other MountConditions) bool {
|
func (m MountConditions) Equals(other MountConditions) bool {
|
||||||
|
|
@ -37,16 +37,18 @@ func (m MountConditions) Equals(other MountConditions) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mount struct {
|
type Mount struct {
|
||||||
|
Rule
|
||||||
Qualifier
|
Qualifier
|
||||||
MountConditions
|
MountConditions
|
||||||
Source string
|
Source string
|
||||||
MountPoint string
|
MountPoint string
|
||||||
}
|
}
|
||||||
|
|
||||||
func MountFromLog(log map[string]string) ApparmorRule {
|
func newMountFromLog(log map[string]string) *Mount {
|
||||||
return &Mount{
|
return &Mount{
|
||||||
Qualifier: NewQualifierFromLog(log),
|
Rule: newRuleFromLog(log),
|
||||||
MountConditions: MountConditionsFromLog(log),
|
Qualifier: newQualifierFromLog(log),
|
||||||
|
MountConditions: newMountConditionsFromLog(log),
|
||||||
Source: log["srcname"],
|
Source: log["srcname"],
|
||||||
MountPoint: log["name"],
|
MountPoint: log["name"],
|
||||||
}
|
}
|
||||||
|
|
@ -54,15 +56,15 @@ func MountFromLog(log map[string]string) ApparmorRule {
|
||||||
|
|
||||||
func (r *Mount) Less(other any) bool {
|
func (r *Mount) Less(other any) bool {
|
||||||
o, _ := other.(*Mount)
|
o, _ := other.(*Mount)
|
||||||
if r.Qualifier.Equals(o.Qualifier) {
|
if r.Source != o.Source {
|
||||||
if r.Source == o.Source {
|
|
||||||
if r.MountPoint == o.MountPoint {
|
|
||||||
return r.MountConditions.Less(o.MountConditions)
|
|
||||||
}
|
|
||||||
return r.MountPoint < o.MountPoint
|
|
||||||
}
|
|
||||||
return r.Source < o.Source
|
return r.Source < o.Source
|
||||||
}
|
}
|
||||||
|
if r.MountPoint != o.MountPoint {
|
||||||
|
return r.MountPoint < o.MountPoint
|
||||||
|
}
|
||||||
|
if r.MountConditions.Equals(o.MountConditions) {
|
||||||
|
return r.MountConditions.Less(o.MountConditions)
|
||||||
|
}
|
||||||
return r.Qualifier.Less(o.Qualifier)
|
return r.Qualifier.Less(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,27 +76,29 @@ func (r *Mount) Equals(other any) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Umount struct {
|
type Umount struct {
|
||||||
|
Rule
|
||||||
Qualifier
|
Qualifier
|
||||||
MountConditions
|
MountConditions
|
||||||
MountPoint string
|
MountPoint string
|
||||||
}
|
}
|
||||||
|
|
||||||
func UmountFromLog(log map[string]string) ApparmorRule {
|
func newUmountFromLog(log map[string]string) *Umount {
|
||||||
return &Umount{
|
return &Umount{
|
||||||
Qualifier: NewQualifierFromLog(log),
|
Rule: newRuleFromLog(log),
|
||||||
MountConditions: MountConditionsFromLog(log),
|
Qualifier: newQualifierFromLog(log),
|
||||||
|
MountConditions: newMountConditionsFromLog(log),
|
||||||
MountPoint: log["name"],
|
MountPoint: log["name"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Umount) Less(other any) bool {
|
func (r *Umount) Less(other any) bool {
|
||||||
o, _ := other.(*Umount)
|
o, _ := other.(*Umount)
|
||||||
if r.Qualifier.Equals(o.Qualifier) {
|
if r.MountPoint != o.MountPoint {
|
||||||
if r.MountPoint == o.MountPoint {
|
|
||||||
return r.MountConditions.Less(o.MountConditions)
|
|
||||||
}
|
|
||||||
return r.MountPoint < o.MountPoint
|
return r.MountPoint < o.MountPoint
|
||||||
}
|
}
|
||||||
|
if r.MountConditions.Equals(o.MountConditions) {
|
||||||
|
return r.MountConditions.Less(o.MountConditions)
|
||||||
|
}
|
||||||
return r.Qualifier.Less(o.Qualifier)
|
return r.Qualifier.Less(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,27 +110,29 @@ func (r *Umount) Equals(other any) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Remount struct {
|
type Remount struct {
|
||||||
|
Rule
|
||||||
Qualifier
|
Qualifier
|
||||||
MountConditions
|
MountConditions
|
||||||
MountPoint string
|
MountPoint string
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemountFromLog(log map[string]string) ApparmorRule {
|
func newRemountFromLog(log map[string]string) *Remount {
|
||||||
return &Remount{
|
return &Remount{
|
||||||
Qualifier: NewQualifierFromLog(log),
|
Rule: newRuleFromLog(log),
|
||||||
MountConditions: MountConditionsFromLog(log),
|
Qualifier: newQualifierFromLog(log),
|
||||||
|
MountConditions: newMountConditionsFromLog(log),
|
||||||
MountPoint: log["name"],
|
MountPoint: log["name"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Remount) Less(other any) bool {
|
func (r *Remount) Less(other any) bool {
|
||||||
o, _ := other.(*Remount)
|
o, _ := other.(*Remount)
|
||||||
if r.Qualifier.Equals(o.Qualifier) {
|
if r.MountPoint != o.MountPoint {
|
||||||
if r.MountPoint == o.MountPoint {
|
|
||||||
return r.MountConditions.Less(o.MountConditions)
|
|
||||||
}
|
|
||||||
return r.MountPoint < o.MountPoint
|
return r.MountPoint < o.MountPoint
|
||||||
}
|
}
|
||||||
|
if r.MountConditions.Equals(o.MountConditions) {
|
||||||
|
return r.MountConditions.Less(o.MountConditions)
|
||||||
|
}
|
||||||
return r.Qualifier.Less(o.Qualifier)
|
return r.Qualifier.Less(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,12 @@
|
||||||
|
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
type Mqueue struct {
|
type Mqueue struct {
|
||||||
|
Rule
|
||||||
Qualifier
|
Qualifier
|
||||||
Access string
|
Access string
|
||||||
Type string
|
Type string
|
||||||
|
|
@ -14,7 +17,7 @@ type Mqueue struct {
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func MqueueFromLog(log map[string]string) ApparmorRule {
|
func newMqueueFromLog(log map[string]string) *Mqueue {
|
||||||
mqueueType := "posix"
|
mqueueType := "posix"
|
||||||
if strings.Contains(log["class"], "posix") {
|
if strings.Contains(log["class"], "posix") {
|
||||||
mqueueType = "posix"
|
mqueueType = "posix"
|
||||||
|
|
@ -22,7 +25,8 @@ func MqueueFromLog(log map[string]string) ApparmorRule {
|
||||||
mqueueType = "sysv"
|
mqueueType = "sysv"
|
||||||
}
|
}
|
||||||
return &Mqueue{
|
return &Mqueue{
|
||||||
Qualifier: NewQualifierFromLog(log),
|
Rule: newRuleFromLog(log),
|
||||||
|
Qualifier: newQualifierFromLog(log),
|
||||||
Access: toAccess(log["requested"]),
|
Access: toAccess(log["requested"]),
|
||||||
Type: mqueueType,
|
Type: mqueueType,
|
||||||
Label: log["label"],
|
Label: log["label"],
|
||||||
|
|
@ -32,19 +36,20 @@ func MqueueFromLog(log map[string]string) ApparmorRule {
|
||||||
|
|
||||||
func (r *Mqueue) Less(other any) bool {
|
func (r *Mqueue) Less(other any) bool {
|
||||||
o, _ := other.(*Mqueue)
|
o, _ := other.(*Mqueue)
|
||||||
if r.Qualifier.Equals(o.Qualifier) {
|
if r.Access != o.Access {
|
||||||
if r.Access == o.Access {
|
|
||||||
if r.Type == o.Type {
|
|
||||||
return r.Label < o.Label
|
|
||||||
}
|
|
||||||
return r.Type < o.Type
|
|
||||||
}
|
|
||||||
return r.Access < o.Access
|
return r.Access < o.Access
|
||||||
}
|
}
|
||||||
|
if r.Type != o.Type {
|
||||||
|
return r.Type < o.Type
|
||||||
|
}
|
||||||
|
if r.Label != o.Label {
|
||||||
|
return r.Label < o.Label
|
||||||
|
}
|
||||||
return r.Qualifier.Less(o.Qualifier)
|
return r.Qualifier.Less(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Mqueue) Equals(other any) bool {
|
func (r *Mqueue) Equals(other any) bool {
|
||||||
o, _ := other.(*Mqueue)
|
o, _ := other.(*Mqueue)
|
||||||
return r.Access == o.Access && r.Type == o.Type && r.Label == o.Label && r.Qualifier.Equals(o.Qualifier)
|
return r.Access == o.Access && r.Type == o.Type && r.Label == o.Label &&
|
||||||
|
r.Name == o.Name && r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,54 +10,63 @@ type AddressExpr struct {
|
||||||
Port string
|
Port string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newAddressExprFromLog(log map[string]string) AddressExpr {
|
||||||
|
return AddressExpr{
|
||||||
|
Source: log["laddr"],
|
||||||
|
Destination: log["faddr"],
|
||||||
|
Port: log["lport"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r AddressExpr) Less(other AddressExpr) bool {
|
||||||
|
if r.Source != other.Source {
|
||||||
|
return r.Source < other.Source
|
||||||
|
}
|
||||||
|
if r.Destination != other.Destination {
|
||||||
|
return r.Destination < other.Destination
|
||||||
|
}
|
||||||
|
return r.Port < other.Port
|
||||||
|
}
|
||||||
|
|
||||||
func (r AddressExpr) Equals(other AddressExpr) bool {
|
func (r AddressExpr) Equals(other AddressExpr) bool {
|
||||||
return r.Source == other.Source && r.Destination == other.Destination &&
|
return r.Source == other.Source && r.Destination == other.Destination &&
|
||||||
r.Port == other.Port
|
r.Port == other.Port
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r AddressExpr) Less(other AddressExpr) bool {
|
|
||||||
if r.Source == other.Source {
|
|
||||||
if r.Destination == other.Destination {
|
|
||||||
return r.Port < other.Port
|
|
||||||
}
|
|
||||||
return r.Destination < other.Destination
|
|
||||||
}
|
|
||||||
return r.Source < other.Source
|
|
||||||
}
|
|
||||||
|
|
||||||
type Network struct {
|
type Network struct {
|
||||||
|
Rule
|
||||||
Qualifier
|
Qualifier
|
||||||
|
AddressExpr
|
||||||
Domain string
|
Domain string
|
||||||
Type string
|
Type string
|
||||||
Protocol string
|
Protocol string
|
||||||
AddressExpr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NetworkFromLog(log map[string]string) ApparmorRule {
|
func newNetworkFromLog(log map[string]string) *Network {
|
||||||
return &Network{
|
return &Network{
|
||||||
Qualifier: NewQualifierFromLog(log),
|
Rule: newRuleFromLog(log),
|
||||||
AddressExpr: AddressExpr{
|
Qualifier: newQualifierFromLog(log),
|
||||||
Source: log["laddr"],
|
AddressExpr: newAddressExprFromLog(log),
|
||||||
Destination: log["faddr"],
|
Domain: log["family"],
|
||||||
Port: log["lport"],
|
Type: log["sock_type"],
|
||||||
},
|
Protocol: log["protocol"],
|
||||||
Domain: log["family"],
|
|
||||||
Type: log["sock_type"],
|
|
||||||
Protocol: log["protocol"],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Network) Less(other any) bool {
|
func (r *Network) Less(other any) bool {
|
||||||
o, _ := other.(*Network)
|
o, _ := other.(*Network)
|
||||||
if r.Qualifier.Equals(o.Qualifier) {
|
if r.Domain != o.Domain {
|
||||||
if r.Domain == o.Domain {
|
|
||||||
if r.Type == o.Type {
|
|
||||||
return r.Protocol < o.Protocol
|
|
||||||
}
|
|
||||||
return r.Type < o.Type
|
|
||||||
}
|
|
||||||
return r.Domain < o.Domain
|
return r.Domain < o.Domain
|
||||||
}
|
}
|
||||||
|
if r.Type != o.Type {
|
||||||
|
return r.Type < o.Type
|
||||||
|
}
|
||||||
|
if r.Protocol != o.Protocol {
|
||||||
|
return r.Protocol < o.Protocol
|
||||||
|
}
|
||||||
|
if r.AddressExpr.Less(o.AddressExpr) {
|
||||||
|
return r.AddressExpr.Less(o.AddressExpr)
|
||||||
|
}
|
||||||
return r.Qualifier.Less(o.Qualifier)
|
return r.Qualifier.Less(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,17 @@
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
type PivotRoot struct {
|
type PivotRoot struct {
|
||||||
|
Rule
|
||||||
Qualifier
|
Qualifier
|
||||||
OldRoot string
|
OldRoot string
|
||||||
NewRoot string
|
NewRoot string
|
||||||
TargetProfile string
|
TargetProfile string
|
||||||
}
|
}
|
||||||
|
|
||||||
func PivotRootFromLog(log map[string]string) ApparmorRule {
|
func newPivotRootFromLog(log map[string]string) *PivotRoot {
|
||||||
return &PivotRoot{
|
return &PivotRoot{
|
||||||
Qualifier: NewQualifierFromLog(log),
|
Rule: newRuleFromLog(log),
|
||||||
|
Qualifier: newQualifierFromLog(log),
|
||||||
OldRoot: log["srcname"],
|
OldRoot: log["srcname"],
|
||||||
NewRoot: log["name"],
|
NewRoot: log["name"],
|
||||||
TargetProfile: "",
|
TargetProfile: "",
|
||||||
|
|
@ -22,15 +24,15 @@ func PivotRootFromLog(log map[string]string) ApparmorRule {
|
||||||
|
|
||||||
func (r *PivotRoot) Less(other any) bool {
|
func (r *PivotRoot) Less(other any) bool {
|
||||||
o, _ := other.(*PivotRoot)
|
o, _ := other.(*PivotRoot)
|
||||||
if r.Qualifier.Equals(o.Qualifier) {
|
if r.OldRoot != o.OldRoot {
|
||||||
if r.OldRoot == o.OldRoot {
|
|
||||||
if r.NewRoot == o.NewRoot {
|
|
||||||
return r.TargetProfile < o.TargetProfile
|
|
||||||
}
|
|
||||||
return r.NewRoot < o.NewRoot
|
|
||||||
}
|
|
||||||
return r.OldRoot < o.OldRoot
|
return r.OldRoot < o.OldRoot
|
||||||
}
|
}
|
||||||
|
if r.NewRoot != o.NewRoot {
|
||||||
|
return r.NewRoot < o.NewRoot
|
||||||
|
}
|
||||||
|
if r.TargetProfile != o.TargetProfile {
|
||||||
|
return r.TargetProfile < o.TargetProfile
|
||||||
|
}
|
||||||
return r.Qualifier.Less(o.Qualifier)
|
return r.Qualifier.Less(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
87
pkg/aa/preamble.go
Normal file
87
pkg/aa/preamble.go
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
// apparmor.d - Full set of apparmor profiles
|
||||||
|
// Copyright (C) 2021-2024 Alexandre Pujol <alexandre@pujol.io>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
package aa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Abi struct {
|
||||||
|
Rule
|
||||||
|
Path string
|
||||||
|
IsMagic bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Abi) Less(other any) bool {
|
||||||
|
o, _ := other.(*Abi)
|
||||||
|
if r.Path != o.Path {
|
||||||
|
return r.Path < o.Path
|
||||||
|
}
|
||||||
|
return r.IsMagic == o.IsMagic
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Abi) Equals(other any) bool {
|
||||||
|
o, _ := other.(*Abi)
|
||||||
|
return r.Path == o.Path && r.IsMagic == o.IsMagic
|
||||||
|
}
|
||||||
|
|
||||||
|
type Alias struct {
|
||||||
|
Rule
|
||||||
|
Path string
|
||||||
|
RewrittenPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Alias) Less(other any) bool {
|
||||||
|
o, _ := other.(*Alias)
|
||||||
|
if r.Path != o.Path {
|
||||||
|
return r.Path < o.Path
|
||||||
|
}
|
||||||
|
return r.RewrittenPath < o.RewrittenPath
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Alias) Equals(other any) bool {
|
||||||
|
o, _ := other.(*Alias)
|
||||||
|
return r.Path == o.Path && r.RewrittenPath == o.RewrittenPath
|
||||||
|
}
|
||||||
|
|
||||||
|
type Include struct {
|
||||||
|
Rule
|
||||||
|
IfExists bool
|
||||||
|
Path string
|
||||||
|
IsMagic bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Include) Less(other any) bool {
|
||||||
|
o, _ := other.(*Include)
|
||||||
|
if r.Path == o.Path {
|
||||||
|
return r.Path < o.Path
|
||||||
|
}
|
||||||
|
if r.IsMagic != o.IsMagic {
|
||||||
|
return r.IsMagic
|
||||||
|
}
|
||||||
|
return r.IfExists
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Include) Equals(other any) bool {
|
||||||
|
o, _ := other.(*Include)
|
||||||
|
return r.Path == o.Path && r.IsMagic == o.IsMagic && r.IfExists == o.IfExists
|
||||||
|
}
|
||||||
|
|
||||||
|
type Variable struct {
|
||||||
|
Rule
|
||||||
|
Name string
|
||||||
|
Values []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Variable) Less(other Variable) bool {
|
||||||
|
if r.Name != other.Name {
|
||||||
|
return r.Name < other.Name
|
||||||
|
}
|
||||||
|
return len(r.Values) < len(other.Values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Variable) Equals(other Variable) bool {
|
||||||
|
return r.Name == other.Name && slices.Equal(r.Values, other.Values)
|
||||||
|
}
|
||||||
|
|
@ -31,10 +31,10 @@ type AppArmorProfile struct {
|
||||||
|
|
||||||
// Preamble section of a profile
|
// Preamble section of a profile
|
||||||
type Preamble struct {
|
type Preamble struct {
|
||||||
Abi []Abi
|
Abi []*Abi
|
||||||
Includes []Include
|
Includes []*Include
|
||||||
Aliases []Alias
|
Aliases []*Alias
|
||||||
Variables []Variable
|
Variables []*Variable
|
||||||
}
|
}
|
||||||
|
|
||||||
// Profile section of a profile
|
// Profile section of a profile
|
||||||
|
|
@ -78,7 +78,7 @@ func (p *AppArmorProfile) AddRule(log map[string]string) {
|
||||||
}
|
}
|
||||||
case "-13":
|
case "-13":
|
||||||
if strings.Contains(log["info"], "namespace creation restricted") {
|
if strings.Contains(log["info"], "namespace creation restricted") {
|
||||||
p.Rules = append(p.Rules, UsernsFromLog(log))
|
p.Rules = append(p.Rules, newUsernsFromLog(log))
|
||||||
} else if strings.Contains(log["info"], "disconnected path") && !slices.Contains(p.Flags, "attach_disconnected") {
|
} else if strings.Contains(log["info"], "disconnected path") && !slices.Contains(p.Flags, "attach_disconnected") {
|
||||||
p.Flags = append(p.Flags, "attach_disconnected")
|
p.Flags = append(p.Flags, "attach_disconnected")
|
||||||
}
|
}
|
||||||
|
|
@ -87,49 +87,51 @@ func (p *AppArmorProfile) AddRule(log map[string]string) {
|
||||||
|
|
||||||
switch log["class"] {
|
switch log["class"] {
|
||||||
case "cap":
|
case "cap":
|
||||||
p.Rules = append(p.Rules, CapabilityFromLog(log))
|
p.Rules = append(p.Rules, newCapabilityFromLog(log))
|
||||||
case "net":
|
case "net":
|
||||||
if log["family"] == "unix" {
|
if log["family"] == "unix" {
|
||||||
p.Rules = append(p.Rules, UnixFromLog(log))
|
p.Rules = append(p.Rules, newUnixFromLog(log))
|
||||||
} else {
|
} else {
|
||||||
p.Rules = append(p.Rules, NetworkFromLog(log))
|
p.Rules = append(p.Rules, newNetworkFromLog(log))
|
||||||
}
|
}
|
||||||
case "mount":
|
case "mount":
|
||||||
if strings.Contains(log["flags"], "remount") {
|
if strings.Contains(log["flags"], "remount") {
|
||||||
p.Rules = append(p.Rules, RemountFromLog(log))
|
p.Rules = append(p.Rules, newRemountFromLog(log))
|
||||||
} else {
|
} else {
|
||||||
switch log["operation"] {
|
switch log["operation"] {
|
||||||
case "mount":
|
case "mount":
|
||||||
p.Rules = append(p.Rules, MountFromLog(log))
|
p.Rules = append(p.Rules, newMountFromLog(log))
|
||||||
case "umount":
|
case "umount":
|
||||||
p.Rules = append(p.Rules, UmountFromLog(log))
|
p.Rules = append(p.Rules, newUmountFromLog(log))
|
||||||
case "remount":
|
case "remount":
|
||||||
p.Rules = append(p.Rules, RemountFromLog(log))
|
p.Rules = append(p.Rules, newRemountFromLog(log))
|
||||||
case "pivotroot":
|
case "pivotroot":
|
||||||
p.Rules = append(p.Rules, PivotRootFromLog(log))
|
p.Rules = append(p.Rules, newPivotRootFromLog(log))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "posix_mqueue", "sysv_mqueue":
|
case "posix_mqueue", "sysv_mqueue":
|
||||||
p.Rules = append(p.Rules, MqueueFromLog(log))
|
p.Rules = append(p.Rules, newMqueueFromLog(log))
|
||||||
case "signal":
|
case "signal":
|
||||||
p.Rules = append(p.Rules, SignalFromLog(log))
|
p.Rules = append(p.Rules, newSignalFromLog(log))
|
||||||
case "ptrace":
|
case "ptrace":
|
||||||
p.Rules = append(p.Rules, PtraceFromLog(log))
|
p.Rules = append(p.Rules, newPtraceFromLog(log))
|
||||||
case "namespace":
|
case "namespace":
|
||||||
p.Rules = append(p.Rules, UsernsFromLog(log))
|
p.Rules = append(p.Rules, newUsernsFromLog(log))
|
||||||
case "unix":
|
case "unix":
|
||||||
p.Rules = append(p.Rules, UnixFromLog(log))
|
p.Rules = append(p.Rules, newUnixFromLog(log))
|
||||||
|
case "dbus":
|
||||||
|
p.Rules = append(p.Rules, newDbusFromLog(log))
|
||||||
case "file":
|
case "file":
|
||||||
if log["operation"] == "change_onexec" {
|
if log["operation"] == "change_onexec" {
|
||||||
p.Rules = append(p.Rules, ChangeProfileFromLog(log))
|
p.Rules = append(p.Rules, newChangeProfileFromLog(log))
|
||||||
} else {
|
} else {
|
||||||
p.Rules = append(p.Rules, FileFromLog(log))
|
p.Rules = append(p.Rules, newFileFromLog(log))
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if strings.Contains(log["operation"], "dbus") {
|
if strings.Contains(log["operation"], "dbus") {
|
||||||
p.Rules = append(p.Rules, DbusFromLog(log))
|
p.Rules = append(p.Rules, newDbusFromLog(log))
|
||||||
} else if log["family"] == "unix" {
|
} else if log["family"] == "unix" {
|
||||||
p.Rules = append(p.Rules, UnixFromLog(log))
|
p.Rules = append(p.Rules, newUnixFromLog(log))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -155,7 +157,7 @@ func (p *AppArmorProfile) Sort() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// MergeRules merge similar rules together
|
// MergeRules merge similar rules together.
|
||||||
// Steps:
|
// Steps:
|
||||||
// - Remove identical rules
|
// - Remove identical rules
|
||||||
// - Merge rule access. Eg: for same path, 'r' and 'w' becomes 'rw'
|
// - Merge rule access. Eg: for same path, 'r' and 'w' becomes 'rw'
|
||||||
|
|
@ -179,7 +181,7 @@ func (p *AppArmorProfile) MergeRules() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format the profile for better readability before printing it
|
// Format the profile for better readability before printing it.
|
||||||
// Follow: https://apparmor.pujol.io/development/guidelines/#the-file-block
|
// Follow: https://apparmor.pujol.io/development/guidelines/#the-file-block
|
||||||
func (p *AppArmorProfile) Format() {
|
func (p *AppArmorProfile) Format() {
|
||||||
const prefixOwner = " "
|
const prefixOwner = " "
|
||||||
|
|
|
||||||
|
|
@ -43,10 +43,10 @@ func TestAppArmorProfile_String(t *testing.T) {
|
||||||
name: "foo",
|
name: "foo",
|
||||||
p: &AppArmorProfile{
|
p: &AppArmorProfile{
|
||||||
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"}},
|
||||||
Aliases: []Alias{{Path: "/mnt/usr", RewrittenPath: "/usr"}},
|
Aliases: []*Alias{{Path: "/mnt/usr", RewrittenPath: "/usr"}},
|
||||||
Variables: []Variable{{
|
Variables: []*Variable{{
|
||||||
Name: "exec_path",
|
Name: "exec_path",
|
||||||
Values: []string{"@{bin}/foo", "@{lib}/foo"},
|
Values: []string{"@{bin}/foo", "@{lib}/foo"},
|
||||||
}},
|
}},
|
||||||
|
|
@ -83,11 +83,11 @@ func TestAppArmorProfile_String(t *testing.T) {
|
||||||
},
|
},
|
||||||
&Ptrace{Access: "read", Peer: "nautilus"},
|
&Ptrace{Access: "read", Peer: "nautilus"},
|
||||||
&Unix{
|
&Unix{
|
||||||
Access: "send receive",
|
Access: "send receive",
|
||||||
Type: "stream",
|
Type: "stream",
|
||||||
Address: "@/tmp/.ICE-unix/1995",
|
Address: "@/tmp/.ICE-unix/1995",
|
||||||
Peer: "gnome-shell",
|
PeerLabel: "gnome-shell",
|
||||||
PeerAddr: "none",
|
PeerAddr: "none",
|
||||||
},
|
},
|
||||||
&Dbus{
|
&Dbus{
|
||||||
Access: "bind",
|
Access: "bind",
|
||||||
|
|
@ -97,11 +97,11 @@ func TestAppArmorProfile_String(t *testing.T) {
|
||||||
&Dbus{
|
&Dbus{
|
||||||
Access: "receive",
|
Access: "receive",
|
||||||
Bus: "system",
|
Bus: "system",
|
||||||
Name: ":1.3",
|
|
||||||
Path: "/org/freedesktop/DBus",
|
Path: "/org/freedesktop/DBus",
|
||||||
Interface: "org.freedesktop.DBus",
|
Interface: "org.freedesktop.DBus",
|
||||||
Member: "AddMatch",
|
Member: "AddMatch",
|
||||||
Label: "power-profiles-daemon",
|
PeerName: ":1.3",
|
||||||
|
PeerLabel: "power-profiles-daemon",
|
||||||
},
|
},
|
||||||
&File{Path: "/opt/intel/oneapi/compiler/*/linux/lib/*.so./*", Access: "rm"},
|
&File{Path: "/opt/intel/oneapi/compiler/*/linux/lib/*.so./*", Access: "rm"},
|
||||||
&File{Path: "@{PROC}/@{pid}/task/@{tid}/comm", Access: "rw"},
|
&File{Path: "@{PROC}/@{pid}/task/@{tid}/comm", Access: "rw"},
|
||||||
|
|
@ -290,9 +290,9 @@ func TestAppArmorProfile_Integration(t *testing.T) {
|
||||||
name: "aa-status",
|
name: "aa-status",
|
||||||
p: &AppArmorProfile{
|
p: &AppArmorProfile{
|
||||||
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"}},
|
||||||
Variables: []Variable{{
|
Variables: []*Variable{{
|
||||||
Name: "exec_path",
|
Name: "exec_path",
|
||||||
Values: []string{"@{bin}/aa-status", "@{bin}/apparmor_status"},
|
Values: []string{"@{bin}/aa-status", "@{bin}/apparmor_status"},
|
||||||
}},
|
}},
|
||||||
|
|
@ -310,7 +310,7 @@ func TestAppArmorProfile_Integration(t *testing.T) {
|
||||||
&File{Path: "@{sys}/kernel/security/apparmor/profiles", Access: "r"},
|
&File{Path: "@{sys}/kernel/security/apparmor/profiles", Access: "r"},
|
||||||
&File{Path: "@{PROC}/@{pids}/attr/current", Access: "r"},
|
&File{Path: "@{PROC}/@{pids}/attr/current", Access: "r"},
|
||||||
&Include{IsMagic: true, Path: "abstractions/consoles"},
|
&Include{IsMagic: true, Path: "abstractions/consoles"},
|
||||||
&File{Qualifier: Qualifier{Owner: true}, Path: "@{PROC}/@{pid}/mounts", Access: "r"},
|
&File{Owner: true, Path: "@{PROC}/@{pid}/mounts", Access: "r"},
|
||||||
&Include{IsMagic: true, Path: "abstractions/base"},
|
&Include{IsMagic: true, Path: "abstractions/base"},
|
||||||
&File{Path: "/dev/tty@{int}", Access: "rw"},
|
&File{Path: "/dev/tty@{int}", Access: "rw"},
|
||||||
&Capability{Name: "sys_ptrace"},
|
&Capability{Name: "sys_ptrace"},
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,16 @@
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
type Ptrace struct {
|
type Ptrace struct {
|
||||||
|
Rule
|
||||||
Qualifier
|
Qualifier
|
||||||
Access string
|
Access string
|
||||||
Peer string
|
Peer string
|
||||||
}
|
}
|
||||||
|
|
||||||
func PtraceFromLog(log map[string]string) ApparmorRule {
|
func newPtraceFromLog(log map[string]string) *Ptrace {
|
||||||
return &Ptrace{
|
return &Ptrace{
|
||||||
Qualifier: NewQualifierFromLog(log),
|
Rule: newRuleFromLog(log),
|
||||||
|
Qualifier: newQualifierFromLog(log),
|
||||||
Access: toAccess(log["requested_mask"]),
|
Access: toAccess(log["requested_mask"]),
|
||||||
Peer: log["peer"],
|
Peer: log["peer"],
|
||||||
}
|
}
|
||||||
|
|
@ -20,12 +22,12 @@ func PtraceFromLog(log map[string]string) ApparmorRule {
|
||||||
|
|
||||||
func (r *Ptrace) Less(other any) bool {
|
func (r *Ptrace) Less(other any) bool {
|
||||||
o, _ := other.(*Ptrace)
|
o, _ := other.(*Ptrace)
|
||||||
if r.Qualifier.Equals(o.Qualifier) {
|
if r.Access != o.Access {
|
||||||
if r.Access == o.Access {
|
|
||||||
return r.Peer == o.Peer
|
|
||||||
}
|
|
||||||
return r.Access < o.Access
|
return r.Access < o.Access
|
||||||
}
|
}
|
||||||
|
if r.Peer != o.Peer {
|
||||||
|
return r.Peer == o.Peer
|
||||||
|
}
|
||||||
return r.Qualifier.Less(o.Qualifier)
|
return r.Qualifier.Less(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,24 @@ type Rlimit struct {
|
||||||
Value string
|
Value string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newRlimitFromLog(log map[string]string) *Rlimit {
|
||||||
|
return &Rlimit{
|
||||||
|
Rule: newRuleFromLog(log),
|
||||||
|
Key: log["key"],
|
||||||
|
Op: log["op"],
|
||||||
|
Value: log["value"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Rlimit) Less(other any) bool {
|
func (r *Rlimit) Less(other any) bool {
|
||||||
o, _ := other.(*Rlimit)
|
o, _ := other.(*Rlimit)
|
||||||
if r.Key == o.Key {
|
if r.Key != o.Key {
|
||||||
if r.Op == o.Op {
|
return r.Key < o.Key
|
||||||
return r.Value < o.Value
|
}
|
||||||
}
|
if r.Op != o.Op {
|
||||||
return r.Op < o.Op
|
return r.Op < o.Op
|
||||||
}
|
}
|
||||||
return r.Key < o.Key
|
return r.Value < o.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Rlimit) Equals(other any) bool {
|
func (r *Rlimit) Equals(other any) bool {
|
||||||
|
|
|
||||||
108
pkg/aa/rules.go
108
pkg/aa/rules.go
|
|
@ -5,6 +5,7 @@
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -12,43 +13,12 @@ type Rule struct {
|
||||||
Comment string
|
Comment string
|
||||||
NoNewPrivs bool
|
NoNewPrivs bool
|
||||||
FileInherit bool
|
FileInherit bool
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Rule) Less(other any) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Rule) Equals(other any) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Qualifier to apply extra settings to a rule
|
|
||||||
type Qualifier struct {
|
|
||||||
Audit bool
|
|
||||||
AccessType string
|
|
||||||
Owner bool
|
|
||||||
NoNewPrivs bool
|
|
||||||
FileInherit bool
|
|
||||||
Optional bool
|
|
||||||
Comment string
|
|
||||||
Prefix string
|
Prefix string
|
||||||
Padding string
|
Padding string
|
||||||
|
Optional bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewQualifierFromLog(log map[string]string) Qualifier {
|
func newRuleFromLog(log map[string]string) Rule {
|
||||||
owner := false
|
|
||||||
fsuid, hasFsUID := log["fsuid"]
|
|
||||||
ouid, hasOuUID := log["ouid"]
|
|
||||||
isDbus := strings.Contains(log["operation"], "dbus")
|
|
||||||
if hasFsUID && hasOuUID && fsuid == ouid && ouid != "0" && !isDbus {
|
|
||||||
owner = true
|
|
||||||
}
|
|
||||||
|
|
||||||
audit := false
|
|
||||||
if log["apparmor"] == "AUDIT" {
|
|
||||||
audit = true
|
|
||||||
}
|
|
||||||
|
|
||||||
fileInherit := false
|
fileInherit := false
|
||||||
if log["operation"] == "file_inherit" {
|
if log["operation"] == "file_inherit" {
|
||||||
fileInherit = true
|
fileInherit = true
|
||||||
|
|
@ -76,62 +46,54 @@ func NewQualifierFromLog(log map[string]string) Qualifier {
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
return Qualifier{
|
return Rule{
|
||||||
Audit: audit,
|
Comment: msg,
|
||||||
Owner: owner,
|
|
||||||
NoNewPrivs: noNewPrivs,
|
NoNewPrivs: noNewPrivs,
|
||||||
FileInherit: fileInherit,
|
FileInherit: fileInherit,
|
||||||
Optional: optional,
|
Optional: optional,
|
||||||
Comment: msg,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r Rule) Less(other any) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Rule) Equals(other any) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type Qualifier struct {
|
||||||
|
Audit bool
|
||||||
|
AccessType string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newQualifierFromLog(log map[string]string) Qualifier {
|
||||||
|
audit := false
|
||||||
|
if log["apparmor"] == "AUDIT" {
|
||||||
|
audit = true
|
||||||
|
}
|
||||||
|
return Qualifier{Audit: audit}
|
||||||
|
}
|
||||||
|
|
||||||
func (r Qualifier) Less(other Qualifier) bool {
|
func (r Qualifier) Less(other Qualifier) bool {
|
||||||
if r.Owner == other.Owner {
|
if r.Audit != other.Audit {
|
||||||
if r.Audit == other.Audit {
|
|
||||||
return r.AccessType < other.AccessType
|
|
||||||
}
|
|
||||||
return r.Audit
|
return r.Audit
|
||||||
}
|
}
|
||||||
return other.Owner
|
return r.AccessType < other.AccessType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Qualifier) Equals(other Qualifier) bool {
|
func (r Qualifier) Equals(other Qualifier) bool {
|
||||||
return r.Audit == other.Audit && r.AccessType == other.AccessType &&
|
return r.Audit == other.Audit && r.AccessType == other.AccessType
|
||||||
r.Owner == other.Owner && r.NoNewPrivs == other.NoNewPrivs &&
|
|
||||||
r.FileInherit == other.FileInherit
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preamble specific rules
|
type All struct {
|
||||||
|
Rule
|
||||||
type Abi struct {
|
|
||||||
Path string
|
|
||||||
IsMagic bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Abi) Less(other Abi) bool {
|
func (r *All) Less(other any) bool {
|
||||||
if r.Path == other.Path {
|
return false
|
||||||
return r.IsMagic == other.IsMagic
|
|
||||||
}
|
|
||||||
return r.Path < other.Path
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Abi) Equals(other Abi) bool {
|
func (r *All) Equals(other any) bool {
|
||||||
return r.Path == other.Path && r.IsMagic == other.IsMagic
|
return false
|
||||||
}
|
|
||||||
|
|
||||||
type Alias struct {
|
|
||||||
Path string
|
|
||||||
RewrittenPath string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r Alias) Less(other Alias) bool {
|
|
||||||
if r.Path == other.Path {
|
|
||||||
return r.RewrittenPath < other.RewrittenPath
|
|
||||||
}
|
|
||||||
return r.Path < other.Path
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r Alias) Equals(other Alias) bool {
|
|
||||||
return r.Path == other.Path && r.RewrittenPath == other.RewrittenPath
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,76 +17,100 @@ func TestRule_FromLog(t *testing.T) {
|
||||||
want ApparmorRule
|
want ApparmorRule
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "capbability",
|
name: "capbability",
|
||||||
fromLog: CapabilityFromLog,
|
fromLog: func(m map[string]string) ApparmorRule {
|
||||||
log: capability1Log,
|
return newCapabilityFromLog(m)
|
||||||
want: capability1,
|
},
|
||||||
|
log: capability1Log,
|
||||||
|
want: capability1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "network",
|
name: "network",
|
||||||
fromLog: NetworkFromLog,
|
fromLog: func(m map[string]string) ApparmorRule {
|
||||||
log: network1Log,
|
return newNetworkFromLog(m)
|
||||||
want: network1,
|
},
|
||||||
|
log: network1Log,
|
||||||
|
want: network1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "mount",
|
name: "mount",
|
||||||
fromLog: MountFromLog,
|
fromLog: func(m map[string]string) ApparmorRule {
|
||||||
log: mount1Log,
|
return newMountFromLog(m)
|
||||||
want: mount1,
|
},
|
||||||
|
log: mount1Log,
|
||||||
|
want: mount1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "umount",
|
name: "umount",
|
||||||
fromLog: UmountFromLog,
|
fromLog: func(m map[string]string) ApparmorRule {
|
||||||
log: umount1Log,
|
return newUmountFromLog(m)
|
||||||
want: umount1,
|
},
|
||||||
|
log: umount1Log,
|
||||||
|
want: umount1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pivotroot",
|
name: "pivotroot",
|
||||||
fromLog: PivotRootFromLog,
|
fromLog: func(m map[string]string) ApparmorRule {
|
||||||
log: pivotroot1Log,
|
return newPivotRootFromLog(m)
|
||||||
want: pivotroot1,
|
},
|
||||||
|
log: pivotroot1Log,
|
||||||
|
want: pivotroot1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "changeprofile",
|
name: "changeprofile",
|
||||||
fromLog: ChangeProfileFromLog,
|
fromLog: func(m map[string]string) ApparmorRule {
|
||||||
log: changeprofile1Log,
|
return newChangeProfileFromLog(m)
|
||||||
want: changeprofile1,
|
},
|
||||||
|
log: changeprofile1Log,
|
||||||
|
want: changeprofile1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "signal",
|
name: "signal",
|
||||||
fromLog: SignalFromLog,
|
fromLog: func(m map[string]string) ApparmorRule {
|
||||||
log: signal1Log,
|
return newSignalFromLog(m)
|
||||||
want: signal1,
|
},
|
||||||
|
log: signal1Log,
|
||||||
|
want: signal1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ptrace/xdg-document-portal",
|
name: "ptrace/xdg-document-portal",
|
||||||
fromLog: PtraceFromLog,
|
fromLog: func(m map[string]string) ApparmorRule {
|
||||||
log: ptrace1Log,
|
return newPtraceFromLog(m)
|
||||||
want: ptrace1,
|
},
|
||||||
|
log: ptrace1Log,
|
||||||
|
want: ptrace1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ptrace/snap-update-ns.firefox",
|
name: "ptrace/snap-update-ns.firefox",
|
||||||
fromLog: PtraceFromLog,
|
fromLog: func(m map[string]string) ApparmorRule {
|
||||||
log: ptrace2Log,
|
return newPtraceFromLog(m)
|
||||||
want: ptrace2,
|
},
|
||||||
|
log: ptrace2Log,
|
||||||
|
want: ptrace2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "unix",
|
name: "unix",
|
||||||
fromLog: UnixFromLog,
|
fromLog: func(m map[string]string) ApparmorRule {
|
||||||
log: unix1Log,
|
return newUnixFromLog(m)
|
||||||
want: unix1,
|
},
|
||||||
|
log: unix1Log,
|
||||||
|
want: unix1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "dbus",
|
name: "dbus",
|
||||||
fromLog: DbusFromLog,
|
fromLog: func(m map[string]string) ApparmorRule {
|
||||||
log: dbus1Log,
|
return newDbusFromLog(m)
|
||||||
want: dbus1,
|
},
|
||||||
|
log: dbus1Log,
|
||||||
|
want: dbus1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "file",
|
name: "file",
|
||||||
fromLog: FileFromLog,
|
fromLog: func(m map[string]string) ApparmorRule {
|
||||||
log: file1Log,
|
return newFileFromLog(m)
|
||||||
want: file1,
|
},
|
||||||
|
log: file1Log,
|
||||||
|
want: file1,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|
@ -109,13 +133,13 @@ func TestRule_Less(t *testing.T) {
|
||||||
name: "include1",
|
name: "include1",
|
||||||
rule: include1,
|
rule: include1,
|
||||||
other: includeLocal1,
|
other: includeLocal1,
|
||||||
want: true,
|
want: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "include2",
|
name: "include2",
|
||||||
rule: include1,
|
rule: include1,
|
||||||
other: include2,
|
other: include2,
|
||||||
want: true,
|
want: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "include3",
|
name: "include3",
|
||||||
|
|
@ -245,9 +269,9 @@ func TestRule_Less(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "file/owner",
|
name: "file/owner",
|
||||||
rule: &File{Path: "/usr/share/poppler/cMap/Identity-H", Qualifier: Qualifier{Owner: true}},
|
rule: &File{Path: "/usr/share/poppler/cMap/Identity-H", Owner: true},
|
||||||
other: &File{Path: "/usr/share/poppler/cMap/Identity-H"},
|
other: &File{Path: "/usr/share/poppler/cMap/Identity-H"},
|
||||||
want: false,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "file/access",
|
name: "file/access",
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,17 @@
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
type Signal struct {
|
type Signal struct {
|
||||||
|
Rule
|
||||||
Qualifier
|
Qualifier
|
||||||
Access string
|
Access string
|
||||||
Set string
|
Set string
|
||||||
Peer string
|
Peer string
|
||||||
}
|
}
|
||||||
|
|
||||||
func SignalFromLog(log map[string]string) ApparmorRule {
|
func newSignalFromLog(log map[string]string) *Signal {
|
||||||
return &Signal{
|
return &Signal{
|
||||||
Qualifier: NewQualifierFromLog(log),
|
Rule: newRuleFromLog(log),
|
||||||
|
Qualifier: newQualifierFromLog(log),
|
||||||
Access: toAccess(log["requested_mask"]),
|
Access: toAccess(log["requested_mask"]),
|
||||||
Set: log["signal"],
|
Set: log["signal"],
|
||||||
Peer: log["peer"],
|
Peer: log["peer"],
|
||||||
|
|
@ -22,15 +24,15 @@ func SignalFromLog(log map[string]string) ApparmorRule {
|
||||||
|
|
||||||
func (r *Signal) Less(other any) bool {
|
func (r *Signal) Less(other any) bool {
|
||||||
o, _ := other.(*Signal)
|
o, _ := other.(*Signal)
|
||||||
if r.Qualifier.Equals(o.Qualifier) {
|
if r.Access != o.Access {
|
||||||
if r.Access == o.Access {
|
|
||||||
if r.Set == o.Set {
|
|
||||||
return r.Peer < o.Peer
|
|
||||||
}
|
|
||||||
return r.Set < o.Set
|
|
||||||
}
|
|
||||||
return r.Access < o.Access
|
return r.Access < o.Access
|
||||||
}
|
}
|
||||||
|
if r.Set != o.Set {
|
||||||
|
return r.Set < o.Set
|
||||||
|
}
|
||||||
|
if r.Peer != o.Peer {
|
||||||
|
return r.Peer < o.Peer
|
||||||
|
}
|
||||||
return r.Qualifier.Less(o.Qualifier)
|
return r.Qualifier.Less(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,5 @@
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
{{ " \"" }}{{ .Path }}{{ "\"" }}
|
{{ " \"" }}{{ .Path }}{{ "\"" }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
{{- template "comment" . -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Rlimit" -}}
|
{{- if eq $type "Rlimit" -}}
|
||||||
{{ "set rlimit " }}{{ .Key }} {{ .Op }} {{ .Value }}{{ "," }}
|
{{ "set rlimit " }}{{ .Key }} {{ .Op }} {{ .Value }}{{ "," }}{{ template "comment" . }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if eq $type "Capability" -}}
|
{{- if eq $type "Capability" -}}
|
||||||
|
|
@ -191,15 +191,24 @@
|
||||||
{{- with .Type -}}
|
{{- with .Type -}}
|
||||||
{{ " type=" }}{{ . }}
|
{{ " type=" }}{{ . }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
{{- with .Protocol -}}
|
||||||
|
{{ " protocol=" }}{{ . }}
|
||||||
|
{{- end -}}
|
||||||
{{- with .Address -}}
|
{{- with .Address -}}
|
||||||
{{ " addr=" }}{{ . }}
|
{{ " addr=" }}{{ . }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if .Peer -}}
|
{{- with .Label -}}
|
||||||
{{ " peer=(label=" }}{{ .Peer }}
|
{{ " label=" }}{{ . }}
|
||||||
{{- with .PeerAddr -}}
|
{{- end -}}
|
||||||
{{ ", addr="}}{{ . }}
|
{{- if and .PeerLabel .PeerAddr -}}
|
||||||
|
{{ " peer=(label=" }}{{ .PeerLabel }}{{ ", addr="}}{{ .PeerAddr }}{{ ")" }}
|
||||||
|
{{- else -}}
|
||||||
|
{{- with .PeerLabel -}}
|
||||||
|
{{ overindent "peer=(label=" }}{{ . }}{{ ")" }}
|
||||||
|
{{- end -}}
|
||||||
|
{{- with .PeerAddr -}}
|
||||||
|
{{ overindent "peer=(addr=" }}{{ . }}{{ ")" }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- ")" -}}
|
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- "," -}}
|
{{- "," -}}
|
||||||
{{- template "comment" . -}}
|
{{- template "comment" . -}}
|
||||||
|
|
@ -256,13 +265,13 @@
|
||||||
{{- with .Member -}}
|
{{- with .Member -}}
|
||||||
{{ overindent "member=" }}{{ . }}{{ "\n" }}
|
{{ overindent "member=" }}{{ . }}{{ "\n" }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if and .Name .Label -}}
|
{{- if and .PeerName .PeerLabel -}}
|
||||||
{{ overindent "peer=(name=" }}{{ .Name }}{{ ", label="}}{{ .Label }}{{ ")" }}
|
{{ overindent "peer=(name=" }}{{ .PeerName }}{{ ", label="}}{{ .PeerLabel }}{{ ")" }}
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
{{- with .Name -}}
|
{{- with .PeerName -}}
|
||||||
{{ overindent "peer=(name=" }}{{ . }}{{ ")" }}
|
{{ overindent "peer=(name=" }}{{ . }}{{ ")" }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- with .Label -}}
|
{{- with .PeerLabel -}}
|
||||||
{{ overindent "peer=(label=" }}{{ . }}{{ ")" }}
|
{{ overindent "peer=(label=" }}{{ . }}{{ ")" }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
@ -273,6 +282,9 @@
|
||||||
|
|
||||||
{{- if eq $type "File" -}}
|
{{- if eq $type "File" -}}
|
||||||
{{- template "qualifier" . -}}
|
{{- template "qualifier" . -}}
|
||||||
|
{{- if .Owner -}}
|
||||||
|
{{- "owner " -}}
|
||||||
|
{{- end -}}
|
||||||
{{- .Path -}}
|
{{- .Path -}}
|
||||||
{{- " " -}}
|
{{- " " -}}
|
||||||
{{- with .Padding -}}
|
{{- with .Padding -}}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,6 @@
|
||||||
{{- with .Prefix -}}
|
{{- with .Prefix -}}
|
||||||
{{ . }}
|
{{ . }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if .Owner -}}
|
|
||||||
{{- "owner " -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if .Audit -}}
|
{{- if .Audit -}}
|
||||||
{{- "audit " -}}
|
{{- "audit " -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
|
||||||
|
|
@ -5,62 +5,64 @@
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
type Unix struct {
|
type Unix struct {
|
||||||
|
Rule
|
||||||
Qualifier
|
Qualifier
|
||||||
Access string
|
Access string
|
||||||
Type string
|
Type string
|
||||||
Protocol string
|
Protocol string
|
||||||
Address string
|
Address string
|
||||||
Label string
|
Label string
|
||||||
Attr string
|
Attr string
|
||||||
Opt string
|
Opt string
|
||||||
Peer string
|
PeerLabel string
|
||||||
PeerAddr string
|
PeerAddr string
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnixFromLog(log map[string]string) ApparmorRule {
|
func newUnixFromLog(log map[string]string) *Unix {
|
||||||
return &Unix{
|
return &Unix{
|
||||||
Qualifier: NewQualifierFromLog(log),
|
Rule: newRuleFromLog(log),
|
||||||
|
Qualifier: newQualifierFromLog(log),
|
||||||
Access: toAccess(log["requested_mask"]),
|
Access: toAccess(log["requested_mask"]),
|
||||||
Type: log["sock_type"],
|
Type: log["sock_type"],
|
||||||
Protocol: log["protocol"],
|
Protocol: log["protocol"],
|
||||||
Address: log["addr"],
|
Address: log["addr"],
|
||||||
Label: log["peer_label"],
|
Label: log["label"],
|
||||||
Attr: log["attr"],
|
Attr: log["attr"],
|
||||||
Opt: log["opt"],
|
Opt: log["opt"],
|
||||||
Peer: log["peer"],
|
PeerLabel: log["peer"],
|
||||||
PeerAddr: log["peer_addr"],
|
PeerAddr: log["peer_addr"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Unix) Less(other any) bool {
|
func (r *Unix) Less(other any) bool {
|
||||||
o, _ := other.(*Unix)
|
o, _ := other.(*Unix)
|
||||||
if r.Qualifier.Equals(o.Qualifier) {
|
if r.Access != o.Access {
|
||||||
if r.Access == o.Access {
|
|
||||||
if r.Type == o.Type {
|
|
||||||
if r.Protocol == o.Protocol {
|
|
||||||
if r.Address == o.Address {
|
|
||||||
if r.Label == o.Label {
|
|
||||||
if r.Attr == o.Attr {
|
|
||||||
if r.Opt == o.Opt {
|
|
||||||
if r.Peer == o.Peer {
|
|
||||||
return r.PeerAddr < o.PeerAddr
|
|
||||||
}
|
|
||||||
return r.Peer < o.Peer
|
|
||||||
}
|
|
||||||
return r.Opt < o.Opt
|
|
||||||
}
|
|
||||||
return r.Attr < o.Attr
|
|
||||||
}
|
|
||||||
return r.Label < o.Label
|
|
||||||
}
|
|
||||||
return r.Address < o.Address
|
|
||||||
}
|
|
||||||
return r.Protocol < o.Protocol
|
|
||||||
}
|
|
||||||
return r.Type < o.Type
|
|
||||||
}
|
|
||||||
return r.Access < o.Access
|
return r.Access < o.Access
|
||||||
}
|
}
|
||||||
|
if r.Type != o.Type {
|
||||||
|
return r.Type < o.Type
|
||||||
|
}
|
||||||
|
if r.Protocol != o.Protocol {
|
||||||
|
return r.Protocol < o.Protocol
|
||||||
|
}
|
||||||
|
if r.Address != o.Address {
|
||||||
|
return r.Address < o.Address
|
||||||
|
}
|
||||||
|
if r.Label != o.Label {
|
||||||
|
return r.Label < o.Label
|
||||||
|
}
|
||||||
|
if r.Attr != o.Attr {
|
||||||
|
return r.Attr < o.Attr
|
||||||
|
}
|
||||||
|
if r.Opt != o.Opt {
|
||||||
|
return r.Opt < o.Opt
|
||||||
|
}
|
||||||
|
if r.PeerLabel != o.PeerLabel {
|
||||||
|
return r.PeerLabel < o.PeerLabel
|
||||||
|
}
|
||||||
|
if r.PeerAddr != o.PeerAddr {
|
||||||
|
return r.PeerAddr < o.PeerAddr
|
||||||
|
}
|
||||||
return r.Qualifier.Less(o.Qualifier)
|
return r.Qualifier.Less(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,5 +71,6 @@ func (r *Unix) Equals(other any) bool {
|
||||||
return r.Access == o.Access && r.Type == o.Type &&
|
return r.Access == o.Access && r.Type == o.Type &&
|
||||||
r.Protocol == o.Protocol && r.Address == o.Address &&
|
r.Protocol == o.Protocol && r.Address == o.Address &&
|
||||||
r.Label == o.Label && r.Attr == o.Attr && r.Opt == o.Opt &&
|
r.Label == o.Label && r.Attr == o.Attr && r.Opt == o.Opt &&
|
||||||
r.Peer == o.Peer && r.PeerAddr == o.PeerAddr && r.Qualifier.Equals(o.Qualifier)
|
r.PeerLabel == o.PeerLabel && r.PeerAddr == o.PeerAddr &&
|
||||||
|
r.Qualifier.Equals(o.Qualifier)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,22 @@
|
||||||
package aa
|
package aa
|
||||||
|
|
||||||
type Userns struct {
|
type Userns struct {
|
||||||
|
Rule
|
||||||
Qualifier
|
Qualifier
|
||||||
Create bool
|
Create bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func UsernsFromLog(log map[string]string) ApparmorRule {
|
func newUsernsFromLog(log map[string]string) *Userns {
|
||||||
return &Userns{
|
return &Userns{
|
||||||
Qualifier: NewQualifierFromLog(log),
|
Rule: newRuleFromLog(log),
|
||||||
|
Qualifier: newQualifierFromLog(log),
|
||||||
Create: true,
|
Create: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Userns) Less(other any) bool {
|
func (r *Userns) Less(other any) bool {
|
||||||
o, _ := other.(*Userns)
|
o, _ := other.(*Userns)
|
||||||
if r.Qualifier.Equals(o.Qualifier) {
|
if r.Create != o.Create {
|
||||||
return r.Create
|
return r.Create
|
||||||
}
|
}
|
||||||
return r.Qualifier.Less(o.Qualifier)
|
return r.Qualifier.Less(o.Qualifier)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ package aa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"slices"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -18,35 +17,19 @@ var (
|
||||||
regVariablesRef = regexp.MustCompile(`@{([^{}]+)}`)
|
regVariablesRef = regexp.MustCompile(`@{([^{}]+)}`)
|
||||||
)
|
)
|
||||||
|
|
||||||
type Variable struct {
|
|
||||||
Name string
|
|
||||||
Values []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r Variable) Less(other Variable) bool {
|
|
||||||
if r.Name == other.Name {
|
|
||||||
return len(r.Values) < len(other.Values)
|
|
||||||
}
|
|
||||||
return r.Name < other.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r Variable) Equals(other Variable) bool {
|
|
||||||
return r.Name == other.Name && slices.Equal(r.Values, other.Values)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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() *AppArmorProfile {
|
||||||
return &AppArmorProfile{
|
return &AppArmorProfile{
|
||||||
Preamble: Preamble{
|
Preamble: Preamble{
|
||||||
Variables: []Variable{
|
Variables: []*Variable{
|
||||||
{"bin", []string{"/{,usr/}{,s}bin"}},
|
{Name: "bin", Values: []string{"/{,usr/}{,s}bin"}},
|
||||||
{"lib", []string{"/{,usr/}lib{,exec,32,64}"}},
|
{Name: "lib", Values: []string{"/{,usr/}lib{,exec,32,64}"}},
|
||||||
{"multiarch", []string{"*-linux-gnu*"}},
|
{Name: "multiarch", Values: []string{"*-linux-gnu*"}},
|
||||||
{"HOME", []string{"/home/*"}},
|
{Name: "HOME", Values: []string{"/home/*"}},
|
||||||
{"user_share_dirs", []string{"/home/*/.local/share"}},
|
{Name: "user_share_dirs", Values: []string{"/home/*/.local/share"}},
|
||||||
{"etc_ro", []string{"/{,usr/}etc/"}},
|
{Name: "etc_ro", Values: []string{"/{,usr/}etc/"}},
|
||||||
{"int", []string{"[0-9]{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}"}},
|
{Name: "int", Values: []string{"[0-9]{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -68,7 +51,7 @@ func (p *AppArmorProfile) ParseVariables(content string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
variable := Variable{Name: key, Values: values}
|
variable := &Variable{Name: key, Values: values}
|
||||||
p.Variables = append(p.Variables, variable)
|
p.Variables = append(p.Variables, variable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,10 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: space in variable need to be tested.
|
||||||
|
// @{name} = "Mullvad VPN"
|
||||||
|
// profile mullvad-gui /{opt/"Mullvad/mullvad-gui,opt/VPN"/mullvad-gui,mullvad-gui} flags=(attach_disconnected,complain) {
|
||||||
|
|
||||||
func TestDefaultTunables(t *testing.T) {
|
func TestDefaultTunables(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
@ -18,14 +22,14 @@ func TestDefaultTunables(t *testing.T) {
|
||||||
name: "aa",
|
name: "aa",
|
||||||
want: &AppArmorProfile{
|
want: &AppArmorProfile{
|
||||||
Preamble: Preamble{
|
Preamble: Preamble{
|
||||||
Variables: []Variable{
|
Variables: []*Variable{
|
||||||
{"bin", []string{"/{,usr/}{,s}bin"}},
|
{Name: "bin", Values: []string{"/{,usr/}{,s}bin"}},
|
||||||
{"lib", []string{"/{,usr/}lib{,exec,32,64}"}},
|
{Name: "lib", Values: []string{"/{,usr/}lib{,exec,32,64}"}},
|
||||||
{"multiarch", []string{"*-linux-gnu*"}},
|
{Name: "multiarch", Values: []string{"*-linux-gnu*"}},
|
||||||
{"HOME", []string{"/home/*"}},
|
{Name: "HOME", Values: []string{"/home/*"}},
|
||||||
{"user_share_dirs", []string{"/home/*/.local/share"}},
|
{Name: "user_share_dirs", Values: []string{"/home/*/.local/share"}},
|
||||||
{"etc_ro", []string{"/{,usr/}etc/"}},
|
{Name: "etc_ro", Values: []string{"/{,usr/}etc/"}},
|
||||||
{"int", []string{"[0-9]{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}"}},
|
{Name: "int", Values: []string{"[0-9]{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -44,7 +48,7 @@ func TestAppArmorProfile_ParseVariables(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
content string
|
content string
|
||||||
want []Variable
|
want []*Variable
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "firefox",
|
name: "firefox",
|
||||||
|
|
@ -54,12 +58,12 @@ func TestAppArmorProfile_ParseVariables(t *testing.T) {
|
||||||
@{firefox_cache_dirs} = @{user_cache_dirs}/mozilla/
|
@{firefox_cache_dirs} = @{user_cache_dirs}/mozilla/
|
||||||
@{exec_path} = /{usr/,}bin/@{firefox_name} @{firefox_lib_dirs}/@{firefox_name}
|
@{exec_path} = /{usr/,}bin/@{firefox_name} @{firefox_lib_dirs}/@{firefox_name}
|
||||||
`,
|
`,
|
||||||
want: []Variable{
|
want: []*Variable{
|
||||||
{"firefox_name", []string{"firefox{,-esr,-bin}"}},
|
{Name: "firefox_name", Values: []string{"firefox{,-esr,-bin}"}},
|
||||||
{"firefox_lib_dirs", []string{"/{usr/,}lib{,32,64}/@{firefox_name}", "/opt/@{firefox_name}"}},
|
{Name: "firefox_lib_dirs", Values: []string{"/{usr/,}lib{,32,64}/@{firefox_name}", "/opt/@{firefox_name}"}},
|
||||||
{"firefox_config_dirs", []string{"@{HOME}/.mozilla/"}},
|
{Name: "firefox_config_dirs", Values: []string{"@{HOME}/.mozilla/"}},
|
||||||
{"firefox_cache_dirs", []string{"@{user_cache_dirs}/mozilla/"}},
|
{Name: "firefox_cache_dirs", Values: []string{"@{user_cache_dirs}/mozilla/"}},
|
||||||
{"exec_path", []string{"/{usr/,}bin/@{firefox_name}", "@{firefox_lib_dirs}/@{firefox_name}"}},
|
{Name: "exec_path", Values: []string{"/{usr/,}bin/@{firefox_name}", "@{firefox_lib_dirs}/@{firefox_name}"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -68,8 +72,8 @@ func TestAppArmorProfile_ParseVariables(t *testing.T) {
|
||||||
@{exec_path} += /{usr/,}bin/Xorg{,.bin}
|
@{exec_path} += /{usr/,}bin/Xorg{,.bin}
|
||||||
@{exec_path} += /{usr/,}lib/Xorg{,.wrap}
|
@{exec_path} += /{usr/,}lib/Xorg{,.wrap}
|
||||||
@{exec_path} += /{usr/,}lib/xorg/Xorg{,.wrap}`,
|
@{exec_path} += /{usr/,}lib/xorg/Xorg{,.wrap}`,
|
||||||
want: []Variable{
|
want: []*Variable{
|
||||||
{"exec_path", []string{
|
{Name: "exec_path", Values: []string{
|
||||||
"/{usr/,}bin/X",
|
"/{usr/,}bin/X",
|
||||||
"/{usr/,}bin/Xorg{,.bin}",
|
"/{usr/,}bin/Xorg{,.bin}",
|
||||||
"/{usr/,}lib/Xorg{,.wrap}",
|
"/{usr/,}lib/Xorg{,.wrap}",
|
||||||
|
|
@ -81,9 +85,9 @@ func TestAppArmorProfile_ParseVariables(t *testing.T) {
|
||||||
name: "snapd",
|
name: "snapd",
|
||||||
content: `@{lib_dirs} = @{lib}/ /snap/snapd/@{int}@{lib}
|
content: `@{lib_dirs} = @{lib}/ /snap/snapd/@{int}@{lib}
|
||||||
@{exec_path} = @{lib_dirs}/snapd/snapd`,
|
@{exec_path} = @{lib_dirs}/snapd/snapd`,
|
||||||
want: []Variable{
|
want: []*Variable{
|
||||||
{"lib_dirs", []string{"@{lib}/", "/snap/snapd/@{int}@{lib}"}},
|
{Name: "lib_dirs", Values: []string{"@{lib}/", "/snap/snapd/@{int}@{lib}"}},
|
||||||
{"exec_path", []string{"@{lib_dirs}/snapd/snapd"}},
|
{Name: "exec_path", Values: []string{"@{lib_dirs}/snapd/snapd"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -104,11 +108,21 @@ func TestAppArmorProfile_resolve(t *testing.T) {
|
||||||
input string
|
input string
|
||||||
want []string
|
want []string
|
||||||
}{
|
}{
|
||||||
|
{
|
||||||
|
name: "default",
|
||||||
|
input: "@{etc_ro}",
|
||||||
|
want: []string{"/{,usr/}etc/"},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "empty",
|
name: "empty",
|
||||||
input: "@{}",
|
input: "@{}",
|
||||||
want: []string{"@{}"},
|
want: []string{"@{}"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "nil",
|
||||||
|
input: "@{foo}",
|
||||||
|
want: []string{},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
@ -123,15 +137,15 @@ func TestAppArmorProfile_resolve(t *testing.T) {
|
||||||
func TestAppArmorProfile_ResolveAttachments(t *testing.T) {
|
func TestAppArmorProfile_ResolveAttachments(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
variables []Variable
|
variables []*Variable
|
||||||
want []string
|
want []string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "firefox",
|
name: "firefox",
|
||||||
variables: []Variable{
|
variables: []*Variable{
|
||||||
{"firefox_name", []string{"firefox{,-esr,-bin}"}},
|
{Name: "firefox_name", Values: []string{"firefox{,-esr,-bin}"}},
|
||||||
{"firefox_lib_dirs", []string{"/{usr/,}/lib{,32,64}/@{firefox_name}", "/opt/@{firefox_name}"}},
|
{Name: "firefox_lib_dirs", Values: []string{"/{usr/,}/lib{,32,64}/@{firefox_name}", "/opt/@{firefox_name}"}},
|
||||||
{"exec_path", []string{"/{usr/,}bin/@{firefox_name}", "@{firefox_lib_dirs}/@{firefox_name}"}},
|
{Name: "exec_path", Values: []string{"/{usr/,}bin/@{firefox_name}", "@{firefox_lib_dirs}/@{firefox_name}"}},
|
||||||
},
|
},
|
||||||
want: []string{
|
want: []string{
|
||||||
"/{usr/,}bin/firefox{,-esr,-bin}",
|
"/{usr/,}bin/firefox{,-esr,-bin}",
|
||||||
|
|
@ -141,10 +155,10 @@ func TestAppArmorProfile_ResolveAttachments(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "chromium",
|
name: "chromium",
|
||||||
variables: []Variable{
|
variables: []*Variable{
|
||||||
{"name", []string{"chromium"}},
|
{Name: "name", Values: []string{"chromium"}},
|
||||||
{"lib_dirs", []string{"/{usr/,}lib/@{name}"}},
|
{Name: "lib_dirs", Values: []string{"/{usr/,}lib/@{name}"}},
|
||||||
{"exec_path", []string{"@{lib_dirs}/@{name}"}},
|
{Name: "exec_path", Values: []string{"@{lib_dirs}/@{name}"}},
|
||||||
},
|
},
|
||||||
want: []string{
|
want: []string{
|
||||||
"/{usr/,}lib/chromium/chromium",
|
"/{usr/,}lib/chromium/chromium",
|
||||||
|
|
@ -152,9 +166,9 @@ func TestAppArmorProfile_ResolveAttachments(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "geoclue",
|
name: "geoclue",
|
||||||
variables: []Variable{
|
variables: []*Variable{
|
||||||
{"libexec", []string{"/{usr/,}libexec"}},
|
{Name: "libexec", Values: []string{"/{usr/,}libexec"}},
|
||||||
{"exec_path", []string{"@{libexec}/geoclue", "@{libexec}/geoclue-2.0/demos/agent"}},
|
{Name: "exec_path", Values: []string{"@{libexec}/geoclue", "@{libexec}/geoclue-2.0/demos/agent"}},
|
||||||
},
|
},
|
||||||
want: []string{
|
want: []string{
|
||||||
"/{usr/,}libexec/geoclue",
|
"/{usr/,}libexec/geoclue",
|
||||||
|
|
@ -163,11 +177,11 @@ func TestAppArmorProfile_ResolveAttachments(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "opera",
|
name: "opera",
|
||||||
variables: []Variable{
|
variables: []*Variable{
|
||||||
{"multiarch", []string{"*-linux-gnu*"}},
|
{Name: "multiarch", Values: []string{"*-linux-gnu*"}},
|
||||||
{"name", []string{"opera{,-beta,-developer}"}},
|
{Name: "name", Values: []string{"opera{,-beta,-developer}"}},
|
||||||
{"lib_dirs", []string{"/{usr/,}lib/@{multiarch}/@{name}"}},
|
{Name: "lib_dirs", Values: []string{"/{usr/,}lib/@{multiarch}/@{name}"}},
|
||||||
{"exec_path", []string{"@{lib_dirs}/@{name}"}},
|
{Name: "exec_path", Values: []string{"@{lib_dirs}/@{name}"}},
|
||||||
},
|
},
|
||||||
want: []string{
|
want: []string{
|
||||||
"/{usr/,}lib/*-linux-gnu*/opera{,-beta,-developer}/opera{,-beta,-developer}",
|
"/{usr/,}lib/*-linux-gnu*/opera{,-beta,-developer}/opera{,-beta,-developer}",
|
||||||
|
|
|
||||||
|
|
@ -303,16 +303,16 @@ func TestAppArmorLogs_ParseToProfiles(t *testing.T) {
|
||||||
Name: "kmod",
|
Name: "kmod",
|
||||||
Rules: aa.Rules{
|
Rules: aa.Rules{
|
||||||
&aa.Unix{
|
&aa.Unix{
|
||||||
Qualifier: aa.Qualifier{FileInherit: true},
|
Rule: aa.Rule{FileInherit: true},
|
||||||
Access: "send receive",
|
Access: "send receive",
|
||||||
Type: "stream",
|
Type: "stream",
|
||||||
Protocol: "0",
|
Protocol: "0",
|
||||||
},
|
},
|
||||||
&aa.Unix{
|
&aa.Unix{
|
||||||
Qualifier: aa.Qualifier{FileInherit: true},
|
Rule: aa.Rule{FileInherit: true},
|
||||||
Access: "send receive",
|
Access: "send receive",
|
||||||
Type: "stream",
|
Type: "stream",
|
||||||
Protocol: "0",
|
Protocol: "0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -324,11 +324,11 @@ func TestAppArmorLogs_ParseToProfiles(t *testing.T) {
|
||||||
&aa.Dbus{
|
&aa.Dbus{
|
||||||
Access: "send",
|
Access: "send",
|
||||||
Bus: "system",
|
Bus: "system",
|
||||||
Name: "org.freedesktop.DBus",
|
|
||||||
Path: "/org/freedesktop/DBus",
|
Path: "/org/freedesktop/DBus",
|
||||||
Interface: "org.freedesktop.DBus",
|
Interface: "org.freedesktop.DBus",
|
||||||
Member: "AddMatch",
|
Member: "AddMatch",
|
||||||
Label: "dbus-daemon",
|
PeerName: "org.freedesktop.DBus",
|
||||||
|
PeerLabel: "dbus-daemon",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ func (d Dbus) own(rules map[string]string) *aa.AppArmorProfile {
|
||||||
Bus: rules["bus"],
|
Bus: rules["bus"],
|
||||||
Path: rules["path"],
|
Path: rules["path"],
|
||||||
Interface: iface,
|
Interface: iface,
|
||||||
Name: `":1.@{int}"`,
|
PeerName: `":1.@{int}"`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for _, iface := range interfaces {
|
for _, iface := range interfaces {
|
||||||
|
|
@ -116,7 +116,7 @@ func (d Dbus) own(rules map[string]string) *aa.AppArmorProfile {
|
||||||
Bus: rules["bus"],
|
Bus: rules["bus"],
|
||||||
Path: rules["path"],
|
Path: rules["path"],
|
||||||
Interface: iface,
|
Interface: iface,
|
||||||
Name: `"{:1.@{int},org.freedesktop.DBus}"`,
|
PeerName: `"{:1.@{int},org.freedesktop.DBus}"`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
p.Rules = append(p.Rules, &aa.Dbus{
|
p.Rules = append(p.Rules, &aa.Dbus{
|
||||||
|
|
@ -125,7 +125,7 @@ func (d Dbus) own(rules map[string]string) *aa.AppArmorProfile {
|
||||||
Path: rules["path"],
|
Path: rules["path"],
|
||||||
Interface: "org.freedesktop.DBus.Introspectable",
|
Interface: "org.freedesktop.DBus.Introspectable",
|
||||||
Member: "Introspect",
|
Member: "Introspect",
|
||||||
Name: `":1.@{int}"`,
|
PeerName: `":1.@{int}"`,
|
||||||
})
|
})
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
@ -139,8 +139,8 @@ func (d Dbus) talk(rules map[string]string) *aa.AppArmorProfile {
|
||||||
Bus: rules["bus"],
|
Bus: rules["bus"],
|
||||||
Path: rules["path"],
|
Path: rules["path"],
|
||||||
Interface: iface,
|
Interface: iface,
|
||||||
Name: `"{:1.@{int},` + rules["name"] + `}"`,
|
PeerName: `"{:1.@{int},` + rules["name"] + `}"`,
|
||||||
Label: rules["label"],
|
PeerLabel: rules["label"],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for _, iface := range interfaces {
|
for _, iface := range interfaces {
|
||||||
|
|
@ -149,8 +149,8 @@ func (d Dbus) talk(rules map[string]string) *aa.AppArmorProfile {
|
||||||
Bus: rules["bus"],
|
Bus: rules["bus"],
|
||||||
Path: rules["path"],
|
Path: rules["path"],
|
||||||
Interface: iface,
|
Interface: iface,
|
||||||
Name: `"{:1.@{int},` + rules["name"] + `}"`,
|
PeerName: `"{:1.@{int},` + rules["name"] + `}"`,
|
||||||
Label: rules["label"],
|
PeerLabel: rules["label"],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return p
|
return p
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue