背景
最近有个小伙伴求助笔者,在系统启动完成进入bash,也就是systemd的某个服务或者某个定制进程改变了路由,他想要在系统完成启动的期间捕获这个行为。
1.思路
设置路由的内核接口为ipv6_route_ioctl ,跟踪内核调用可以使用bcc或者bpftrace来完成,在systemd启动服务的期间无非就是加个早点儿启动的service呗,但是无奈的是这个系统里面没有引入bcc的源,并且客户还不允许加脚本之类的进服务器,那办法就比较局限了,使用ftrace抓取调用ipv6_route_ioctl的进程,如果是route命令之类的,再获取一下在这之前执行sys_execve的进程就可以了。
2. 查找cmdline启动项
如果默认开启ftrace捕获启动期间事件,肯定需要某个cmdline传入参数进行支持,在不知道具体实现及哪个cmdline的情况下,有两个办法:
1.找到ftrace.c($KERN_ROOT/trace/ftrace.c),查找__setup宏;
2.查找内核启动参数文档,$KERN_ROOT/Documentation/admin-guide/kernel-parameters.txt;
这两个方式适合我们对某个子系统不熟悉的时候作为查找启动项入口,通过搜索找到了我们想要的启动项:
ftrace及ftrace_filter,与在/sys/kernel/debug/tracing下面使用一致,ftrace指定要使用的tracer,此处我们使用function就行,ftrace_filter为要设置的filter_functions列表,使用逗号隔开。
3.验证
修改grub.cfg,在启动参数添加ftrace=function ftrace_filter=__x64_sys_execve进行验证,重启系统,查看trace日志:
[root@localhost ~]# cat /sys/kernel/debug/tracing/trace
# tracer: function
#
# entries-in-buffer/entries-written: 19450/19450 #P:4
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
awk-1693 [000] .... 214.667040: __x64_sys_execve <-do_syscall_64
<...>-1695 [001] .... 214.667687: __x64_sys_execve <-do_syscall_64
<...>-1696 [003] .... 214.667762: __x64_sys_execve <-do_syscall_64
bash-1699 [003] .... 214.669529: __x64_sys_execve <-do_syscall_64
awk-1701 [002] .... 214.669613: __x64_sys_execve <-do_syscall_64
bash-1702 [003] .... 214.669701: __x64_sys_execve <-do_syscall_64
cat-1704 [002] .... 214.671459: __x64_sys_execve <-do_syscall_64
awk-1705 [001] .... 214.671561: __x64_sys_execve <-do_syscall_64
bash-1709 [001] .... 214.673221: __x64_sys_execve <-do_syscall_64
cat-1710 [002] .... 214.673319: __x64_sys_execve <-do_syscall_64
awk-1711 [001] .... 214.673407: __x64_sys_execve <-do_syscall_64
df-1714 [002] .... 214.675070: __x64_sys_execve <-do_syscall_64
总结
ftrace功能强大,虽然使用起来不怎么方便,但是许多生产环境还是比较实用的,除了本文用到的function外,启动时也支持设置function_graph,后面有空再实践试试。