bur*_*ino 28 linux shell ftrace echo linux-kernel
我最近一直在玩ftrace来监控我系统的某些行为特征.我一直在处理通过一个小脚本打开/关闭跟踪.运行脚本后,我的系统会崩溃并自行重启.最初,我认为脚本本身可能存在错误,但我已经确定崩溃和重启是由于设置为function_graph echo时某些跟踪器到/ sys/kernel/debug/tracing/current_tracer的结果current_tracer.
也就是说,以下命令序列将产生崩溃/重启:
echo "function_graph" > /sys/kernel/debug/tracing/current_tracer
echo "function" > /sys/kernel/debug/tracing/current_tracer
Run Code Online (Sandbox Code Playgroud)
在上述echo语句导致崩溃后重启,我看到很多输出内容如下:
清除孤儿inode
<inode>
我试图通过将current_tracerfunction_graph中的值替换为C程序中的其他内容来重现此问题:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int openCurrentTracer()
{
int fd = open("/sys/kernel/debug/tracing/current_tracer", O_WRONLY);
if(fd < 0)
exit(1);
return fd;
}
int writeTracer(int fd, char* tracer)
{
if(write(fd, tracer, strlen(tracer)) != strlen(tracer)) {
printf("Failure writing %s\n", tracer);
return 0;
}
return 1;
}
int main(int argc, char* argv[])
{
int fd = openCurrentTracer();
char* blockTracer = "blk";
if(!writeTracer(fd, blockTracer))
return 1;
close(fd);
fd = openCurrentTracer();
char* graphTracer = "function_graph";
if(!writeTracer(fd, graphTracer))
return 1;
close(fd);
printf("Preparing to fail!\n");
fd = openCurrentTracer();
if(!writeTracer(fd, blockTracer))
return 1;
close(fd);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
奇怪的是,C程序不会崩溃我的系统.
我最初在使用Ubuntu(Unity环境)16.04 LTS时遇到了这个问题,并确认它是4.4.0和4.5.5内核的问题.我还在4.2.0和4.5.5内核上运行Ubuntu(Mate环境)15.10的机器上测试了这个问题,但无法重现该问题.这让我更加困惑.
任何人都可以让我了解正在发生的事情吗?具体来说,为什么我能够write()但不能echo到/ sys/kernel/debug/tracing/current_tracer?
更新
作为vielmetti指出,其他人也有类似的问题(如看到这里).
假设
ftrace_disable_ftrace_graph_caller()jmp指令在ftrace_graph_calljmp(e9)附近是5个字节,则修改jmp指令 .然而,它是一个短的jmp,只包含2个字节(eb).并且ftrace_stub()位于ftrace_graph_caller上面这样的修改之下,打破导致内核oops的指令ftrace_stub()与无效的操作码如下所示:
补丁(如下所示)解决了这个echo问题,但我仍然不明白为什么echo以前write()没有破坏.
diff --git a/arch/x86/kernel/mcount_64.S b/arch/x86/kernel/mcount_64.S
index ed48a9f465f8..e13a695c3084 100644
--- a/arch/x86/kernel/mcount_64.S
+++ b/arch/x86/kernel/mcount_64.S
@@ -182,7 +182,8 @@ GLOBAL(ftrace_graph_call)
jmp ftrace_stub
#endif
-GLOBAL(ftrace_stub)
+/* This is weak to keep gas from relaxing the jumps */
+WEAK(ftrace_stub)
retq
END(ftrace_caller)
Run Code Online (Sandbox Code Playgroud)
看来您不是唯一注意到此行为的人。我懂了
作为问题报告,以及
作为解决该问题的内核补丁。通读整个线程,问题似乎出在一些编译器优化上。