From 29ce4013f40152b89cad4f48dbd273f1318c3761 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Wed, 15 Nov 2023 16:01:11 +1030 Subject: [PATCH] x-pack/auditbeat/module/socket/guess: fix creds trigger for newer kernels In kernel commit 981ee95c (into v6.3) calls to access_override_creds were gated behind a test for the requirement for the call. This change results in non-execution of prepare_creds and so failure of the guess. An alternative has been identified that does not exhibit this behaviour, mq_open which calls dentry_open with creds in the third parameter. So replace the sys_access trigger with sys_mq_open and add the probe to dentry_open with P3 for the address. Approach developed by Christiano Haesbaert. --- CHANGELOG.next.asciidoc | 1 + .../module/system/socket/guess/creds.go | 50 ++++++++++++++----- x-pack/auditbeat/seccomp_linux.go | 14 +++++- 3 files changed, 50 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index ccac6ce5650..ab800fe74c7 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -67,6 +67,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] *Auditbeat* - Fix documentation regarding socket type selection. {issue}37174[37174] {pull}37175[37175] +- Fix guess trigger for system/socket creds on newer kernels. {issue}36905[36905] {pull}37136[37136] *Filebeat* diff --git a/x-pack/auditbeat/module/system/socket/guess/creds.go b/x-pack/auditbeat/module/system/socket/guess/creds.go index 4180725addf..7df1b0c1c2f 100644 --- a/x-pack/auditbeat/module/system/socket/guess/creds.go +++ b/x-pack/auditbeat/module/system/socket/guess/creds.go @@ -19,6 +19,17 @@ import ( "github.com/elastic/elastic-agent-libs/mapstr" ) +/* +struct mq_attr { + long mq_flags; + long mq_maxmsg; + long mq_msgsize; + long mq_curmsgs; + long __reserved[4]; +}; +*/ +import "C" + /* creds guess discovers the offsets of (E)UID/(E)GID fields within a struct cred (defined in {linux}/include/linux.cred.h): @@ -77,20 +88,20 @@ func (g *guessStructCreds) Provides() []string { // Requires declares the variables required to run this guess. func (g *guessStructCreds) Requires() []string { return []string{ - "RET", + "P3", } } -// Probes returns a kretprobe on prepare_creds that dumps the first bytes -// pointed to by the return value, which is a struct cred. +// Probes returns a kprobe on dentry_open that dumps the first bytes +// pointed to by the third parameter value, which is a struct cred. func (g *guessStructCreds) Probes() ([]helper.ProbeDef, error) { return []helper.ProbeDef{ { Probe: tracing.Probe{ - Type: tracing.TypeKRetProbe, + Type: tracing.TypeKProbe, Name: "guess_struct_creds", - Address: "prepare_creds", - Fetchargs: helper.MakeMemoryDump("{{.RET}}", 0, credDumpBytes), + Address: "dentry_open", + Fetchargs: helper.MakeMemoryDump("{{.P3}}", 0, credDumpBytes), }, Decoder: tracing.NewDumpDecoder, }, @@ -138,13 +149,26 @@ func (g *guessStructCreds) Extract(ev interface{}) (mapstr.M, bool) { }, true } -// Trigger invokes the SYS_ACCESS syscall: -// -// int access(const char *pathname, int mode); +// Trigger invokes the SYS_MQ_OPEN syscall: // -// The function call will return an error due to path being NULL, but it will -// have invoked prepare_creds before argument validation. +// int mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr); func (g *guessStructCreds) Trigger() error { - syscall.Syscall(unix.SYS_ACCESS, 0, 0, 0) - return nil + name, err := unix.BytePtrFromString("__guess_creds") + if err != nil { + return err + } + attr := C.struct_mq_attr{ + mq_maxmsg: 1, + mq_msgsize: 8, + } + mqd, _, errno := syscall.Syscall6(unix.SYS_MQ_OPEN, + uintptr(unsafe.Pointer(name)), + uintptr(os.O_CREATE|os.O_RDWR), + 0o644, + uintptr(unsafe.Pointer(&attr)), + 0, 0) + if errno != 0 { + return errno + } + return unix.Close(int(mqd)) } diff --git a/x-pack/auditbeat/seccomp_linux.go b/x-pack/auditbeat/seccomp_linux.go index c5c3469525e..9bde50c77d0 100644 --- a/x-pack/auditbeat/seccomp_linux.go +++ b/x-pack/auditbeat/seccomp_linux.go @@ -16,12 +16,22 @@ func init() { // The system/package dataset uses librpm which has additional syscall // requirements beyond the default policy from libbeat so whitelist // these additional syscalls. - if err := seccomp.ModifyDefaultPolicy(seccomp.AddSyscall, "umask", "mremap"); err != nil { + if err := seccomp.ModifyDefaultPolicy(seccomp.AddSyscall, + "mremap", + "umask", + ); err != nil { panic(err) } // The system/socket dataset uses additional syscalls - if err := seccomp.ModifyDefaultPolicy(seccomp.AddSyscall, "perf_event_open", "eventfd2", "ppoll", "mount", "umount2"); err != nil { + if err := seccomp.ModifyDefaultPolicy(seccomp.AddSyscall, + "eventfd2", + "mount", + "mq_open", // required for creds kprobe guess trigger. + "perf_event_open", + "ppoll", + "umount2", + ); err != nil { panic(err) } }