mirror of
https://github.com/roddhjav/apparmor.d.git
synced 2024-11-14 23:43:56 +01:00
refractor: update aa-log to the new structure.
This commit is contained in:
parent
400ecc52f5
commit
322866d902
@ -49,7 +49,7 @@ tests:
|
|||||||
- chmod 755 /usr/bin/journalctl
|
- chmod 755 /usr/bin/journalctl
|
||||||
- mkdir -p /var/log/audit/
|
- mkdir -p /var/log/audit/
|
||||||
- touch /var/log/audit/audit.log /var/log/audit/audit.log.1
|
- touch /var/log/audit/audit.log /var/log/audit/audit.log.1
|
||||||
- go test ./cmd/aa-log -v -cover -coverprofile=coverage.out
|
- go test ./cmd/... ./pkg/... -v -cover -coverprofile=coverage.out
|
||||||
- go tool cover -func=coverage.out
|
- go tool cover -func=coverage.out
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,20 +5,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"github.com/roddhjav/apparmor.d/pkg/logs"
|
||||||
"regexp"
|
"github.com/roddhjav/apparmor.d/pkg/util"
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const usage = `aa-log [-h] [--systemd] [--file file] [profile]
|
const usage = `aa-log [-h] [--systemd] [--file file] [profile]
|
||||||
@ -45,279 +38,22 @@ var (
|
|||||||
systemd bool
|
systemd bool
|
||||||
)
|
)
|
||||||
|
|
||||||
// LogFiles is the list of default path to query
|
|
||||||
var LogFiles = []string{
|
|
||||||
"/var/log/audit/audit.log",
|
|
||||||
"/var/log/syslog",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Colors
|
|
||||||
const (
|
|
||||||
Reset = "\033[0m"
|
|
||||||
FgGreen = "\033[32m"
|
|
||||||
FgYellow = "\033[33m"
|
|
||||||
FgBlue = "\033[34m"
|
|
||||||
FgMagenta = "\033[35m"
|
|
||||||
FgCian = "\033[36m"
|
|
||||||
FgWhite = "\033[37m"
|
|
||||||
BoldRed = "\033[1;31m"
|
|
||||||
BoldGreen = "\033[1;32m"
|
|
||||||
BoldYellow = "\033[1;33m"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AppArmorLog describes a apparmor log entry
|
|
||||||
type AppArmorLog map[string]string
|
|
||||||
|
|
||||||
// AppArmorLogs describes all apparmor log entries
|
|
||||||
type AppArmorLogs []AppArmorLog
|
|
||||||
|
|
||||||
// SystemdLog is a simplified systemd json log representation.
|
|
||||||
type SystemdLog struct {
|
|
||||||
Message string `json:"MESSAGE"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
quoted bool
|
|
||||||
isHexa = regexp.MustCompile("^[0-9A-Fa-f]+$")
|
|
||||||
)
|
|
||||||
|
|
||||||
func inSlice(item string, slice []string) bool {
|
|
||||||
sort.Strings(slice)
|
|
||||||
i := sort.SearchStrings(slice, item)
|
|
||||||
return i < len(slice) && slice[i] == item
|
|
||||||
}
|
|
||||||
|
|
||||||
func splitQuoted(r rune) bool {
|
|
||||||
if r == '"' {
|
|
||||||
quoted = !quoted
|
|
||||||
}
|
|
||||||
return !quoted && r == ' '
|
|
||||||
}
|
|
||||||
|
|
||||||
func toQuote(str string) string {
|
|
||||||
if strings.Contains(str, " ") {
|
|
||||||
return `"` + str + `"`
|
|
||||||
}
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeHex(str string) string {
|
|
||||||
if isHexa.MatchString(str) {
|
|
||||||
bs, _ := hex.DecodeString(str)
|
|
||||||
return string(bs)
|
|
||||||
}
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeDuplicateLog(logs []string) []string {
|
|
||||||
list := []string{}
|
|
||||||
keys := map[string]interface{}{"": true}
|
|
||||||
for _, log := range logs {
|
|
||||||
if _, v := keys[log]; !v {
|
|
||||||
keys[log] = true
|
|
||||||
list = append(list, log)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAuditLogs return a reader with the logs entries from Auditd
|
|
||||||
func getAuditLogs(path string) (io.Reader, error) {
|
|
||||||
file, err := os.Open(filepath.Clean(path))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return file, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// getJournalctlLogs return a reader with the logs entries from Systemd
|
|
||||||
func getJournalctlLogs(path string, useFile bool) (io.Reader, error) {
|
|
||||||
var logs []SystemdLog
|
|
||||||
var stdout bytes.Buffer
|
|
||||||
var value string
|
|
||||||
|
|
||||||
if useFile {
|
|
||||||
// content, err := os.ReadFile(filepath.Clean(path))
|
|
||||||
content, err := ioutil.ReadFile(filepath.Clean(path))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
value = string(content)
|
|
||||||
} else {
|
|
||||||
// journalctl -b -o json > systemd.log
|
|
||||||
cmd := exec.Command("journalctl", "--boot", "--output=json")
|
|
||||||
cmd.Stdout = &stdout
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
value = stdout.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
value = strings.Replace(value, "\n", ",\n", -1)
|
|
||||||
value = strings.TrimSuffix(value, ",\n")
|
|
||||||
value = `[` + value + `]`
|
|
||||||
if err := json.Unmarshal([]byte(value), &logs); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res := ""
|
|
||||||
for _, log := range logs {
|
|
||||||
res += log.Message + "\n"
|
|
||||||
}
|
|
||||||
return strings.NewReader(res), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewApparmorLogs return a new ApparmorLogs list of map from a log file
|
|
||||||
func NewApparmorLogs(file io.Reader, profile string) AppArmorLogs {
|
|
||||||
log := ""
|
|
||||||
exp := `apparmor=("DENIED"|"ALLOWED"|"AUDIT")`
|
|
||||||
if profile != "" {
|
|
||||||
exp = fmt.Sprintf(exp+`.* (profile="%s.*"|label="%s.*")`, profile, profile)
|
|
||||||
}
|
|
||||||
isAppArmorLog := regexp.MustCompile(exp)
|
|
||||||
|
|
||||||
// Select Apparmor logs
|
|
||||||
scanner := bufio.NewScanner(file)
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := scanner.Text()
|
|
||||||
if isAppArmorLog.MatchString(line) {
|
|
||||||
log += line + "\n"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean logs
|
|
||||||
regex := regexp.MustCompile(`.*apparmor="`)
|
|
||||||
log = regex.ReplaceAllLiteralString(log, `apparmor="`)
|
|
||||||
regexAppArmorLogs := map[*regexp.Regexp]string{
|
|
||||||
regexp.MustCompile(`(peer_|)pid=[0-9]* `): "",
|
|
||||||
regexp.MustCompile(` fsuid.*`): "",
|
|
||||||
regexp.MustCompile(` exe=.*`): "",
|
|
||||||
}
|
|
||||||
for regex, value := range regexAppArmorLogs {
|
|
||||||
log = regex.ReplaceAllLiteralString(log, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove doublon in logs
|
|
||||||
logs := strings.Split(log, "\n")
|
|
||||||
logs = removeDuplicateLog(logs)
|
|
||||||
|
|
||||||
// Parse log into ApparmorLog struct
|
|
||||||
aaLogs := make(AppArmorLogs, 0)
|
|
||||||
for _, log := range logs {
|
|
||||||
quoted = false
|
|
||||||
tmp := strings.FieldsFunc(log, splitQuoted)
|
|
||||||
|
|
||||||
aa := make(AppArmorLog)
|
|
||||||
for _, item := range tmp {
|
|
||||||
kv := strings.Split(item, "=")
|
|
||||||
if len(kv) >= 2 {
|
|
||||||
aa[kv[0]] = strings.Trim(kv[1], `"`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
aa["profile"] = decodeHex(aa["profile"])
|
|
||||||
toDecode := []string{"name", "comm"}
|
|
||||||
for _, name := range toDecode {
|
|
||||||
if value, ok := aa[name]; ok {
|
|
||||||
aa[name] = decodeHex(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
aaLogs = append(aaLogs, aa)
|
|
||||||
}
|
|
||||||
|
|
||||||
return aaLogs
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a formatted AppArmor logs string
|
|
||||||
func (aaLogs AppArmorLogs) String() string {
|
|
||||||
res := ""
|
|
||||||
state := map[string]string{
|
|
||||||
"DENIED": BoldRed + "DENIED " + Reset,
|
|
||||||
"ALLOWED": BoldGreen + "ALLOWED" + Reset,
|
|
||||||
"AUDIT": BoldYellow + "AUDIT " + Reset,
|
|
||||||
}
|
|
||||||
// Order of impression
|
|
||||||
keys := []string{
|
|
||||||
"profile", "label", // Profile name
|
|
||||||
"operation", "name",
|
|
||||||
"mask", "bus", "path", "interface", "member", // dbus
|
|
||||||
"info", "comm",
|
|
||||||
"laddr", "lport", "faddr", "fport", "family", "sock_type", "protocol",
|
|
||||||
"requested_mask", "denied_mask", "signal", "peer", // "fsuid", "ouid", "FSUID", "OUID",
|
|
||||||
}
|
|
||||||
// Optional colors template to use
|
|
||||||
colors := map[string]string{
|
|
||||||
"profile": FgBlue,
|
|
||||||
"label": FgBlue,
|
|
||||||
"operation": FgYellow,
|
|
||||||
"name": FgMagenta,
|
|
||||||
"mask": BoldRed,
|
|
||||||
"bus": FgCian + "bus=",
|
|
||||||
"path": "path=" + FgWhite,
|
|
||||||
"requested_mask": "requested_mask=" + BoldRed,
|
|
||||||
"denied_mask": "denied_mask=" + BoldRed,
|
|
||||||
"interface": "interface=" + FgWhite,
|
|
||||||
"member": "member=" + FgGreen,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, log := range aaLogs {
|
|
||||||
seen := map[string]bool{"apparmor": true}
|
|
||||||
res += state[log["apparmor"]]
|
|
||||||
|
|
||||||
for _, key := range keys {
|
|
||||||
if log[key] != "" {
|
|
||||||
if colors[key] != "" {
|
|
||||||
res += " " + colors[key] + toQuote(log[key]) + Reset
|
|
||||||
} else {
|
|
||||||
res += " " + key + "=" + toQuote(log[key])
|
|
||||||
}
|
|
||||||
seen[key] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, value := range log {
|
|
||||||
if !seen[key] && value != "" {
|
|
||||||
res += " " + key + "=" + toQuote(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res += "\n"
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func getLogFile(path string) string {
|
|
||||||
info, err := os.Stat(filepath.Clean(path))
|
|
||||||
if err == nil && !info.IsDir() {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
for _, logfile := range LogFiles {
|
|
||||||
if _, err := os.Stat(logfile); err == nil {
|
|
||||||
oldLogfile := filepath.Clean(logfile + "." + path)
|
|
||||||
if _, err := os.Stat(oldLogfile); err == nil {
|
|
||||||
return oldLogfile
|
|
||||||
} else {
|
|
||||||
return logfile
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func aaLog(logger string, path string, profile string) error {
|
func aaLog(logger string, path string, profile string) error {
|
||||||
var err error
|
var err error
|
||||||
var file io.Reader
|
var file io.Reader
|
||||||
|
|
||||||
switch logger {
|
switch logger {
|
||||||
case "auditd":
|
case "auditd":
|
||||||
file, err = getAuditLogs(path)
|
file, err = logs.GetAuditLogs(path)
|
||||||
case "systemd":
|
case "systemd":
|
||||||
file, err = getJournalctlLogs(path, !inSlice(path, LogFiles))
|
file, err = logs.GetJournalctlLogs(path, !util.InSlice(path, logs.LogFiles))
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("Logger %s not supported.", logger)
|
err = fmt.Errorf("Logger %s not supported.", logger)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
aaLogs := NewApparmorLogs(file, profile)
|
aaLogs := logs.NewApparmorLogs(file, profile)
|
||||||
fmt.Print(aaLogs.String())
|
fmt.Print(aaLogs.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -349,7 +85,7 @@ func main() {
|
|||||||
logger = "systemd"
|
logger = "systemd"
|
||||||
}
|
}
|
||||||
|
|
||||||
logfile := getLogFile(path)
|
logfile := logs.GetLogFile(path)
|
||||||
err := aaLog(logger, logfile, profile)
|
err := aaLog(logger, logfile, profile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
@ -5,338 +5,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
"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",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
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",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "dbus_system",
|
|
||||||
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",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "dbus_session",
|
|
||||||
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",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
name string
|
|
||||||
path string
|
|
||||||
want AppArmorLogs
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "dnsmasq",
|
|
||||||
path: "../../tests/audit.log",
|
|
||||||
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",
|
|
||||||
path: "../../tests/audit.log",
|
|
||||||
want: refKmod,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "man",
|
|
||||||
path: "../../tests/audit.log",
|
|
||||||
want: refMan,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_getJournalctlLogs(t *testing.T) {
|
|
||||||
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",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "journalctl",
|
|
||||||
useFile: false,
|
|
||||||
path: "",
|
|
||||||
want: AppArmorLogs{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAppArmorLogs_String(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
aaLogs AppArmorLogs
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "kmod",
|
|
||||||
aaLogs: refKmod,
|
|
||||||
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: "\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",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_getLogFile(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
path string
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Get audit.log",
|
|
||||||
path: "../../tests/audit.log",
|
|
||||||
want: "../../tests/audit.log",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Get /var/log/audit/audit.log.1",
|
|
||||||
path: "1",
|
|
||||||
want: "/var/log/audit/audit.log.1",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Get default log file",
|
|
||||||
path: "",
|
|
||||||
want: "/var/log/audit/audit.log",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
if got := getLogFile(tt.path); got != tt.want {
|
|
||||||
t.Errorf("getLogFile() = %v, want %v", got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_app(t *testing.T) {
|
func Test_app(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
Loading…
Reference in New Issue
Block a user