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.
  • Loading branch information
haesbaert committed Jul 2, 2024
1 parent b171c6c commit 8c0a849
Show file tree
Hide file tree
Showing 6 changed files with 258 additions and 333 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
149 changes: 53 additions & 96 deletions kprobe_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
#define XS(_a) S(_a)
#define PWD_K(_t, _o) "task_struct.fs fs_struct.pwd.dentry " XS(RPT(_t, _o, dentry.d_parent))
#define PWD_S(_t, _o) "task_struct.fs fs_struct.pwd.dentry " XS(RPT(_t, _o, dentry.d_parent)) " dentry.d_name.name +0"
#define TTY_MAJOR "task_struct.signal signal_struct.tty tty_struct.driver tty_driver.major"
#define TTY_MINOR_START "task_struct.signal signal_struct.tty tty_struct.driver tty_driver.minor_start"
#define TTY_MINOR_INDEX "task_struct.signal signal_struct.tty tty_struct.index"

struct kprobe_arg ka_task_old_pgid = {
"pgid", "di", "u32", "task_struct.group_leader (task_struct.pids+8) (pid.numbers+0).upid.nr"
Expand All @@ -39,65 +36,71 @@ struct kprobe_arg ka_task_new_sid = {
};


#define TASK_SAMPLE { \
{ "cap_inheritable", "di", "u64", "task_struct.cred cred.cap_inheritable" }, \
{ "cap_permitted", "di", "u64", "task_struct.cred cred.cap_permitted", }, \
{ "cap_effective", "di", "u64", "task_struct.cred cred.cap_effective" }, \
{ "cap_bset", "di", "u64", "task_struct.cred cred.cap_bset" }, \
{ "cap_ambient", "di", "u64", "task_struct.cred cred.cap_ambient" }, \
{ "start_boottime", "di", "u64", "task_struct.start_boottime" }, \
{ "tty_addr", "di", "u64", "task_struct.signal signal_struct.tty" }, \
{ "root_k", "di", "u64", "task_struct.fs fs_struct.root.dentry" }, \
{ "mnt_root_k", "di", "u64", "task_struct.fs fs_struct.pwd.mnt vfsmount.mnt_root" }, \
{ "mnt_mountpoint_k", "di", "u64", "task_struct.fs fs_struct.pwd.mnt (mount.mnt_mountpoint-mount.mnt)" }, \
{ "pwd_k0", "di", "u64", PWD_K(0, 0) }, \
{ "pwd_k1", "di", "u64", PWD_K(0, 1) }, \
{ "pwd_k2", "di", "u64", PWD_K(0, 2) }, \
{ "pwd_k3", "di", "u64", PWD_K(0, 3) }, \
{ "pwd_k4", "di", "u64", PWD_K(0, 4) }, \
{ "pwd_k5", "di", "u64", PWD_K(0, 5) }, \
{ "pwd_k6", "di", "u64", PWD_K(0, 6) }, \
{ "root_s", "di", "string", "task_struct.fs fs_struct.root.dentry dentry.d_name.name +0" }, \
{ "mnt_root_s", "di", "string", "task_struct.fs fs_struct.pwd.mnt vfsmount.mnt_root dentry.d_name.name +0" }, \
{ "mnt_mountpoint_s", "di", "string", "task_struct.fs fs_struct.pwd.mnt (mount.mnt_mountpoint-mount.mnt) dentry.d_name.name +0" }, \
{ "pwd_s0", "di", "string", PWD_S(0, 0) }, \
{ "pwd_s1", "di", "string", PWD_S(0, 1) }, \
{ "pwd_s2", "di", "string", PWD_S(0, 2) }, \
{ "pwd_s3", "di", "string", PWD_S(0, 3) }, \
{ "pwd_s4", "di", "string", PWD_S(0, 4) }, \
{ "pwd_s5", "di", "string", PWD_S(0, 5) }, \
{ "pwd_s6", "di", "string", PWD_S(0, 6) }, \
{ "comm", "di", "string", "task_struct.comm" }, \
{ "uid", "di", "u32", "task_struct.cred cred.uid" }, \
{ "gid", "di", "u32", "task_struct.cred cred.gid" }, \
{ "suid", "di", "u32", "task_struct.cred cred.suid" }, \
{ "sgid", "di", "u32", "task_struct.cred cred.sgid" }, \
{ "euid", "di", "u32", "task_struct.cred cred.euid" }, \
{ "egid", "di", "u32", "task_struct.cred cred.egid" }, \
{ "pgid", "di", "u32", "KLUDGE - see kprobe_kludge_arg()" }, \
{ "sid", "di", "u32", "KLUDGE - see kprobe_kludge_arg()" }, \
{ "pid", "di", "u32", "task_struct.tgid" }, \
{ "tid", "di", "u32", "task_struct.pid" }, \
{ "exit_code", "di", "s32", "task_struct.exit_code" }, \
{ "tty_major", "di", "u32", TTY_MAJOR }, \
{ "tty_minor_start", "di", "u32", TTY_MINOR_START }, \
{ "tty_minor_index", "di", "u32", TTY_MINOR_INDEX }, \
{ NULL, NULL, NULL, NULL }}
#define TASK_SAMPLE(_r) \
{ "cap_inheritable", S(_r), "u64", "task_struct.cred cred.cap_inheritable" }, \
{ "cap_permitted", S(_r), "u64", "task_struct.cred cred.cap_permitted", }, \
{ "cap_effective", S(_r), "u64", "task_struct.cred cred.cap_effective" }, \
{ "cap_bset", S(_r), "u64", "task_struct.cred cred.cap_bset" }, \
{ "cap_ambient", S(_r), "u64", "task_struct.cred cred.cap_ambient" }, \
{ "start_boottime", S(_r), "u64", "task_struct.start_boottime" }, \
{ "tty_addr", S(_r), "u64", "task_struct.signal signal_struct.tty" }, \
{ "root_k", S(_r), "u64", "task_struct.fs fs_struct.root.dentry" }, \
{ "mnt_root_k", S(_r), "u64", "task_struct.fs fs_struct.pwd.mnt vfsmount.mnt_root" }, \
{ "mnt_mountpoint_k", S(_r), "u64", "task_struct.fs fs_struct.pwd.mnt (mount.mnt_mountpoint-mount.mnt)" }, \
{ "pwd_k0", S(_r), "u64", PWD_K(0, 0) }, \
{ "pwd_k1", S(_r), "u64", PWD_K(0, 1) }, \
{ "pwd_k2", S(_r), "u64", PWD_K(0, 2) }, \
{ "pwd_k3", S(_r), "u64", PWD_K(0, 3) }, \
{ "pwd_k4", S(_r), "u64", PWD_K(0, 4) }, \
{ "pwd_k5", S(_r), "u64", PWD_K(0, 5) }, \
{ "pwd_k6", S(_r), "u64", PWD_K(0, 6) }, \
{ "root_s", S(_r), "string", "task_struct.fs fs_struct.root.dentry dentry.d_name.name +0" }, \
{ "mnt_root_s", S(_r), "string", "task_struct.fs fs_struct.pwd.mnt vfsmount.mnt_root dentry.d_name.name +0" }, \
{ "mnt_mountpoint_s", S(_r), "string", "task_struct.fs fs_struct.pwd.mnt (mount.mnt_mountpoint-mount.mnt) dentry.d_name.name +0" }, \
{ "pwd_s0", S(_r), "string", PWD_S(0, 0) }, \
{ "pwd_s1", S(_r), "string", PWD_S(0, 1) }, \
{ "pwd_s2", S(_r), "string", PWD_S(0, 2) }, \
{ "pwd_s3", S(_r), "string", PWD_S(0, 3) }, \
{ "pwd_s4", S(_r), "string", PWD_S(0, 4) }, \
{ "pwd_s5", S(_r), "string", PWD_S(0, 5) }, \
{ "pwd_s6", S(_r), "string", PWD_S(0, 6) }, \
{ "comm", S(_r), "string", "task_struct.comm" }, \
{ "uid", S(_r), "u32", "task_struct.cred cred.uid" }, \
{ "gid", S(_r), "u32", "task_struct.cred cred.gid" }, \
{ "suid", S(_r), "u32", "task_struct.cred cred.suid" }, \
{ "sgid", S(_r), "u32", "task_struct.cred cred.sgid" }, \
{ "euid", S(_r), "u32", "task_struct.cred cred.euid" }, \
{ "egid", S(_r), "u32", "task_struct.cred cred.egid" }, \
{ "pgid", S(_r), "u32", "KLUDGE - see kprobe_kludge_arg()" }, \
{ "sid", S(_r), "u32", "KLUDGE - see kprobe_kludge_arg()" }, \
{ "pid", S(_r), "u32", "task_struct.tgid" }, \
{ "tid", S(_r), "u32", "task_struct.pid" }, \
{ "ppid", S(_r), "u32", "task_struct.group_leader task_struct.real_parent task_struct.tgid" }, \
{ "exit_code", S(_r), "s32", "task_struct.exit_code" }, \
{ "tty_major", S(_r), "u32", "task_struct.signal signal_struct.tty tty_struct.driver tty_driver.major" }, \
{ "tty_minor_start", S(_r), "u32", "task_struct.signal signal_struct.tty tty_struct.driver tty_driver.minor_start" }, \
{ "tty_minor_index", S(_r), "u32", "task_struct.signal signal_struct.tty tty_struct.index" }

