randomize_va_space对SystemTap/cmdline_str()的影响

  • A+
所属分类:逆向工程

randomize_va_space对SystemTap/cmdline_str()的影响

标题: randomize_va_space对SystemTap/cmdline_str()的影响

http://scz.617.cn:8/unix/202103111654.txt

这类问题都是上下文强相关的,先说一下关键环境信息,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。

扯远了,就这样吧。

本文始发于微信公众号(青衣十三楼飞花堂):randomize_va_space对SystemTap/cmdline_str()的影响

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: