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] Add namespace ID field resolver for ptrace #32413

Merged
merged 1 commit into from
Dec 20, 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
17 changes: 16 additions & 1 deletion pkg/security/probe/field_handlers_ebpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/DataDog/datadog-agent/pkg/security/resolvers"
sprocess "github.com/DataDog/datadog-agent/pkg/security/resolvers/process"
"github.com/DataDog/datadog-agent/pkg/security/secl/containerutils"
"github.com/DataDog/datadog-agent/pkg/security/utils"

"github.com/DataDog/datadog-agent/pkg/security/secl/args"
"github.com/DataDog/datadog-agent/pkg/security/secl/model"
Expand Down Expand Up @@ -230,7 +231,7 @@ func (fh *EBPFFieldHandlers) ResolveRights(_ *model.Event, e *model.FileFields)
return int(e.Mode) & (syscall.S_ISUID | syscall.S_ISGID | syscall.S_ISVTX | syscall.S_IRWXU | syscall.S_IRWXG | syscall.S_IRWXO)
}

// ResolveChownUID resolves the ResolveProcessCacheEntry id of a chown event to a username
// ResolveChownUID resolves the user id of a chown event to a username
func (fh *EBPFFieldHandlers) ResolveChownUID(ev *model.Event, e *model.ChownEvent) string {
if len(e.User) == 0 {
e.User, _ = fh.resolvers.UserGroupResolver.ResolveUser(int(e.UID), ev.ContainerContext.ContainerID)
Expand Down Expand Up @@ -731,3 +732,17 @@ func (fh *EBPFFieldHandlers) ResolveOnDemandArg4Str(_ *model.Event, e *model.OnD
func (fh *EBPFFieldHandlers) ResolveOnDemandArg4Uint(_ *model.Event, e *model.OnDemandEvent) int {
return int(binary.NativeEndian.Uint64(e.Data[192 : 192+8]))
}

// ResolveProcessNSID resolves the process namespace ID
func (fh *EBPFFieldHandlers) ResolveProcessNSID(e *model.Event) (uint64, error) {
if e.ProcessCacheEntry.Process.NSID != 0 {
return e.ProcessCacheEntry.Process.NSID, nil
}

nsid, err := utils.GetProcessPidNamespace(e.ProcessCacheEntry.Process.Pid)
if err != nil {
return 0, err
}
e.ProcessCacheEntry.Process.NSID = nsid
return nsid, nil
}
9 changes: 8 additions & 1 deletion pkg/security/probe/probe_ebpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -1090,7 +1090,14 @@ func (p *EBPFProbe) handleEvent(CPU int, data []byte) {
if containerID == "" && event.PTrace.Request != unix.PTRACE_ATTACH {
pidToResolve = event.PTrace.NSPID
} else {
pid, err := utils.TryToResolveTraceePid(event.ProcessContext.Process.Pid, event.PTrace.NSPID)
nsid, err := p.fieldHandlers.ResolveProcessNSID(event)
if err != nil {
seclog.Debugf("PTrace NSID resolution error for process %s in container %s: %v",
event.ProcessContext.Process.FileEvent.PathnameStr, containerID, err)
return
}

pid, err := utils.TryToResolveTraceePid(event.ProcessContext.Process.Pid, nsid, event.PTrace.NSPID)
if err != nil {
seclog.Debugf("PTrace tracee resolution error for process %s in container %s: %v",
event.ProcessContext.Process.FileEvent.PathnameStr, containerID, err)
Expand Down
12 changes: 2 additions & 10 deletions pkg/security/utils/proc_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -567,22 +567,14 @@ var isNsPidAvailable = sync.OnceValue(func() bool {
})

// TryToResolveTraceePid tries to resolve and returnt the HOST tracee PID, given the HOST tracer PID and the namespaced tracee PID.
func TryToResolveTraceePid(hostTracerPID, NsTraceePid uint32) (uint32, error) {
func TryToResolveTraceePid(hostTracerPID uint32, tracerNSID uint64, NsTraceePid uint32) (uint32, error) {
// Look if the NSpid status field is available or not (it should be, except for Centos7).
if isNsPidAvailable() {
/*
If it's available, we will search for an host pid having the same PID namespace as the
tracer, and having the corresponding NS PID in its status field
*/

// 1. get the pid namespace of the tracer
ns, err := GetProcessPidNamespace(hostTracerPID)
if err != nil {
return 0, fmt.Errorf("Failed to resolve PID namespace: %v", err)
}

// 2. find the host pid matching the arg pid with he tracer namespace
pid, err := FindPidNamespace(NsTraceePid, ns)
pid, err := FindPidNamespace(NsTraceePid, tracerNSID)
if err != nil {
return 0, fmt.Errorf("Failed to resolve tracee PID namespace: %v", err)
}
Expand Down
Loading