mirror of
https://github.com/roddhjav/apparmor.d.git
synced 2024-11-14 23:43:56 +01:00
feat(aa-log): improve logs cleaning and varible resolution.
This commit is contained in:
parent
83bc7d3ade
commit
00d6a664eb
@ -17,7 +17,7 @@ import (
|
|||||||
|
|
||||||
const usage = `aa-log [-h] [--systemd] [--file file] [--rules | --raw] [profile]
|
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.
|
auditd, systemd, syslog as well as dbus session events.
|
||||||
|
|
||||||
It can be given an optional profile name to filter the output with.
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
aaLogs := logs.NewApparmorLogs(file, profile)
|
aaLogs := logs.New(file, profile)
|
||||||
if rules {
|
if rules {
|
||||||
profiles := aaLogs.ParseToProfiles()
|
profiles := aaLogs.ParseToProfiles()
|
||||||
for _, p := range profiles {
|
for _, p := range profiles {
|
||||||
|
@ -76,10 +76,10 @@ func getIndentationLevel(input string) int {
|
|||||||
return level
|
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
|
var raw string
|
||||||
paragraphs := []string{}
|
paragraphs := []string{}
|
||||||
rulesByParagraph := []aa.Rules{}
|
rulesByParagraph := aa.ParaRules{}
|
||||||
|
|
||||||
switch kind {
|
switch kind {
|
||||||
case isTunable, isProfile:
|
case isTunable, isProfile:
|
||||||
@ -110,9 +110,6 @@ func formatFile(kind kind, profile string) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
for idx, rules := range rulesByParagraph {
|
for idx, rules := range rulesByParagraph {
|
||||||
if err := rules.Validate(); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
aa.IndentationLevel = getIndentationLevel(paragraphs[idx])
|
aa.IndentationLevel = getIndentationLevel(paragraphs[idx])
|
||||||
rules = rules.Merge().Sort().Format()
|
rules = rules.Merge().Sort().Format()
|
||||||
profile = strings.Replace(profile, paragraphs[idx], rules.String()+"\n", -1)
|
profile = strings.Replace(profile, paragraphs[idx], rules.String()+"\n", -1)
|
||||||
@ -202,8 +199,12 @@ func main() {
|
|||||||
logging.Fatal("%s", err.Error())
|
logging.Fatal("%s", err.Error())
|
||||||
}
|
}
|
||||||
err = aaFormat(files)
|
err = aaFormat(files)
|
||||||
|
|
||||||
case tree:
|
case tree:
|
||||||
err = aaTree()
|
err = aaTree()
|
||||||
|
|
||||||
|
default:
|
||||||
|
flag.Usage()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -30,7 +30,7 @@ func TestGetJournalctlLogs(t *testing.T) {
|
|||||||
"apparmor": "ALLOWED",
|
"apparmor": "ALLOWED",
|
||||||
"label": "gsd-xsettings",
|
"label": "gsd-xsettings",
|
||||||
"operation": "dbus_method_call",
|
"operation": "dbus_method_call",
|
||||||
"name": ":*",
|
"name": "@{busname}",
|
||||||
"mask": "receive",
|
"mask": "receive",
|
||||||
"bus": "session",
|
"bus": "session",
|
||||||
"path": "/org/gtk/Settings",
|
"path": "/org/gtk/Settings",
|
||||||
@ -50,8 +50,8 @@ func TestGetJournalctlLogs(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
reader, _ := GetJournalctlLogs(tt.path, tt.useFile)
|
reader, _ := GetJournalctlLogs(tt.path, tt.useFile)
|
||||||
if got := NewApparmorLogs(reader, tt.name); !reflect.DeepEqual(got, tt.want) {
|
if got := New(reader, tt.name); !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("NewApparmorLogs() = %v, want %v", got, tt.want)
|
t.Errorf("New() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -28,11 +28,14 @@ const (
|
|||||||
boldYellow = "\033[1;33m"
|
boldYellow = "\033[1;33m"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
h = `[0-9a-fA-F]`
|
||||||
|
d = `[0-9]`
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
quoted bool
|
quoted bool
|
||||||
isAppArmorLogTemplate = regexp.MustCompile(`apparmor=("DENIED"|"ALLOWED"|"AUDIT")`)
|
isAppArmorLogTemplate = regexp.MustCompile(`apparmor=("DENIED"|"ALLOWED"|"AUDIT")`)
|
||||||
_hex = `[0-9a-fA-F]`
|
|
||||||
_int = `[0-9]`
|
|
||||||
regCleanLogs = util.ToRegexRepl([]string{
|
regCleanLogs = util.ToRegexRepl([]string{
|
||||||
// Clean apparmor log file
|
// Clean apparmor log file
|
||||||
`.*apparmor="`, `apparmor="`,
|
`.*apparmor="`, `apparmor="`,
|
||||||
@ -61,40 +64,45 @@ var (
|
|||||||
`/home/[^/]+/`, `@{HOME}/`,
|
`/home/[^/]+/`, `@{HOME}/`,
|
||||||
|
|
||||||
// Resolve system variables
|
// Resolve system variables
|
||||||
`/usr/(lib|lib32|lib64|libexec)`, `@{lib}`,
|
`/usr/lib(32|64|exec)`, `@{lib}`,
|
||||||
|
`/usr/lib`, `@{lib}`,
|
||||||
`/usr/(bin|sbin)`, `@{bin}`,
|
`/usr/(bin|sbin)`, `@{bin}`,
|
||||||
`x86_64-pc-linux-gnu[^/]?`, `@{multiarch}`,
|
`(x86_64|amd64|i386|i686)`, `@{arch}`,
|
||||||
|
`@{arch}-*linux-gnu[^/]?`, `@{multiarch}`,
|
||||||
`/usr/etc/`, `@{etc_ro}/`,
|
`/usr/etc/`, `@{etc_ro}/`,
|
||||||
`/var/run/`, `@{run}/`,
|
`/var/run/`, `@{run}/`,
|
||||||
`/run/`, `@{run}/`,
|
`/run/`, `@{run}/`,
|
||||||
`user/[0-9]*/`, `user/@{uid}/`,
|
`user/[0-9]*/`, `user/@{uid}/`,
|
||||||
`/tmp/user/@{uid}/`, `@{tmp}/`,
|
`/tmp/user/@{uid}/`, `@{tmp}/`,
|
||||||
`/proc/`, `@{PROC}/`,
|
`/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}/[0-9]*/`, `@{PROC}/@{pid}/`,
|
||||||
|
`@{PROC}/one/`, `@{PROC}/1/`,
|
||||||
`@{PROC}/@{pid}/task/[0-9]*/`, `@{PROC}/@{pid}/task/@{tid}/`,
|
`@{PROC}/@{pid}/task/[0-9]*/`, `@{PROC}/@{pid}/task/@{tid}/`,
|
||||||
`/sys/`, `@{sys}/`,
|
`/sys/`, `@{sys}/`,
|
||||||
`@{PROC}@{sys}/`, `@{PROC}/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}/`,
|
`@{pci_bus}/[0-9a-f:*./]*`, `@{pci}/`,
|
||||||
`1000`, `@{uid}`,
|
`1000`, `@{uid}`,
|
||||||
|
|
||||||
// Some system glob
|
// 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
|
`@{bin}/(|ba|da)sh`, `@{sh_path}`, // collect all shell
|
||||||
`@{lib}/modules/[^/]+\/`, `@{lib}/modules/*/`, // strip kernel version numbers from kernel module accesses
|
`@{lib}/modules/[^/]+\/`, `@{lib}/modules/*/`, // strip kernel version numbers from kernel module accesses
|
||||||
|
|
||||||
// int, hex, uuid
|
// 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(h, 8) + `[-_]` + strings.Repeat(h, 4) + `[-_]` + strings.Repeat(h, 4) + `[-_]` + strings.Repeat(h, 4) + `[-_]` + strings.Repeat(h, 12), `@{uuid}`,
|
||||||
strings.Repeat(_int, 64), `@{int64}`,
|
strings.Repeat(d, 64), `@{int64}`,
|
||||||
strings.Repeat(_hex, 64), `@{hex64}`,
|
strings.Repeat(h, 64), `@{hex64}`,
|
||||||
strings.Repeat(_hex, 38), `@{hex38}`,
|
strings.Repeat(h, 38), `@{hex38}`,
|
||||||
strings.Repeat(_int, 32), `@{int32}`,
|
strings.Repeat(d, 32), `@{int32}`,
|
||||||
strings.Repeat(_hex, 32), `@{hex32}`,
|
strings.Repeat(h, 32), `@{hex32}`,
|
||||||
strings.Repeat(_int, 16), `@{int16}`,
|
strings.Repeat(d, 16), `@{int16}`,
|
||||||
strings.Repeat(_hex, 16), `@{hex16}`,
|
strings.Repeat(h, 16), `@{hex16}`,
|
||||||
strings.Repeat(_int, 10), `@{int10}`,
|
strings.Repeat(d, 10), `@{int10}`,
|
||||||
strings.Repeat(_int, 8), `@{int8}`,
|
strings.Repeat(d, 8), `@{int8}`,
|
||||||
strings.Repeat(_int, 6), `@{int6}`,
|
strings.Repeat(d, 6), `@{int6}`,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -117,8 +125,8 @@ func toQuote(str string) string {
|
|||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewApparmorLogs return a new ApparmorLogs list of map from a log file
|
// New returns a new ApparmorLogs list of map from a log file
|
||||||
func NewApparmorLogs(file io.Reader, profile string) AppArmorLogs {
|
func New(file io.Reader, profile string) AppArmorLogs {
|
||||||
logs := GetApparmorLogs(file, profile)
|
logs := GetApparmorLogs(file, profile)
|
||||||
|
|
||||||
// Parse log into ApparmorLog struct
|
// Parse log into ApparmorLog struct
|
||||||
|
@ -174,14 +174,14 @@ func TestAppArmorEvents(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
file := strings.NewReader(tt.event)
|
file := strings.NewReader(tt.event)
|
||||||
if got := NewApparmorLogs(file, ""); !reflect.DeepEqual(got, tt.want) {
|
if got := New(file, ""); !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("NewApparmorLogs() = %v, want %v", got, tt.want)
|
t.Errorf("New() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewApparmorLogs(t *testing.T) {
|
func TestNew(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
path string
|
path string
|
||||||
@ -208,7 +208,7 @@ func TestNewApparmorLogs(t *testing.T) {
|
|||||||
"apparmor": "DENIED",
|
"apparmor": "DENIED",
|
||||||
"profile": "dnsmasq",
|
"profile": "dnsmasq",
|
||||||
"operation": "open",
|
"operation": "open",
|
||||||
"name": "@{PROC}/@{pid}/environ",
|
"name": "@{PROC}/1/environ",
|
||||||
"comm": "dnsmasq",
|
"comm": "dnsmasq",
|
||||||
"requested_mask": "r",
|
"requested_mask": "r",
|
||||||
"denied_mask": "r",
|
"denied_mask": "r",
|
||||||
@ -251,8 +251,8 @@ func TestNewApparmorLogs(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
file, _ := os.Open(tt.path)
|
file, _ := os.Open(tt.path)
|
||||||
if got := NewApparmorLogs(file, tt.name); !reflect.DeepEqual(got, tt.want) {
|
if got := New(file, tt.name); !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("NewApparmorLogs() = %v, want %v", got, tt.want)
|
t.Errorf("New() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user