免责声明
本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者及本公众号不为此承担任何责任。
内核调度切换
-
保存当前执行任务的状态(寄存器、程序计数器、栈等)。 -
更新任务状态信息(内存管理信息、调度信息等)。 -
选择下一个要执行的任务。 -
加载新任务的上下文到处理器中。 -
开始执行新的任务。
BCC作为一个流行的ebpf开发方案,提供了很多案例供开发者学习,其中/examples/tracing/task_switch.c是BCC官方提供的过滤HTTP请求的案例。过滤HTTP请求对于入侵检测和免杀木马(后面会重点讲解)很有帮助,值得学习。
内核态代码
-
创建一个记录调度切换的哈希表,键为key_t记录了前一个进程pid和后一个进程pid,值为无符号整数;
struct key_t {
u32 prev_pid;
u32 curr_pid;
};
BPF_HASH(stats, struct key_t, u64, 1024);
2. 完成将由内核在调度事件发生时触发的核心函数count_sched,获取当前的pid和切换前的pid,记录在哈希表中:
int count_sched(struct pt_regs *ctx, struct task_struct *prev) {
struct key_t key = {};
u64 zero = 0, *val;
key.curr_pid = bpf_get_current_pid_tgid();
key.prev_pid = prev->pid;
// could also use `stats.increment(key);`
val = stats.lookup_or_try_init(&key, &zero);
if (val) {
(*val)++;
}
return 0;
}
用户态代码
-
创建BPF对象,把我们的内核态代码附加到内核中调用切换有关的函数里:
b = BPF(src_file="task_switch.c")
b.attach_kprobe(event_re=r'^finish_task_switch$|^finish_task_switch.isra.d$',
fn_name="count_sched")
2. 在等待短暂时间后,打印等待期间的内核调用情况:
# generate many schedule events
for i in range(0, 100): sleep(0.01)
for k, v in b["stats"].items():
print("task_switch[%5d->%5d]=%u" % (k.prev_pid, k.curr_pid, v.value))
执行效果
原文始发于微信公众号(赛博安全狗):【eBPF】BCC跟踪内核调度切换
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论