-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tail calls don't work with AArch64 pointer authentication #6799
Comments
Ah, we missed the SP dependence here when thinking about this earlier: we had assumed that moving the return address would be safe. It looks like we'll need to decrypt and re-encrypt in the tail-call sequence; the |
I was poking at this a bit more and trying to see what LLVM does but I don't think LLVM handles this where it doesn't use a tail call with stack arguments and using I was also wondering if what you said would work, because wouldn't that have the problem that the stack pointer is temporarily decremented to not encompass the current frame? I'm not sure how that interacts with red zone/etc or whether it's ok for the stack pointer to be temporarily invalid. Alternatively though, looking at the various instructions, there may be a few other options too:
|
Ah, yeah, I was forgetting that on aarch64 the return address goes in That tells me that the |
The signatures-must-match thing is for the regular calling conventions. It has a bunch of other calling conventions designed to support tail calls (used by like ghc and such) that don't have this restriction. But also I wouldn't be surprised if those conventions just don't support pointer auth. |
I'm a bit surprised that we didn't catch this earlier, as I made sure to have our filetests enable pointer auth for the tail calls runtests, and everything passed so I assumed everything was Just Working. |
So does that mean that qemu isn't doing the pointer auth for our runtests that claim to enable pointer auth? Or do I have some other misunderstanding here? |
While possible I think the
That's probably because we don't have pointer authentication enabled in QEMU so AFAIK the only way to run into this is on macOS aarch64 hardware. I don't run the cranelift tests that often locally so I first ran into it recently after #6774. I believe at the time of the original writing QEMU didn't support pointer authentication (or something like that). If it does support it now, which it may, then we'll want to configure it to turn that on and it should get auto-detected with |
This commit fixes an issue where a `return_call` would not decrypt the return address when pointer authentication is enabled. The return address would be encrypted upon entry into the function but would never get restored later on. This addresses the issue by changing the encryption keys in use from the A/B key plus SP to instead using A/B plus the zero key. The reason for this is that during a normal function call before returning the SP value is guaranteed to be the same as it was upon entry. For tail calls though SP may be different due to differing numbers of stack arguments. This means that the modifier of SP can't be used for the tail convention. New `APIKey` definitions were added and that now additionally represents the A/B key plus the modifier. Non-`tail` calling conventions still use the same keys as before, it's just the `tail` convention that's different. Closes bytecodealliance#6799
I've posted using |
…6810) * aarch64: Fix `return_call`'s interaction with pointer authentication This commit fixes an issue where a `return_call` would not decrypt the return address when pointer authentication is enabled. The return address would be encrypted upon entry into the function but would never get restored later on. This addresses the issue by changing the encryption keys in use from the A/B key plus SP to instead using A/B plus the zero key. The reason for this is that during a normal function call before returning the SP value is guaranteed to be the same as it was upon entry. For tail calls though SP may be different due to differing numbers of stack arguments. This means that the modifier of SP can't be used for the tail convention. New `APIKey` definitions were added and that now additionally represents the A/B key plus the modifier. Non-`tail` calling conventions still use the same keys as before, it's just the `tail` convention that's different. Closes #6799 * Fix tests * Fix test expectations * Allow `sign_return_address` at all times in filetests
…ytecodealliance#6810) * aarch64: Fix `return_call`'s interaction with pointer authentication This commit fixes an issue where a `return_call` would not decrypt the return address when pointer authentication is enabled. The return address would be encrypted upon entry into the function but would never get restored later on. This addresses the issue by changing the encryption keys in use from the A/B key plus SP to instead using A/B plus the zero key. The reason for this is that during a normal function call before returning the SP value is guaranteed to be the same as it was upon entry. For tail calls though SP may be different due to differing numbers of stack arguments. This means that the modifier of SP can't be used for the tail convention. New `APIKey` definitions were added and that now additionally represents the A/B key plus the modifier. Non-`tail` calling conventions still use the same keys as before, it's just the `tail` convention that's different. Closes bytecodealliance#6799 * Fix tests * Fix test expectations * Allow `sign_return_address` at all times in filetests
Currently Wasmtime will enable pointer authentication bits on AArch64 when possible, notably for macOS by default. This does not currently work with tail calls which means that
cargo test
currently fails with various segfaults.From what I can understand the general pointer authentication scheme right now is:
lr
, is "encrypted" with bothsp
and the B keysp
and the B keyFor tail calls this decryption isn't happening currently, meaning that the return address is corrupted for when the tail-called function finally returns.
I've attempted a naive fix for this where I insert an
auti*sp
instruction before the branch for theReturnCall
instruction, but this does not work because if a function tail calls a function with stack arguments it means thatsp
is different from the beginning of the function and the end of the function. This means that different values go into the encryption/decryption phases which means that the return address gets corrupted again.I'm not entirely sure how to fix this myself, but I'm also a little tired right now so may be missing something. cc @fitzgen
The text was updated successfully, but these errors were encountered: