Skip to content

Incorrect code generation with -arch arm64e -mbranch-protection=standard or =pac-ret #60239

Closed as not planned
@lelegard

Description

@lelegard

Summary

On macOS, Arm64, the combination of options -arch arm64e -mbranch-protection=standard generates invalid code (redundant pointer authentication) leading to application crash on return.

Platform

Demonstrated on a Macbook with M1 chip, macOS 13.1, arm64e API enabled, Apple clang 14.0.0. This is the clang version coming with the latest "Command Line Tools for Xcode 14.2" from December 13, 2022.

$ sw_vers 
ProductName:            macOS
ProductVersion:         13.1
BuildVersion:           22C65
$ 
$ uname -a
Darwin mactest 22.2.0 Darwin Kernel Version 22.2.0: Fri Nov 11 02:04:44 PST 2022; root:xnu-8792.61.2~4/RELEASE_ARM64_T8103 arm64
$ 
$ nvram boot-args
boot-args       -arm64e_preview_abi
$ 
$ clang --version
Apple clang version 14.0.0 (clang-1400.0.29.202)
Target: arm64-apple-darwin22.2.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
$ 

Demonstration

This simple "hello world" code crashes with -arch arm64e -mbranch-protection=standard. It does not crash without -mbranch-protection or with -mbranch-protection=bti only.

$ cat hi.c
#include <stdio.h>
int main(int argc, char* argv[])
{
    printf("hi\n");
}
$
$ clang -O2 -march=armv8.5-a -arch arm64e hi.c -o hi
$ ./hi
hi
$ clang -O2 -march=armv8.5-a -arch arm64e hi.c -o hi -mbranch-protection=bti
$ ./hi
hi
$ clang -O2 -march=armv8.5-a -arch arm64e hi.c -o hi -mbranch-protection=standard
$ ./hi
hi
Segmentation fault: 11
$

Details

The combination -arch arm64e -mbranch-protection=standard is fatal. The same problem is seen with -mbranch-protection=pac-ret instead of standard (the latter includes the former).

  • -mbranch-protection=pac-ret or =standard authenticates the caller's return address using pacia x30, sp, updating x30 with a pointer authentication code.
  • -arch arm64e authenticates the caller's return address using pacibsp (same as pacib x30, sp). This second instruction trashes the PAC in x30, recomputing a PAC with key B.
  • The return sequence is autibsp and retaa. The autibsp removes the PAC from x30. When retaa authenticates x30, there is no longer any PAC, the authentication fails and the program crashes.

Solution: There must be only one authentication sequence. Using -mbranch-protection=pac-ret or =standard shall not add PACIA instructions when -arch arm64e is specified since pointer authentication is already used. Alternatively, an error message may report the incompatible options. But no invalid code should be generated.

Generated code below:

$ clang -O2 -march=armv8.5-a -arch arm64e hi.c -mbranch-protection=standard -S -o -
        .section        __TEXT,__text,regular,pure_instructions
        .build_version macos, 13, 0     sdk_version 13, 1
        .ptrauth_abi_version 0
        .globl  _main                           ; -- Begin function main
        .p2align        2
_main:                                  ; @main
        .cfi_startproc
; %bb.0:
        bti     c
        pacia   x30, sp     <------------ generated by -mbranch-protection=standard
        .cfi_negate_ra_state
        pacibsp             <------------ generated by -arch arm64e
        stp     x29, x30, [sp, #-16]!           ; 16-byte Folded Spill
        mov     x29, sp
        .cfi_def_cfa w29, 16
        .cfi_offset w30, -8
        .cfi_offset w29, -16
Lloh0:
        adrp    x0, l_str@PAGE
Lloh1:
        add     x0, x0, l_str@PAGEOFF
        bl      _puts
        mov     w0, #0
        ldp     x29, x30, [sp], #16             ; 16-byte Folded Reload
        autibsp             <------------ generated by -arch arm64e
        retaa               <------------ generated by -mbranch-protection=standard
        .loh AdrpAdd    Lloh0, Lloh1
        .cfi_endproc
                                        ; -- End function
        .section        __TEXT,__cstring,cstring_literals
l_str:                                  ; @str
        .asciz  "hi"

.subsections_via_symbols
$ 

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions