Skip to content

Instantly share code, notes, and snippets.

@ancat
Last active March 2, 2020 03:40
Show Gist options
  • Save ancat/919ab9831db9a36589e5a50afa4bbef8 to your computer and use it in GitHub Desktop.
Save ancat/919ab9831db9a36589e5a50afa4bbef8 to your computer and use it in GitHub Desktop.
/*
Question: how hook into the creation of new processes /and/ threads?
Attempt #1: Attach a kprobe to the `execve` syscall
- This works, but will not catch threads created via clone.
Attempt #2: Add an additional kretprobe to the `clone` syscall
- On success, clone returns the newly created thread id. This works fine
until you start dealing with pid namespaces. If clone is called from a
different pid namespace, the return value will only be valid for that
namespace, making it useless outside (eg can't use that as a pid to
query for more information, for logging, etc)
Attempt #3: Attach a kprobe to the `sched_fork` function.
- This function is used internally by both clone() and fork(), so at
first glance this should catch both code paths. On top of this, the
task_struct is made available as the second parameter, so getting the
pid/tgid should be straightforward, right? This turned out not to be
the case.
the function prototype:
int sched_fork(unsigned long clone_flags, struct task_struct *p)
For some reason, p->pid and p->tgid were zero every time. I thought
perhaps sched_fork will set these values internally, but attaching
a kretprobe proved this to be false as well. I think this might be a
PEBKAC type situation, so if you know something I could be doing
wrong, please let me know.
Attempt #4: Attach a tracepoint to sched:sched_process_fork.
- This worked! I couldn't find many examples on how to properly
interact with tracepoints so I had to turn to the kernel headers that
came with my system.
1. Prototype with bpftrace:
sudo bpftrace -e \
'tracepoint:sched:sched_process_fork { printf("%s %ld\n", args->child_comm, args->child_pid) }'
2. skim /usr/src/linux-headers-<kernel-version>/include/trace/events/sched.h
1. cat /sys/kernel/debug/tracing/events/sched/sched_process_fork/format
2. turn this into a struct
3. ???
4. profit! (it's passed as the first arg to the tracepoint handler)
I don't really trust this method since anything requiring me to write
a struct out manually is probably not going to be super portable. I
also haven't used tracepoints much ever, so I don't really know what I'm
doing.
Sample code below...
*/
struct sched_process_fork {
unsigned short common_type;
unsigned char common_flags;
unsigned char common_preempt_count;
int common_pid;
char parent_comm[16];
u32 parent_pid;
char child_comm[16];
u32 child_pid;
};
int sched_process_fork(struct sched_process_fork *ctx) {
bpf_trace_printk("pid = %ld\n", ctx->child_pid);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment