美文网首页
arm64e符号翻译与PAC问题

arm64e符号翻译与PAC问题

作者: Colla | 来源:发表于2019-07-29 21:11 被阅读0次

    arm64e由于引入了PAC机制,导致符号地址发生了巨大变化。也给堆栈回溯带来了问题。

    背景

    从去年新iphone发布后,我们陆陆续续发现crash上报组件上报的crash总很奇怪,堆栈里要么只有栈帧0,要么就只有几个栈帧,而丢失了绝大部分的栈,起初我们没有在意,只是怀疑crash上报组件又引入了什么奇怪的bug,但因为量比较低,并不影响我们解决主要的crash问题(毕竟XS/XR设备还不是主流)。但是后来又遇到了一次QAPM上报的内存监控堆栈,发现也很奇怪堆栈还是丢失了很多,只有栈帧0或者main函数等信息,其它都只是符号地址,如下:

    Thread 1 :
    1 libsystem_kernel.dylib 0x1ab941000 0x1ab959c60
    2 libsystem_kernel.dylib 0x1ab941000 0x1ab9590e8
    3 unkonwn 0x57fe81ab7f7154
    4 unkonwn 0x7dc001ab7f75f0
    5 unkonwn 0x668381aba151f4
    6 unkonwn 0x797701ac975b68
    7 unkonwn 0x656881ac748400
    8 unkonwn 0x56b181ac756554
    9 unkonwn 0x26eb01ac97b9a8
    10 unkonwn 0x73d081ac86a820
    11 unkonwn 0x1c4d01ab7e1884
    12 unkonwn 0xfc01ab7ee404
    13 unkonwn 0x49f081ac7db250
    14 unkonwn 0xce101ac84915c
    15 unkonwn 0x7edd01abd40acc
    16 unkonwn 0x2cad81abd40a8c
    17 unkonwn 0x53ff01abd3ff30
    18 unkonwn 0x661501abd3fbbc
    19 unkonwn 0x5aeb81abcb6768
    20 unkonwn 0x404001abd3f664
    21 unkonwn 0x2ffd81ac73a7c4
    22 unkonwn 0x476581d9099cd8
    23 unkonwn 0x509081d89383c8
    24 unkonwn 0x659f81d8938e5c
    25 unkonwn 0x26c181d8937eb8
    26 unkonwn 0x1ab581d893cea8
    27 unkonwn 0x56c481d8c83904
    28 unkonwn 0x563b81ae794c58
    29 unkonwn 0x4dd581ab7e1884
    30 unkonwn 0x4e4901ab7e4e5c
    31 unkonwn 0x697381ae7d118c
    32 unkonwn 0x1ca181ae7d0e08
    33 unkonwn 0x204381ae7d1404
    34 unkonwn 0x42a001abd62444
    35 unkonwn 0x7ca881abd623c0
    36 unkonwn 0x7e8c81abd61c7c
    37 unkonwn 0x626881abd5c950
    38 unkonwn 0x199c01abd5c254
    39 unkonwn 0x209801adf9bd8c
    40 unkonwn 0x458381d90a44c0
    41 unkonwn 0x62f78102b5047c
    42 libdyld.dylib 0x1ab818000 0x1ab818fd8
    

    地址明显有问题,而导致翻译失败。

    PAC

    偶然间看到内网有人解决了最近某个版本的一个top 2的crash,提到了一个堆栈回溯失败的问题和原因,豁然开朗。
    果然是PAC问题,虽然新iphone刚发布时就知道有PAC的特性,但我们一直没重视。而且本身我们的crash问题堆栈的量又特别特别少,导致我们也没认真对待。
    正好结合最近和以前遇到的问题,发现问题系统设备都是arm64e设备和12系统,才意识到我们的堆栈回溯失败的根因也都是PAC问题,索性就再研究下了PAC。

    什么是PAC

    PAC即Pointer Authentication,它的目的即检测和保护地址不被意外或恶意修改,使得应用执行更加安全。
    比如如果当前pc指向了PAC后的值0x00691e8104c560d4,而我们应用强制将其改为其他地址,则会导致内存访问错误或PAC校验失败而crash。
    PAC特性是由硬件提供的,保护了函数调用期间,栈空间和地址的安全。
    它利用VA的高位来实现,当执行该VA时,会有专门的指令解码VA并读取指令。任何导致该VA在读与写之间不一致的行为,都会触发PAC校验失败。PAC校验失败会触发内存崩溃而crash;

    PAC的结构如下:

    image.png

    在iphone上,由于VA值的上限只用到36bits,所以会利用VA的高28位来作为PAC存储使用。

    备注:xnu规定的iOS的VA最大值为#define MACH_VM_MAX_ADDRESS 0x0000000FC0000000,即只需要36bits即可。

    处理PAC

    根据Apple的文档Preparing Your App to Work with Pointer Authentication ,处理PAC的地址问题我们直接使用ptrauth_strip宏(#include <ptrauth.h>)即可,但该死的苹果限制了该宏仅在arm64e下才生效,所以此路不通。

    但很庆幸,PAC的本质是在arm64e上它把VA无用的高28bits拿来用作PAC了,所以我们只要取低36bits即为实际的VA了。

    备注:准确点是arm64e中PAC只用到了第62bit到36bit共27bits,最高位第63bit在arm64中是tag pointer标记位.

    所以我们只要直接取低36bits就能愉快的玩耍了。

    va = va & 0x0fffffffff;//得到PAC strip后的原始VA值.
    

    结语

    果然任何小问题都不要因为量不多而不重视它,很可能每个小问题的背后都隐藏了一个未知的新问题。
    iOS正向开发果然越来越难了。

    参考

    Preparing Your App to Work with Pointer Authentication

    ARMv8.3 Pointer Authentication

    MACH_VM_MAX_ADDRESS

    iOS Address Space Limitations

    相关文章

      网友评论

          本文标题:arm64e符号翻译与PAC问题

          本文链接:https://www.haomeiwen.com/subject/ainirctx.html