2021-12-05 00:53:32 +01:00
|
|
|
|
// aa-log - Review AppArmor generated messages
|
|
|
|
|
// Copyright (C) 2021 Alexandre Pujol <alexandre@pujol.io>
|
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
|
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"os"
|
|
|
|
|
"reflect"
|
2022-05-02 18:14:42 +02:00
|
|
|
|
"strings"
|
2021-12-05 00:53:32 +01:00
|
|
|
|
"testing"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var refKmod = AppArmorLogs{
|
|
|
|
|
{
|
|
|
|
|
"apparmor": "ALLOWED",
|
|
|
|
|
"profile": "kmod",
|
|
|
|
|
"operation": "file_inherit",
|
|
|
|
|
"comm": "modprobe",
|
|
|
|
|
"family": "unix",
|
|
|
|
|
"sock_type": "stream",
|
|
|
|
|
"protocol": "0",
|
|
|
|
|
"requested_mask": "send receive",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var refMan = AppArmorLogs{
|
|
|
|
|
{
|
|
|
|
|
"apparmor": "ALLOWED",
|
|
|
|
|
"profile": "man",
|
|
|
|
|
"operation": "exec",
|
|
|
|
|
"name": "/usr/bin/preconv",
|
|
|
|
|
"info": "no new privs",
|
|
|
|
|
"comm": "man",
|
|
|
|
|
"requested_mask": "x",
|
|
|
|
|
"denied_mask": "x",
|
|
|
|
|
"error": "-1",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-02 18:14:42 +02:00
|
|
|
|
func TestAppArmorEvents(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
event string
|
|
|
|
|
want AppArmorLogs
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "event_audit_1",
|
|
|
|
|
event: `type=AVC msg=audit(1345027352.096:499): apparmor="ALLOWED" operation="rename_dest" parent=6974 profile="/usr/sbin/httpd2-prefork//vhost_foo" name=2F686F6D652F7777772F666F6F2E6261722E696E2F68747470646F63732F61707061726D6F722F696D616765732F746573742F696D61676520312E6A7067 pid=20143 comm="httpd2-prefork" requested_mask="wc" denied_mask="wc" fsuid=30 ouid=30`,
|
|
|
|
|
want: AppArmorLogs{
|
|
|
|
|
{
|
|
|
|
|
"apparmor": "ALLOWED",
|
|
|
|
|
"profile": "/usr/sbin/httpd2-prefork//vhost_foo",
|
|
|
|
|
"operation": "rename_dest",
|
|
|
|
|
"name": "/home/www/foo.bar.in/httpdocs/apparmor/images/test/image 1.jpg",
|
|
|
|
|
"comm": "httpd2-prefork",
|
|
|
|
|
"requested_mask": "wc",
|
|
|
|
|
"denied_mask": "wc",
|
|
|
|
|
"parent": "6974",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "event_audit_2",
|
|
|
|
|
event: `type=AVC msg=audit(1322614918.292:4376): apparmor="ALLOWED" operation="file_perm" parent=16001 profile=666F6F20626172 name="/home/foo/.bash_history" pid=17011 comm="bash" requested_mask="rw" denied_mask="rw" fsuid=0 ouid=1000`,
|
|
|
|
|
want: AppArmorLogs{
|
|
|
|
|
{
|
|
|
|
|
"apparmor": "ALLOWED",
|
|
|
|
|
"profile": "foo bar",
|
|
|
|
|
"operation": "file_perm",
|
|
|
|
|
"name": "/home/foo/.bash_history",
|
|
|
|
|
"comm": "bash",
|
|
|
|
|
"requested_mask": "rw",
|
|
|
|
|
"denied_mask": "rw",
|
|
|
|
|
"parent": "16001",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "disconnected_path",
|
|
|
|
|
event: `type=AVC msg=audit(1424425690.883:716630): apparmor="ALLOWED" operation="file_mmap" info="Failed name lookup - disconnected path" error=-13 profile="/sbin/klogd" name="var/run/nscd/passwd" pid=25333 comm="id" requested_mask="r" denied_mask="r" fsuid=1002 ouid=0`,
|
|
|
|
|
want: AppArmorLogs{
|
|
|
|
|
{
|
|
|
|
|
"apparmor": "ALLOWED",
|
|
|
|
|
"profile": "/sbin/klogd",
|
|
|
|
|
"operation": "file_mmap",
|
|
|
|
|
"name": "var/run/nscd/passwd",
|
|
|
|
|
"comm": "id",
|
|
|
|
|
"info": "Failed name lookup - disconnected path",
|
|
|
|
|
"requested_mask": "r",
|
|
|
|
|
"denied_mask": "r",
|
|
|
|
|
"error": "-13",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
2022-08-19 20:05:46 +02:00
|
|
|
|
{
|
2023-02-19 18:53:49 +01:00
|
|
|
|
name: "dbus_system",
|
2022-08-19 20:05:46 +02:00
|
|
|
|
event: `type=USER_AVC msg=audit(1111111111.111:1111): pid=1780 uid=102 auid=4294967295 ses=4294967295 subj=? msg='apparmor="ALLOWED" operation="dbus_method_call" bus="system" path="/org/freedesktop/PolicyKit1/Authority" interface="org.freedesktop.PolicyKit1.Authority" member="CheckAuthorization" mask="send" name="org.freedesktop.PolicyKit1" pid=1794 label="snapd" peer_pid=1790 peer_label="polkitd" exe="/usr/bin/dbus-daemon" sauid=102 hostname=? addr=? terminal=?'UID="messagebus" AUID="unset" SAUID="messagebus"`,
|
|
|
|
|
want: AppArmorLogs{
|
|
|
|
|
{
|
|
|
|
|
"apparmor": "ALLOWED",
|
|
|
|
|
"profile": "",
|
|
|
|
|
"label": "snapd",
|
|
|
|
|
"operation": "dbus_method_call",
|
|
|
|
|
"name": "org.freedesktop.PolicyKit1",
|
|
|
|
|
"mask": "send",
|
|
|
|
|
"bus": "system",
|
|
|
|
|
"path": "/org/freedesktop/PolicyKit1/Authority",
|
|
|
|
|
"interface": "org.freedesktop.PolicyKit1.Authority",
|
|
|
|
|
"member": "CheckAuthorization",
|
|
|
|
|
"peer_label": "polkitd",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
2023-02-19 18:53:49 +01:00
|
|
|
|
name: "dbus_session",
|
2022-08-19 20:05:46 +02:00
|
|
|
|
event: `apparmor="ALLOWED" operation="dbus_bind" bus="session" name="org.freedesktop.portal.Documents" mask="bind" pid=2174 label="xdg-document-portal"`,
|
|
|
|
|
want: AppArmorLogs{
|
|
|
|
|
{
|
|
|
|
|
"apparmor": "ALLOWED",
|
|
|
|
|
"profile": "",
|
|
|
|
|
"label": "xdg-document-portal",
|
|
|
|
|
"operation": "dbus_bind",
|
|
|
|
|
"name": "org.freedesktop.portal.Documents",
|
|
|
|
|
"mask": "bind",
|
|
|
|
|
"bus": "session",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
2022-05-02 18:14:42 +02:00
|
|
|
|
}
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
file := strings.NewReader(tt.event)
|
|
|
|
|
if got := NewApparmorLogs(file, ""); !reflect.DeepEqual(got, tt.want) {
|
|
|
|
|
t.Errorf("NewApparmorLogs() = %v, want %v", got, tt.want)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-05 00:53:32 +01:00
|
|
|
|
|
|
|
|
|
func TestNewApparmorLogs(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
path string
|
|
|
|
|
want AppArmorLogs
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "dnsmasq",
|
|
|
|
|
path: "../../tests/audit.log",
|
2022-05-02 18:14:42 +02:00
|
|
|
|
want: AppArmorLogs{
|
|
|
|
|
{
|
|
|
|
|
"apparmor": "DENIED",
|
|
|
|
|
"profile": "dnsmasq",
|
|
|
|
|
"operation": "open",
|
|
|
|
|
"name": "/proc/sys/kernel/osrelease",
|
|
|
|
|
"comm": "dnsmasq",
|
|
|
|
|
"requested_mask": "r",
|
|
|
|
|
"denied_mask": "r",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"apparmor": "DENIED",
|
|
|
|
|
"profile": "dnsmasq",
|
|
|
|
|
"operation": "open",
|
|
|
|
|
"name": "/proc/1/environ",
|
|
|
|
|
"comm": "dnsmasq",
|
|
|
|
|
"requested_mask": "r",
|
|
|
|
|
"denied_mask": "r",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"apparmor": "DENIED",
|
|
|
|
|
"profile": "dnsmasq",
|
|
|
|
|
"operation": "open",
|
|
|
|
|
"name": "/proc/cmdline",
|
|
|
|
|
"comm": "dnsmasq",
|
|
|
|
|
"requested_mask": "r",
|
|
|
|
|
"denied_mask": "r",
|
|
|
|
|
},
|
|
|
|
|
},
|
2021-12-05 00:53:32 +01:00
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "kmod",
|
|
|
|
|
path: "../../tests/audit.log",
|
|
|
|
|
want: refKmod,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "man",
|
|
|
|
|
path: "../../tests/audit.log",
|
|
|
|
|
want: refMan,
|
|
|
|
|
},
|
2022-08-19 20:05:46 +02:00
|
|
|
|
{
|
|
|
|
|
name: "power-profiles-daemon",
|
|
|
|
|
path: "../../tests/audit.log",
|
|
|
|
|
want: AppArmorLogs{
|
|
|
|
|
{
|
|
|
|
|
"apparmor": "ALLOWED",
|
|
|
|
|
"profile": "",
|
|
|
|
|
"label": "power-profiles-daemon",
|
|
|
|
|
"operation": "dbus_method_call",
|
|
|
|
|
"name": "org.freedesktop.DBus",
|
|
|
|
|
"mask": "send",
|
|
|
|
|
"bus": "system",
|
|
|
|
|
"path": "/org/freedesktop/DBus",
|
|
|
|
|
"interface": "org.freedesktop.DBus",
|
|
|
|
|
"member": "AddMatch",
|
|
|
|
|
"peer_label": "dbus-daemon",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
2021-12-05 00:53:32 +01:00
|
|
|
|
}
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
file, _ := os.Open(tt.path)
|
|
|
|
|
if got := NewApparmorLogs(file, tt.name); !reflect.DeepEqual(got, tt.want) {
|
|
|
|
|
t.Errorf("NewApparmorLogs() = %v, want %v", got, tt.want)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-06 22:11:35 +02:00
|
|
|
|
func Test_getJournalctlLogs(t *testing.T) {
|
2022-08-19 20:05:46 +02:00
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
path string
|
|
|
|
|
useFile bool
|
|
|
|
|
want AppArmorLogs
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "gsd-xsettings",
|
|
|
|
|
useFile: true,
|
|
|
|
|
path: "../../tests/systemd.log",
|
|
|
|
|
want: AppArmorLogs{
|
|
|
|
|
{
|
|
|
|
|
"apparmor": "ALLOWED",
|
|
|
|
|
"profile": "",
|
|
|
|
|
"label": "gsd-xsettings",
|
|
|
|
|
"operation": "dbus_method_call",
|
|
|
|
|
"name": ":1.88",
|
|
|
|
|
"mask": "receive",
|
|
|
|
|
"bus": "session",
|
|
|
|
|
"path": "/org/gtk/Settings",
|
|
|
|
|
"interface": "org.freedesktop.DBus.Properties",
|
|
|
|
|
"member": "GetAll",
|
|
|
|
|
"peer_label": "gnome-extension-ding",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
2022-10-15 22:28:57 +02:00
|
|
|
|
{
|
|
|
|
|
name: "journalctl",
|
|
|
|
|
useFile: false,
|
|
|
|
|
path: "",
|
|
|
|
|
want: AppArmorLogs{},
|
|
|
|
|
},
|
2022-08-19 20:05:46 +02:00
|
|
|
|
}
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2023-02-19 18:53:49 +01:00
|
|
|
|
reader, _ := getJournalctlLogs(tt.path, tt.useFile)
|
2022-08-19 20:05:46 +02:00
|
|
|
|
if got := NewApparmorLogs(reader, tt.name); !reflect.DeepEqual(got, tt.want) {
|
|
|
|
|
t.Errorf("NewApparmorLogs() = %v, want %v", got, tt.want)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-05 00:53:32 +01:00
|
|
|
|
func TestAppArmorLogs_String(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
aaLogs AppArmorLogs
|
|
|
|
|
want string
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "kmod",
|
|
|
|
|
aaLogs: refKmod,
|
2022-05-02 18:14:42 +02:00
|
|
|
|
want: "\033[1;32mALLOWED\033[0m \033[34mkmod\033[0m \033[33mfile_inherit\033[0m comm=modprobe family=unix sock_type=stream protocol=0 requested_mask=\033[1;31m\"send receive\"\033[0m\n",
|
2021-12-05 00:53:32 +01:00
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "man",
|
|
|
|
|
aaLogs: refMan,
|
2022-05-02 18:14:42 +02:00
|
|
|
|
want: "\033[1;32mALLOWED\033[0m \033[34mman\033[0m \033[33mexec\033[0m \033[35m/usr/bin/preconv\033[0m info=\"no new privs\" comm=man requested_mask=\033[1;31mx\033[0m denied_mask=\033[1;31mx\033[0m error=-1\n",
|
2021-12-05 00:53:32 +01:00
|
|
|
|
},
|
2022-08-19 20:05:46 +02:00
|
|
|
|
{
|
|
|
|
|
name: "power-profiles-daemon",
|
|
|
|
|
aaLogs: AppArmorLogs{
|
|
|
|
|
{
|
|
|
|
|
"apparmor": "ALLOWED",
|
|
|
|
|
"profile": "",
|
|
|
|
|
"label": "power-profiles-daemon",
|
|
|
|
|
"operation": "dbus_method_call",
|
|
|
|
|
"name": "org.freedesktop.DBus",
|
|
|
|
|
"mask": "send",
|
|
|
|
|
"bus": "system",
|
|
|
|
|
"path": "/org/freedesktop/DBus",
|
|
|
|
|
"interface": "org.freedesktop.DBus",
|
|
|
|
|
"member": "AddMatch",
|
|
|
|
|
"peer_label": "dbus-daemon",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
want: "\033[1;32mALLOWED\033[0m \033[34mpower-profiles-daemon\033[0m \033[33mdbus_method_call\033[0m \033[35morg.freedesktop.DBus\033[0m \033[1;31msend\033[0m \033[36mbus=system\033[0m path=\033[37m/org/freedesktop/DBus\033[0m interface=\033[37morg.freedesktop.DBus\033[0m member=\033[32mAddMatch\033[0m peer_label=dbus-daemon\n",
|
|
|
|
|
},
|
2021-12-05 00:53:32 +01:00
|
|
|
|
}
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
if got := tt.aaLogs.String(); got != tt.want {
|
|
|
|
|
t.Errorf("AppArmorLogs.String() = %v, want %v len: %d - %d", got, tt.want, len(got), len(tt.want))
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-12 13:35:08 +01:00
|
|
|
|
|
|
|
|
|
func Test_app(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
2022-10-06 22:11:35 +02:00
|
|
|
|
logger string
|
2021-12-12 13:35:08 +01:00
|
|
|
|
path string
|
2022-02-10 22:30:51 +01:00
|
|
|
|
profile string
|
2021-12-12 13:35:08 +01:00
|
|
|
|
wantErr bool
|
|
|
|
|
}{
|
|
|
|
|
{
|
2022-08-19 20:05:46 +02:00
|
|
|
|
name: "Test audit.log",
|
2022-10-06 22:11:35 +02:00
|
|
|
|
logger: "auditd",
|
2021-12-12 13:35:08 +01:00
|
|
|
|
path: "../../tests/audit.log",
|
2022-02-10 22:30:51 +01:00
|
|
|
|
profile: "",
|
2022-08-19 20:05:46 +02:00
|
|
|
|
wantErr: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "Test Dbus Session",
|
2022-10-06 22:11:35 +02:00
|
|
|
|
logger: "systemd",
|
2022-08-19 20:05:46 +02:00
|
|
|
|
path: "../../tests/systemd.log",
|
|
|
|
|
profile: "",
|
2021-12-12 13:35:08 +01:00
|
|
|
|
wantErr: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "No logfile",
|
2022-10-06 22:11:35 +02:00
|
|
|
|
logger: "auditd",
|
2021-12-12 13:35:08 +01:00
|
|
|
|
path: "../../tests/log",
|
2022-02-10 22:30:51 +01:00
|
|
|
|
profile: "",
|
2022-10-06 22:11:35 +02:00
|
|
|
|
wantErr: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "Logger not supported",
|
|
|
|
|
logger: "raw",
|
|
|
|
|
path: "../../tests/audit.log",
|
|
|
|
|
profile: "",
|
2021-12-12 13:35:08 +01:00
|
|
|
|
wantErr: true,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2022-10-06 22:11:35 +02:00
|
|
|
|
if err := aaLog(tt.logger, tt.path, tt.profile); (err != nil) != tt.wantErr {
|
2021-12-12 13:35:08 +01:00
|
|
|
|
t.Errorf("aaLog() error = %v, wantErr %v", err, tt.wantErr)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|