服务热线:010-65014696

安全研究

椒图关注 FOCUS ON JOWTO

AIX 系统调用拦截函数 kmod_util() 的实现原理与BUG

[2015-1-19]

环境:

bash-3.2# oslevel -r

6100-06


使用 kdb 调试器分析


bash-3.2# kdb

START              END <name>

0000000000001000 00000000040F0000 start+000FD8

F00000002FF47600 F00000002FFDF9C0 __ublock+000000

000000002FF22FF4 000000002FF22FF8 environ+000000

000000002FF22FF8 000000002FF22FFC errno+000000

F1000F0A00000000 F1000F0A10000000 pvproc+000000

F1000F0A10000000 F1000F0A18000000 pvthread+000000

read vscsi_scsi_ptrs OK, ptr = 0x0

(0)> !ps -ef |grep kctrl

root 7798858 6226150   0 11:00:25  pts/1  0:00 grep kctrl

root 8257756 6750308   0 10:59:37  pts/0  0:00 ./kctrl sc_intercept64


显示kctrl进程环境,找到threadlist地址


(0)> ppid -d 8257756

SLOT NAME     STATE      PID    PPID          ADSPACE  CL #THS


pvproc+01F800  126 kctrl    ACTIVE 07E00DC 0670064 0000000838DEE480   0 0001


NAME……. kctrl

STATE…… stat  :07  …. xstat :0000

FLAGS…… flag  :00200001 LOAD EXECED

……….. flag2 :00000000

……….. flag3 :00000000

……….. atomic :00000000

……….. secflag:0001 ROOT

LINKS…… child      :0000000000000000

……….. siblings   :0000000000000000

……….. uidinfo    :00000000022A2D68

……….. ganchor    :F1000F0A0001F800 <pvproc+01F800>

THREAD….. threadlist :F1000F0A10007300 <pvthread+007300>

DISPATCH… synch      :FFFFFFFFFFFFFFFF

AACCT…… projid      :00000000  ……….. sprojid     :00000000

……….. subproj     :0000000000000000

……….. file id     :0000000000000000 0000000000000000 00000000

……….. kcid       :00000000

……….. flags       :0000

WLM…….. class/wlm  :00/0000

……….. time of SIGTERM:00000000

……….. wlm_nvpages      :0000000000000000  0

……….. totalcputime     :0000000000132600

……….. totalscputime    :00000000000F53E0

……….. totaldiskio      :0000000000000000

IDENTIFIER. uid        :00000000  ……….. suid       :00000000

……….. pid        :007E00DC  ……….. ppid       :00670064

……….. sid        :0047009C  ……….. pgrp       :007E00DC

MISC…… lock       @ F1000F0A0001F8F0 0000000000000000

………. lock_d     @ F1000F0A0001F9A8 0000000000000000

….. parent_lock     @ F1000F0A0001F9A0 0000000000000000

….. session_lock    @ F1000F0A0001F998 0000000000000000

……….. pgrpl      :0000000000000000

……….. pgrpb      :0000000000000000

……….. ttyl       :F1000F0A00019C00 <pvproc+019C00>

……….. ipc        :0000000000000000  … sigs_queued:0

……….. dblist     :0000000000000000  … dbnext     :0000000000000000

……….. eyec       :7076707250524F43  (pvprPROC)

STATISTICS. nframes    :0000000000000009  … npsblks    :0000000000000000

(0)> more (^C to quit) ? Interrupted


显示线程信息,得到其slot


(0)> th F1000F0A10007300

SLOT NAME     STATE    TID PRI   RQ CPUID  CL  WCHAN


pvthread+007300  115 kctrl    SLEEP 73000B 03C    2         0  F1000E0000050878


NAME……………. kctrl

WTYPE…………… WEVENT

……………..tid :000000000073000B  ……tsleep :FFFFFFFFFFFFFFFF

……………flags :00000000  …………..flags2 :00000000

………..pmcontext :00000000

DATA………pvprocp :F1000F0A0001F800 <pvproc+01F800>

LINKS…..prevthread :F1000F0A10007300 <pvthread+007300>

……….nextthread :F1000F0A10007300 <pvthread+007300>

DISPATCH…….synch :FFFFFFFFFFFFFFFF

SCHEDULER…affinity :00000002  ……………..pri :0000003C

………….boosted :00000000  ……………wchan :F1000E0000050878

……………state :00000003  ……………wtype :00000001

MISC       ..tv_eyec :7076746850524F43 (pvthPROC)

CHECKPOINT……vtid :00000000  ………….chkfile :0000000000000000

LOCK…….. lock_d @ F1000F0A10007330 0000000000000000

PROCFS……procfsvn :0000000000000000

NUMA…………rset :0000000000000000

PROFILING…..prbase :0000000000000000  ….prpinned :0000000000000000

………….prflags :00000000  …………prbufcount :00000000

WLM……..class/wlm :00/0000

………….wlm_tag :

THREAD…….threadp :F1000A1801031800  ……..size :00000100


FLAGS…………… WAKEONSIG WAKEONCHKPT

……………..tid :000000000073000B  ……stackp :000000002FF228C0

……………..scp :0000000000000000  …….ulock :0000000000000000

……………uchan :0000000000000000  ….userdata :0000000000000000

………………cv :0000000000000000  …….flags :0000000000010400

…………..atomic :0000000000000000  ……flags2 :0000000000040000

DATA………..procp :F1000A180103DC00 <F1000A180103DC00>

………..pvthreadp :F1000F0A10007300 <pvthread+007300>

……………userp :F00000002FF48000 <__ublock+000A00>

…………uthreadp :F00000002FF47600 <__ublock+000000>

SLEEP/LOCK……usid :0000000000000000  ……wchan1 :0000000000000000

…………..wchan2 :0000000000000000  ……swchan :0000000000000000

………..eventlist :F1000A1801031800  ……result :00000000

………….polevel :00000000  …………..pevent :0000000000000000

…………..wevent :0000000000000000  …….slist :0000000000000000

………..wchan1sid :0000000000000000  wchan1offset :00000000

………..lockcount :00000000  ……….adsp_flags :0000

DISPATCH…….ticks :00000000  ……………prior :0000000000000000

…………….next :0000000000000000  ……dispct :0000000000000003

(0)> more (^C to quit) ? Interrupted


切换到kctrl上下文中


(0)> switch 115

Switch to  thread: <pvthread+007300>


从U area偏移中得到svc table地址,从下面显示信息可以看到索引7的地址(即execve地址)

并无变化,也就说明kmod_util()并没有修改该svc table中的地址


(0)> dd @(__ublock+1898) 10

04EDE000: 0000000002BC0450 0000000002BC0300  …….P……..

04EDE010: 0000000002BC0460 0000000002BC0C08  …….`……..

04EDE020: 0000000002BC3D70 0000000002BC3D80  ……=p……=.

04EDE030: 0000000002BC3D90 0000000002BC3DA0  ……=…….=.

04EDE040: 0000000002BC3DB0 0000000002BC3DC0  ……=…….=.

04EDE050: 0000000002BC3DD0 0000000002BC4788  ……=…….G.

04EDE060: 0000000002BC47A0 0000000002BC47B8  ……G…….G.

04EDE070: 0000000002BC47D0 0000000002BC47E8  ……G…….G.


查看execve的索引地址发现,其symbol address已被更改


(0)> dd 0000000002BC3DA0

execve+000000: F1000000B0000000 0000000002BE5450  …………..TP   –>紧跟后面的是TOC地址


反汇编验证,原execve实现已被修改


(0)> dis F1000000B0000000 6

F1000000B0000000         li    r0,FFFF8000

F1000000B0000004         ld    toc,5000(0)         5000=ktoc

F1000000B0000008        std    r0,20(stkp)         r0=FFFFFFFFFFFF8000

F1000000B000000C         ba    <.ld_intercept_sc>

F1000000B0000010         li    r0,FFFF8000

F1000000B0000014         ba    <intercept2>


下面是使用了KU_INTERCEPT_CANCEL标志后的情况,可以看到symbol address没有被恢复(这样实现是有其好处的)


(0)> dd 0000000002BC3DA0

execve+000000: F1000000B000006C 0000000002BE5450  …….l……TP


只是把原有拦截代码修改该成了直接跳转到execve的function address


(0)> dis F1000000B000006C 6

F1000000B000006C         ba    <.execve>

F1000000B0000070 illegal op

F1000000B0000074 illegal op

F1000000B0000078 illegal op

F1000000B000007C illegal op

F1000000B0000080 illegal op


(0)>


至此kmod_util()这个kernel api的拦截原理已清晰,准确的说法应该是拦截了symbol address,因其svc_instr的调用流程最终会走到这里,所以会间接影响到syscall的流程。但这种拦截方式针对某些syscall是有BUG的,比如这里的execve,在执行脚本时如此脚本没指定解释器,则会“卡死”在那里,如下面这个脚本

bash-3.2# cat test.sh

echo “hello!”

这在用户环境中是不可容忍的,我们原来尝试过此类拦截方式,但最终放弃了。看来IBM对自身系统的了解也还有待加强啊 ;)


作者:椒图实验室


转载请注明出处:http://blog.jowto.com