转载地址:http://blog.chinaunix.net/uid-24774106-id-3512909.html
前些日子,我的同事Qing发现,在我们服务器上PHP代码路径下多了一个log文件,从没注意到有这个log文件,但是log文件的格式明显不是我们生成的,格式比较简单,甚至没有function name,log level,明显是我们使用的某个第三方库的输出。到底是那个进程调用第三方库干的坏事 ? 我们当然是有怀疑对象的,从log的语义也可以初步判断是那个进程干的这件事。可是没有证据。
有的筒子就说了,对这个可疑进程直接执行lsof -p pid或者对文件执行 lsof file不就OK 了,如果这个进程打开了这个莫名其妙的文件,就证明的确是可疑进程写了这个log文件。可惜的是这个进程不是daemon,而且执行时间特别短,来不及对他进行lsof。这有到了我们systemtap横空出世的时候了。 systemtap由于他的可定制,几乎是一把无所不能的瑞士军刀。第一思路就是监控sys_open,看下到底是那个进程在作死,打开了这个莫名其妙的文件。
方法一 : 监控sys_open:
我们都知道systemtap可以监控系统调用,open作为一个系统调用,我们自然可以监控,如果open的文件恰好是我们要追踪的文件,我们就将pid ,execname 打印出来,真相大白。
- function is_open_creating:long(flag:long)
- {
- CREAT_FLAG = 4 // 0x4 = 00000100b
- if (flag& CREAT_FLAG)
- {
- return 1
- }
- return 0
- }
- probe begin
- {
- printf("monitor file beginn")
- }
- probe kernel.function("sys_open")
- {
- if(user_string($filename)=="/home/manu/shell/temp/abc.log")
- {
- creating = is_open_creating($mode);
- if(creating)
- {
- printf("pid %ld (%s) create the file %sn",pid(),execname(),user_string($filename));
- }
- else
- {
- printf("pid %ld (%s) open the file %s n",pid(),execname(),user_string($filename));
- }
- }
- }
- root@manu:~/code/systemtap#
- root@manu:~/code/systemtap# stap file_monitor.stp
- monitor file begin
- root@manu:~/code/shell/temp# echo abefdf>/home/manu/code/shell/temp/abc.log
- root@manu:~/code/shell/temp#
- root@manu:~/code/systemtap# stap file_monitor.stp
- monitor file begin
- pid 3024 (bash) create the file/home/manu/code/shell/temp/abc.log
比如我们再次想abc.log追加写:
- root@manu:~/code/shell/temp# echo"second line " >> abc.log
- root@manu:~/code/shell/temp# cat abc.log
- abefdf
- second line
- root@manu:~/code/shell/temp#
这种方法有缺陷,因为我们不能够假设进程输入的绝对路径还是相对路径。
方法二 :监控文件的inode
文件的名字表示方法可能不同,比如当前路径是 /home/manu/shell/temp/ ,下面表示的都是同一个文件,这就给上面一种方法带来的困难。
- abc.log
- ./abc.log
- ../temp/abc.log
- /home/manu/shell/temp/abc.log
- .....
我们的三元组是(0x08,0x06,2099351)
下面是我们的监控脚本inode_monitor.stp
- probe begin
- {
- printf("watch inode %d %d %ld beginn",$1,$2,$3)
- }
- probe vfs.write
- {
- if (dev== MKDEV($1,$2) # major/minor device
- && ino== $3)
- printf ("%s(%d) %s 0x%x/%un",execname(), pid(), probefunc(), dev, ino)
- }
- root@manu:~/code/systemtap# stap inode_monitor.stp 0x8 0x6 2099351
- watch inode 8 6 2099351 begin
- root@manu:~/code/shell/temp# echo abefdf>abc.log
- root@manu:~/code/shell/temp# echo"second line" >./abc.log
- root@manu:~/code/shell/temp# cat test.sh
- #!/bin/sh
- echo "third line " >> ./abc.log
- root@manu:~/code/shell/temp#./test.sh
- root@manu:~/code/systemtap# stap inode_monitor.stp 0x8 0x6 2099351
- watch inode 8 6 2099351 begin
- bash(3024) vfs_write 0x800006/2099351
- bash(3024) vfs_write 0x800006/2099351
- test.sh(9484) vfs_write 0x800006/2099351
对于文件系统的监控,还有一个更好的神器,fanotify,这个宝贝专业,专门对付文件系统的监控,而且功能强大。有兴趣的筒子可以看下 fanotify 监控文件系统 ,大牛刘明出品,讲的特别清楚,本来我想写一篇关于fanotify的博文,发现自己的功力还是不行,对这个主题理解不深,没有一个点能超越刘明前辈的博文,所以暂时告罢。
参考文献
1 SystemTap:Instrumenting the Linux Kernel for Analyzing Performance and Functional Problems
2 SystemTap Beginners Guide