// apparmor.d - Full set of apparmor profiles // Copyright (C) 2021-2024 Alexandre Pujol // SPDX-License-Identifier: GPL-2.0-only package aa import ( "reflect" "testing" ) func TestRule_FromLog(t *testing.T) { for _, tt := range testRule { if tt.fromLog == nil { continue } t.Run(tt.name, func(t *testing.T) { if got := tt.fromLog(tt.log); !reflect.DeepEqual(got, tt.rule) { t.Errorf("RuleFromLog() = %v, want %v", got, tt.rule) } }) } } func TestRule_String(t *testing.T) { for _, tt := range testRule { t.Run(tt.name, func(t *testing.T) { if got := tt.rule.String(); got != tt.wString { t.Errorf("Rule.String() = %v, want %v", got, tt.wString) } }) } } func TestRule_Validate(t *testing.T) { for _, tt := range testRule { t.Run(tt.name, func(t *testing.T) { if err := tt.rule.Validate(); (err != nil) != tt.wValidErr { t.Errorf("Rules.Validate() error = %v, wantErr %v", err, tt.wValidErr) } }) } } func TestRule_Compare(t *testing.T) { for _, tt := range testRule { t.Run(tt.name, func(t *testing.T) { if got := tt.rule.Compare(tt.other); got != tt.wCompare { t.Errorf("Rule.Compare() = %v, want %v", got, tt.wCompare) } }) } } func TestRule_Merge(t *testing.T) { for _, tt := range testRule { t.Run(tt.name, func(t *testing.T) { if got := tt.rule.Merge(tt.other); got != tt.wMerge { t.Errorf("Rule.Merge() = %v, want %v", got, tt.wMerge) } }) } } var ( // Test cases for the Rule interface testRule = []struct { name string fromLog func(map[string]string) Rule log map[string]string rule Rule wValidErr bool other Rule wCompare int wMerge bool wString string }{ { name: "comment", rule: comment1, other: comment2, wCompare: 0, wMerge: false, wString: "#comment", }, { name: "abi", rule: abi1, other: abi2, wCompare: 1, wMerge: false, wString: "abi ,", }, { name: "alias", rule: alias1, other: alias2, wCompare: -1, wMerge: false, wString: "alias /mnt/usr -> /usr,", }, { name: "include1", rule: include1, other: includeLocal1, wCompare: -11, wMerge: false, wString: "include ", }, { name: "include2", rule: include1, other: include2, wCompare: 1, wMerge: false, wString: "include ", }, { name: "include-local", rule: includeLocal1, other: include1, wCompare: 11, wMerge: false, wString: "include if exists ", }, { name: "include/abs", rule: &Include{Path: "/usr/share/apparmor.d/", IsMagic: false}, other: &Include{Path: "/usr/share/apparmor.d/", IsMagic: true}, wCompare: -1, wMerge: false, wString: `include "/usr/share/apparmor.d/"`, }, { name: "variable", rule: variable1, other: variable2, wCompare: -3, wMerge: false, wString: "@{bin} = /{,usr/}{,s}bin", }, { name: "all", rule: all1, other: all2, wCompare: 0, wMerge: true, wString: "all,", }, { name: "rlimit", rule: rlimit1, other: rlimit2, wCompare: 11, wMerge: false, wString: "set rlimit nproc <= 200,", }, { name: "rlimit2", rule: rlimit2, other: rlimit2, wCompare: 0, wMerge: false, wString: "set rlimit cpu <= 2,", }, { name: "rlimit3", rule: rlimit3, other: rlimit1, wCompare: -1, wMerge: false, wString: "set rlimit nproc < 2,", }, { name: "userns", rule: userns1, other: userns2, wCompare: 1, wMerge: true, wString: "userns,", }, { name: "capbability", fromLog: newCapabilityFromLog, log: capability1Log, rule: capability1, other: capability2, wCompare: -5, wMerge: false, wString: "capability net_admin,", }, { name: "capability/multi", rule: &Capability{Names: []string{"dac_override", "dac_read_search"}}, other: capability2, wCompare: -15, wMerge: false, wString: "capability dac_override dac_read_search,", }, { name: "capability/all", rule: &Capability{}, other: capability2, wCompare: -1, wMerge: false, wString: "capability,", }, { name: "network", fromLog: newNetworkFromLog, log: network1Log, rule: network1, wValidErr: true, other: network2, wCompare: 5, wMerge: false, wString: "network netlink raw,", }, { name: "mount", fromLog: newMountFromLog, log: mount1Log, rule: mount1, other: mount2, wCompare: 38, wMerge: false, wString: "mount fstype=overlay overlay -> /var/lib/docker/overlay2/opaque-bug-check1209538631/merged/, # failed perms check", }, { name: "remount", rule: remount1, other: remount2, wCompare: -6, wMerge: false, wString: "remount /,", }, { name: "umount", fromLog: newUmountFromLog, log: umount1Log, rule: umount1, other: umount2, wCompare: -8, wMerge: false, wString: "umount /,", }, { name: "pivot_root1", fromLog: newPivotRootFromLog, log: pivotroot1Log, rule: pivotroot1, other: pivotroot2, wCompare: 7, wMerge: false, wString: "pivot_root oldroot=@{run}/systemd/mount-rootfs/ @{run}/systemd/mount-rootfs/,", }, { name: "pivot_root2", rule: pivotroot1, other: pivotroot3, wCompare: 28, wMerge: false, wString: "pivot_root oldroot=@{run}/systemd/mount-rootfs/ @{run}/systemd/mount-rootfs/,", }, { name: "change_profile1", fromLog: newChangeProfileFromLog, log: changeprofile1Log, rule: changeprofile1, other: changeprofile2, wCompare: 17, wMerge: false, wString: "change_profile -> systemd-user,", }, { name: "change_profile2", rule: changeprofile2, other: changeprofile3, wCompare: -4, wMerge: false, wString: "change_profile -> brwap,", }, { name: "mqueue", rule: mqueue1, other: mqueue2, wCompare: -3, wMerge: false, wString: "mqueue r type=posix /,", }, { name: "iouring", rule: iouring1, other: iouring2, wCompare: 4, wMerge: false, wString: "io_uring sqpoll label=foo,", }, { name: "signal", fromLog: newSignalFromLog, log: signal1Log, rule: signal1, other: signal2, wCompare: -10, wMerge: true, wString: "signal receive set=kill peer=firefox//&firejail-default,", }, { name: "ptrace/xdg-document-portal", fromLog: newPtraceFromLog, log: ptrace1Log, rule: ptrace1, other: ptrace1, wCompare: 0, wMerge: true, wString: "ptrace read peer=nautilus,", }, { name: "ptrace/snap-update-ns.firefox", fromLog: newPtraceFromLog, log: ptrace2Log, rule: ptrace2, other: ptrace1, wCompare: 2, wMerge: false, wString: "ptrace readby peer=systemd-journald,", }, { name: "unix", fromLog: newUnixFromLog, log: unix1Log, rule: unix1, other: unix1, wCompare: 0, wMerge: true, wString: "unix (send receive) type=stream protocol=0 addr=none peer=(label=dbus-daemon, addr=@/tmp/dbus-AaKMpxzC4k),", }, { name: "dbus", fromLog: newDbusFromLog, log: dbus1Log, rule: dbus1, other: dbus1, wCompare: 0, wMerge: true, wString: "dbus receive bus=session path=/org/gtk/vfs/metadata\n interface=org.gtk.vfs.Metadata\n member=Remove\n peer=(name=:1.15, label=tracker-extract),", }, { name: "dbus2", rule: dbus2, other: dbus3, wCompare: 9, wMerge: false, wString: "dbus bind bus=session name=org.gnome.evolution.dataserver.Sources5,", }, { name: "dbus/bind", rule: &Dbus{Access: []string{"bind"}, Bus: "session", Name: "org.gnome.*"}, other: dbus2, wCompare: -39, wMerge: false, wString: `dbus bind bus=session name=org.gnome.*,`, }, { name: "dbus/full", rule: &Dbus{Bus: "accessibility"}, other: dbus1, wCompare: -1, wMerge: false, wString: `dbus bus=accessibility,`, }, { name: "file", fromLog: newFileFromLog, log: file1Log, rule: file1, other: file2, wCompare: -14, wMerge: false, wString: "/usr/share/poppler/cMap/Identity-H r,", }, { name: "file/empty", rule: &File{}, other: &File{}, wCompare: 0, wMerge: true, wString: " ,", }, { name: "file/equal", rule: &File{Path: "/usr/share/poppler/cMap/Identity-H"}, other: &File{Path: "/usr/share/poppler/cMap/Identity-H"}, wCompare: 0, wMerge: true, wString: "/usr/share/poppler/cMap/Identity-H ,", }, { name: "file/owner", rule: &File{Path: "/usr/share/poppler/cMap/Identity-H", Owner: true}, other: &File{Path: "/usr/share/poppler/cMap/Identity-H"}, wCompare: 1, wMerge: false, wString: "owner /usr/share/poppler/cMap/Identity-H ,", }, { name: "file/access", rule: &File{Path: "/usr/share/poppler/cMap/Identity-H", Access: []string{"r"}}, other: &File{Path: "/usr/share/poppler/cMap/Identity-H", Access: []string{"w"}}, wCompare: -5, wMerge: true, wString: "/usr/share/poppler/cMap/Identity-H r,", }, { name: "file/close", rule: &File{Path: "/usr/share/poppler/cMap/"}, other: &File{Path: "/usr/share/poppler/cMap/Identity-H"}, wCompare: -10, wMerge: false, wString: "/usr/share/poppler/cMap/ ,", }, { name: "link1", fromLog: newLinkFromLog, log: link1Log, rule: link1, other: link2, wCompare: -1, wMerge: false, wString: "link /tmp/mkinitcpio.QDWtza/early@{lib}/firmware/i915/dg1_dmc_ver2_02.bin.zst -> /tmp/mkinitcpio.QDWtza/root@{lib}/firmware/i915/dg1_dmc_ver2_02.bin.zst,", }, { name: "link2", fromLog: newFileFromLog, log: link3Log, rule: link3, other: link1, wCompare: 1, wMerge: false, wString: "owner link @{user_config_dirs}/kiorc -> @{user_config_dirs}/#3954,", }, { name: "profile", rule: profile1, other: profile2, wCompare: -4, wMerge: false, wString: "profile sudo {\n}", }, { name: "hat", rule: hat1, other: hat2, wCompare: 3, wMerge: false, wString: "hat user {\n}", }, } )