Skip to content

Commit

Permalink
Fetch everything, everywhere, all at once. Issue #45
Browse files Browse the repository at this point in the history
This diff unifies the tracking of task_struct{} across all probes and ebpf
events. We now update ~all task_struct values everywhere we can.

Now exit and exec embed a raw_task{} into their own raw_type and functions taht
operate solely on raw_task{} have been unified so we stop repeating code.

TASK_SAMPLE takes a parameter for register as maybe we will have to track from
another register in the future

Now samples can include TASK_SAMPLE, like exec_connector does. This creates an
issue as before we were creating the wire protocol carefully aligned by making
sure it's all ordered 64->32->16->8 and so on. If we place TASK_SAMPLE in the
beginning of the sample, we might end up unaligned, but if we add it in the end,
then a task_sample stops being standalone as it defines `probe_ip` like all
other samples.

We solve this by defining an aligned/non-padded task_sample, and we enforce this
via #pragma forbidden magic. Luckly it is aligned in its current state, if we
add more members in the future, we may manually pad it with additional members.

We also start getting ppid from the wire instead of hardcoding it, that's
because ppid might change either when a process daemonizes or when docker is
doing its magic to start a container, which can change ppid multiple times via
PR_SET_CHILD_SUBREAPER blood magic. See issue #43.

This PR is pending on the merge of elastic/ebpf#197
  • Loading branch information
haesbaert committed Jul 1, 2024
1 parent 779dafd commit e9fa794
Show file tree
Hide file tree
Showing 8 changed files with 266 additions and 334 deletions.
102 changes: 59 additions & 43 deletions bpf_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,34 +33,40 @@ libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
return (0);
}

struct ebpf_ctx {
struct ebpf_pid_info *pids;
struct ebpf_cred_info *creds;
struct ebpf_tty_dev *ctty;
char *comm;
char *cwd;
};

static void
ebpf_events_to_task(struct ebpf_pid_info *pids, struct ebpf_cred_info *creds,
struct ebpf_tty_dev *tty, struct raw_task *task, u32 *pid)
ebpf_ctx_to_task(struct ebpf_ctx *ebpf_ctx, struct raw_task *task)
{
*pid = pids->tid;
task->ppid = pids->ppid;
task->start_boottime = pids->start_time_ns; /* XXX check format */
task->cap_inheritable = 0; /* unavailable */
task->cap_permitted = creds->cap_permitted;
task->cap_effective = creds->cap_effective;
task->cap_permitted = ebpf_ctx->creds->cap_permitted;
task->cap_effective = ebpf_ctx->creds->cap_effective;
task->cap_bset = 0; /* unavailable */
task->cap_ambient = 0; /* unavailable */
task->uid = creds->ruid;
task->gid = creds->rgid;
task->suid = creds->suid;
task->sgid = creds->sgid;
task->euid = creds->euid;
task->egid = creds->egid;
task->pgid = pids->pgid;
task->sid = pids->sid;
if (tty != NULL) {
task->tty_major = tty->major;
task->tty_minor = tty->minor;
} else {
task->tty_major = 0;
task->tty_minor = 0;
}
task->exit_time_event = 0;
task->start_boottime = ebpf_ctx->pids->start_time_ns; /* XXX check format */
task->uid = ebpf_ctx->creds->ruid;
task->gid = ebpf_ctx->creds->rgid;
task->suid = ebpf_ctx->creds->suid;
task->sgid = ebpf_ctx->creds->sgid;
task->euid = ebpf_ctx->creds->euid;
task->egid = ebpf_ctx->creds->egid;
task->pgid = ebpf_ctx->pids->pgid;
task->sid = ebpf_ctx->pids->sid;
task->ppid = ebpf_ctx->pids->ppid;
/* skip exit_* */
task->tty_major = ebpf_ctx->ctty->major;
task->tty_minor = ebpf_ctx->ctty->minor;
if (ebpf_ctx->cwd != NULL)
qstr_strcpy(&task->cwd, ebpf_ctx->cwd);
else
qstr_strcpy(&task->cwd, "(invalid)");
strlcpy(task->comm, ebpf_ctx->comm, sizeof(task->comm));
}

static struct raw_event *
Expand All @@ -71,7 +77,9 @@ ebpf_events_to_raw(struct ebpf_event_header *ev)
struct ebpf_process_exit_event *exit;
struct ebpf_process_exec_event *exec;
struct ebpf_varlen_field *field;
struct ebpf_ctx ebpf_ctx;

bzero(&ebpf_ctx, sizeof(ebpf_ctx));
raw = NULL;

