服务热线:010-65014696

安全研究

椒图关注 FOCUS ON JOWTO

AIX Hardware Storage Keys 调试

[2015-1-19]

为了通杀所有 POWER AIX 系统,我的代码都是在最低平台和版本上进行编译的,如 POWER5 的 AIX 5300-00,为了向后兼容使用了解析内核镜像文件,动态获得函数及结构的方法,但这也带来了一些问题。比如 POWER6 后提供的 Hardware Storage Keys,在此平台编译使用没有任何问题,但拿到 POWER7 上则出现了崩溃现象,但将代码在 POWER7 上编译则没有任何问题,我查了编译选项没有使用任何优化参数,最终当我定位问题后不得不再次感叹,对这种硬件,OS,编译器都是自己的大型封闭系统真是没的治。


KDB(0)> dis @r0 – 4 10


.aix_kernel_get_diskdev+0002C4 bl <.new_hkeyset> –>调用new_hkeyset崩掉的,这是我写的包装函数。


.aix_kernel_get_diskdev+0002C8 ori r0,r0,0


.aix_kernel_get_diskdev+0002CC ld r3,90(stkp)


.aix_kernel_get_diskdev+0002D0 bl <.kputpath>


.aix_kernel_get_diskdev+0002D4 lwa r3,A8(stkp)


.aix_kernel_get_diskdev+0002D8 cmpwi cr0,r3,0


.aix_kernel_get_diskdev+0002DC beq cr0.eq,<.aix_kernel_get_diskdev+0002EC>


.aix_kernel_get_diskdev+0002E0 ld r3,108(stkp)


.aix_kernel_get_diskdev+0002E4 std r3,B8(stkp)


.aix_kernel_get_diskdev+0002E8 b <.aix_kernel_get_diskdev+0002F4>


KDB(0)> dis new_hkeyset 13


.new_hkeyset+000000 mflr r0


.new_hkeyset+000004 stdu stkp,FFFFFF90(stkp)


.new_hkeyset+000008 std r0,80(stkp) –>保存调用函数返回地址


.new_hkeyset+00000C std r3,A0(stkp) –>保存 hkeyset_t 映射值,即 amr 寄存器


.new_hkeyset+000010 ld r3,A0(stkp)


.new_hkeyset+000014 li r4,FFFFFFFF –>这里的 r4 寄存器为 HKEYSET_INVALID 无效值


.new_hkeyset+000018 cmpld cr0,r3,r4 r4=FFFFFFFFFFFFFFFF –>比较 hkeyset_t 有效性


.new_hkeyset+00001C beq cr0.eq,<.new_hkeyset+000024>


.new_hkeyset+000020 bla <.hkeyset_replace> –>如果有效应该调用这里替换 hkeyset_t 的值


.new_hkeyset+000024 ld r0,80(stkp) –>无效才会跳转到这里


.new_hkeyset+000028 mtlr r0


.new_hkeyset+00002C addi stkp,stkp,70


.new_hkeyset+000030 blr


KDB(0)> dr iar


iar : F1000000C06A9A6C


.new_hkeyset+000024 ld r0,80(stkp) r0=F1000000C06B6E0C –>iar 与 lr 的值一样,说明 hkeyset_t 值


有效是在调用系统提供的 hkeyset_replace 时崩掉的


,80(stkp)=F00000002FF47350


KDB(0)> dr lr


lr : F1000000C06A9A6C


.new_hkeyset+000024 ld r0,80(stkp) r0=F1000000C06B6E0C


,80(stkp)=F00000002FF47350


到现在为止自己写的代码没看出问题,为了跟踪并比较 hkeyset_replace() 完整流程,我找了台最新的 POWER7 AIX 7100-02 系统,并把断点下在了 hkeyset_replace+00000C


通过 intpri 寄存器与 prev 可以看到当前为“中断上下文”


KDB(2)> mst


Machine State Save Area


iar : 0000000000014C54 msr : 8000000000029032 cr : 88088287


lr : 0000000004152D64 ctr : 0000000004152D00 xer : 20000001


mq : 00000000 asr : FFFFFFFFFFFFFFFF amr : F3FC000000000000


r0 : 00000000001758A0 r1 : F10004158007F9D0 r2 : 000000000415D160


r3 : F30F000000000000 r4 : F10006C001438100 r5 : 0000000000001000


r6 : F10006C0013E08C0 r7 : 0000000080000000 r8 : 0000000010000000


r9 : 0000000010000000 r10 : 00000C62F0269E5E r11 : 000000000415D058


r12 : F3FC000000000000 r13 : F100060010095400 r14 : F100041580083D00


r15 : 0000000002088A80 r16 : F10004158007FD00 r17 : 000000000000000A


r18 : 000000000000000B r19 : 0000000000000003 r20 : 0000000002C26A88


r21 : 0000000810200000 r22 : 0000000000008000 r23 : 00000000007C6438


r24 : 0000000000000000 r25 : F10006C001420580 r26 : 0000000000000000


r27 : 0000000000000001 r28 : FFFFFFFFFFFFFFFF r29 : 0000000000000000


r30 : 0000000000000000 r31 : F100010014C70000


prev F100041580083D00 stackfix 0000000000000000 int_ticks 0000


cfar 0000000000000005


kjmpbuf 0000000000000000 excbranch 0000000000000000 no_pfault 00


intpri 03 backt 00 flags 00


hw_fru_id 02C41F70 hw_cpu_id 00000000


(2)> more (^C to quit) ?


反汇编调试 hkeyset_replace 存储键函数


KDB(2)> dis @iar – 10 8


.hkeyset_replace+000000 mfaccr r12 ->此条指令将 amr 寄存器值装入 r12 寄存器,即当前“存储键”


.hkeyset_replace+000004 cmpd cr0,r3,r12 ->与 r3 寄存器新的“存储键”值比较


.hkeyset_replace+000008 beqlr cr0.eq ->相等则直接返回调用者(lr 寄存器保存调用者地址)


.hkeyset_replace+00000C isync ->刷新“指令cache”


.hkeyset_replace+000010 mtaccr r3 ->不相等,则使用此条指令确保新的“存储键”装入 r3 寄存器


.hkeyset_replace+000014 isync ->两次刷新“指令cache”以达到“同步”目的


.hkeyset_replace+000018 mr r3,r12 ->替换新的“存储键” r3->r12 = amr


KDB(2)> s


.hkeyset_replace+000010 mtaccr r3 <F30F000000000000>


KDB(2)> dr r3


r3 : F30F000000000000 F30F000000000000 ->r3 = 新的“存储键”


KDB(2)> dr r12


r12 : F3FC000000000000 F3FC000000000000 ->r12 = 当前 “存储键”


KDB(2)> dr amr ->显示 amr 寄存器中的“内核存储键”与“硬件存储键”映射关系


amr : F3FC000000000000


hkey 2 RW PUBLIC


hkey 7 RW PROC INTR VMM LFS CRED LDR KER


KDB(2)> s


.hkeyset_replace+000014 isync


KDB(2)> s


.hkeyset_replace+000018 mr r3,r12 <F3FC000000000000> r3=


F30F000000000000,r12=F3FC000000000000


KDB(2)> s


.hkeyset_replace+00001C blr <04152D64> r3=F3FC0000


00000000


KDB(2)> dr amr ->替换后可以看到新“存储键” 值的范围


amr : F30F000000000000


hkey 2 RW PUBLIC


hkey 4 RW COMMO NETM IPSEC USB GRAPHICS


hkey 5 RW DMA PCI VDEV TRB IOMAP PRIVATE1 PRIVATE17 PRIVATE9 PRIVATE25 …


通过与上面正常流程比较,发现在 hkeyset_replace() 中对 hkeyset_t 设置时插入了一条用于符号扩展的汇编指令,从而影响了 r3 寄存器的值,导致访问违规。问题定位后调整了代码,改用指针传递,算是解决了 POWER6 与 POWER7 兼容问题。


作者:椒图实验室

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