Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CWS] rework mmap hook + rhel 9.3 fix #25518

Merged
merged 6 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions pkg/security/ebpf/c/include/events_definition.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,9 @@ struct mmap_event_t {
struct file_t file;
u64 addr;
u64 offset;
u32 len;
int protection;
int flags;
u32 padding;
u64 len;
u64 protection;
u64 flags;
};

struct dns_event_t {
Expand Down
50 changes: 22 additions & 28 deletions pkg/security/ebpf/c/include/hooks/mmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,31 @@
#include "helpers/syscalls.h"

SEC("tracepoint/syscalls/sys_enter_mmap")
int tracepoint_syscalls_sys_enter_mmap(struct tracepoint_syscalls_sys_enter_mmap_t *args) {
u64 sys_enter_mmap_off_offset;
LOAD_CONSTANT("sys_enter_mmap_off_offset", sys_enter_mmap_off_offset);
u64 sys_enter_mmap_len_offset;
LOAD_CONSTANT("sys_enter_mmap_len_offset", sys_enter_mmap_len_offset);
u64 sys_enter_mmap_prot_offset;
LOAD_CONSTANT("sys_enter_mmap_prot_offset", sys_enter_mmap_prot_offset);
u64 sys_enter_mmap_flags_offset;
LOAD_CONSTANT("sys_enter_mmap_flags_offset", sys_enter_mmap_flags_offset);

int tracepoint_syscalls_sys_enter_mmap(void *args) {
struct policy_t policy = fetch_policy(EVENT_MMAP);
if (is_discarded_by_process(policy.mode, EVENT_MMAP)) {
return 0;
}

u64 off, len, prot, flags;
bpf_probe_read(&off, sizeof(off), (void *)args + sys_enter_mmap_off_offset);
bpf_probe_read(&len, sizeof(len), (void *)args + sys_enter_mmap_len_offset);
bpf_probe_read(&prot, sizeof(prot), (void *)args + sys_enter_mmap_prot_offset);
bpf_probe_read(&flags, sizeof(flags), (void *)args + sys_enter_mmap_flags_offset);

struct syscall_cache_t syscall = {
.type = EVENT_MMAP,
.policy = policy,
.mmap = {
.offset = off,
.len = (u32)len,
.protection = (int)prot,
.flags = (int)flags,
}
};

u64 sys_enter_mmap_off_offset;
LOAD_CONSTANT("sys_enter_mmap_off_offset", sys_enter_mmap_off_offset);
u64 sys_enter_mmap_len_offset;
LOAD_CONSTANT("sys_enter_mmap_len_offset", sys_enter_mmap_len_offset);
u64 sys_enter_mmap_prot_offset;
LOAD_CONSTANT("sys_enter_mmap_prot_offset", sys_enter_mmap_prot_offset);
u64 sys_enter_mmap_flags_offset;
LOAD_CONSTANT("sys_enter_mmap_flags_offset", sys_enter_mmap_flags_offset);

bpf_probe_read(&syscall.mmap.offset, sizeof(u64), args + sys_enter_mmap_off_offset);
bpf_probe_read(&syscall.mmap.len, sizeof(u64), args + sys_enter_mmap_len_offset);
bpf_probe_read(&syscall.mmap.protection, sizeof(u64), args + sys_enter_mmap_prot_offset);
bpf_probe_read(&syscall.mmap.flags, sizeof(u64), args + sys_enter_mmap_flags_offset);

cache_syscall(&syscall);
return 0;
}
Expand Down Expand Up @@ -84,18 +77,19 @@ int __attribute__((always_inline)) sys_mmap_ret(void *ctx, int retval, u64 addr)
return 0;
}

HOOK_SYSCALL_EXIT(mmap) {
return sys_mmap_ret(ctx, (int)SYSCALL_PARMRET(ctx), (u64)SYSCALL_PARMRET(ctx));
SEC("tracepoint/syscalls/sys_exit_mmap")
int tracepoint_syscalls_sys_exit_mmap(struct tracepoint_syscalls_sys_exit_mmap_t *args) {
return sys_mmap_ret(args, (int)args->ret, (u64)args->ret);
}

HOOK_EXIT("fget")
int rethook_fget(ctx_t *ctx) {
struct syscall_cache_t *syscall = peek_syscall(EVENT_MMAP);
HOOK_ENTRY("security_mmap_file")
int hook_security_mmap_file(ctx_t *ctx) {
struct syscall_cache_t *syscall = peek_syscall(EVENT_MMAP);
if (!syscall) {
return 0;
}

struct file *f = (struct file*) CTX_PARMRET(ctx, 1);
struct file *f = (struct file*) CTX_PARM1(ctx);
syscall->mmap.dentry = get_file_dentry(f);
syscall->mmap.file.path_key.mount_id = get_file_mount_id(f);
set_file_inode(syscall->mmap.dentry, &syscall->mmap.file, 0);
Expand Down
6 changes: 3 additions & 3 deletions pkg/security/ebpf/c/include/structs/syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@ struct syscall_cache_t {

struct {
u64 offset;
u32 len;
int protection;
int flags;
u64 len;
u64 protection;
u64 flags;
struct file_t file;
struct dentry *dentry;
} mmap;
Expand Down
9 changes: 2 additions & 7 deletions pkg/security/ebpf/c/include/structs/tracepoints.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,14 @@ struct _tracepoint_sched_process_exec {
pid_t old_pid;
};

struct tracepoint_syscalls_sys_enter_mmap_t {
struct tracepoint_syscalls_sys_exit_mmap_t {
unsigned short common_type;
unsigned char common_flags;
unsigned char common_preempt_count;
int common_pid;

int __syscall_nr;
unsigned long addr;
unsigned long len;
unsigned long protection;
unsigned long flags;
unsigned long fd;
unsigned long offset;
long ret;
};

struct tracepoint_io_uring_io_uring_create_t {
Expand Down
2 changes: 1 addition & 1 deletion pkg/security/ebpf/probes/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func AllProbes(fentry bool) []*manager.Probe {
allProbes = append(allProbes, getSELinuxProbes()...)
allProbes = append(allProbes, getBPFProbes(fentry)...)
allProbes = append(allProbes, getPTraceProbes(fentry)...)
allProbes = append(allProbes, getMMapProbes(fentry)...)
allProbes = append(allProbes, getMMapProbes()...)
allProbes = append(allProbes, getMProtectProbes(fentry)...)
allProbes = append(allProbes, getModuleProbes(fentry)...)
allProbes = append(allProbes, getSignalProbes(fentry)...)
Expand Down
4 changes: 2 additions & 2 deletions pkg/security/ebpf/probes/event_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,10 +373,10 @@ func GetSelectorsPerEventType(fentry bool) map[eval.EventType][]manager.ProbesSe

// List of probes required to capture mmap events
"mmap": {
&manager.BestEffort{Selectors: ExpandSyscallProbesSelector(SecurityAgentUID, "mmap", fentry, Exit)},
&manager.AllOf{Selectors: []manager.ProbesSelector{
&manager.ProbeSelector{ProbeIdentificationPair: manager.ProbeIdentificationPair{UID: SecurityAgentUID, EBPFFuncName: "tracepoint_syscalls_sys_enter_mmap"}},
kretprobeOrFexit("fget"),
&manager.ProbeSelector{ProbeIdentificationPair: manager.ProbeIdentificationPair{UID: SecurityAgentUID, EBPFFuncName: "tracepoint_syscalls_sys_exit_mmap"}},
kprobeOrFentry("security_mmap_file"),
}}},

// List of probes required to capture mprotect events
Expand Down
20 changes: 9 additions & 11 deletions pkg/security/ebpf/probes/mmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ package probes

import manager "github.com/DataDog/ebpf-manager"

func getMMapProbes(fentry bool) []*manager.Probe {
var mmapProbes = []*manager.Probe{
func getMMapProbes() []*manager.Probe {
return []*manager.Probe{
{
ProbeIdentificationPair: manager.ProbeIdentificationPair{
UID: SecurityAgentUID,
EBPFFuncName: "rethook_fget",
EBPFFuncName: "hook_security_mmap_file",
},
},
{
Expand All @@ -24,13 +24,11 @@ func getMMapProbes(fentry bool) []*manager.Probe {
EBPFFuncName: "tracepoint_syscalls_sys_enter_mmap",
},
},
}

mmapProbes = append(mmapProbes, ExpandSyscallProbes(&manager.Probe{
ProbeIdentificationPair: manager.ProbeIdentificationPair{
UID: SecurityAgentUID,
{
ProbeIdentificationPair: manager.ProbeIdentificationPair{
UID: SecurityAgentUID,
EBPFFuncName: "tracepoint_syscalls_sys_exit_mmap",
},
},
SyscallFuncName: "mmap",
}, fentry, Exit)...)
return mmapProbes
}
}
25 changes: 25 additions & 0 deletions pkg/security/probe/constantfetch/quirks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.

//go:build linux

// Package constantfetch holds constantfetch related files
package constantfetch

import "github.com/DataDog/datadog-agent/pkg/security/ebpf/kernel"

// GetRHEL93MMapDelta returns the potential offset in `sys_enter_mmap` fields when reading from the tracepoint
// format
func GetRHEL93MMapDelta(kv *kernel.Version) uint64 {
switch {
// rh 9.3 is completely buggy.. the tracepoint format of `sys_enter_mmap` is not the actual format..
// bpftrace is as confused as us on this
// this check is to fix this manually
case kv.IsInRangeCloseOpen(kernel.Kernel5_14, kernel.Kernel5_15) && kv.IsRH9_3Kernel():
return 8
default:
return 0
}
}
8 changes: 4 additions & 4 deletions pkg/security/probe/probe_ebpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -1560,19 +1560,19 @@ func NewEBPFProbe(probe *Probe, config *config.Config, opts Opts, wmeta optional
},
manager.ConstantEditor{
Name: constantfetch.OffsetNameSysMmapOff,
Value: constantfetch.ReadTracepointFieldOffsetWithFallback("syscalls/sys_enter_mmap", "off", 56),
Value: constantfetch.ReadTracepointFieldOffsetWithFallback("syscalls/sys_enter_mmap", "off", 56) + constantfetch.GetRHEL93MMapDelta(p.kernelVersion),
},
manager.ConstantEditor{
Name: constantfetch.OffsetNameSysMmapLen,
Value: constantfetch.ReadTracepointFieldOffsetWithFallback("syscalls/sys_enter_mmap", "len", 24),
Value: constantfetch.ReadTracepointFieldOffsetWithFallback("syscalls/sys_enter_mmap", "len", 24) + constantfetch.GetRHEL93MMapDelta(p.kernelVersion),
},
manager.ConstantEditor{
Name: constantfetch.OffsetNameSysMmapProt,
Value: constantfetch.ReadTracepointFieldOffsetWithFallback("syscalls/sys_enter_mmap", "prot", 32),
Value: constantfetch.ReadTracepointFieldOffsetWithFallback("syscalls/sys_enter_mmap", "prot", 32) + constantfetch.GetRHEL93MMapDelta(p.kernelVersion),
},
manager.ConstantEditor{
Name: constantfetch.OffsetNameSysMmapFlags,
Value: constantfetch.ReadTracepointFieldOffsetWithFallback("syscalls/sys_enter_mmap", "flags", 40),
Value: constantfetch.ReadTracepointFieldOffsetWithFallback("syscalls/sys_enter_mmap", "flags", 40) + constantfetch.GetRHEL93MMapDelta(p.kernelVersion),
},
)

Expand Down
12 changes: 6 additions & 6 deletions pkg/security/secl/model/accessors_unix.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions pkg/security/secl/model/consts_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ var (
bpfAttachTypeStrings = map[uint32]string{}
ptraceFlagsStrings = map[uint32]string{}
vmStrings = map[uint64]string{}
protStrings = map[int]string{}
protStrings = map[uint64]string{}
mmapFlagStrings = map[uint64]string{}
signalStrings = map[int]string{}
pipeBufFlagStrings = map[int]string{}
Expand Down Expand Up @@ -831,7 +831,7 @@ func initVMConstants() {

func initProtConstansts() {
for k, v := range protConstants {
seclConstants[k] = &eval.IntEvaluator{Value: v}
seclConstants[k] = &eval.IntEvaluator{Value: int(v)}
}

for k, v := range protConstants {
Expand Down Expand Up @@ -1796,10 +1796,10 @@ func (vmf VMFlag) String() string {
}

// Protection represents a virtual memory protection bitmask value
type Protection int
type Protection uint64

func (p Protection) String() string {
return bitmaskToString(int(p), protStrings)
return bitmaskU64ToString(uint64(p), protStrings)
}

// MMapFlag represents a mmap flag value
Expand Down
2 changes: 1 addition & 1 deletion pkg/security/secl/model/consts_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ var (

// protConstants are the supported protections for the mmap syscall
// generate_constants:Protection constants,Protection constants are the supported protections for the mmap syscall.
protConstants = map[string]int{
protConstants = map[string]uint64{
"PROT_NONE": unix.PROT_NONE,
"PROT_READ": unix.PROT_READ,
"PROT_WRITE": unix.PROT_WRITE,
Expand Down
2 changes: 1 addition & 1 deletion pkg/security/secl/model/consts_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var (
unlinkFlagsConstants = map[string]int{}
ptraceConstants = map[string]uint32{}
ptraceArchConstants = map[string]uint32{}
protConstants = map[string]int{}
protConstants = map[string]uint64{}
mmapFlagConstants = map[string]uint64{}
mmapFlagArchConstants = map[string]uint64{}
// SignalConstants list of signals
Expand Down
8 changes: 4 additions & 4 deletions pkg/security/secl/model/field_accessors_unix.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions pkg/security/secl/model/model_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -450,9 +450,9 @@ type MMapEvent struct {
File FileEvent `field:"file"`
Addr uint64 `field:"-"`
Offset uint64 `field:"-"`
Len uint32 `field:"-"`
Protection int `field:"protection"` // SECLDoc[protection] Definition:`memory segment protection` Constants:`Protection constants`
Flags int `field:"flags"` // SECLDoc[flags] Definition:`memory segment flags` Constants:`MMap flags`
Len uint64 `field:"-"`
Protection uint64 `field:"protection"` // SECLDoc[protection] Definition:`memory segment protection` Constants:`Protection constants`
Flags uint64 `field:"flags"` // SECLDoc[flags] Definition:`memory segment flags` Constants:`MMap flags`
}

// MProtectEvent represents a mprotect event
Expand Down
10 changes: 5 additions & 5 deletions pkg/security/secl/model/unmarshallers_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -777,16 +777,16 @@ func (e *MMapEvent) UnmarshalBinary(data []byte) (int, error) {
return 0, err
}

if len(data)-read < 28 {
if len(data)-read < 40 {
return 0, ErrNotEnoughData
}

e.Addr = binary.NativeEndian.Uint64(data[read : read+8])
e.Offset = binary.NativeEndian.Uint64(data[read+8 : read+16])
e.Len = binary.NativeEndian.Uint32(data[read+16 : read+20])
e.Protection = int(binary.NativeEndian.Uint32(data[read+20 : read+24]))
e.Flags = int(binary.NativeEndian.Uint32(data[read+24 : read+28]))
return read + 28, nil
e.Len = binary.NativeEndian.Uint64(data[read+16 : read+24])
e.Protection = binary.NativeEndian.Uint64(data[read+24 : read+32])
e.Flags = binary.NativeEndian.Uint64(data[read+32 : read+40])
return read + 40, nil
}

// UnmarshalBinary unmarshals a binary representation of itself
Expand Down
2 changes: 1 addition & 1 deletion pkg/security/serializers/serializers_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ type MMapEventSerializer struct {
// file offset
Offset uint64 `json:"offset"`
// memory segment length
Len uint32 `json:"length"`
Len uint64 `json:"length"`
// memory segment protection
Protection string `json:"protection"`
// memory segment flags
Expand Down
Loading
Loading