switch (ev->type) {
Expand All @@ -81,56 +89,61 @@ ebpf_events_to_raw(struct ebpf_event_header *ev)
goto bad;
if ((raw = raw_event_alloc(RAW_WAKE_UP_NEW_TASK)) == NULL)
goto bad;
raw->pid = fork->child_pids.tid;
raw->time = ev->ts;
ebpf_events_to_task(&fork->child_pids, &fork->creds, &fork->ctty,
&raw->task, &raw->pid);
ebpf_ctx.pids = &fork->child_pids;
ebpf_ctx.creds = &fork->creds;
ebpf_ctx.ctty = &fork->ctty;
ebpf_ctx.comm = fork->comm;
ebpf_ctx.cwd = NULL;
/* the macro doesn't take a pointer so we can't pass down :) */
FOR_EACH_VARLEN_FIELD(fork->vl_fields, field) {
switch (field->type) {
case EBPF_VL_FIELD_CWD:
qstr_strcpy(&raw->task.cwd, field->data);
ebpf_ctx.cwd = field->data;
break;
default:
break;
}
}
ebpf_ctx_to_task(&ebpf_ctx, &raw->task);

break;
case EBPF_EVENT_PROCESS_EXIT:
exit = (struct ebpf_process_exit_event *)ev;
if (exit->pids.tid != exit->pids.tgid)
goto bad;
if ((raw = raw_event_alloc(RAW_EXIT_THREAD)) == NULL)
goto bad;
raw->pid = exit->pids.tid;
raw->time = ev->ts;
ebpf_events_to_task(&exit->pids, &exit->creds, NULL,
&raw->task, &raw->pid);
ebpf_ctx.pids = &exit->pids;
ebpf_ctx.creds = &exit->creds;
ebpf_ctx.ctty = &exit->ctty;
ebpf_ctx.comm = exit->comm;
ebpf_ctx.cwd = NULL;
raw->task.exit_code = exit->exit_code;
raw->task.exit_time_event = raw->time;
/* the macro doesn't take a pointer so we can't pass down :) */
FOR_EACH_VARLEN_FIELD(exit->vl_fields, field) {
switch (field->type) {
case EBPF_VL_FIELD_CWD:
qstr_strcpy(&raw->task.cwd, field->data);
break;
default:
break;
}
}
ebpf_ctx_to_task(&ebpf_ctx, &raw->task);

break;
case EBPF_EVENT_PROCESS_EXEC:
exec = (struct ebpf_process_exec_event *)ev;
if ((raw = raw_event_alloc(RAW_EXEC)) == NULL)
goto bad;
raw->pid = exec->pids.tid;
raw->time = ev->ts;
raw->exec.flags |= RAW_EXEC_F_EXT;
ebpf_events_to_task(&exec->pids, &exec->creds, &exec->ctty,
&raw->exec.ext.task, &raw->pid);
strlcpy(raw->exec.ext.comm, exec->comm,
sizeof(raw->exec.ext.comm));
ebpf_ctx.pids = &exec->pids;
ebpf_ctx.creds = &exec->creds;
ebpf_ctx.ctty = &exec->ctty;
ebpf_ctx.comm = exec->comm;
ebpf_ctx.cwd = NULL;

FOR_EACH_VARLEN_FIELD(exec->vl_fields, field) {
switch (field->type) {
case EBPF_VL_FIELD_CWD:
qstr_strcpy(&raw->exec.ext.task.cwd, field->data);
ebpf_ctx.cwd = field->data;
break;
case EBPF_VL_FIELD_FILENAME:
qstr_strcpy(&raw->exec.filename, field->data);
Expand All @@ -149,6 +162,8 @@ ebpf_events_to_raw(struct ebpf_event_header *ev)
break;
}
}
ebpf_ctx_to_task(&ebpf_ctx, &raw->exec.ext.task);

break;
default:
warnx("%s unhandled type %lu", __func__, ev->type);
Expand All @@ -160,6 +175,7 @@ ebpf_events_to_raw(struct ebpf_event_header *ev)
bad:
if (raw != NULL)
raw_event_free(raw);

return (NULL);
}

Expand Down
1 change: 1 addition & 0 deletions btf.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ struct quark_btf_target targets[] = {
{ "task_struct.mm", -1 },
{ "task_struct.pid", -1 },
{ "task_struct.pids", -1 },
{ "task_struct.real_parent", -1 },
{ "task_struct.start_boottime", -1 }, /* or task_struct.real_start_time */
{ "task_struct.signal", -1 }, /* or task_struct.pids via KLUDGE */
{ "task_struct.tgid", -1 },
Expand Down
3 changes: 2 additions & 1 deletion elastic-ebpf/GPL/Events/EbpfEventProto.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,9 @@ struct ebpf_process_exit_event {
struct ebpf_event_header hdr;
struct ebpf_pid_info pids;
struct ebpf_cred_info creds;
int32_t exit_code;
struct ebpf_tty_dev ctty;
char comm[TASK_COMM_LEN];
int32_t exit_code;

// Variable length fields: pids_ss_cgroup_path
struct ebpf_varlen_fields_start vl_fields;
Expand Down
6 changes: 6 additions & 0 deletions elastic-ebpf/GPL/Events/Process/Probe.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ int BPF_PROG(sched_process_fork, const struct task_struct *parent, const struct
size = ebpf_resolve_pids_ss_cgroup_path_to_string(field->data, child);
ebpf_vl_field__set_size(&event->vl_fields, field, size);

// cwd
field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_CWD);
size = ebpf_resolve_path_to_string(field->data, &child->fs->pwd, child);
ebpf_vl_field__set_size(&event->vl_fields, field, size);

bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0);

out:
Expand Down Expand Up @@ -201,6 +206,7 @@ static int taskstats_exit__enter(const struct task_struct *task, int group_dead)
event->exit_code = (exit_code >> 8) & 0xFF;
ebpf_pid_info__fill(&event->pids, task);
ebpf_cred_info__fill(&event->creds, task);
ebpf_ctty__fill(&event->ctty, task);
ebpf_comm__fill(event->comm, sizeof(event->comm), task);

// Variable length fields
Expand Down
Loading

0 comments on commit e9fa794

Please sign in to comment.