feat(aa-log): improve logs cleaning and varible resolution.

This commit is contained in:
Alexandre Pujol 2024-09-26 22:25:24 +01:00
parent 83bc7d3ade
commit 00d6a664eb
No known key found for this signature in database
GPG Key ID: C5469996F0DF68EC
5 changed files with 44 additions and 35 deletions

View File

@ -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 {

View File

@ -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 {

View File

@ -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)
}
})
}

View File

@ -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

View File

@ -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)
}
})
}