Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle audit events with multiple messages #148

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 70 additions & 9 deletions aucoalesce/coalesce.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ type Event struct {
Dest *Address `json:"destination,omitempty" yaml:"destination,omitempty"`
Net *Network `json:"network,omitempty" yaml:"network,omitempty"`

Data map[string]string `json:"data,omitempty" yaml:"data,omitempty"`
Paths []map[string]string `json:"paths,omitempty" yaml:"paths,omitempty"`
Data map[string]string `json:"data,omitempty" yaml:"data,omitempty"`
AVCData []map[string]string `json:"avc_data,omitempty" yaml:"avc_data,omitempty"`
NetfilterCFGData []map[string]string `json:"netfilter_cfg_data,omitempty" yaml:"netfilter_cfg_data,omitempty"`
Paths []map[string]string `json:"paths,omitempty" yaml:"paths,omitempty"`

ECS ECSFields `json:"ecs" yaml:"ecs"`

Expand Down Expand Up @@ -218,13 +220,21 @@ func normalizeCompound(msgs []*auparse.AuditMessage) (*Event, error) {
break
}
}
if syscall == nil {
// All compound records have syscall messages.
return nil, errors.New("missing syscall message in compound event")
}

event := newEvent(special, syscall)

keyCollision := false
seen := make(map[string]bool)
for _, msg := range msgs {
switch msg.RecordType {
case auparse.AUDIT_AVC, auparse.AUDIT_NETFILTER_CFG:
if hasKeyCollision(msg, seen) {
keyCollision = true
}
}
}

dups := make(map[string]bool)
for _, msg := range msgs {
switch msg.RecordType {
case auparse.AUDIT_SYSCALL:
Expand All @@ -235,10 +245,23 @@ func normalizeCompound(msgs []*auparse.AuditMessage) (*Event, error) {
addSockaddrRecord(msg, event)
case auparse.AUDIT_EXECVE:
addExecveRecord(msg, event)
case auparse.AUDIT_AVC:
if keyCollision {
addAVCRecord(msg, event)
}
addFieldsToEventData(msg, event, true, dups)
case auparse.AUDIT_NETFILTER_CFG:
if keyCollision {
addNetfilterCfgRecord(msg, event)
}
addFieldsToEventData(msg, event, true, dups)
default:
addFieldsToEventData(msg, event)
addFieldsToEventData(msg, event, false, dups)
}
}
for k := range dups {
delete(event.Data, k)
}

return event, nil
}
Expand Down Expand Up @@ -378,6 +401,43 @@ func addPathRecord(path *auparse.AuditMessage, event *Event) {
event.Paths = append(event.Paths, data)
}

func hasKeyCollision(msg *auparse.AuditMessage, seen map[string]bool) bool {
data, err := msg.Data()
if err != nil {
return false
}

for k := range data {
if seen[k] {
return true
}
seen[k] = true
}
return false
}

func addAVCRecord(path *auparse.AuditMessage, event *Event) {
data, err := path.Data()
if err != nil {
event.Warnings = append(event.Warnings, fmt.Errorf(
"failed to parse AVC message: %w", err))
return
}

event.AVCData = append(event.AVCData, data)
}

func addNetfilterCfgRecord(path *auparse.AuditMessage, event *Event) {
data, err := path.Data()
if err != nil {
event.Warnings = append(event.Warnings, fmt.Errorf(
"failed to parse NETFILTER_CFG message: %w", err))
return
}

event.NetfilterCFGData = append(event.NetfilterCFGData, data)
}

