Skip to content

Commit

Permalink
Feature/ptrace (#381)
Browse files Browse the repository at this point in the history
* Added ptrace eBPF

* WIP: Modified struct

* WIP: Added events

* added tracer

* WIP: Added ptrace to container watcher

* WIP: Rules

* WIP: Added to rule manager

* WIP: Added ptrace rule

* Added rule & tests

* Added pool

* Removed prints

* Added ptrace to new infrastructure

* WIP: Fixed CR

* WIP: added component test

* WIP: Remove component test

* WIP: Updated struct
  • Loading branch information
afek854 authored Oct 8, 2024
1 parent 1396765 commit dfd15ec
Show file tree
Hide file tree
Showing 17 changed files with 825 additions and 24 deletions.
23 changes: 23 additions & 0 deletions pkg/containerwatcher/v1/container_watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,15 @@ import (
tracerhardlinktype "github.com/kubescape/node-agent/pkg/ebpf/gadgets/hardlink/types"
tracerhttp "github.com/kubescape/node-agent/pkg/ebpf/gadgets/http/tracer"
tracerhttptype "github.com/kubescape/node-agent/pkg/ebpf/gadgets/http/types"
tracerptrace "github.com/kubescape/node-agent/pkg/ebpf/gadgets/ptrace/tracer"
tracerptracetype "github.com/kubescape/node-agent/pkg/ebpf/gadgets/ptrace/tracer/types"
tracerandomx "github.com/kubescape/node-agent/pkg/ebpf/gadgets/randomx/tracer"
tracerandomxtype "github.com/kubescape/node-agent/pkg/ebpf/gadgets/randomx/types"
tracerssh "github.com/kubescape/node-agent/pkg/ebpf/gadgets/ssh/tracer"
tracersshtype "github.com/kubescape/node-agent/pkg/ebpf/gadgets/ssh/types"
tracersymlink "github.com/kubescape/node-agent/pkg/ebpf/gadgets/symlink/tracer"
tracersymlinktype "github.com/kubescape/node-agent/pkg/ebpf/gadgets/symlink/types"

"github.com/kubescape/node-agent/pkg/malwaremanager"
"github.com/kubescape/node-agent/pkg/metricsmanager"
"github.com/kubescape/node-agent/pkg/networkmanager"
Expand All @@ -56,6 +59,7 @@ const (
networkTraceName = "trace_network"
dnsTraceName = "trace_dns"
openTraceName = "trace_open"
ptraceTraceName = "trace_ptrace"
randomxTraceName = "trace_randomx"
symlinkTraceName = "trace_symlink"
hardlinkTraceName = "trace_hardlink"
Expand All @@ -64,6 +68,7 @@ const (
capabilitiesWorkerPoolSize = 1
execWorkerPoolSize = 2
openWorkerPoolSize = 8
ptraceWorkerPoolSize = 1
networkWorkerPoolSize = 1
dnsWorkerPoolSize = 5
randomxWorkerPoolSize = 1
Expand Down Expand Up @@ -99,6 +104,7 @@ type IGContainerWatcher struct {
capabilitiesTracer *tracercapabilities.Tracer
execTracer *tracerexec.Tracer
openTracer *traceropen.Tracer
ptraceTracer *tracerptrace.Tracer
syscallTracer *tracerseccomp.Tracer
networkTracer *tracernetwork.Tracer
dnsTracer *tracerdns.Tracer
Expand All @@ -118,6 +124,7 @@ type IGContainerWatcher struct {
capabilitiesWorkerPool *ants.PoolWithFunc
execWorkerPool *ants.PoolWithFunc
openWorkerPool *ants.PoolWithFunc
ptraceWorkerPool *ants.PoolWithFunc
networkWorkerPool *ants.PoolWithFunc
dnsWorkerPool *ants.PoolWithFunc
randomxWorkerPool *ants.PoolWithFunc
Expand All @@ -129,6 +136,7 @@ type IGContainerWatcher struct {
capabilitiesWorkerChan chan *tracercapabilitiestype.Event
execWorkerChan chan *tracerexectype.Event
openWorkerChan chan *traceropentype.Event
ptraceWorkerChan chan *tracerptracetype.Event
networkWorkerChan chan *tracernetworktype.Event
dnsWorkerChan chan *tracerdnstype.Event
randomxWorkerChan chan *tracerandomxtype.Event
Expand Down Expand Up @@ -374,6 +382,19 @@ func CreateIGContainerWatcher(cfg config.Config, applicationProfileManager appli
return nil, fmt.Errorf("creating http worker pool: %w", err)
}

// Create a ptrace worker pool
ptraceWorkerPool, err := ants.NewPoolWithFunc(ptraceWorkerPoolSize, func(i interface{}) {
event := i.(tracerptracetype.Event)
if event.K8s.ContainerName == "" {
return
}
ruleManager.ReportEvent(utils.PtraceEventType, &event)
})

if err != nil {
return nil, fmt.Errorf("creating ptrace worker pool: %w", err)
}

return &IGContainerWatcher{
// Configuration
cfg: cfg,
Expand Down Expand Up @@ -404,13 +425,15 @@ func CreateIGContainerWatcher(cfg config.Config, applicationProfileManager appli
hardlinkWorkerPool: hardlinkWorkerPool,
sshdWorkerPool: sshWorkerPool,
httpWorkerPool: httpWorkerPool,
ptraceWorkerPool: ptraceWorkerPool,
metrics: metrics,
preRunningContainersIDs: preRunningContainers,

// Channels
capabilitiesWorkerChan: make(chan *tracercapabilitiestype.Event, 1000),
execWorkerChan: make(chan *tracerexectype.Event, 10000),
openWorkerChan: make(chan *traceropentype.Event, 500000),
ptraceWorkerChan: make(chan *tracerptracetype.Event, 1000),
networkWorkerChan: make(chan *tracernetworktype.Event, 500000),
dnsWorkerChan: make(chan *tracerdnstype.Event, 100000),
randomxWorkerChan: make(chan *tracerandomxtype.Event, 5000),
Expand Down
13 changes: 12 additions & 1 deletion pkg/containerwatcher/v1/container_watcher_private.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,11 @@ func (ch *IGContainerWatcher) startTracers() error {
return err
}

if err := ch.startPtraceTracing(); err != nil {
logger.L().Error("error starting ptrace tracing", helpers.Error(err))
return err
}

// Start third party tracers
for tracer := range ch.thirdPartyTracers.Iter() {
if err := tracer.Start(); err != nil {
Expand Down Expand Up @@ -355,7 +360,13 @@ func (ch *IGContainerWatcher) stopTracers() error {

// Stop ssh tracer
if err := ch.stopSshTracing(); err != nil {
logger.L().Error("error stopping ssh tracing", helpers.Error(err))
logger.L().Error("error starting ssh tracing", helpers.Error(err))
errs = errors.Join(errs, err)
}

// Stop ptrace tracer
if err := ch.stopPtraceTracing(); err != nil {
logger.L().Error("error starting ptrace tracing", helpers.Error(err))
errs = errors.Join(errs, err)
}

Expand Down
52 changes: 52 additions & 0 deletions pkg/containerwatcher/v1/ptrace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package containerwatcher

import (
"fmt"

"github.com/inspektor-gadget/inspektor-gadget/pkg/types"
tracerptrace "github.com/kubescape/node-agent/pkg/ebpf/gadgets/ptrace/tracer"
tracerptracetype "github.com/kubescape/node-agent/pkg/ebpf/gadgets/ptrace/tracer/types"
)

func (ch *IGContainerWatcher) ptraceEventCallback(event *tracerptracetype.Event) {
if event.Type != types.NORMAL {
return
}

ch.ptraceWorkerChan <- event

}

func (ch *IGContainerWatcher) startPtraceTracing() error {
if err := ch.tracerCollection.AddTracer(ptraceTraceName, ch.containerSelector); err != nil {
return fmt.Errorf("adding tracer: %w", err)
}

// Get mount namespace map to filter by containers
ptraceMountnsmap, err := ch.tracerCollection.TracerMountNsMap(ptraceTraceName)
if err != nil {
return fmt.Errorf("getting ptraceMountnsmap: %w", err)
}

tracerPtrace, err := tracerptrace.NewTracer(&tracerptrace.Config{MountnsMap: ptraceMountnsmap}, ch.containerCollection, ch.ptraceEventCallback)
if err != nil {
return fmt.Errorf("creating tracer: %w", err)
}
go func() {
for event := range ch.ptraceWorkerChan {
_ = ch.ptraceWorkerPool.Invoke(*event)
}
}()

ch.ptraceTracer = tracerPtrace

return nil
}

func (ch *IGContainerWatcher) stopPtraceTracing() error {
if err := ch.tracerCollection.RemoveTracer(ptraceTraceName); err != nil {
return fmt.Errorf("removing tracer: %w", err)
}
ch.ptraceTracer.Close()
return nil
}
24 changes: 3 additions & 21 deletions pkg/ebpf/gadgets/http/tracer/tracepoint_definitions.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
package tracer

import (
"fmt"
import tracepointlib "github.com/kubescape/node-agent/pkg/ebpf/lib"

"github.com/cilium/ebpf"
"github.com/cilium/ebpf/link"
)

type TracepointInfo struct {
Syscall string
ObjFunc interface{}
}

func GetTracepointDefinitions(objs *http_snifferPrograms) []TracepointInfo {
return []TracepointInfo{
func GetTracepointDefinitions(objs *http_snifferPrograms) []tracepointlib.TracepointInfo {
return []tracepointlib.TracepointInfo{
{"sys_enter_accept", objs.SysEnterAccept},
{"sys_enter_accept4", objs.SysEnterAccept4},
{"sys_exit_accept", objs.SysExitAccept},
Expand All @@ -39,11 +29,3 @@ func GetTracepointDefinitions(objs *http_snifferPrograms) []TracepointInfo {
{"sys_exit_readv", objs.SyscallProbeRetReadv},
}
}

func AttachTracepoint(tracepoint TracepointInfo) (link.Link, error) {
l, err := link.Tracepoint("syscalls", tracepoint.Syscall, tracepoint.ObjFunc.(*ebpf.Program), nil)
if err != nil {
return nil, fmt.Errorf("failed to attach tracepoint %s: %v", tracepoint.Syscall, err)
}
return l, nil
}
3 changes: 2 additions & 1 deletion pkg/ebpf/gadgets/http/tracer/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets"
"github.com/kubescape/go-logger"
"github.com/kubescape/node-agent/pkg/ebpf/gadgets/http/types"
tracepointlib "github.com/kubescape/node-agent/pkg/ebpf/lib"
)

//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -strip /usr/bin/llvm-strip-18 -cc /usr/bin/clang -no-global-types -target bpfel -cc clang -cflags "-g -O2 -Wall" -type active_connection_info -type packet_buffer -type httpevent http_sniffer bpf/http-sniffer.c -- -I./bpf/
Expand Down Expand Up @@ -100,7 +101,7 @@ func (t *Tracer) install() error {
tracepoints := GetTracepointDefinitions(&t.objs.http_snifferPrograms)
var links []link.Link
for _, tp := range tracepoints {
l, err := AttachTracepoint(tp)
l, err := tracepointlib.AttachTracepoint(tp)
if err != nil {
logger.L().Error(fmt.Sprintf("Error attaching tracepoint: %s", err))
}
Expand Down
84 changes: 84 additions & 0 deletions pkg/ebpf/gadgets/ptrace/tracer/bpf/ptrace_detector.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#include "ptrace_detector.h"

struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(key_size, sizeof(u32));
__uint(value_size, sizeof(u32));
} events SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__uint(max_entries, 1);
__type(key, u32);
__type(value, struct event);
} empty_event SEC(".maps");


static __always_inline int should_discard()
{
u64 mntns_id;
mntns_id = gadget_get_mntns_id();

if (gadget_should_discard_mntns_id(mntns_id))
{
return 1;
}

return 0;
}

static __always_inline char * get_exe_path(struct task_struct* current_task ) {
struct file *exe_file = BPF_CORE_READ(current_task, mm, exe_file);
char *exepath;
exepath = get_path_str(&exe_file->f_path);
return exepath;
}


static __always_inline void populate_event(struct event* event) {
u64 mntns_id = gadget_get_mntns_id();
u64 pid_tgid = bpf_get_current_pid_tgid();
event->pid = pid_tgid >> 32;

u64 uid_gid = bpf_get_current_uid_gid();
event->uid = uid_gid & 0xFFFFFFFF;
event->gid = uid_gid >> 32;
event->timestamp = bpf_ktime_get_boot_ns();
event->mntns_id = mntns_id;
bpf_get_current_comm(&event->comm, sizeof(event->comm));
}

SEC("tracepoint/syscalls/sys_enter_ptrace")
int trace_enter_ptrace(struct trace_event_raw_sys_enter *ctx)
{
long request = (long)ctx->args[0];
long pid = (long)ctx->args[1];

if (should_discard()) {
return 0;
}

struct event *event;
u32 zero = 0;
event = bpf_map_lookup_elem(&empty_event, &zero);
if (!event) {
return 0;
}

struct task_struct *current_task = (struct task_struct*)bpf_get_current_task();
if (!current_task) {
return 0;
}

if (request == PTRACE_SETREGS || request == PTRACE_POKETEXT || request == PTRACE_POKEDATA) {
char* exepath = get_exe_path(current_task);
bpf_probe_read_kernel_str(event->exepath, MAX_STRING_SIZE, exepath);
event->ppid = BPF_CORE_READ(current_task, real_parent, pid);
event->request = request;
populate_event(event);
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, event, sizeof(struct event));
}
return 0;
}

char _license[] SEC("license") = "GPL";
37 changes: 37 additions & 0 deletions pkg/ebpf/gadgets/ptrace/tracer/bpf/ptrace_detector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include "../../../../include/amd64/vmlinux.h"
#include "../../../../include/types.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>

#include "../../../../include/mntns_filter.h"
#include "../../../../include/filesystem.h"
#include "../../../../include/macros.h"
#include "../../../../include/buffer.h"

#define TASK_COMM_LEN 16
#define MAX_STRING_SIZE 4096

#ifndef PTRACE_SETREGS
#define PTRACE_SETREGS 13
#endif

#ifndef PTRACE_POKETEXT
#define PTRACE_POKETEXT 4
#endif

#ifndef PTRACE_POKEDATA
#define PTRACE_POKEDATA 5
#endif


struct event {
gadget_timestamp timestamp;
gadget_mntns_id mntns_id;
__u32 pid;
__u32 ppid;
__u32 uid;
__u32 gid;
__u32 request;
__u8 comm[TASK_COMM_LEN];
__u8 exepath[MAX_STRING_SIZE];
};
Loading

0 comments on commit dfd15ec

Please sign in to comment.