Skip to content
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

The "tail" calling convention is not working with AArch64 pointer address signing #6567

Closed
alexcrichton opened this issue Jun 12, 2023 · 1 comment · Fixed by #6634
Closed
Labels
cranelift:area:aarch64 Issues related to AArch64 backend.

Comments

@alexcrichton
Copy link
Member

Locally on an AArch64 macbook I get:

$ cargo run -q test filetests/filetests/runtests/tail-call-conv.clif
zsh: bus error  cargo run -q test filetests/filetests/runtests/tail-call-conv.clif

If I comment out the target aarch64 has_pauth sign_return_address directive the test passes, and the first test that fails is:

test run

target aarch64 has_pauth sign_return_address

;; Test the `tail` calling convention with non-tail calls and stack arguments.

function %tail_callee_stack_args(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64) -> i64 tail {
block0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64, v5: i64, v6: i64, v7: i64, v8: i64, v9: i64, v10: i64, v11: i64, v12: i64, v13: i64, v14: i64):
    return v14
}

function %tail_caller_stack_args() -> i64 {
    fn0 = %tail_callee_stack_args(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64) -> i64 tail

block0:
    v0 = iconst.i64 10
    v1 = iconst.i64 15
    v2 = iconst.i64 20
    v3 = iconst.i64 25
    v4 = iconst.i64 30
    v5 = iconst.i64 35
    v6 = iconst.i64 40
    v7 = iconst.i64 45
    v8 = iconst.i64 50
    v9 = iconst.i64 55
    v10 = iconst.i64 60
    v11 = iconst.i64 65
    v12 = iconst.i64 70
    v13 = iconst.i64 75
    v14 = iconst.i64 80
    v15 = call fn0(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)
    return v15
}

; run: %tail_caller_stack_args() == 80

Running in a debugger isn't too useful because the crashing thread says it's at address 0x0000000000000037

I don't know much about pointer authentication myself, but stepping through in a debugger this is the entire function tail_caller_stack_args with the highlighted instruction where when at that instruction the debugger no longer produces a backtrace:

    0x103fa80c8: paciasp
    0x103fa80cc: stp    x29, x30, [sp, #-0x10]!
    0x103fa80d0: mov    x29, sp
    0x103fa80d4: mov    x0, #0xa
    0x103fa80d8: mov    x1, #0xf
    0x103fa80dc: mov    x2, #0x14
    0x103fa80e0: mov    x3, #0x19
    0x103fa80e4: mov    x4, #0x1e
    0x103fa80e8: mov    x5, #0x23
    0x103fa80ec: mov    x6, #0x28
    0x103fa80f0: mov    x7, #0x2d
    0x103fa80f4: mov    x8, #0x32
    0x103fa80f8: mov    x9, #0x37
    0x103fa80fc: mov    x10, #0x3c
    0x103fa8100: mov    x11, #0x41
    0x103fa8104: mov    x12, #0x46
    0x103fa8108: mov    x13, #0x4b
    0x103fa810c: mov    x14, #0x50
    0x103fa8110: sub    sp, sp, #0x40
    0x103fa8114: stur   x8, [sp]
    0x103fa8118: stur   x9, [sp, #0x8]
    0x103fa811c: stur   x10, [sp, #0x10]
    0x103fa8120: stur   x11, [sp, #0x18]
    0x103fa8124: stur   x12, [sp, #0x20]
    0x103fa8128: stur   x13, [sp, #0x28]
    0x103fa812c: stur   x14, [sp, #0x30]
    0x103fa8130: ldr    x9, #0x8
    0x103fa8134: b      0x103fa8140
    0x103fa8138: .long  0x03fa8000                ; unknown opcode
    0x103fa813c: udf    #0x1
    0x103fa8140: blr    x9
    0x103fa8144: ldp    x29, x30, [sp], #0x10
->  0x103fa8148: retaa

The disassembly of tail_callee_stack_args looks like:

    0x103fa8000: paciasp
    0x103fa8004: stp    x29, x30, [sp, #-0x10]!
    0x103fa8008: mov    x29, sp
    0x103fa800c: ldur   x9, [x29, #0x10]
    0x103fa8010: ldur   x11, [x29, #0x18]
    0x103fa8014: ldur   x13, [x29, #0x20]
    0x103fa8018: ldur   x15, [x29, #0x28]
    0x103fa801c: ldur   x1, [x29, #0x30]
    0x103fa8020: ldur   x3, [x29, #0x38]
    0x103fa8024: ldur   x0, [x29, #0x40]
    0x103fa8028: ldp    x29, x30, [sp], #0x10
    0x103fa802c: retaa
@alexcrichton alexcrichton added the cranelift:area:aarch64 Issues related to AArch64 backend. label Jun 12, 2023
@alexcrichton
Copy link
Member Author

With some tweaks I could reproduce this in QEMU. I downloaded and built QEMU 8.0.2 (not sure if that's required it's just the latest) and then changed this condition to always return true. I then ran this in one window:

$ qemu-aarch64 -g 1234 -cpu max /home/acrichto/code/wasmtime/target/debug/clif-util test filetests/filetests/runtests/tail-call-conv.clif

and this in another window:

$ gdb /home/acrichto/code/wasmtime/target/debug/clif-util
(gdb) target remote :1234
Remote debugging using :1234
warning: remote target does not support file transfer, attempting to access files from local filesystem.
Reading symbols from /lib/ld-linux-aarch64.so.1...
(No debugging symbols found in /lib/ld-linux-aarch64.so.1)
0x000000550470e140 in ?? () from /lib/ld-linux-aarch64.so.1
(gdb) c
Continuing.
[New Thread 1.753689]
[New Thread 1.753686]

Thread 2 received signal SIGSEGV, Segmentation fault.
[Switching to Thread 1.753689]
0x0020000000000037 in ?? ()

which I think reproduces the issue (although I'm not 100% sure, but it's at least the same crashing address as it was natively)

@fitzgen fitzgen changed the title Tail calls seem incompatible with AArch64 pointer address signing The "tail" calling convention is not working with AArch64 pointer address signing Jun 13, 2023
alexcrichton added a commit to alexcrichton/wasmtime that referenced this issue Jun 23, 2023
This commit fixes an accidental issue with bytecodealliance#6478 where when pointer
authentication was enabled and stack bytes are being popped during a
return this didn't work. In this situation an authenticated return
instruction was used, such as `retab`, and no extra stack bytes were
popped. The fix here is to use the non-`retab` path which handles stack
bytes being popped if there are stack bytes to pop.

Closes bytecodealliance#6567
github-merge-queue bot pushed a commit that referenced this issue Jun 23, 2023
* aarch64: Fix `AuthenticatedRet` when stack bytes are popped

This commit fixes an accidental issue with #6478 where when pointer
authentication was enabled and stack bytes are being popped during a
return this didn't work. In this situation an authenticated return
instruction was used, such as `retab`, and no extra stack bytes were
popped. The fix here is to use the non-`retab` path which handles stack
bytes being popped if there are stack bytes to pop.

Closes #6567

* Still use `retab` for `is_hint: false`
alexcrichton added a commit to alexcrichton/wasmtime that referenced this issue Jun 27, 2023
…alliance#6634)

* aarch64: Fix `AuthenticatedRet` when stack bytes are popped

This commit fixes an accidental issue with bytecodealliance#6478 where when pointer
authentication was enabled and stack bytes are being popped during a
return this didn't work. In this situation an authenticated return
instruction was used, such as `retab`, and no extra stack bytes were
popped. The fix here is to use the non-`retab` path which handles stack
bytes being popped if there are stack bytes to pop.

Closes bytecodealliance#6567

* Still use `retab` for `is_hint: false`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cranelift:area:aarch64 Issues related to AArch64 backend.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant