Which ARM64 processors support the PACIB instruction?

298 views Asked by At

I'm trying to do some tests with the PACIB instruction but it looks that my M1 processor does not support it (I'm trying on Windows 11 with Parallels)

I have an older Snapdragon PC (Samsumg Galaxy Book S) with Windows but it does not support it either.

Do you know any current processor that runs Windows 11 ARM64 that can execute that instruction and not just NOPing it?

From what I found the PACIB instruction is present on the ARMv8.3 instruction set. Not sure which processors uses that instruction set.

1

There are 1 answers

0
Siguza On

All ARMv8-compliant CPUs that implement ARMv8.3 or higher must support PAC (as in, FEAT_PAuth).

This includes the main application processors of all Apple Silicon Macs ever released to the public (even the Developer Transition Kit), as well as all of Apple's mobile chips since the A12.

However, operating systems can configure quite a few aspects of PAC at runtime. Of the five keys (IA, IB, DA, DB and GA), all but one (GA) can be disabled via bits in SCTLR_ELn, which turns some of the instructions that use them into NOPs (pacia, autia, ...) and others into "PAC-less" versions of themselves (ldraa -> ldr, retaa -> ret). In addition, it is possible for both EL3 and EL2 to trap the use of all instructions that would use the PAC keys, as well as direct accesses to the registers holding those keys.

On Apple operating systems for A12 and later, all the system libraries are built with PAC support, but it depends on a few factors whether PAC is fully enabled for a given process or not. Usually only binaries shipped with the OS get all keys enabled, while the rest only get the IB (and GA) key(s). (There are specific exceptions, but Apple's "arm64e" ABI is still not declared stable to this day, so any 3rd parties cannot rely on it as of yet.)

Now: I neither know what tests you ran, nor what their exact outcome was. If you ran an actual PACIB instruction on a CPU that doesn't support PAC, then that would cause an exception. If you can PACIBSP, however, then that would just be a NOP on older hardware. But of course it's also possible for an operating system to trap illegal instructions, check whether it was a PAC-related one, and manually step over it.

I know the Apple M1 supports PAC. From looking at XNU hypervisor support, it seems that the userland hypervisor software should be able to control whether PAC instructions and key registers get trapped or not (HCR_EL2 bits 40 and 41). I have no idea what Parallels does with this, nor do I know whether Windows supports PAC at all. And looking up what CPU your Galaxy Book S has, it seems that its architecture is ARMv8.2. While it is apparently allowed for implementors to cherry-pick features from one minor revision higher than the baseline they support, I have no idea whether this is the case for this Snapdragon CPU.

If you have the ability to run your own firmware on the chip, you can examine ID_AA64ISAR1_EL1 and see whether and what kind of PAC support is declared by the CPU. But if you just want to know whether the hardware supports PAC at all, then you can test this from EL0:

#include <stdbool.h>
#include <stdio.h>

#ifdef __USER_LABEL_PREFIX__
#   define INDIRECT(token) #token
#   define STRINGIFY(token) INDIRECT(token)
#   define ASM_PREFIX(sym) STRINGIFY(__USER_LABEL_PREFIX__) sym
#else
#   define ASM_PREFIX(sym) sym
#endif

extern bool is_pac_supported(void);

__asm__
(
    ".p2align 2\n"
    ".globl " ASM_PREFIX("is_pac_supported") "\n"
    ASM_PREFIX("is_pac_supported") ":\n"
    "    mov x8, x30\n"
    "    mov x0, 0x80000000000000\n"
    "    mov x30, x0\n"
    "    .4byte 0xd50320ff\n" // xpaclri
    "    cmp x30, x0\n"
    "    cset w0, ne\n"
    "    ret x8\n"
);

int main(void)
{
    printf("CPU supports PAC: %s\n", is_pac_supported() ? "yes" : "no");
    return 0;
}

This works by leveraging two interesting properties of XPACLRI: it is encoded in instruction space that was previously NOPs, so it's just a NOP on older hardware, and since it merely strips PAC bits from the target register (x30), it doesn't need access to the PAC keys, and thus neither gets disabled by the bits in SCTLR_ELn, nor trapped to EL2 or EL3.

PAC'ed pointers use bit 55 to determine whether they belong to the lower or upper half of the address space, so feeding the value 0x80000000000000 to a PAC stripping function will turn it into something like 0xffff800000000000 on hardware the supports PAC (and it will stay unchanged otherwise).

The instruction is encoded as a raw 4-byte constant because compilers will usually refuse to assemble xpaclri if not targeting ARMv8.3 or later.