繁体   English   中英

如何在 macOS 上启用 Arm 指针验证码 (PAC)?

[英]How to enable the Arm Pointer Authentication Code (PAC) on macOS?

如何在 macOS 上启用 Arm 指针验证码 (PAC)?

我有一台配备 Apple M1 芯片的 MacBook Air。 CPU 实现 Arm 架构版本 v8.5-A,其中包括指针验证码 (PAC) 指令。 此功能通常用于防止通过 ROP 链注入恶意代码,通常利用堆栈上的缓冲区溢出。

我尝试通过简单的代码来演示一些 PAC 指令的行为。

在原生 macOS 上,身份验证指令(PACIA、PACDA 等)似乎没有效果,就好像该功能没有在 CPU 中实现一样。 这是可能的,因为大多数 Arm 功能都是可选的。 但是,在同一台 MacBook 上安装 Linux 虚拟机后,相同的 PAC 指令在 Linux VM 内部运行。 在同一个物理 CPU 上,因此支持 PAC 功能。

因此,必须有一些方法可以基于进程禁用 PAC 的行为:在本机 macOS 应用程序中不活动,在 Linux VM 中运行的应用程序中活动。

您将如何在 macOS 上启用 PAC?

下面的示例代码pacia.c

  1. 显示指令地址,
  2. 使用 PACIA 指令添加 PAC 并显示它
  3. 使用 AUTIA 指令“验证”它(如果 PAC 正确则恢复其原始值)并显示它。

我们预计第二个地址的 MSB 部分会被 PAC 更改。 我们希望第三个地址与第一个地址相同。

#include <stdio.h>
#include <inttypes.h>

// noinline for easier inspection of generated code in main
__attribute__((noinline)) void report(uint64_t value)
{
    printf("%016" PRIX64 "\n", value);
}

int main(int argc, char* argv[])
{
    uint64_t data = (uint64_t)(&&lab);
    uint64_t modifier = 2;
 lab:
    report(data);
    asm("pacia %[reg], %[mod]" : [reg] "+r" (data) : [mod] "r" (modifier) : );
    report(data);
    asm("autia %[reg], %[mod]" : [reg] "+r" (data) : [mod] "r" (modifier) : );
    report( data);
}

汇编:

cc -O2 -march=armv8.5-a pacia.c -o pacia

在主机系统 macOS 13.1 上,PACIA 指令不会修改地址以进行身份验证。

$ ./pacia 
00000001028B3F50
00000001028B3F50  <-- not modified, no PAC
00000001028B3F50
$ ./pacia 
000000010080FF50
000000010080FF50
000000010080FF50
$ ./pacia 
0000000102A7FF50
0000000102A7FF50
0000000102A7FF50
$ 

在 Ubuntu 22.10 虚拟机上,地址的 MSB 部分由 PACIA 使用 PAC 更新,并由 AUTIA 正确删除。

$ ./pacia
0000AAAACF3D0680
0043AAAACF3D0680  <-- 0043 PAC added
0000AAAACF3D0680  <-- PAC removed, address restored
$ ./pacia
0000AAAAD7CF0680
0023AAAAD7CF0680
0000AAAAD7CF0680
$ ./pacia
0000AAAAAAE00680
0036AAAAAAE00680
0000AAAAAAE00680

为了确定,我在 macOS 上检查了生成的代码。 实际使用的是 PACIA 指令。

cc -O2 -march=armv8.5-a pacia.c -S -o pacia.s

在 clang 14.0.0 的 macOS 上生成的main()代码:

_main:                                  ; @main
        .cfi_startproc
; %bb.0:
Ltmp0:                                  ; Block address taken
; %bb.1:
        stp     x20, x19, [sp, #-32]!           ; 16-byte Folded Spill
        stp     x29, x30, [sp, #16]             ; 16-byte Folded Spill
        add     x29, sp, #16
        .cfi_def_cfa w29, 16
        .cfi_offset w30, -8
        .cfi_offset w29, -16
        .cfi_offset w19, -24
        .cfi_offset w20, -32
Lloh2:
        adrp    x19, lCPI1_0@PAGE
Lloh3:
        ldr     x19, [x19, lCPI1_0@PAGEOFF]  <--- data = (uint64_t)(&&lab) in x19
        mov     x0, x19       <--- x19 is printed (first time)
        bl      _report
        mov     w20, #2       <--- modifier = 2 in x20
        ; InlineAsm Start
        pacia   x19, x20      <--- x19 should receive a PAC code
        ; InlineAsm End
        mov     x0, x19       <--- x19 is printed (second time)
        bl      _report
        ; InlineAsm Start
        autia   x19, x20
        ; InlineAsm End
        mov     x0, x19
        bl      _report
        mov     w0, #0
        ldp     x29, x30, [sp, #16]             ; 16-byte Folded Reload
        ldp     x20, x19, [sp], #32             ; 16-byte Folded Reload
        ret

在@fuz 的建议下,除了-march=armv8.5-a之外,我还添加了-arch arm64e arm64e 。 这将二进制文件标记为arch64e而不是arm64 ,例如file所示:

$ file pacia
pacia: Mach-O 64-bit executable arm64e

尝试运行它失败并显示Killed: 9 谷歌搜索一下,我发现您需要使用启动标志-arm64e_preview_abi在系统范围内启用arm64e架构:

sudo nvram boot-args=-arm64e_preview_abi

但是,您只能在禁用系统完整性后才能这样做。 因此,我在恢复模式下重新启动, csrutil disable ,在正常模式下重新启动,设置引导标志,在恢复模式下重新启动,在正常模式下重新启动csrutil enable 运气不好,仍然Killed: 9 使用nvram -p检查启动标志,选项-arm64e_preview_abi在那里。

事实上,您似乎需要保持禁用系统完整性才能运行arm64e二进制文件。 这很遗憾,因为 PAC 指令应该可以提高应用程序的安全性,但您需要禁用系统完整性(并因此降低系统安全性)才能运行更安全的应用程序。 诡异的...

无论如何,在几次重新启动并永久禁用系统完整性后,应用程序运行了。

但是,它最初会产生奇怪的结果:

$ ./pacia
5F3A800100787F3C
0000000100787F3C
2000000100787F3C
$ ./pacia
B273800102563F3C
0080000102563F3C
BFFF800102563F3C
$ ./pacia
555C80010065FF3C
000000010065FF3C
200000010065FF3C
$

输入地址的 MSB 部分已经有额外信息。 PACIA 主要删除它(两种情况下为0000 ,一种情况下为0080 ),而 AUTIA 不会恢复以前的地址。

事实上,使用-arch arm64e也影响了代码生成。 采用&&lab中的真实代码地址生成隐式指针身份验证:

    add x16, x16, Ltmp0@PAGEOFF
    mov x17, #13503
    pacia   x16, x17. <-- added PACIA due to -arch arm64e
    mov x19, x16
    mov x0, x16
    bl  _report
    mov w20, #2
    ; InlineAsm Start
    pacia   x19, x20.  <-- my explicit PACIA
    ; InlineAsm End
    mov x0, x19
    bl  _report

所以,我明确的 PACIA 处理了一个已经有 PAC 的地址。 这破坏了以前的 PAC。

为了展示 PACIA 的确切行为,我只是使用 integer 值data = 0x12345678来控制我的显式 PACIA 的确切输入值。

这一次,它按预期工作:

0000000012345678
2503000012345678
0000000012345678

所以,我们现在知道如何在 macOS 上启用 PAC。 令人不安的一点是您需要永久禁用系统完整性。 适合某些开发人员测试,不适用于生产用途。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM