diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index cccaace964a9..0cbabf853982 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -65,6 +65,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] *Auditbeat* +- 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 4180725addfb..bb4988bc2a4b 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("omg") + 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 c5c3469525ea..9bde50c77d03 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) } }