From 00d6a664eb11eedf8bee418174cd85dad4bd2cc4 Mon Sep 17 00:00:00 2001 From: Alexandre Pujol Date: Thu, 26 Sep 2024 22:25:24 +0100 Subject: [PATCH] feat(aa-log): improve logs cleaning and varible resolution. --- cmd/aa-log/main.go | 4 ++-- cmd/aa/main.go | 11 +++++----- pkg/logs/loggers_test.go | 6 +++--- pkg/logs/logs.go | 46 +++++++++++++++++++++++----------------- pkg/logs/logs_test.go | 12 +++++------ 5 files changed, 44 insertions(+), 35 deletions(-) diff --git a/cmd/aa-log/main.go b/cmd/aa-log/main.go index 184e6d11..f7c484fd 100644 --- a/cmd/aa-log/main.go +++ b/cmd/aa-log/main.go @@ -17,7 +17,7 @@ import ( const usage = `aa-log [-h] [--systemd] [--file file] [--rules | --raw] [profile] - Review AppArmor generated messages in a colorful way. Supports logs from + Review AppArmor generated messages in a colorful way. It supports logs from auditd, systemd, syslog as well as dbus session events. It can be given an optional profile name to filter the output with. @@ -64,7 +64,7 @@ func aaLog(logger string, path string, profile string) error { return nil } - aaLogs := logs.NewApparmorLogs(file, profile) + aaLogs := logs.New(file, profile) if rules { profiles := aaLogs.ParseToProfiles() for _, p := range profiles { diff --git a/cmd/aa/main.go b/cmd/aa/main.go index ec64e8cf..d5bc10d5 100644 --- a/cmd/aa/main.go +++ b/cmd/aa/main.go @@ -76,10 +76,10 @@ func getIndentationLevel(input string) int { return level } -func parse(kind kind, profile string) ([]aa.Rules, []string, error) { +func parse(kind kind, profile string) (aa.ParaRules, []string, error) { var raw string paragraphs := []string{} - rulesByParagraph := []aa.Rules{} + rulesByParagraph := aa.ParaRules{} switch kind { case isTunable, isProfile: @@ -110,9 +110,6 @@ func formatFile(kind kind, profile string) (string, error) { return "", err } for idx, rules := range rulesByParagraph { - if err := rules.Validate(); err != nil { - return "", err - } aa.IndentationLevel = getIndentationLevel(paragraphs[idx]) rules = rules.Merge().Sort().Format() profile = strings.Replace(profile, paragraphs[idx], rules.String()+"\n", -1) @@ -202,8 +199,12 @@ func main() { logging.Fatal("%s", err.Error()) } err = aaFormat(files) + case tree: err = aaTree() + + default: + flag.Usage() } if err != nil { diff --git a/pkg/logs/loggers_test.go b/pkg/logs/loggers_test.go index 15fa1fbc..d1a48534 100644 --- a/pkg/logs/loggers_test.go +++ b/pkg/logs/loggers_test.go @@ -30,7 +30,7 @@ func TestGetJournalctlLogs(t *testing.T) { "apparmor": "ALLOWED", "label": "gsd-xsettings", "operation": "dbus_method_call", - "name": ":*", + "name": "@{busname}", "mask": "receive", "bus": "session", "path": "/org/gtk/Settings", @@ -50,8 +50,8 @@ func TestGetJournalctlLogs(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { reader, _ := GetJournalctlLogs(tt.path, tt.useFile) - if got := NewApparmorLogs(reader, tt.name); !reflect.DeepEqual(got, tt.want) { - t.Errorf("NewApparmorLogs() = %v, want %v", got, tt.want) + if got := New(reader, tt.name); !reflect.DeepEqual(got, tt.want) { + t.Errorf("New() = %v, want %v", got, tt.want) } }) } diff --git a/pkg/logs/logs.go b/pkg/logs/logs.go index 587e0b7b..67197e53 100644 --- a/pkg/logs/logs.go +++ b/pkg/logs/logs.go @@ -28,11 +28,14 @@ const ( boldYellow = "\033[1;33m" ) +const ( + h = `[0-9a-fA-F]` + d = `[0-9]` +) + var ( quoted bool isAppArmorLogTemplate = regexp.MustCompile(`apparmor=("DENIED"|"ALLOWED"|"AUDIT")`) - _hex = `[0-9a-fA-F]` - _int = `[0-9]` regCleanLogs = util.ToRegexRepl([]string{ // Clean apparmor log file `.*apparmor="`, `apparmor="`, @@ -61,40 +64,45 @@ var ( `/home/[^/]+/`, `@{HOME}/`, // Resolve system variables - `/usr/(lib|lib32|lib64|libexec)`, `@{lib}`, + `/usr/lib(32|64|exec)`, `@{lib}`, + `/usr/lib`, `@{lib}`, `/usr/(bin|sbin)`, `@{bin}`, - `x86_64-pc-linux-gnu[^/]?`, `@{multiarch}`, + `(x86_64|amd64|i386|i686)`, `@{arch}`, + `@{arch}-*linux-gnu[^/]?`, `@{multiarch}`, `/usr/etc/`, `@{etc_ro}/`, `/var/run/`, `@{run}/`, `/run/`, `@{run}/`, `user/[0-9]*/`, `user/@{uid}/`, `/tmp/user/@{uid}/`, `@{tmp}/`, `/proc/`, `@{PROC}/`, + `@{PROC}/1/`, `@{PROC}/one/`, // Go does not support lookahead assertions like (?!1\b)d+, so we have to use a workaround `@{PROC}/[0-9]*/`, `@{PROC}/@{pid}/`, + `@{PROC}/one/`, `@{PROC}/1/`, `@{PROC}/@{pid}/task/[0-9]*/`, `@{PROC}/@{pid}/task/@{tid}/`, `/sys/`, `@{sys}/`, `@{PROC}@{sys}/`, `@{PROC}/sys/`, - `pci` + strings.Repeat(_hex, 4) + `:` + strings.Repeat(_hex, 2), `@{pci_bus}`, + `pci` + strings.Repeat(h, 4) + `:` + strings.Repeat(h, 2), `@{pci_bus}`, `@{pci_bus}/[0-9a-f:*./]*`, `@{pci}/`, `1000`, `@{uid}`, // Some system glob - `:1.[0-9]*`, `:*`, // dbus peer name + `:not.active.yet`, `@{busname}`, // dbus unique bus name + `:1.[0-9]*`, `@{busname}`, // dbus unique bus name `@{bin}/(|ba|da)sh`, `@{sh_path}`, // collect all shell `@{lib}/modules/[^/]+\/`, `@{lib}/modules/*/`, // strip kernel version numbers from kernel module accesses // int, hex, uuid - strings.Repeat(_hex, 8) + `[-_]` + strings.Repeat(_hex, 4) + `[-_]` + strings.Repeat(_hex, 4) + `[-_]` + strings.Repeat(_hex, 4) + `[-_]` + strings.Repeat(_hex, 12), `@{uuid}`, - strings.Repeat(_int, 64), `@{int64}`, - strings.Repeat(_hex, 64), `@{hex64}`, - strings.Repeat(_hex, 38), `@{hex38}`, - strings.Repeat(_int, 32), `@{int32}`, - strings.Repeat(_hex, 32), `@{hex32}`, - strings.Repeat(_int, 16), `@{int16}`, - strings.Repeat(_hex, 16), `@{hex16}`, - strings.Repeat(_int, 10), `@{int10}`, - strings.Repeat(_int, 8), `@{int8}`, - strings.Repeat(_int, 6), `@{int6}`, + strings.Repeat(h, 8) + `[-_]` + strings.Repeat(h, 4) + `[-_]` + strings.Repeat(h, 4) + `[-_]` + strings.Repeat(h, 4) + `[-_]` + strings.Repeat(h, 12), `@{uuid}`, + strings.Repeat(d, 64), `@{int64}`, + strings.Repeat(h, 64), `@{hex64}`, + strings.Repeat(h, 38), `@{hex38}`, + strings.Repeat(d, 32), `@{int32}`, + strings.Repeat(h, 32), `@{hex32}`, + strings.Repeat(d, 16), `@{int16}`, + strings.Repeat(h, 16), `@{hex16}`, + strings.Repeat(d, 10), `@{int10}`, + strings.Repeat(d, 8), `@{int8}`, + strings.Repeat(d, 6), `@{int6}`, }) ) @@ -117,8 +125,8 @@ func toQuote(str string) string { return str } -// NewApparmorLogs return a new ApparmorLogs list of map from a log file -func NewApparmorLogs(file io.Reader, profile string) AppArmorLogs { +// New returns a new ApparmorLogs list of map from a log file +func New(file io.Reader, profile string) AppArmorLogs { logs := GetApparmorLogs(file, profile) // Parse log into ApparmorLog struct diff --git a/pkg/logs/logs_test.go b/pkg/logs/logs_test.go index cc4b93ed..c70909dc 100644 --- a/pkg/logs/logs_test.go +++ b/pkg/logs/logs_test.go @@ -174,14 +174,14 @@ func TestAppArmorEvents(t *testing.T) { 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) + if got := New(file, ""); !reflect.DeepEqual(got, tt.want) { + t.Errorf("New() = %v, want %v", got, tt.want) } }) } } -func TestNewApparmorLogs(t *testing.T) { +func TestNew(t *testing.T) { tests := []struct { name string path string @@ -208,7 +208,7 @@ func TestNewApparmorLogs(t *testing.T) { "apparmor": "DENIED", "profile": "dnsmasq", "operation": "open", - "name": "@{PROC}/@{pid}/environ", + "name": "@{PROC}/1/environ", "comm": "dnsmasq", "requested_mask": "r", "denied_mask": "r", @@ -251,8 +251,8 @@ func TestNewApparmorLogs(t *testing.T) { 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) + if got := New(file, tt.name); !reflect.DeepEqual(got, tt.want) { + t.Errorf("New() = %v, want %v", got, tt.want) } }) }