标题: randomize_va_space对SystemTap/cmdline_str()的影响 这类问题都是上下文强相关的,先说一下关键环境信息,CentOS 7.x。 $ uname -r 3.10.0-1160.11.1.el7.x86_64 $ stap -V Systemtap translator/driver (version 4.0/0.176, rpm 4.0-13.el7) 当时用如下命令监控对sshd_config的读写操作: stap -e 'probe kernel.function("vfs_read"),kernel.function("vfs_write") {filename=fullpath_struct_file(task_current(),$file);if(filename == @1) {printf("[%u][%s][%s]\n",pid(),cmdline_str(),probefunc())}}' /etc/ssh/sshd_config 然后在另一个bash中手工执行: grep PermitRootLogin /etc/ssh/sshd_config cmdline_str()可以取回命令行。然后将stap丢那里保持执行,意外发现有个进程读 取sshd_config,但cmdline_str()取不到命令行。 [16097][grep --color=auto PermitRootLogin /etc/ssh/sshd_config][vfs_read] [17108][ "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""][vfs_read] 16097是手工执行的grep,17108是另一个进程。"ps auwx | grep 17108"发现该进程 已经退出了。 -------------------------------------------------------------------------- # # stap -v filemonitor_1.stp /etc/ssh/sshd_config # grep PermitRootLogin /etc/ssh/sshd_config # # $ uname -r # 3.10.0-1160.11.1.el7.x86_64 # # # 返回指定pid的ppid,没有容错 # function ppid_ex:long ( pid:long ) { task = pid2task( pid ) ppid = task_pid( task_parent( task ) ) return ppid } probe kernel.function("vfs_read"), kernel.function("vfs_write") { filename = fullpath_struct_file( task_current(), $file ); if ( filename == @1 ) { p = pid() p1 = ppid() p2 = ppid_ex( p1 ) p3 = ppid_ex( p2 ) p4 = ppid_ex( p3 ) printf ( "[%u][%s][%u][%s][%u][%s][%u][%s][%u][%s][%s][%s]\n", p, pid2execname( p ), p1, pid2execname( p1 ), p2, pid2execname( p2 ), p3, pid2execname( p3 ), p4, pid2execname( p4 ), probefunc(), cmdline_str() ) } } -------------------------------------------------------------------------- 后来用filemonitor_1.stp发现有这么一种进程树关系: systemd(1) bash(18341) // 执行完会退出 some.sh(18354) // 执行完会退出 some.sh(18420) // 执行完会退出 grep(18430) // 执行完会退出 有个定时任务在执行some.sh,最终有条grep命令访问sshd_config。 SystemTap/cmdline_str()取不到前述grep(18430)的命令行。grep(16097)是在bash 中手工执行的,不存在该问题。 排查过程比较偶然,直接说结论,最后发现是randomize_va_space的锅。 cat /proc/sys/kernel/randomize_va_space sysctl -n kernel.randomize_va_space 此时为0,cmdline_str()受影响,取不到前述grep(18430)的命令行。 echo 2 > /proc/sys/kernel/randomize_va_space sysctl -w kernel.randomize_va_space=2 此时为2,cmdline_str()始终正常,可以取到前述grep(18430)的命令行。 如今一般环境中randomize_va_space缺省为2,但我这个环境中因故该值为0,意外发 现这个坑。难道ASLR会影响对task->mm->arg_start、task->mm->arg_end的访问?不 予深究。 开头就强调过,这类问题都是上下文强相关的。若没有碰上这种问题,无所谓,若碰 上了,不妨检查一下randomize_va_space。 顺便说一下为什么SystemTap没有提供API获取指定进程的cmdline。 参看 /usr/share/systemtap/tapset/linux/context.stp function cmdline_args:string(n:long, m:long, delim:string) function cmdline_arg:string(n:long) function cmdline_str:string() /usr/share/systemtap/tapset/linux/task.stp function pid2execname:string (pid:long) function task_execname:string (task:long) kernel_string(@task(task)->comm) 虽然可以指定task,但并未切换task,task->mm->arg_start、task->mm->arg_end这 两个指针无法用user_string()访问用户态内存。 pid2execname()从task->comm取字符串,这个变量在内核态,无需切换task。下面是 在crash中查看task->comm: crash> struct task_struct.comm -xo struct task_struct { [0x678] char comm[16]; } 如果欺骗ps,只改task->mm->arg_start处的argv[0]不行,还得改task->comm。 扯远了,就这样吧。