Skip to content

Commit

Permalink
[mq] working branch - merge f1b09ef on top of main at 67b7ab9
Browse files Browse the repository at this point in the history
{"baseBranch":"main","baseCommit":"67b7ab971beccf985fe91653ee67bdfed1af06c4","createdAt":"2024-05-13T12:40:48.045391Z","headSha":"f1b09ef62fb9b4dd99b7a4de9575dbe9fbfa44b4","id":"6c3c43cc-864c-4e30-8a6f-e6869333b411","priority":"200","pullRequestNumber":"25513","queuedAt":"2024-05-13T12:40:48.044728Z","status":"STATUS_QUEUED","triggeredBy":"sylvain.afchain@datadoghq.com"}
  • Loading branch information
dd-mergequeue[bot] committed May 13, 2024
2 parents 14d3c95 + f1b09ef commit a83fa43
Show file tree
Hide file tree
Showing 12 changed files with 213 additions and 58 deletions.
4 changes: 1 addition & 3 deletions pkg/security/probe/actions.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
//go:generate go run github.com/mailru/easyjson/easyjson -gen_build_flags=-mod=mod -no_std_marshalers -build_tags linux $GOFILE
//go:generate go run github.com/mailru/easyjson/easyjson -gen_build_flags=-mod=mod -no_std_marshalers $GOFILE

// 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 probe holds probe related files
package probe

Expand Down
3 changes: 0 additions & 3 deletions pkg/security/probe/actions_easyjson.go

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

4 changes: 0 additions & 4 deletions pkg/security/probe/probe_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
package probe

import (
"time"

"github.com/DataDog/datadog-agent/comp/core/workloadmeta"
"github.com/DataDog/datadog-agent/pkg/security/config"
"github.com/DataDog/datadog-agent/pkg/util/optional"
Expand All @@ -19,8 +17,6 @@ const (
EBPFOrigin = "ebpf"
// EBPFLessOrigin eBPF less origin
EBPFLessOrigin = "ebpfless"

defaultKillActionFlushDelay = 2 * time.Second
)

// NewProbe instantiates a new runtime security agent probe
Expand Down
33 changes: 29 additions & 4 deletions pkg/security/probe/probe_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ type WindowsProbe struct {
// discarders
discardedPaths *lru.Cache[string, struct{}]
discardedBasenames *lru.Cache[string, struct{}]

// actions
processKiller *ProcessKiller
}

type renameState struct {
Expand Down Expand Up @@ -474,6 +477,9 @@ func (p *WindowsProbe) Start() error {
}

p.DispatchEvent(ev)

// flush pending kill actions
p.processKiller.FlushPendingReports()
}
}()
return p.pm.Start()
Expand Down Expand Up @@ -535,11 +541,15 @@ func (p *WindowsProbe) handleProcessStop(ev *model.Event, stop *procmon.ProcessS
log.Errorf("unable to resolve pid %d", pid)
return false
}
pce.ExitTime = time.Now()
ev.Exit.Process = &pce.Process
// use ProcessCacheEntry process context as process context
ev.ProcessCacheEntry = pce
ev.ProcessContext = &pce.ProcessContext

// update kill action reports
p.processKiller.HandleProcessExited(ev)

p.Resolvers.ProcessResolver.DequeueExited()
return true
}
Expand Down Expand Up @@ -649,7 +659,7 @@ func (p *WindowsProbe) setProcessContext(pid uint32, event *model.Event) error {
err := backoff.Retry(func() error {
pce := p.Resolvers.ProcessResolver.GetEntry(pid)
if pce == nil {
return fmt.Errorf("Could not resolve process for Process: %v", pid)
return fmt.Errorf("could not resolve process for Process: %v", pid)
}
event.ProcessCacheEntry = pce
event.ProcessContext = &pce.ProcessContext
Expand All @@ -661,7 +671,6 @@ func (p *WindowsProbe) setProcessContext(pid uint32, event *model.Event) error {

// DispatchEvent sends an event to the probe event handler
func (p *WindowsProbe) DispatchEvent(event *model.Event) {

traceEvent("Dispatching event %s", func() ([]byte, model.EventType, error) {
eventJSON, err := serializers.MarshalEvent(event, nil)
return eventJSON, event.GetEventType(), err
Expand All @@ -672,7 +681,6 @@ func (p *WindowsProbe) DispatchEvent(event *model.Event) {

// send event to specific event handlers, like the event monitor consumers, subsequently
p.probe.sendEventToSpecificEventTypeHandlers(event)

}

// Snapshot runs the different snapshot functions of the resolvers that
Expand Down Expand Up @@ -803,6 +811,8 @@ func NewWindowsProbe(probe *Probe, config *config.Config, opts Opts) (*WindowsPr

discardedPaths: discardedPaths,
discardedBasenames: discardedBasenames,

processKiller: NewProcessKiller(),
}

p.Resolvers, err = resolvers.NewResolvers(config, p.statsdClient, probe.scrubber)
Expand Down Expand Up @@ -880,7 +890,22 @@ func (p *WindowsProbe) NewEvent() *model.Event {
}

// HandleActions executes the actions of a triggered rule
func (p *WindowsProbe) HandleActions(_ *eval.Context, _ *rules.Rule) {}
func (p *WindowsProbe) HandleActions(ctx *eval.Context, rule *rules.Rule) {
ev := ctx.Event.(*model.Event)

for _, action := range rule.Definition.Actions {
if !action.IsAccepted(ctx) {
continue
}

switch {
case action.Kill != nil:
p.processKiller.KillAndReport(action.Kill.Scope, action.Kill.Signal, ev, func(pid uint32, sig uint32) error {
return p.processKiller.KillFromUserspace(pid, sig, ev)
})
}
}
}

// AddDiscarderPushedCallback add a callback to the list of func that have to be called when a discarder is pushed to kernel
func (p *WindowsProbe) AddDiscarderPushedCallback(_ DiscarderPushedCallback) {}
Expand Down
52 changes: 11 additions & 41 deletions pkg/security/probe/process_killer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,24 @@
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.

//go:build linux
//go:build linux || windows

// Package probe holds probe related files
package probe

import (
"errors"
"fmt"
"slices"
"sync"
"syscall"
"time"

psutil "github.com/shirou/gopsutil/v3/process"

"github.com/DataDog/datadog-agent/pkg/security/secl/model"
"github.com/DataDog/datadog-agent/pkg/security/seclog"
"github.com/DataDog/datadog-agent/pkg/security/utils"
"github.com/DataDog/datadog-agent/pkg/util/log"
)

const (
userSpaceKillWithinMillis = 2000
defaultKillActionFlushDelay = 2 * time.Second
)

// ProcessKiller defines a process killer structure
Expand Down Expand Up @@ -83,50 +78,25 @@ func (p *ProcessKiller) HandleProcessExited(event *model.Event) {
})
}

// KillFromUserspace tries to kill from userspace
func (p *ProcessKiller) KillFromUserspace(pid uint32, sig uint32, ev *model.Event) error {
proc, err := psutil.NewProcess(int32(pid))
if err != nil {
return errors.New("process not found in procfs")
}

name, err := proc.Name()
if err != nil {
return errors.New("process not found in procfs")
}

createdAt, err := proc.CreateTime()
if err != nil {
return errors.New("process not found in procfs")
}
evCreatedAt := ev.ProcessContext.ExecTime.UnixMilli()

within := uint64(evCreatedAt) >= uint64(createdAt-userSpaceKillWithinMillis) && uint64(evCreatedAt) <= uint64(createdAt+userSpaceKillWithinMillis)

if !within || ev.ProcessContext.Comm != name {
return fmt.Errorf("not sharing the same namespace: %s/%s", ev.ProcessContext.Comm, name)
}

return syscall.Kill(int(pid), syscall.Signal(sig))
}

// KillAndReport kill and report
func (p *ProcessKiller) KillAndReport(scope string, signal string, ev *model.Event, killFnc func(pid uint32, sig uint32) error) {
entry, exists := ev.ResolveProcessCacheEntry()
if !exists {
return
}

var pids []uint32

if entry.ContainerID != "" && scope == "container" {
pids = entry.GetContainerPIDs()
scope = "container"
} else {
pids = []uint32{ev.ProcessContext.Pid}
switch scope {
case "container", "process":
default:
scope = "process"
}

pids, err := p.getPids(scope, ev, entry)
if err != nil {
log.Errorf("unable to kill: %s", err)
return
}

sig := model.SignalConstants[signal]

killedAt := time.Now()
Expand Down
59 changes: 59 additions & 0 deletions pkg/security/probe/process_killer_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// 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.

// Package probe holds probe related files
package probe

import (
"errors"
"fmt"
"syscall"

psutil "github.com/shirou/gopsutil/v3/process"

"github.com/DataDog/datadog-agent/pkg/security/secl/model"
)

const (
userSpaceKillWithinMillis = 2000
)

// KillFromUserspace tries to kill from userspace
func (p *ProcessKiller) KillFromUserspace(pid uint32, sig uint32, ev *model.Event) error {
proc, err := psutil.NewProcess(int32(pid))
if err != nil {
return errors.New("process not found in procfs")
}

name, err := proc.Name()
if err != nil {
return errors.New("process not found in procfs")
}

createdAt, err := proc.CreateTime()
if err != nil {
return errors.New("process not found in procfs")
}
evCreatedAt := ev.ProcessContext.ExecTime.UnixMilli()

within := uint64(evCreatedAt) >= uint64(createdAt-userSpaceKillWithinMillis) && uint64(evCreatedAt) <= uint64(createdAt+userSpaceKillWithinMillis)

if !within || ev.ProcessContext.Comm != name {
return fmt.Errorf("not sharing the same namespace: %s/%s", ev.ProcessContext.Comm, name)
}

return syscall.Kill(int(pid), syscall.Signal(sig))
}

func (p *ProcessKiller) getPids(scope string, ev *model.Event, entry *model.ProcessCacheEntry) ([]uint32, error) {
var pids []uint32

if entry.ContainerID != "" && scope == "container" {
pids = entry.GetContainerPIDs()
} else {
pids = []uint32{ev.ProcessContext.Pid}
}
return pids, nil
}
29 changes: 29 additions & 0 deletions pkg/security/probe/process_killer_windows.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.

// Package probe holds probe related files
package probe

import (
"errors"

"github.com/DataDog/datadog-agent/pkg/security/secl/model"
"github.com/DataDog/datadog-agent/pkg/util/winutil"
)

// KillFromUserspace tries to kill from userspace
func (p *ProcessKiller) KillFromUserspace(pid uint32, sig uint32, _ *model.Event) error {
if sig != model.SIGKILL {
return nil
}
return winutil.KillProcess(int(pid), 0)
}

func (p *ProcessKiller) getPids(scope string, ev *model.Event, _ *model.ProcessCacheEntry) ([]uint32, error) {
if scope == "container" {
return nil, errors.New("container scope not supported")
}
return []uint32{ev.ProcessContext.Pid}, nil
}
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 @@ -3,7 +3,7 @@
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.

//go:build !linux
//go:build !linux && !windows

package model

Expand Down
33 changes: 33 additions & 0 deletions pkg/security/secl/model/consts_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// 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.

// Package model holds model related files
package model

const (
// SIGKILL id for the kill action
SIGKILL = iota + 1
)

var (
errorConstants = map[string]int{}
openFlagsConstants = map[string]int{}
fileModeConstants = map[string]int{}
inodeModeConstants = map[string]int{}
// KernelCapabilityConstants list of kernel capabilities
KernelCapabilityConstants = map[string]uint64{}
unlinkFlagsConstants = map[string]int{}
ptraceConstants = map[string]uint32{}
ptraceArchConstants = map[string]uint32{}
protConstants = map[string]int{}
mmapFlagConstants = map[string]uint64{}
mmapFlagArchConstants = map[string]uint64{}
addressFamilyConstants = map[string]uint16{}

// SignalConstants list of signals
SignalConstants = map[string]int{
"SIGKILL": SIGKILL,
}
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.

//go:build linux

// Package utils holds utils related files
package utils

Expand Down
18 changes: 18 additions & 0 deletions pkg/security/utils/proc_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// 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 utils holds utils related files
package utils

import (
"os"
)

// Getpid returns the current process ID in the host namespace
func Getpid() uint32 {
return uint32(os.Getpid())
}

0 comments on commit a83fa43

Please sign in to comment.