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

Fix ProcessTree rogue entries #4582

Merged
merged 7 commits into from
Feb 19, 2025
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
90 changes: 45 additions & 45 deletions pkg/ebpf/c/tracee.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ int tracepoint__sched__sched_process_fork(struct bpf_raw_tracepoint_args *ctx)
save_to_submit_buf(&p.event->args_buf, (void *) &parent_ns_pid, sizeof(int), 3);
save_to_submit_buf(&p.event->args_buf, (void *) &parent_start_time, sizeof(u64), 4);

// Child (might be a lwp or a process, sched_process_fork trace is calle by clone() also).
// Child (might be a lwp or a process, sched_process_fork trace is called by clone() also).
save_to_submit_buf(&p.event->args_buf, (void *) &child_tid, sizeof(int), 5);
save_to_submit_buf(&p.event->args_buf, (void *) &child_ns_tid, sizeof(int), 6);
save_to_submit_buf(&p.event->args_buf, (void *) &child_pid, sizeof(int), 7);
Expand All @@ -719,7 +719,7 @@ int tracepoint__sched__sched_process_fork(struct bpf_raw_tracepoint_args *ctx)
// as a parent of the child in the hierarchy), are needed by the userland process tree.
// The userland process tree default source of events is the signal events, but there is
// an option to use regular event for maintaining it as well (and it is needed for some
// situatins). These arguments will always be removed by userland event processors.
// situations). These arguments will always be removed by userland event processors.
struct task_struct *leader = get_leader_task(child);
struct task_struct *parent_process = get_leader_task(get_parent_task(leader));

Expand Down Expand Up @@ -7035,26 +7035,31 @@ int sched_process_exec_signal(struct bpf_raw_tracepoint_args *ctx)
if (unlikely(signal == NULL))
return 0;

// Hashes

struct task_struct *task = (struct task_struct *) ctx->args[0];
if (task == NULL)
return -1;
struct task_struct *leader = get_leader_task(task);
struct task_struct *parent = get_leader_task(get_parent_task(leader));

// The hash is always calculated with "task_struct->pid + start_time".
u32 task_hash = hash_task_id(get_task_host_pid(task), get_task_start_time(task));
u32 parent_hash = hash_task_id(get_task_host_pid(parent), get_task_start_time(parent));
u32 leader_hash = hash_task_id(get_task_host_pid(leader), get_task_start_time(leader));

// The event timestamp, so process tree info can be changelog'ed.
u64 timestamp = get_current_time_in_ns();
save_to_submit_buf(&signal->args_buf, &timestamp, sizeof(u64), 0);

save_to_submit_buf(&signal->args_buf, (void *) &task_hash, sizeof(u32), 1);
save_to_submit_buf(&signal->args_buf, (void *) &parent_hash, sizeof(u32), 2);
save_to_submit_buf(&signal->args_buf, (void *) &leader_hash, sizeof(u32), 3);
// Fields required for hash computation (start times and pids)

u64 task_start_time = get_task_start_time(task);
u64 parent_start_time = get_task_start_time(parent);
u64 leader_start_time = get_task_start_time(leader);
save_to_submit_buf(&signal->args_buf, &task_start_time, sizeof(task_start_time), 1);
save_to_submit_buf(&signal->args_buf, &parent_start_time, sizeof(parent_start_time), 2);
save_to_submit_buf(&signal->args_buf, &leader_start_time, sizeof(leader_start_time), 3);

u32 task_pid = get_task_host_pid(task);
u32 parent_pid = get_task_host_pid(parent);
u32 leader_pid = get_task_host_pid(leader);
save_to_submit_buf(&signal->args_buf, &task_pid, sizeof(task_pid), 4);
save_to_submit_buf(&signal->args_buf, &parent_pid, sizeof(parent_pid), 5);
save_to_submit_buf(&signal->args_buf, &leader_pid, sizeof(leader_pid), 6);

// Exec logic

Expand All @@ -7081,18 +7086,18 @@ int sched_process_exec_signal(struct bpf_raw_tracepoint_args *ctx)
u64 ctime = get_ctime_nanosec_from_file(file);
umode_t inode_mode = get_inode_mode_from_file(file);

save_str_to_buf(&signal->args_buf, (void *) filename, 4); // executable name
save_str_to_buf(&signal->args_buf, file_path, 5); // executable path
save_to_submit_buf(&signal->args_buf, &s_dev, sizeof(dev_t), 6); // device number
save_to_submit_buf(&signal->args_buf, &inode_nr, sizeof(unsigned long), 7); // inode number
save_to_submit_buf(&signal->args_buf, &ctime, sizeof(u64), 8); // creation time
save_to_submit_buf(&signal->args_buf, &inode_mode, sizeof(umode_t), 9); // inode mode
save_str_to_buf(&signal->args_buf, (void *) filename, 7); // executable name
save_str_to_buf(&signal->args_buf, file_path, 8); // executable path
save_to_submit_buf(&signal->args_buf, &s_dev, sizeof(dev_t), 9); // device number
save_to_submit_buf(&signal->args_buf, &inode_nr, sizeof(unsigned long), 10); // inode number
save_to_submit_buf(&signal->args_buf, &ctime, sizeof(u64), 11); // creation time
save_to_submit_buf(&signal->args_buf, &inode_mode, sizeof(umode_t), 12); // inode mode

// The proc_info interpreter field is set by "load_elf_phdrs" kprobe program.
save_str_to_buf(&signal->args_buf, &proc_info->interpreter.pathname, 10); // interpreter path
save_to_submit_buf(&signal->args_buf, &proc_info->interpreter.id.device, sizeof(dev_t), 11); // interpreter device number
save_to_submit_buf(&signal->args_buf, &proc_info->interpreter.id.inode, sizeof(u64), 12); // interpreter inode number
save_to_submit_buf(&signal->args_buf, &proc_info->interpreter.id.ctime, sizeof(u64), 13); // interpreter creation time
// The proc_info interpreter field is set by "load_elf_phdrs" kprobe program
save_str_to_buf(&signal->args_buf, &proc_info->interpreter.pathname, 13); // interpreter path
save_to_submit_buf(&signal->args_buf, &proc_info->interpreter.id.device, sizeof(dev_t), 14); // interpreter device number
save_to_submit_buf(&signal->args_buf, &proc_info->interpreter.id.inode, sizeof(u64), 15); // interpreter inode number
save_to_submit_buf(&signal->args_buf, &proc_info->interpreter.id.ctime, sizeof(u64), 16); // interpreter creation time

struct mm_struct *mm = get_mm_from_task(task); // bprm->mm is null here, but task->mm is not

Expand All @@ -7108,12 +7113,12 @@ int sched_process_exec_signal(struct bpf_raw_tracepoint_args *ctx)

bool invoked_from_kernel = !!(get_task_parent_flags(task) & PF_KTHREAD);

save_args_str_arr_to_buf(&signal->args_buf, (void *) arg_start, (void *) arg_end, argc, 14); // argv
save_str_to_buf(&signal->args_buf, (void *) interp, 15); // interp
save_to_submit_buf(&signal->args_buf, &stdin_type, sizeof(unsigned short), 16); // stdin type
save_str_to_buf(&signal->args_buf, stdin_path, 17); // stdin path
save_to_submit_buf(&signal->args_buf, &invoked_from_kernel, sizeof(bool), 18); // invoked from kernel ?

save_args_str_arr_to_buf(&signal->args_buf, (void *) arg_start, (void *) arg_end, argc, 17); // argv
save_str_to_buf(&signal->args_buf, (void *) interp, 18); // interp
save_to_submit_buf(&signal->args_buf, &stdin_type, sizeof(unsigned short), 19); // stdin type
save_str_to_buf(&signal->args_buf, stdin_path, 20); // stdin path
save_to_submit_buf(&signal->args_buf, &invoked_from_kernel, sizeof(bool), 21); // invoked from kernel ?
signal_perf_submit(ctx, signal);

return 0;
Expand All @@ -7128,28 +7133,23 @@ int sched_process_exit_signal(struct bpf_raw_tracepoint_args *ctx)
if (unlikely(signal == NULL))
return 0;

// Hashes

struct task_struct *task = (struct task_struct *) bpf_get_current_task();
if (task == NULL)
return -1;
struct task_struct *leader = get_leader_task(task);
struct task_struct *parent = get_leader_task(get_parent_task(leader));

// The hash is always calculated with "task_struct->pid + start_time".
u32 task_hash = hash_task_id(get_task_host_pid(task), get_task_start_time(task));
u32 parent_hash = hash_task_id(get_task_host_pid(parent), get_task_start_time(parent));
u32 leader_hash = hash_task_id(get_task_host_pid(leader), get_task_start_time(leader));

// The event timestamp, so process tree info can be changelog'ed.
u64 timestamp = get_current_time_in_ns();
save_to_submit_buf(&signal->args_buf, &timestamp, sizeof(u64), 0);

save_to_submit_buf(&signal->args_buf, (void *) &task_hash, sizeof(u32), 1);
save_to_submit_buf(&signal->args_buf, (void *) &parent_hash, sizeof(u32), 2);
save_to_submit_buf(&signal->args_buf, (void *) &leader_hash, sizeof(u32), 3);
// Fields required for hash computation (start times and pids)

u64 task_start_time = get_task_start_time(task);
save_to_submit_buf(&signal->args_buf, &task_start_time, sizeof(task_start_time), 1);

pid_t task_pid = (pid_t) get_task_host_pid(task);
save_to_submit_buf(&signal->args_buf, &task_pid, sizeof(task_pid), 2);

// Exit logic.
// Exit logic

bool group_dead = false;
struct signal_struct *s = BPF_CORE_READ(task, signal);
Expand All @@ -7163,12 +7163,12 @@ int sched_process_exit_signal(struct bpf_raw_tracepoint_args *ctx)
int exit_code = get_task_exit_code(task);
int exit_code_real = exit_code >> 8;

save_to_submit_buf(&signal->args_buf, (void *) &exit_code_real, sizeof(int), 4);
save_to_submit_buf(&signal->args_buf, (void *) &exit_code_real, sizeof(int), 3);
if (task_flags & PF_SIGNALED) {
int signal_code = exit_code & 0xFF;
save_to_submit_buf(&signal->args_buf, (void *) &signal_code, sizeof(int), 5);
save_to_submit_buf(&signal->args_buf, (void *) &signal_code, sizeof(int), 4);
}
save_to_submit_buf(&signal->args_buf, (void *) &group_dead, sizeof(bool), 6);
save_to_submit_buf(&signal->args_buf, (void *) &group_dead, sizeof(bool), 5);

signal_perf_submit(ctx, signal);

Expand Down
41 changes: 41 additions & 0 deletions pkg/ebpf/controlplane/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/aquasecurity/libbpfgo"

"github.com/aquasecurity/tracee/pkg/containers"
"github.com/aquasecurity/tracee/pkg/errfmt"
"github.com/aquasecurity/tracee/pkg/events"
"github.com/aquasecurity/tracee/pkg/logger"
"github.com/aquasecurity/tracee/pkg/proctree"
Expand Down Expand Up @@ -116,10 +117,50 @@ func (ctrl *Controller) processSignal(signal *signal) error {
case events.SignalCgroupRmdir:
return ctrl.processCgroupRmdir(signal.args)
case events.SignalSchedProcessFork:
err := events.NormalizeTimeArgs(
signal.args,
[]string{
"timestamp",
"parent_process_start_time",
"leader_start_time",
"start_time",
},
)
if err != nil {
signalName := events.Core.GetDefinitionByID(signal.id).GetName()
return errfmt.Errorf("error normalizing time args for signal %s: %v", signalName, err)
}

return ctrl.procTreeForkProcessor(signal.args)
case events.SignalSchedProcessExec:
err := events.NormalizeTimeArgs(
signal.args,
[]string{
"timestamp",
"task_start_time",
"parent_start_time",
"leader_start_time",
},
)
if err != nil {
signalName := events.Core.GetDefinitionByID(signal.id).GetName()
return errfmt.Errorf("error normalizing time args for signal %s: %v", signalName, err)
}

return ctrl.procTreeExecProcessor(signal.args)
case events.SignalSchedProcessExit:
err := events.NormalizeTimeArgs(
signal.args,
[]string{
"timestamp",
"task_start_time",
},
)
if err != nil {
signalName := events.Core.GetDefinitionByID(signal.id).GetName()
return errfmt.Errorf("error normalizing time args for signal %s: %v", signalName, err)
}

return ctrl.procTreeExitProcessor(signal.args)
}

Expand Down
70 changes: 47 additions & 23 deletions pkg/ebpf/controlplane/processes.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package controlplane

import (
"github.com/aquasecurity/tracee/pkg/events/parse"
"github.com/aquasecurity/tracee/pkg/time"
"github.com/aquasecurity/tracee/pkg/utils"
"github.com/aquasecurity/tracee/types/trace"
)
Expand Down Expand Up @@ -95,14 +94,10 @@ func (ctrl *Controller) procTreeForkProcessor(args []trace.Argument) error {
return err
}

forkFeed.TimeStamp = time.BootToEpochNS(forkFeed.TimeStamp)
forkFeed.ChildStartTime = time.BootToEpochNS(forkFeed.ChildStartTime)
forkFeed.ParentStartTime = time.BootToEpochNS(forkFeed.ParentStartTime)
forkFeed.LeaderStartTime = time.BootToEpochNS(forkFeed.LeaderStartTime)

forkFeed.ChildHash = utils.HashTaskID(uint32(forkFeed.ChildTid), forkFeed.ChildStartTime)
// Hashes
forkFeed.ParentHash = utils.HashTaskID(uint32(forkFeed.ParentTid), forkFeed.ParentStartTime)
forkFeed.LeaderHash = utils.HashTaskID(uint32(forkFeed.LeaderTid), forkFeed.LeaderStartTime)
forkFeed.ChildHash = utils.HashTaskID(uint32(forkFeed.ChildTid), forkFeed.ChildStartTime)

return ctrl.processTree.FeedFromFork(forkFeed)
}
Expand All @@ -118,14 +113,41 @@ func (ctrl *Controller) procTreeExecProcessor(args []trace.Argument) error {
execFeed := ctrl.processTree.GetExecFeedFromPool()
defer ctrl.processTree.PutExecFeedInPool(execFeed)

// Process & Event identification arguments (won't exist for regular events)
// not available from this signal
execFeed.Pid = -1
execFeed.Tid = -1
execFeed.PPid = -1

// Process & Event identification arguments
execFeed.TimeStamp, err = parse.ArgVal[uint64](args, "timestamp")
if err != nil {
return err
}
execFeed.TaskHash, _ = parse.ArgVal[uint32](args, "task_hash")
execFeed.ParentHash, _ = parse.ArgVal[uint32](args, "parent_hash")
execFeed.LeaderHash, _ = parse.ArgVal[uint32](args, "leader_hash")
execFeed.StartTime, err = parse.ArgVal[uint64](args, "task_start_time")
if err != nil {
return err
}
parentStartTime, err := parse.ArgVal[uint64](args, "parent_start_time")
if err != nil {
return err
}
leaderStartTime, err := parse.ArgVal[uint64](args, "leader_start_time")
if err != nil {
return err
}

execFeed.HostTid, err = parse.ArgVal[int32](args, "task_pid")
if err != nil {
return err
}
execFeed.HostPPid, err = parse.ArgVal[int32](args, "parent_pid")
if err != nil {
return err
}
execFeed.HostPid, err = parse.ArgVal[int32](args, "leader_pid")
if err != nil {
return err
}

// Executable
execFeed.CmdPath, err = parse.ArgVal[string](args, "cmdpath")
Expand Down Expand Up @@ -179,6 +201,11 @@ func (ctrl *Controller) procTreeExecProcessor(args []trace.Argument) error {
return err
}

// Hashes
execFeed.TaskHash = utils.HashTaskID(uint32(execFeed.HostTid), execFeed.StartTime)
execFeed.ParentHash = utils.HashTaskID(uint32(execFeed.HostPPid), parentStartTime)
execFeed.LeaderHash = utils.HashTaskID(uint32(execFeed.HostPid), leaderStartTime)

return ctrl.processTree.FeedFromExec(execFeed)
}

Expand All @@ -197,26 +224,20 @@ func (ctrl *Controller) procTreeExitProcessor(args []trace.Argument) error {
exitFeed := ctrl.processTree.GetExitFeedFromPool()
defer ctrl.processTree.PutExitFeedInPool(exitFeed)

// Process & Event identification arguments (won't exist for regular events)
// Process & Event identification arguments
exitFeed.TimeStamp, err = parse.ArgVal[uint64](args, "timestamp")
if err != nil {
return err
}
// time of exit is already a timestamp)
exitFeed.TimeStamp = time.BootToEpochNS(exitFeed.TimeStamp)
startTime, err := parse.ArgVal[uint64](args, "task_start_time")
if err != nil {
return err
}

exitFeed.TaskHash, err = parse.ArgVal[uint32](args, "task_hash")
taskPid, err := parse.ArgVal[int32](args, "task_pid")
if err != nil {
return err
}
// exitFeed.ParentHash, err = parse.ArgVal[uint32](args, "parent_hash")
// if err != nil {
// return err
// }
// exitFeed.LeaderHash, err = parse.ArgVal[uint32](args, "leader_hash")
// if err != nil {
// return err
// }

// // Exit logic arguments
// exitFeed.ExitCode, err = parse.ArgVal[int32](args, "exit_code")
Expand All @@ -232,5 +253,8 @@ func (ctrl *Controller) procTreeExitProcessor(args []trace.Argument) error {
// return err
// }

// Hash
exitFeed.TaskHash = utils.HashTaskID(uint32(taskPid), startTime)

return ctrl.processTree.FeedFromExit(exitFeed)
}
19 changes: 7 additions & 12 deletions pkg/ebpf/events_pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/aquasecurity/tracee/pkg/errfmt"
"github.com/aquasecurity/tracee/pkg/events"
"github.com/aquasecurity/tracee/pkg/logger"
"github.com/aquasecurity/tracee/pkg/time"
traceetime "github.com/aquasecurity/tracee/pkg/time"
"github.com/aquasecurity/tracee/pkg/utils"
"github.com/aquasecurity/tracee/types/trace"
)
Expand Down Expand Up @@ -242,14 +242,8 @@ func (t *Tracee) decodeEvents(ctx context.Context, sourceChan chan []byte) (<-ch

// populate all the fields of the event used in this stage, and reset the rest

// normalize timestamp context fields for later use
normalizedTs := time.BootToEpochNS(eCtx.Ts)
normalizedThreadStartTime := time.BootToEpochNS(eCtx.StartTime)
normalizedLeaderStartTime := time.BootToEpochNS(eCtx.LeaderStartTime)
normalizedParentStartTime := time.BootToEpochNS(eCtx.ParentStartTime)

evt.Timestamp = int(normalizedTs)
evt.ThreadStartTime = int(normalizedThreadStartTime)
evt.Timestamp = int(traceetime.BootToEpochNS(eCtx.Ts)) // normalize time
evt.ThreadStartTime = int(traceetime.BootToEpochNS(eCtx.StartTime)) // normalize time
evt.ProcessorID = int(eCtx.ProcessorId)
evt.ProcessID = int(eCtx.Pid)
evt.ThreadID = int(eCtx.Tid)
Expand Down Expand Up @@ -279,9 +273,10 @@ func (t *Tracee) decodeEvents(ctx context.Context, sourceChan chan []byte) (<-ch
evt.ContextFlags = flags
evt.Syscall = syscall
evt.Metadata = nil
evt.ThreadEntityId = utils.HashTaskID(eCtx.HostTid, normalizedThreadStartTime)
evt.ProcessEntityId = utils.HashTaskID(eCtx.HostPid, normalizedLeaderStartTime)
evt.ParentEntityId = utils.HashTaskID(eCtx.HostPpid, normalizedParentStartTime)
// compute hashes using normalized times
evt.ThreadEntityId = utils.HashTaskID(eCtx.HostTid, uint64(evt.ThreadStartTime))
evt.ProcessEntityId = utils.HashTaskID(eCtx.HostPid, traceetime.BootToEpochNS(eCtx.LeaderStartTime))
evt.ParentEntityId = utils.HashTaskID(eCtx.HostPpid, traceetime.BootToEpochNS(eCtx.ParentStartTime))

// If there aren't any policies that need filtering in userland, tracee **may** skip
// this event, as long as there aren't any derivatives or signatures that depend on it.
Expand Down
2 changes: 1 addition & 1 deletion pkg/ebpf/net_capture.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func (t *Tracee) processNetCapEvent(event *trace.Event) {

// sanity checks

payloadArg := events.GetArg(event, "payload")
payloadArg := events.GetArg(event.Args, "payload")
if payloadArg == nil {
logger.Debugw("Network capture: no payload packet")
return
Expand Down
Loading
Loading