feat(aa): rename the main profile struct.
This commit is contained in:
parent
4b753210e7
commit
890275fb22
11 changed files with 287 additions and 274 deletions
338
pkg/aa/apparmor_test.go
Normal file
338
pkg/aa/apparmor_test.go
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
// 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 (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/arduino/go-paths-helper"
|
||||
)
|
||||
|
||||
func readprofile(path string) string {
|
||||
file := paths.New("../../").Join(path)
|
||||
lines, err := file.ReadFileAsLines()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
res := ""
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
res += line + "\n"
|
||||
}
|
||||
return res[:len(res)-1]
|
||||
}
|
||||
|
||||
func TestAppArmorProfile_String(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
f *AppArmorProfileFile
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
f: &AppArmorProfileFile{},
|
||||
want: ``,
|
||||
},
|
||||
{
|
||||
name: "foo",
|
||||
f: &AppArmorProfileFile{
|
||||
Preamble: Preamble{
|
||||
Abi: []*Abi{{IsMagic: true, Path: "abi/4.0"}},
|
||||
Includes: []*Include{{IsMagic: true, Path: "tunables/global"}},
|
||||
Aliases: []*Alias{{Path: "/mnt/usr", RewrittenPath: "/usr"}},
|
||||
Variables: []*Variable{{
|
||||
Name: "exec_path",
|
||||
Values: []string{"@{bin}/foo", "@{lib}/foo"},
|
||||
}},
|
||||
},
|
||||
Profiles: []*Profile{{
|
||||
Header: Header{
|
||||
Name: "foo",
|
||||
Attachments: []string{"@{exec_path}"},
|
||||
Attributes: map[string]string{"security.tagged": "allowed"},
|
||||
Flags: []string{"complain", "attach_disconnected"},
|
||||
},
|
||||
Rules: []ApparmorRule{
|
||||
&Include{IsMagic: true, Path: "abstractions/base"},
|
||||
&Include{IsMagic: true, Path: "abstractions/nameservice-strict"},
|
||||
rlimit1,
|
||||
&Capability{Name: "dac_read_search"},
|
||||
&Capability{Name: "dac_override"},
|
||||
&Network{Domain: "inet", Type: "stream"},
|
||||
&Network{Domain: "inet6", Type: "stream"},
|
||||
&Mount{
|
||||
MountConditions: MountConditions{
|
||||
FsType: "fuse.portal",
|
||||
Options: []string{"rw", "rbind"},
|
||||
},
|
||||
Source: "@{run}/user/@{uid}/ ",
|
||||
MountPoint: "/",
|
||||
},
|
||||
&Umount{
|
||||
MountConditions: MountConditions{},
|
||||
MountPoint: "@{run}/user/@{uid}/",
|
||||
},
|
||||
&Signal{
|
||||
Access: "receive",
|
||||
Set: "term",
|
||||
Peer: "at-spi-bus-launcher",
|
||||
},
|
||||
&Ptrace{Access: "read", Peer: "nautilus"},
|
||||
&Unix{
|
||||
Access: "send receive",
|
||||
Type: "stream",
|
||||
Address: "@/tmp/.ICE-unix/1995",
|
||||
PeerLabel: "gnome-shell",
|
||||
PeerAddr: "none",
|
||||
},
|
||||
&Dbus{
|
||||
Access: "bind",
|
||||
Bus: "session",
|
||||
Name: "org.gnome.*",
|
||||
},
|
||||
&Dbus{
|
||||
Access: "receive",
|
||||
Bus: "system",
|
||||
Path: "/org/freedesktop/DBus",
|
||||
Interface: "org.freedesktop.DBus",
|
||||
Member: "AddMatch",
|
||||
PeerName: ":1.3",
|
||||
PeerLabel: "power-profiles-daemon",
|
||||
},
|
||||
&File{Path: "/opt/intel/oneapi/compiler/*/linux/lib/*.so./*", Access: "rm"},
|
||||
&File{Path: "@{PROC}/@{pid}/task/@{tid}/comm", Access: "rw"},
|
||||
&File{Path: "@{sys}/devices/@{pci}/class", Access: "r"},
|
||||
includeLocal1,
|
||||
},
|
||||
}},
|
||||
},
|
||||
want: readprofile("tests/string.aa"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.f.String(); got != tt.want {
|
||||
t.Errorf("AppArmorProfile.String() = |%v|, want |%v|", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppArmorProfile_AddRule(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
log map[string]string
|
||||
want *AppArmorProfileFile
|
||||
}{
|
||||
{
|
||||
name: "capability",
|
||||
log: capability1Log,
|
||||
want: &AppArmorProfileFile{
|
||||
Profiles: []*Profile{{
|
||||
Rules: []ApparmorRule{capability1},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "network",
|
||||
log: network1Log,
|
||||
want: &AppArmorProfileFile{
|
||||
Profiles: []*Profile{{
|
||||
Rules: []ApparmorRule{network1},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mount",
|
||||
log: mount2Log,
|
||||
want: &AppArmorProfileFile{
|
||||
Profiles: []*Profile{{
|
||||
Rules: []ApparmorRule{mount2},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "signal",
|
||||
log: signal1Log,
|
||||
want: &AppArmorProfileFile{
|
||||
Profiles: []*Profile{{
|
||||
Rules: []ApparmorRule{signal1},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ptrace",
|
||||
log: ptrace2Log,
|
||||
want: &AppArmorProfileFile{
|
||||
Profiles: []*Profile{{
|
||||
Rules: []ApparmorRule{ptrace2},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unix",
|
||||
log: unix1Log,
|
||||
want: &AppArmorProfileFile{
|
||||
Profiles: []*Profile{{
|
||||
Rules: []ApparmorRule{unix1},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dbus",
|
||||
log: dbus2Log,
|
||||
want: &AppArmorProfileFile{
|
||||
Profiles: []*Profile{{
|
||||
Rules: []ApparmorRule{dbus2},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "file",
|
||||
log: file2Log,
|
||||
want: &AppArmorProfileFile{
|
||||
Profiles: []*Profile{{
|
||||
Rules: []ApparmorRule{file2},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := NewAppArmorProfile()
|
||||
got.AddRule(tt.log)
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("AppArmorProfile.AddRule() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppArmorProfile_Sort(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
origin *AppArmorProfileFile
|
||||
want *AppArmorProfileFile
|
||||
}{
|
||||
{
|
||||
name: "all",
|
||||
origin: &AppArmorProfileFile{
|
||||
Profiles: []*Profile{{
|
||||
Rules: []ApparmorRule{
|
||||
file2, network1, includeLocal1, dbus2, signal1, ptrace1,
|
||||
capability2, file1, dbus1, unix2, signal2, mount2,
|
||||
},
|
||||
}},
|
||||
},
|
||||
want: &AppArmorProfileFile{
|
||||
Profiles: []*Profile{{
|
||||
Rules: []ApparmorRule{
|
||||
capability2, network1, mount2, signal1, signal2, ptrace1,
|
||||
unix2, dbus2, dbus1, file1, file2, includeLocal1,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := tt.origin
|
||||
got.Sort()
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("AppArmorProfile.Sort() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppArmorProfile_MergeRules(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
origin *AppArmorProfileFile
|
||||
want *AppArmorProfileFile
|
||||
}{
|
||||
{
|
||||
name: "all",
|
||||
origin: &AppArmorProfileFile{
|
||||
Profiles: []*Profile{{
|
||||
Rules: []ApparmorRule{capability1, capability1, network1, network1, file1, file1},
|
||||
}},
|
||||
},
|
||||
want: &AppArmorProfileFile{
|
||||
Profiles: []*Profile{{
|
||||
Rules: []ApparmorRule{capability1, network1, file1},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := tt.origin
|
||||
got.MergeRules()
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("AppArmorProfile.MergeRules() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppArmorProfile_Integration(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
f *AppArmorProfileFile
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "aa-status",
|
||||
f: &AppArmorProfileFile{
|
||||
Preamble: Preamble{
|
||||
Abi: []*Abi{{IsMagic: true, Path: "abi/3.0"}},
|
||||
Includes: []*Include{{IsMagic: true, Path: "tunables/global"}},
|
||||
Variables: []*Variable{{
|
||||
Name: "exec_path",
|
||||
Values: []string{"@{bin}/aa-status", "@{bin}/apparmor_status"},
|
||||
}},
|
||||
},
|
||||
Profiles: []*Profile{{
|
||||
Header: Header{
|
||||
Name: "aa-status",
|
||||
Attachments: []string{"@{exec_path}"},
|
||||
},
|
||||
Rules: Rules{
|
||||
&Include{IfExists: true, IsMagic: true, Path: "local/aa-status"},
|
||||
&Capability{Name: "dac_read_search"},
|
||||
&File{Path: "@{exec_path}", Access: "mr"},
|
||||
&File{Path: "@{PROC}/@{pids}/attr/apparmor/current", Access: "r"},
|
||||
&File{Path: "@{PROC}/", Access: "r"},
|
||||
&File{Path: "@{sys}/module/apparmor/parameters/enabled", Access: "r"},
|
||||
&File{Path: "@{sys}/kernel/security/apparmor/profiles", Access: "r"},
|
||||
&File{Path: "@{PROC}/@{pids}/attr/current", Access: "r"},
|
||||
&Include{IsMagic: true, Path: "abstractions/consoles"},
|
||||
&File{Owner: true, Path: "@{PROC}/@{pid}/mounts", Access: "r"},
|
||||
&Include{IsMagic: true, Path: "abstractions/base"},
|
||||
&File{Path: "/dev/tty@{int}", Access: "rw"},
|
||||
&Capability{Name: "sys_ptrace"},
|
||||
&Ptrace{Access: "read"},
|
||||
},
|
||||
}},
|
||||
},
|
||||
want: readprofile("apparmor.d/profiles-a-f/aa-status"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.f.Sort()
|
||||
tt.f.MergeRules()
|
||||
tt.f.Format()
|
||||
if got := tt.f.String(); "\n"+got != tt.want {
|
||||
t.Errorf("AppArmorProfile = |%v|, want |%v|", "\n"+got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue