elastic / go-libaudit

go-libaudit is a library for communicating with the Linux Audit Framework.
https://www.elastic.co/products/beats/auditbeat
Apache License 2.0
2 stars 71 forks source link

aucoalesce: CoalesceMessages fails with "missing syscall message in compound event" #127

Open stephen-fox opened 1 year ago

stephen-fox commented 1 year ago

Hello,

While experimenting with this library on flatcar Linux, I noticed that the aucoalesce.CoalesceMessages function returns the following error when it encounters certain audit events: missing syscall message in compound event

If I supply the same events to the aureport tool (installed as a part of auditd package on Ubuntu), it appears to successfully parse those events - at least in the sense it does not produce error messages or exit with a non-zero status. It looks like commit 666ff1c30fe624e9fcd9a108b20fceb82331f5fa introduced the formerly-mentioned error - but it does not reference any Linux audit documentation or code that contextualizes the check.

tl;dr - I am not sure if this check is required - or if the audit logs I happened to encounter are just broken. Any kind of guidance would be appreciated :)

Below are the three audit events and the aureport stderr/out for them. For reference, the --debug argument should result in error messages if any events cannot be parsed and -e generates a report about events:

Failure 1

root@x:~# cat avc-failure-audit.log
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
root@x:~# aureport -if avc-failure-audit.log --debug -e 

Event Report
===================================
# date time event type auid success
===================================
1. 11/11/2022 15:17:18 649407 AVC -2 no
root@x:~# echo $?
0

Failure 2

root@x:~# cat execve-uname-failure-audit.log
type=EXECVE msg=audit(1671230062.742:657491): argc=2 a0="uname" a1="-p"
type=CWD msg=audit(1671230062.742:657491): cwd="/root"
type=PATH msg=audit(1671230062.742:657491): item=0 name="/usr/bin/uname" inode=76040 dev=fe:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:unlabeled_t:s0 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(1671230062.742:657491): item=1 name="/lib64/ld-linux-x86-64.so.2" inode=98548 dev=fe:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:unlabeled_t:s0 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PROCTITLE msg=audit(1671230062.742:657491): proctitle=756E616D65002D70
root@x:~# aureport -if execve-uname-failure-audit.log --debug -e

Event Report
===================================
# date time event type auid success
===================================
1. 12/16/2022 22:34:22 657491 EXECVE -2 unset
root@x:~# echo $?
0

Failure 3

root@x:~# cat execve-ethtool-failure-audit.log
type=EXECVE msg=audit(1671230063.745:657579): argc=3 a0="/usr/sbin/ethtool" a1="-T" a2="lxc61be96845005"
type=CWD msg=audit(1671230063.745:657579): cwd="/root"
type=PATH msg=audit(1671230063.745:657579): item=0 name="/usr/sbin/ethtool" inode=162594 dev=fe:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:unlabeled_t:s0 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(1671230063.745:657579): item=1 name="/lib64/ld-linux-x86-64.so.2" inode=98548 dev=fe:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:unlabeled_t:s0 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PROCTITLE msg=audit(1671230063.745:657579): proctitle=2F7573722F7362696E2F657468746F6F6C002D54006C7863363162653936383435303035
root@x:~# aureport -if execve-ethtool-failure-audit.log --debug -e

Event Report
===================================
# date time event type auid success
===================================
1. 12/16/2022 22:34:23 657579 EXECVE -2 unset
root@x:~# echo $?
0

Other notes

I commented out the code that returns the error and tried running the project's Go tests with go test ./.... The tests ran successfully. Based on the test result and the error being generated with errors.New - it appears to be both untested and not programmatically checkable (e.g., errors.As).

drewr commented 1 year ago

👋 @v1v @andrewkroh!! I work with @stephen-fox. Think you could give this a quick look and see what may be involved here? We could maybe contribute a fix for it. Thanks!

andrewkroh commented 1 year ago

Hi @drewr 😄 , it looks like the assumption that a type=SYSCALL message is always present when there is more than one message with the same sequence number may be wrong. This assumption looks particularly wrong with respect to failure case 1 where you have multiple AVC messages which will not be tied in with a particular syscall.

For failure cases 2 and 3, what auditd rules were used to generate those groups of messages? If you were auditing execve then I would have expected one type=SYSCALL along with the others. It is possible to have a filter applied that could have discarded that SYSCALL message, but I would say to not do that.

I think it should possible to relax the requirement on having a type=SYSCALL when there is more than one message and still have today's test cases pass.

One other problem I see is with failure case 1. Normally the key/value pairs are dumped into the data map, but with three of the same message types there will be key collisions. So perhaps special handling will be required for AVC message (like we have for type=PATH). The same issue popped up for type=NETFILTER_CFG in #71 and it has not been addressed.

stephen-fox commented 1 year ago

Hi @andrewkroh! Thank you for the explanation. All three examples came from a single computer that has the following /etc/audit/audit.rules:

## This file is automatically generated from /etc/audit/rules.d
-D
-b 32768
-f 1
--backlog_wait_time 60000
--loginuid-immutable
-a always,exit -F arch=b32 -S init_module,finit_module -F key=module-load
-a always,exit -F arch=b64 -S init_module,finit_module -F key=module-load
-a always,exit -F arch=b32 -S delete_module -F key=module-unload
-a always,exit -F arch=b64 -S delete_module -F key=module-unload 
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/passwd -F auid=500 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/passwd -F auid=500 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/passwd -F auid=500 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/passwd -F auid=500 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/shadow -F auid=500 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/shadow -F auid=500 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/shadow -F auid=500 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/shadow -F auid=500 -F auid!=unset -F key=user-modify
-a always,exit -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify
-a always,exit -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify
-a always,exit -F path=/etc/passwd -F perm=wa -F auid=500 -F auid!=unset -F key=user-modify
-a always,exit -F path=/etc/shadow -F perm=wa -F auid=500 -F auid!=unset -F key=user-modify
-a always,exit -F path=/etc/group -F perm=wa -F auid=500 -F auid!=unset -F key=group-modify
-a always,exit -F path=/etc/gshadow -F perm=wa -F auid=500 -F auid!=unset -F key=group-modify
-a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid=500 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/mount -F perm=x -F auid=500 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid=500 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/newuidmap -F perm=x -F auid=500 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid=500 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/newgidmap -F perm=x -F auid=500 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/umount -F perm=x -F auid=500 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/passwd -F perm=x -F auid=500 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/etc/sudoers -F perm=wa -F key=special-config-changes
-a always,exit -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes
-a always,exit -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail
-a always,exit -F dir=/var/log/audit/ -F perm=r -F auid=500 -F auid!=unset -F key=access-audit-trail
-a always,exit -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session
-a always,exit -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session
-a always,exit -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session
-a always,exit -F path=/var/run/utmp -F perm=wa -F auid=500 -F auid!=unset -F key=session
-a always,exit -F path=/var/log/btmp -F perm=wa -F auid=500 -F auid!=unset -F key=session
-a always,exit -F path=/var/log/wtmp -F perm=wa -F auid=500 -F auid!=unset -F key=session
-a always,exit -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy
-a always,exit -F dir=/etc/selinux/ -F perm=wa -F auid=500 -F auid!=unset -F key=MAC-policy
-a always,exit -F path=/bin/crictl -F perm=x -F auid>=1000 -F auid!=unset -F key=container-management
-a always,exit -F path=/bin/crictl -F perm=x -F auid=500 -F auid!=unset -F key=container-management
-a always,exit -F path=/bin/docker -F perm=x -F auid>=1000 -F auid!=unset -F key=container-management
-a always,exit -F path=/bin/docker -F perm=x -F auid=500 -F auid!=unset -F key=container-management
-a always,exit -F path=/opt/bin/argocd -F perm=x -F auid>=1000 -F auid!=unset -F key=container-management
-a always,exit -F path=/opt/bin/argocd -F perm=x -F auid=500 -F auid!=unset -F key=container-management
-a always,exit -F path=/opt/bin/crictl -F perm=x -F auid>=1000 -F auid!=unset -F key=container-management
-a always,exit -F path=/opt/bin/crictl -F perm=x -F auid=500 -F auid!=unset -F key=container-management
-a always,exit -F path=/opt/bin/kubeadm -F perm=x -F auid>=1000 -F auid!=unset -F key=container-management
-a always,exit -F path=/opt/bin/kubeadm -F perm=x -F auid=500 -F auid!=unset -F key=container-management
-a always,exit -F path=/opt/bin/kubectl -F perm=x -F auid>=1000 -F auid!=unset -F key=container-management
-a always,exit -F path=/opt/bin/kubectl -F perm=x -F auid=500 -F auid!=unset -F key=container-management
-a always,exit -F path=/opt/bin/kubectl -F perm=x -F auid=0 -F auid!=unset -F key=container-management
-a always,exit -F path=/opt/bin/nerdctl -F perm=x -F auid>=1000 -F auid!=unset -F key=container-management
-a always,exit -F path=/opt/bin/nerdctl -F perm=x -F auid=500 -F auid!=unset -F key=container-management
-a always,exit -F path=/opt/bin/nerdctl -F perm=x -F auid=0 -F auid!=unset -F key=container-management
-r 60
-a exit,always -F arch=b64 -S execve -F key=auditcmd -F auid=500
-a exit,always -F arch=b32 -S execve -F key=auditcmd -F auid=500
-e 1