diff --git a/go.mod b/go.mod index 52a62c9..373313c 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,10 @@ require ( golang.org/x/sync v0.1.0 ) +replace ( + github.com/elastic/go-libaudit/v2 v2.3.2 => github.com/metal-toolbox/go-libaudit/v2 v2.3.3 +) + require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect diff --git a/go.sum b/go.sum index db3f87e..ea721b9 100644 --- a/go.sum +++ b/go.sum @@ -174,6 +174,8 @@ github.com/metal-toolbox/auditevent v0.5.2 h1:gmfxurtDZfDqQGpUrwndMcIhg/jEO+N2h9 github.com/metal-toolbox/auditevent v0.5.2/go.mod h1:tGA0raecPdRdz8lnckb8HQrciBNdL1Ft7C7mPxe1tvk= github.com/metal-toolbox/auditevent v0.6.1 h1:E+Z2xk4moiqm0r85UCQP7imquUXCToePLyPqipOz85s= github.com/metal-toolbox/auditevent v0.6.1/go.mod h1:EyW3Sncc68qfizhtviR5ZvDC09H001PC+a7gfyhe+/Q= +github.com/metal-toolbox/go-libaudit/v2 v2.3.3 h1:Dxr/VRBYYRB6pKC9z7GNuaRfSv+J/OO7jOzsioJFR08= +github.com/metal-toolbox/go-libaudit/v2 v2.3.3/go.mod h1:+ZE0czqmbqtnRkl0fNgpI+HvVVRo/ZMJdcXv/PaKcOo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/internal/auditd/auditd_test.go b/internal/auditd/auditd_test.go index cf669ce..65bfa85 100644 --- a/internal/auditd/auditd_test.go +++ b/internal/auditd/auditd_test.go @@ -1,7 +1,10 @@ package auditd import ( + "bufio" "context" + "strconv" + "strings" "testing" "time" @@ -402,3 +405,85 @@ func TestReassemblerCB_ReassemblyComplete_CancelOnSend(t *testing.T) { // Good. } } + +// Refer to the following GitHub issue for details: +// https://github.com/elastic/go-libaudit/issues/127 +func TestReassemblerCB_CompoundEventsMissingSyscall(t *testing.T) { + t.Parallel() + + ctx, cancelFn := context.WithTimeout(context.Background(), time.Second) + defer cancelFn() + + const case0 = `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 +` + + const case1 = `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 +` + + const case2 = `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 +` + + cases := []string{case0, case1, case2} + + assert.NotEmpty(t, cases) + + //nolint:paralleltest // All tests being parallel results in early exit. + for i, messageLinesSet := range cases { + t.Run("TestCase"+strconv.Itoa(i), func(t *testing.T) { + results := make(chan reassembleAuditdEventResult, 1) + + reassembler, err := libaudit.NewReassembler(maxEventsInFlight, eventTimeout, &reassemblerCB{ + ctx: ctx, + results: results, + after: time.Time{}, + }) + if err != nil { + t.Fatalf("failed to create resassembler - %s", err) + } + defer reassembler.Close() + + scanner := bufio.NewScanner(strings.NewReader(messageLinesSet)) + + for scanner.Scan() { + message, err := auparse.ParseLogLine(scanner.Text()) + if err != nil { + t.Fatalf("parse log line failed for case %d - %s", i, err) + } + + x := make(chan struct{}) + go func() { + reassembler.PushMessage(message) + close(x) + }() + + select { + case <-ctx.Done(): + t.Fatal(ctx.Err()) + case <-x: + } + } + + // Force event to be spat out. + _ = reassembler.Close() + + select { + case <-ctx.Done(): + t.Fatal(ctx.Err()) + case r := <-results: + if r.err != nil { + t.Fatalf("got non-nil error for case %d - %s", i, r.err) + } + } + }) + } +}