diff --git a/cmd/aa-log/main.go b/cmd/aa-log/main.go index 7536f9c5..a6e61246 100644 --- a/cmd/aa-log/main.go +++ b/cmd/aa-log/main.go @@ -6,8 +6,10 @@ package main import ( "bufio" + "encoding/hex" "flag" "fmt" + "io" "os" "path/filepath" "regexp" @@ -80,7 +82,7 @@ func removeDuplicateLog(logs []string) []string { } // NewApparmorLogs return a new ApparmorLogs list of map from a log file -func NewApparmorLogs(file *os.File, profile string) AppArmorLogs { +func NewApparmorLogs(file io.Reader, profile string) AppArmorLogs { log := "" exp := "apparmor=(\"DENIED\"|\"ALLOWED\"|\"AUDIT\")" if profile != "" { @@ -201,7 +203,7 @@ func aaLog(path string, profile string) error { func init() { flag.BoolVar(&help, "h", false, "Show this help message and exit.") flag.StringVar(&path, "f", LogFile, - "Set a log`file` or a prefix to the default log file.") + "Set a log`file` or a suffix to the default log file.") } func main() { diff --git a/cmd/aa-log/main_test.go b/cmd/aa-log/main_test.go index 359d71ac..2ddca15d 100644 --- a/cmd/aa-log/main_test.go +++ b/cmd/aa-log/main_test.go @@ -7,39 +7,10 @@ package main import ( "os" "reflect" + "strings" "testing" ) -var refDnsmasq = 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", - }, -} - var refKmod = AppArmorLogs{ { "apparmor": "ALLOWED", @@ -67,8 +38,71 @@ var refMan = AppArmorLogs{ }, } -var refStringKmod = "\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" -var refStringMan = "\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" +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", + }, + }, + }, + } + 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) + } + }) + } +} func TestNewApparmorLogs(t *testing.T) { tests := []struct { @@ -79,7 +113,35 @@ func TestNewApparmorLogs(t *testing.T) { { name: "dnsmasq", path: "../../tests/audit.log", - want: refDnsmasq, + 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", + }, + }, }, { name: "kmod", @@ -111,12 +173,12 @@ func TestAppArmorLogs_String(t *testing.T) { { name: "kmod", aaLogs: refKmod, - want: refStringKmod, + 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", }, { name: "man", aaLogs: refMan, - want: refStringMan, + 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", }, } for _, tt := range tests {