Thanks for your celerity.

The architecture specifies that the number of bits used for the
signature depends on various properties of the CPU and of
the configuration that the host OS has put it into.
Yes, this is why I checked for the TCR value, because basically it only depends on its value and if BTI is enabled.

This sounds like a bug -- can you provide a repro case ?
Also, if you could confirm that this still happens on a
QEMU built from current git that would be helpful.

(We do have some test cases for pauth -- see tests/tcg/aarch64/pauth*.c --
but it looks like they only test against the aut* instructions, not
against retab.)
I checked using commit 64c01c7da449bcafc614b27ecf1325bb08031c84 and the RETAB was honored.

You can't change TCR from usermode, because it's a privileged
register. What you get is what QEMU sets it as, which in theory
should be the value that a real Linux kernel would set it to
for the kind of CPU that is being emulated. Looking at the code
I'm not sure if we're setting TCR the same way the kernel does:
to confirm that we'd need to look at the kernel source code and
cross-check what values it uses.
I do not have a clue about how the Linux kernel set the TCR, but I do not understand why we cannot change it
(for example with a command-line option), since we just emulate code ?
I guess it would be possible if I implement a new machine which derives from TYPE_VIRT_MACHINE
and I set custom page granule size and page size.


On 1/11/22 16:57, Peter Maydell wrote:
On Tue, 11 Jan 2022 at 15:28, zadig <za...@qbool.fr> wrote:
Hello,

I am running some dummy aarch64 ELF I have built using clang with
-mbranch-protection=pac-ret+leaf+b-key.

qemu successfully emulates the code, however the pointer authentication
signature seems weird to me: only one byte is used for the signature.
The architecture specifies that the number of bits used for the
signature depends on various properties of the CPU and of
the configuration that the host OS has put it into.

Here is an example:

FE 07 C1 DA PACIB X30, SP

Before the LR gets signed, its value is   0x00000000FEFDD99C.
After being signed by PACIB, its value is 0x00610000FEFDD99C.

If I disable BTI, the signature takes 2 bytes, which is "better".
However on real aarch64 system (like Apple M1 chips), the signature uses
the remaining bytes.
That probably indicates that that specific system happens to
configure the CPU differently. (For instance, I think the
M1 has a different implemented address space size.)
7 bits of signature would be expected for a CPU with TBI (top-byte-ignore)
enabled and a 48-bit virtual-address size.

In both cases (with or without BTI), the signature is not honored: if I
manually strip the signature or change it using gdb, the RETAB
instruction does not change the LR for generating a fault, which should
be the right behavior.
This sounds like a bug -- can you provide a repro case ?
Also, if you could confirm that this still happens on a
QEMU built from current git that would be helpful.

(We do have some test cases for pauth -- see tests/tcg/aarch64/pauth*.c --
but it looks like they only test against the aut* instructions, not
against retab.)

I have explored the qemu source code, and I guess the following code is
responsible for adding the signature to the pointer:

target/arm/pauth_helper.c:
----------------------------------------------------------------------
static uint64_t pauth_addpac(CPUARMState *env, uint64_t ptr, uint64_t
modifier, ARMPACKey *key, bool data) {
    ...
    top_bit = 64 - 8 * param.tbi;
    bot_bit = 64 - param.tsz;
    ext_ptr = deposit64(ptr, bot_bit, top_bit - bot_bit, ext);
----------------------------------------------------------------------

We notice how BTI reduces the size of the signature, and how tsz is
reducing it too.

So, my question is how can we manipulate TCR from qemu-user, in order to
change tsz, so we can store the signature on more bytes ?
You can't change TCR from usermode, because it's a privileged
register. What you get is what QEMU sets it as, which in theory
should be the value that a real Linux kernel would set it to
for the kind of CPU that is being emulated. Looking at the code
I'm not sure if we're setting TCR the same way the kernel does:
to confirm that we'd need to look at the kernel source code and
cross-check what values it uses.

thanks
-- PMM

Attachment: OpenPGP_signature
Description: OpenPGP digital signature

Reply via email to