Skip to content
Draft
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
44 changes: 44 additions & 0 deletions pkg/security/ebpf/c/include/constants/offsets/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,30 @@ u32 __attribute__((always_inline)) get_mount_offset_of_mount_id(void) {
return offset; // offsetof(struct mount, mnt_id)
}

u32 __attribute__((always_inline)) get_mount_offset_of_mount_id_unique(void) {
u64 offset;
LOAD_CONSTANT("mount_id_unique_offset", offset);
return offset; // offsetof(struct mount, mnt_id_unique)
}

u32 __attribute__((always_inline)) get_mount_offset_of_mount_ns(void) {
u64 offset;
LOAD_CONSTANT("mount_ns_offset", offset);
return offset; // offsetof(struct mount, mnt_ns)
}

u32 __attribute__((always_inline)) get_mount_offset_of_nscommon_inum(void) {
u64 offset;
LOAD_CONSTANT("ns_common_inum_offset", offset);
return offset; // offsetof(struct ns_common, inum)
}

u32 __attribute__((always_inline)) get_mnt_namespace_ns(void) {
u64 offset;
LOAD_CONSTANT("mnt_namespace_ns", offset);
return offset; // offsetof(struct mnt_namespace, ns)
}

int __attribute__((always_inline)) get_vfsmount_mount_id(struct vfsmount *mnt) {
int mount_id;
// bpf_probe_read(&mount_id, sizeof(mount_id), (char *)mnt + offsetof(struct mount, mnt_id) - offsetof(struct mount, mnt));
Expand Down Expand Up @@ -121,6 +145,26 @@ int __attribute__((always_inline)) get_mount_mount_id(void *mnt) {
return mount_id;
}

u64 __attribute__((always_inline)) get_mount_mount_id_unique(void *mnt) {
u64 mount_id;

bpf_probe_read(&mount_id, sizeof(mount_id), (char *)mnt + get_mount_offset_of_mount_id_unique());
return mount_id;
}

u64 __attribute__((always_inline)) get_mount_mount_ns_inum(void *mnt) {
void* mnt_ns = NULL;
u64 inum = 0;

bpf_probe_read(&mnt_ns, sizeof(mnt_ns), mnt + get_mount_offset_of_mount_ns());
if (!mnt_ns) {
return 0;
}

bpf_probe_read(&inum, sizeof(inum), mnt_ns + get_mnt_namespace_ns() + get_mount_offset_of_nscommon_inum());
return inum;
}

struct dentry *__attribute__((always_inline)) get_mount_mountpoint_dentry(struct mount *mnt) {
u64 mount_mnt_mountpoint_offset;
LOAD_CONSTANT("mount_mnt_mountpoint_offset", mount_mnt_mountpoint_offset);
Expand Down
4 changes: 2 additions & 2 deletions pkg/security/ebpf/c/include/events_definition.h
Original file line number Diff line number Diff line change
Expand Up @@ -549,8 +549,8 @@ struct setsockopt_event_t {
u16 socket_protocol;
int level;
int optname;
u32 truncated;
int sent_size;
u32 truncated;
int sent_size;
char bpf_filters_buffer[MAX_BPF_FILTER_SIZE];
};

Expand Down
39 changes: 29 additions & 10 deletions pkg/security/ebpf/c/include/hooks/mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ void __attribute__((always_inline)) fill_mount_fields(struct syscall_cache_t *sy
mfields->mountpoint_key = syscall->mount.mountpoint_key;
mfields->device = syscall->mount.device;
mfields->bind_src_mount_id = syscall->mount.bind_src_mount_id;
mfields->ns_inum = syscall->mount.ns_inum;
mfields->mount_id_unique = syscall->mount.mount_id_unique;
mfields->parent_mount_id_unique = syscall->mount.parent_mount_id_unique;
mfields->bind_src_mount_id_unique = syscall->mount.bind_src_mount_id_unique;
bpf_probe_read_str(&mfields->fstype, sizeof(mfields->fstype), (void *)syscall->mount.fstype);
}

Expand Down Expand Up @@ -179,12 +183,14 @@ void __attribute__((always_inline)) handle_new_mount(void *ctx, struct syscall_c
// populate the root dentry key
struct dentry *root_dentry = get_vfsmount_dentry(get_mount_vfsmount(syscall->mount.newmnt));
syscall->mount.root_key.mount_id = get_mount_mount_id(syscall->mount.newmnt);
syscall->mount.mount_id_unique = get_mount_mount_id_unique(syscall->mount.newmnt);
syscall->mount.root_key.ino = get_dentry_ino(root_dentry);
update_path_id(&syscall->mount.root_key, 0, 0);

if(!detached) {
// populate the mountpoint dentry key
syscall->mount.mountpoint_key.mount_id = get_mount_mount_id(syscall->mount.parent);
syscall->mount.parent_mount_id_unique = get_mount_mount_id_unique(syscall->mount.parent);
syscall->mount.mountpoint_key.ino = get_dentry_ino(syscall->mount.mountpoint_dentry);
update_path_id(&syscall->mount.mountpoint_key, 0, 0);
}
Expand Down Expand Up @@ -314,6 +320,7 @@ int hook_mnt_change_mountpoint(ctx_t *ctx)
return 0;
}

syscall->mount.ns_inum = get_mount_mount_ns_inum(newmnt);
syscall->mount.newmnt = newmnt;
syscall->mount.parent = (struct mount *)CTX_PARM1(ctx);
struct mountpoint *mp = (struct mountpoint *)CTX_PARM2(ctx);
Expand All @@ -337,9 +344,10 @@ int hook_attach_mnt(ctx_t *ctx) {
return 0;
}

syscall->mount.newmnt = newmnt;
syscall->mount.parent = (struct mount *)CTX_PARM2(ctx);
struct mountpoint *mp = (struct mountpoint *)CTX_PARM3(ctx);
syscall->mount.ns_inum = get_mount_mount_ns_inum(newmnt);
syscall->mount.newmnt = newmnt;
syscall->mount.parent = (struct mount *)CTX_PARM2(ctx);
struct mountpoint *mp = (struct mountpoint *)CTX_PARM3(ctx);
syscall->mount.mountpoint_dentry = get_mountpoint_dentry(mp);

handle_new_mount(ctx, syscall, KPROBE_OR_FENTRY_TYPE, false);
Expand All @@ -360,8 +368,9 @@ int hook___attach_mnt(ctx_t *ctx) {
return 0;
}

syscall->mount.newmnt = newmnt;
syscall->mount.parent = (struct mount *)CTX_PARM2(ctx);
syscall->mount.ns_inum = get_mount_mount_ns_inum(newmnt);
syscall->mount.newmnt = newmnt;
syscall->mount.parent = (struct mount *)CTX_PARM2(ctx);
syscall->mount.mountpoint_dentry = get_mount_mountpoint_dentry(newmnt);

handle_new_mount(ctx, syscall, KPROBE_OR_FENTRY_TYPE, false);
Expand All @@ -382,9 +391,11 @@ int hook_mnt_set_mountpoint(ctx_t *ctx) {
return 0;
}

syscall->mount.newmnt = newmnt;
syscall->mount.parent = (struct mount *)CTX_PARM1(ctx);
struct mountpoint *mp = (struct mountpoint *)CTX_PARM2(ctx);
syscall->mount.ns_inum = get_mount_mount_ns_inum(newmnt);

syscall->mount.newmnt = newmnt;
syscall->mount.parent = (struct mount *)CTX_PARM1(ctx);
struct mountpoint *mp = (struct mountpoint *)CTX_PARM2(ctx);
syscall->mount.mountpoint_dentry = get_mountpoint_dentry(mp);

handle_new_mount(ctx, syscall, KPROBE_OR_FENTRY_TYPE, false);
Expand All @@ -404,8 +415,10 @@ int hook_clone_mnt(ctx_t *ctx) {
}

struct mount *bind_src_mnt = (struct mount *)CTX_PARM1(ctx);
int mount_id = get_mount_mount_id(bind_src_mnt);
syscall->mount.bind_src_mount_id = mount_id;
syscall->mount.ns_inum = get_mount_mount_ns_inum(bind_src_mnt);

syscall->mount.bind_src_mount_id = get_mount_mount_id(bind_src_mnt);
syscall->mount.bind_src_mount_id_unique = get_mount_mount_id_unique(bind_src_mnt);
syscall->mount.clone_mnt_ctr++;

return 0;
Expand All @@ -424,6 +437,8 @@ int rethook_clone_mnt(ctx_t *ctx) {
}

struct mount *ret = (struct mount *)CTX_PARMRET(ctx);
syscall->mount.ns_inum = get_mount_mount_ns_inum(ret);

syscall->mount.newmnt = ret;
handle_new_mount(ctx, syscall, KPROBE_OR_FENTRY_TYPE, true);
return 0;
Expand All @@ -446,6 +461,8 @@ int hook_attach_recursive_mnt(ctx_t *ctx) {
syscall->mount.newmnt = newmnt;
syscall->mount.parent = (struct mount *)CTX_PARM2(ctx);
struct mountpoint *mp = (struct mountpoint *)CTX_PARM3(ctx);
struct mount *topmnt = (struct mount *)CTX_PARM2(ctx);
syscall->mount.ns_inum = get_mount_mount_ns_inum(topmnt);
syscall->mount.mountpoint_dentry = get_mountpoint_dentry(mp);

if (syscall->type != EVENT_MOUNT) {
Expand All @@ -467,6 +484,8 @@ int hook_propagate_mnt(ctx_t *ctx) {
return 0;
}

syscall->mount.ns_inum = get_mount_mount_ns_inum(newmnt);

syscall->mount.newmnt = newmnt;
syscall->mount.parent = (struct mount *)CTX_PARM1(ctx);
struct mountpoint *mp = (struct mountpoint *)CTX_PARM2(ctx);
Expand Down
4 changes: 4 additions & 0 deletions pkg/security/ebpf/c/include/structs/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ struct mount_fields_t {
struct path_key_t mountpoint_key;
dev_t device;
u32 bind_src_mount_id;
u64 mount_id_unique;
u64 parent_mount_id_unique;
u64 bind_src_mount_id_unique;
char fstype[FSTYPE_LEN];
u16 visible; // Is mount visible in the VFS?
u16 detached; // A detached mount is always not visible, but an invisible mount isn't always detached
u64 ns_inum; // mount namespace inode
};

#endif
5 changes: 5 additions & 0 deletions pkg/security/ebpf/c/include/structs/syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,18 @@ struct syscall_cache_t {
struct mount *parent;
struct dentry *mountpoint_dentry;
u32 bind_src_mount_id;
u64 mount_id_unique;
u64 parent_mount_id_unique;
u64 bind_src_mount_id_unique;

// populated from collected
const char *fstype;
struct path_key_t root_key;
struct path_key_t mountpoint_key;
dev_t device;
int clone_mnt_ctr;
int source;
u64 ns_inum;
} mount;

struct {
Expand Down
4 changes: 4 additions & 0 deletions pkg/security/probe/constantfetch/constant_names.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ const (
OffsetNameFileFpath = "file_f_path_offset"
OffsetNameDentryDSb = "dentry_d_sb_offset"
OffsetNameMountMntID = "mount_id_offset"
OffsetNameMountMntIDUnique = "mount_id_unique_offset"
OffsetNameMountMntNs = "mount_ns_offset"
OffsetNameMntNamespaceNs = "mnt_namespace_ns"
OffsetNameNsCommonInum = "ns_common_inum_offset"
OffsetNameSbDev = "sb_dev_offset"
OffsetNameDentryDInode = "dentry_d_inode_offset"
OffsetNamePathDentry = "path_dentry_offset"
Expand Down
10 changes: 5 additions & 5 deletions pkg/security/probe/field_handlers_ebpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func (fh *EBPFFieldHandlers) ResolveFileFilesystem(ev *model.Event, f *model.Fil
if f.IsFileless() {
f.Filesystem = model.TmpFS
} else {
fs, err := fh.resolvers.MountResolver.ResolveFilesystem(f.FileFields.MountID, f.FileFields.Device, ev.PIDContext.Pid, ev.ContainerContext.ContainerID)
fs, err := fh.resolvers.MountResolver.ResolveFilesystem(f.FileFields.MountID, ev.PIDContext.Pid, ev.ContainerContext.ContainerID)
if err != nil {
ev.SetPathResolutionError(f, err)
}
Expand Down Expand Up @@ -177,7 +177,7 @@ func (fh *EBPFFieldHandlers) ResolveMountPointPath(ev *model.Event, e *model.Mou
return "/"
}
if len(e.MountPointPath) == 0 {
mountPointPath, _, _, err := fh.resolvers.MountResolver.ResolveMountPath(e.MountID, 0, ev.PIDContext.Pid, ev.ContainerContext.ContainerID)
mountPointPath, _, _, err := fh.resolvers.MountResolver.ResolveMountPath(e.MountID, ev.PIDContext.Pid, ev.ContainerContext.ContainerID)
if err != nil {
e.MountPointPathResolutionError = err
return ""
Expand All @@ -190,7 +190,7 @@ func (fh *EBPFFieldHandlers) ResolveMountPointPath(ev *model.Event, e *model.Mou
// ResolveMountSourcePath resolves a mount source path
func (fh *EBPFFieldHandlers) ResolveMountSourcePath(ev *model.Event, e *model.MountEvent) string {
if e.BindSrcMountID != 0 && len(e.MountSourcePath) == 0 {
bindSourceMountPath, _, _, err := fh.resolvers.MountResolver.ResolveMountPath(e.BindSrcMountID, 0, ev.PIDContext.Pid, ev.ContainerContext.ContainerID)
bindSourceMountPath, _, _, err := fh.resolvers.MountResolver.ResolveMountPath(e.BindSrcMountID, ev.PIDContext.Pid, ev.ContainerContext.ContainerID)
if err != nil {
e.MountSourcePathResolutionError = err
return ""
Expand All @@ -208,7 +208,7 @@ func (fh *EBPFFieldHandlers) ResolveMountSourcePath(ev *model.Event, e *model.Mo
// ResolveMountRootPath resolves a mount root path
func (fh *EBPFFieldHandlers) ResolveMountRootPath(ev *model.Event, e *model.MountEvent) string {
if len(e.MountRootPath) == 0 {
mountRootPath, _, _, err := fh.resolvers.MountResolver.ResolveMountRoot(e.MountID, 0, ev.PIDContext.Pid, ev.ContainerContext.ContainerID)
mountRootPath, _, _, err := fh.resolvers.MountResolver.ResolveMountRoot(e.MountID, ev.PIDContext.Pid, ev.ContainerContext.ContainerID)
if err != nil {
e.MountRootPathResolutionError = err
return ""
Expand Down Expand Up @@ -586,7 +586,7 @@ func (fh *EBPFFieldHandlers) ResolveCGroupID(ev *model.Event, cont *model.CGroup
// ResolveCGroupVersion resolves the version of the cgroup API
func (fh *EBPFFieldHandlers) ResolveCGroupVersion(ev *model.Event, e *model.CGroupContext) int {
if e.CGroupVersion == 0 {
if filesystem, _ := fh.resolvers.MountResolver.ResolveFilesystem(e.CGroupFile.MountID, 0, ev.PIDContext.Pid, ev.ContainerContext.ContainerID); filesystem == "cgroup2" {
if filesystem, _ := fh.resolvers.MountResolver.ResolveFilesystem(e.CGroupFile.MountID, ev.PIDContext.Pid, ev.ContainerContext.ContainerID); filesystem == "cgroup2" {
e.CGroupVersion = 2
} else {
e.CGroupVersion = 1
Expand Down
9 changes: 6 additions & 3 deletions pkg/security/probe/probe_ebpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -1202,7 +1202,7 @@ func (p *EBPFProbe) handleRegularEvent(event *model.Event, offset int, dataLen u
// TODO: this should be moved in the resolver itself in order to handle the fallbacks
if event.Mount.GetFSType() == "nsfs" {
nsid := uint32(event.Mount.RootPathKey.Inode)
mountPath, _, _, err := p.Resolvers.MountResolver.ResolveMountPath(event.Mount.MountID, event.Mount.Device, event.PIDContext.Pid, event.ContainerContext.ContainerID)
mountPath, _, _, err := p.Resolvers.MountResolver.ResolveMountPath(event.Mount.MountID, event.PIDContext.Pid, event.ContainerContext.ContainerID)
if err != nil {
seclog.Debugf("failed to get mount path: %v", err)
} else {
Expand All @@ -1217,7 +1217,7 @@ func (p *EBPFProbe) handleRegularEvent(event *model.Event, offset int, dataLen u
}

// we can skip this error as this is for the umount only and there is no impact on the filepath resolution
mount, _, _, _ := p.Resolvers.MountResolver.ResolveMount(event.Umount.MountID, 0, event.PIDContext.Pid, event.ContainerContext.ContainerID)
mount, _, _, _ := p.Resolvers.MountResolver.ResolveMount(event.Umount.MountID, event.PIDContext.Pid, event.ContainerContext.ContainerID)
if mount != nil && mount.GetFSType() == "nsfs" {
nsid := uint32(mount.RootPathKey.Inode)
if namespace := p.Resolvers.NamespaceResolver.ResolveNetworkNamespace(nsid); namespace != nil {
Expand Down Expand Up @@ -1279,7 +1279,6 @@ func (p *EBPFProbe) handleRegularEvent(event *model.Event, offset int, dataLen u
}
exists := p.Resolvers.ProcessResolver.ApplyExitEntry(event, newEntryCb)
if exists {
p.Resolvers.MountResolver.DelPid(event.Exit.Pid)
// update action reports
p.processKiller.HandleProcessExited(event)
p.fileHasher.HandleProcessExited(event)
Expand Down Expand Up @@ -3133,6 +3132,10 @@ func AppendProbeRequestsToFetcher(constantFetcher constantfetch.ConstantFetcher,
appendOffsetofRequest(constantFetcher, constantfetch.OffsetNameFileFpath, "struct file", "f_path")
appendOffsetofRequest(constantFetcher, constantfetch.OffsetNameDentryDSb, "struct dentry", "d_sb")
appendOffsetofRequest(constantFetcher, constantfetch.OffsetNameMountMntID, "struct mount", "mnt_id")
appendOffsetofRequest(constantFetcher, constantfetch.OffsetNameMountMntIDUnique, "struct mount", "mnt_id_unique")
appendOffsetofRequest(constantFetcher, constantfetch.OffsetNameMountMntNs, "struct mount", "mnt_ns")
appendOffsetofRequest(constantFetcher, constantfetch.OffsetNameMntNamespaceNs, "struct mnt_namespace", "ns")
appendOffsetofRequest(constantFetcher, constantfetch.OffsetNameNsCommonInum, "struct ns_common", "inum")
if kv.Code >= kernel.Kernel5_3 {
appendOffsetofRequest(constantFetcher, constantfetch.OffsetNameKernelCloneArgsExitSignal, "struct kernel_clone_args", "exit_signal")
}
Expand Down
57 changes: 57 additions & 0 deletions pkg/security/resolvers/mount/dentry_positions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// 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 mount holds mount related files
package mount

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

// GetVFSLinkDentryPosition gets VFS link dentry position
func GetVFSLinkDentryPosition(kernelVersion *skernel.Version) uint64 {
position := uint64(2)

if kernelVersion.Code != 0 && kernelVersion.Code >= skernel.Kernel5_12 {
position = 3
}

return position
}

// GetVFSMKDirDentryPosition gets VFS MKDir dentry position
func GetVFSMKDirDentryPosition(kernelVersion *skernel.Version) uint64 {
position := uint64(2)

if kernelVersion.Code != 0 && kernelVersion.Code >= skernel.Kernel5_12 {
position = 3
}

return position
}

// GetVFSSetxattrDentryPosition gets VFS set xattr dentry position
func GetVFSSetxattrDentryPosition(kernelVersion *skernel.Version) uint64 {
position := uint64(1)

if kernelVersion.Code != 0 && kernelVersion.Code >= skernel.Kernel5_12 {
position = 2
}

return position
}

// GetVFSRemovexattrDentryPosition gets VFS remove xattr dentry position
func GetVFSRemovexattrDentryPosition(kernelVersion *skernel.Version) uint64 {
position := uint64(1)

if kernelVersion.Code != 0 && kernelVersion.Code >= skernel.Kernel5_12 {
position = 2
}

return position
}
29 changes: 29 additions & 0 deletions pkg/security/resolvers/mount/extra.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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 mount holds mount related files
package mount

import (
"fmt"
"strconv"
"strings"
)

func getInodeNumFromLink(link string) (uint64, error) {
start := strings.LastIndexByte(link, '[')
end := strings.LastIndexByte(link, ']')
if start == -1 || end == -1 || start >= end-1 {
return 0, fmt.Errorf("invalid link: %s", link)
}
inodeStr := link[start+1 : end]
ino, err := strconv.ParseUint(inodeStr, 10, 64)
if err != nil {
return 0, fmt.Errorf("invalid link: %s", link)
}
return ino, nil
}
Loading
Loading