struct kprobe kp_wake_up_new_task = {
"quark_wake_up_new_task",
"wake_up_new_task",
WAKE_UP_NEW_TASK_SAMPLE,
0,
TASK_SAMPLE
{
TASK_SAMPLE(di),
{ NULL, NULL, NULL, NULL },
}
};

struct kprobe kp_exit_thread = {
"quark_exit_thread",
"exit_thread",
EXIT_THREAD_SAMPLE,
0,
TASK_SAMPLE
{
TASK_SAMPLE(di),
{ NULL, NULL, NULL, NULL },
}
};

struct kprobe kp_exec_connector = {
Expand All @@ -106,6 +109,7 @@ struct kprobe kp_exec_connector = {
EXEC_CONNECTOR_SAMPLE,
0,
{
TASK_SAMPLE(di),
{ "argc", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +0" },
{ "stack_0", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +0" },
{ "stack_1", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +8" },
Expand Down Expand Up @@ -167,56 +171,9 @@ struct kprobe kp_exec_connector = {
{ "stack_57", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +464" },
{ "stack_58", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +472" },
{ "stack_59", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +480" },
{ "stack_60", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +488" },
{ "stack_61", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +496" },
{ "stack_62", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +504" },
{ "stack_63", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +512" },
{ "stack_64", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +520" },
{ "stack_65", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +528" },
{ "stack_66", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +536" },
{ "stack_67", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +544" },
{ "stack_68", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +552" },
{ "stack_69", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +560" },
{ "stack_70", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +568" },
{ "stack_71", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +576" },
{ "stack_72", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +584" },
{ "stack_73", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +592" },
{ "stack_74", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +600" },
{ "stack_75", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +608" },
{ "stack_76", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +616" },
{ "stack_77", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +624" },
{ "stack_78", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +632" },
{ "stack_79", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +640" },
{ "stack_80", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +648" },
{ "stack_81", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +656" },
{ "stack_82", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +664" },
{ "stack_83", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +672" },
{ "stack_84", "di", "u64", "task_struct.mm mm_struct.(anon).start_stack +8 +680" },
{ "cap_inheritable", "di", "u64", "task_struct.cred cred.cap_inheritable" },
{ "cap_permitted", "di", "u64", "task_struct.cred cred.cap_permitted", },
{ "cap_effective", "di", "u64", "task_struct.cred cred.cap_effective" },
{ "cap_bset", "di", "u64", "task_struct.cred cred.cap_bset" },
{ "cap_ambient", "di", "u64", "task_struct.cred cred.cap_ambient" },
{ "start_boottime", "di", "u64", "task_struct.start_boottime" },
{ "tty_addr", "di", "u64", "task_struct.signal signal_struct.tty" },
{ "comm", "di", "string", "task_struct.comm" },
{ "uid", "di", "u32", "task_struct.cred cred.uid" },
{ "gid", "di", "u32", "task_struct.cred cred.gid" },
{ "suid", "di", "u32", "task_struct.cred cred.suid" },
{ "sgid", "di", "u32", "task_struct.cred cred.sgid" },
{ "euid", "di", "u32", "task_struct.cred cred.euid" },
{ "egid", "di", "u32", "task_struct.cred cred.egid" },
{ "pgid", "di", "u32", "task_struct.group_leader task_struct.signal (signal_struct.pids+16) (pid.numbers+0).upid.nr" }, \
{ "sid", "di", "u32", "task_struct.group_leader task_struct.signal (signal_struct.pids+24) (pid.numbers+0).upid.nr" }, \
{ "tty_major", "di", "u32", TTY_MAJOR },
{ "tty_minor_start", "di", "u32", TTY_MINOR_START },
{ "tty_minor_index", "di", "u32", TTY_MINOR_INDEX },
{ NULL, NULL, NULL, NULL },
}};

#undef TTY_MINOR_INDEX
#undef TTY_MINOR_START
#undef TTY_MAJOR
#undef PWD_S
#undef PWD_K
#undef XS
Expand Down
Loading

0 comments on commit 8c0a849

Please sign in to comment.