Skip to content

Commit

Permalink
x-pack/auditbeat/module/socket/guess: fix creds trigger for newer ker…
Browse files Browse the repository at this point in the history
…nels (backport #37136) (#38027)

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.

(cherry picked from commit 284683d)

---------

Co-authored-by: Dan Kortschak <90160302+efd6@users.noreply.github.com>
  • Loading branch information
mergify[bot] and efd6 committed Feb 16, 2024
1 parent c299121 commit a0acfd6
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d

*Auditbeat*

- Fix guess trigger for system/socket creds on newer kernels. {issue}36905[36905] {pull}37136[37136]

*Filebeat*

Expand Down
50 changes: 37 additions & 13 deletions x-pack/auditbeat/module/system/socket/guess/creds.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ import (
"github.com/elastic/beats/v7/x-pack/auditbeat/tracing"
)

/*
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):
Expand Down Expand Up @@ -79,20 +90,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,
},
Expand Down Expand Up @@ -140,13 +151,26 @@ func (g *guessStructCreds) Extract(ev interface{}) (common.MapStr, 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))
}
14 changes: 12 additions & 2 deletions x-pack/auditbeat/seccomp_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down

0 comments on commit a0acfd6

Please sign in to comment.