func addProcess(event *Event) {
event.Process.PID = event.Data["pid"]
delete(event.Data, "pid")
Expand Down Expand Up @@ -434,7 +494,7 @@ func addExecveRecord(execve *auparse.AuditMessage, event *Event) {
event.Process.Args = args
}

func addFieldsToEventData(msg *auparse.AuditMessage, event *Event) {
func addFieldsToEventData(msg *auparse.AuditMessage, event *Event, allowDuplicate bool, dups map[string]bool) {
data, err := msg.Data()
if err != nil {
event.Warnings = append(event.Warnings,
Expand All @@ -443,9 +503,10 @@ func addFieldsToEventData(msg *auparse.AuditMessage, event *Event) {
}

for k, v := range data {
if _, found := event.Data[k]; found {
if o, found := event.Data[k]; found && (o != v || !allowDuplicate) {
event.Warnings = append(event.Warnings, fmt.Errorf(
"duplicate key (%v) from %v message", k, msg.RecordType))
dups[k] = true
continue
}
event.Data[k] = v
Expand Down
96 changes: 96 additions & 0 deletions aucoalesce/testdata/issue-127.json.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
[
{
"test_name": "multiple_avc_messages",
"event": {
"@timestamp": "2022-11-11T15:17:18.476Z",
"sequence": 649407,
"category": "mac-decision",
"record_type": "avc",
"result": "unknown",
"session": "",
"summary": {
"actor": {
"primary": "system_u:system_r:svirt_lxc_net_t:s0:c222,c955"
},
"action": "violated-selinux-policy",
"object": {
"primary": "system_u:object_r:sysctl_crypto_t:s0"
},
"how": "cephcsi"
},
"user": {},
"process": {
"pid": "4059486",
"name": "cephcsi"
},
"data": {
"dev": "proc",
"path": "/proc/sys/crypto/fips_enabled",
"permissive": "1",
"scontext": "system_u:system_r:svirt_lxc_net_t:s0:c222,c955",
"seresult": "denied",
"tcontext": "system_u:object_r:sysctl_crypto_t:s0"
},
"avc_data": [
{
"comm": "cephcsi",
"dev": "proc",
"ino": "475090959",
"name": "crypto",
"permissive": "1",
"pid": "4059486",
"scontext": "system_u:system_r:svirt_lxc_net_t:s0:c222,c955",
"seperms": "search",
"seresult": "denied",
"tclass": "dir",
"tcontext": "system_u:object_r:sysctl_crypto_t:s0"
},
{
"comm": "cephcsi",
"dev": "proc",
"ino": "475090960",
"name": "fips_enabled",
"permissive": "1",
"pid": "4059486",
"scontext": "system_u:system_r:svirt_lxc_net_t:s0:c222,c955",
"seperms": "read",
"seresult": "denied",
"tclass": "file",
"tcontext": "system_u:object_r:sysctl_crypto_t:s0"
},
{
"comm": "cephcsi",
"dev": "proc",
"ino": "475090960",
"path": "/proc/sys/crypto/fips_enabled",
"permissive": "1",
"pid": "4059486",
"scontext": "system_u:system_r:svirt_lxc_net_t:s0:c222,c955",
"seperms": "open",
"seresult": "denied",
"tclass": "file",
"tcontext": "system_u:object_r:sysctl_crypto_t:s0"
}
],
"ecs": {
"event": {},
"user": {
"effective": {},
"target": {},
"changes": {}
},
"group": {}
}
},
"warnings": [
"duplicate key (ino) from AVC message",
"duplicate key (ino) from AVC message",
"duplicate key (name) from AVC message",
"duplicate key (seperms) from AVC message",
"duplicate key (seperms) from AVC message",
"duplicate key (tclass) from AVC message",
"duplicate key (tclass) from AVC message",
"failed to set object secondary using keys=[tclass] because they were not found"
]
}
]
7 changes: 7 additions & 0 deletions aucoalesce/testdata/issue-127.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---

tests:
multiple_avc_messages: |
type=AVC msg=audit(1668179838.476:649407): avc: denied { search } for pid=4059486 comm="cephcsi" name="crypto" dev="proc" ino=475090959 scontext=system_u:system_r:svirt_lxc_net_t:s0:c222,c955 tcontext=system_u:object_r:sysctl_crypto_t:s0 tclass=dir permissive=1
type=AVC msg=audit(1668179838.476:649407): avc: denied { read } for pid=4059486 comm="cephcsi" name="fips_enabled" dev="proc" ino=475090960 scontext=system_u:system_r:svirt_lxc_net_t:s0:c222,c955 tcontext=system_u:object_r:sysctl_crypto_t:s0 tclass=file permissive=1
type=AVC msg=audit(1668179838.476:649407): avc: denied { open } for pid=4059486 comm="cephcsi" path="/proc/sys/crypto/fips_enabled" dev="proc" ino=475090960 scontext=system_u:system_r:svirt_lxc_net_t:s0:c222,c955 tcontext=system_u:object_r:sysctl_crypto_t:s0 tclass=file permissive=1
96 changes: 96 additions & 0 deletions aucoalesce/testdata/issue-71.json.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
[
{
"test_name": "multiple_netfilter_cfg_messages",
"event": {
"@timestamp": "2020-07-03T14:23:52.477Z",
"sequence": 31,
"category": "configuration",
"record_type": "netfilter_cfg",
"result": "success",
"session": "unset",
"summary": {
"actor": {
"primary": "unset",
"secondary": "0"
},
"action": "loaded-firewall-rule-to",
"object": {
"type": "firewall",
"primary": "filter"
},
"how": "/usr/lib/systemd/systemd"
},
"user": {
"ids": {
"auid": "unset",
"egid": "0",
"euid": "0",
"fsgid": "0",
"fsuid": "0",
"gid": "0",
"sgid": "0",
"suid": "0",
"uid": "0"
},
"selinux": {
"domain": "init_t",
"level": "s0",
"role": "system_r",
"user": "system_u"
}
},
"process": {
"pid": "769",
"ppid": "1",
"title": "(ostnamed)",
"name": "(ostnamed)",
"exe": "/usr/lib/systemd/systemd"
},
"data": {
"a0": "40000000",
"a1": "7fffd2436fb0",
"a2": "40000040",
"a3": "22",
"arch": "x86_64",
"entries": "0",
"exit": "0",
"syscall": "unshare",
"table": "filter",
"tty": "(none)"
},
"netfilter_cfg_data": [
{
"entries": "0",
"family": "2",
"table": "filter"
},
{
"entries": "0",
"family": "10",
"table": "filter"
}
],
"ecs": {
"event": {
"category": [
"configuration",
"process"
],
"type": [
"change",
"info"
]
},
"user": {
"effective": {},
"target": {},
"changes": {}
},
"group": {}
}
},
"warnings": [
"duplicate key (family) from NETFILTER_CFG message"
]
}
]
8 changes: 8 additions & 0 deletions aucoalesce/testdata/issue-71.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---

tests:
multiple_netfilter_cfg_messages: |
type=NETFILTER_CFG msg=audit(1593786232.477:31): table=filter family=2 entries=0
type=NETFILTER_CFG msg=audit(1593786232.477:31): table=filter family=10 entries=0
type=SYSCALL msg=audit(1593786232.477:31): arch=c000003e syscall=272 success=yes exit=0 a0=40000000 a1=7fffd2436fb0 a2=40000040 a3=22 items=0 ppid=1 pid=769 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="(ostnamed)" exe="/usr/lib/systemd/systemd" subj=system_u:system_r:init_t:s0 key=(null)
type=PROCTITLE msg=audit(1593786232.477:31): proctitle="(ostnamed)"
Loading