Skip to content

x86/morestack_unwind fails with Debian-13-trixie #4062

@bernhardu

Description

@bernhardu

Hello, that is the other failure I found.

When debugging it manually the _syscall_hook_trampoline is only reached in the exit handlers, while in Debian 12 bookworm it stops below __GI___libc_write and _syscall_hook_trampoline_48_3d_00_f0_ff_ff.

So this is maybe a missing syscall_patch_hooks?

I attempted to create a fix by just copying the _syscall_hook_trampoline_c3_nop with the additional pop %rbx.
And the test then stops indeed inside the __GI___libc_write, but the backtrace looks not clean,
and the third finish instruction of the test fails.
So I guess there is some more cfi/cfa magic needed to adjust for the additional pop %rbx.

Debian 13 trixie
(gdb) disassemble /r __GI___libc_write
Dump of assembler code for function __GI___libc_write:
   0x00007ffff7e90960 <+0>:     48 83 ec 10             sub    $0x10,%rsp
   0x00007ffff7e90964 <+4>:     48 63 ff                movslq %edi,%rdi
   0x00007ffff7e90967 <+7>:     45 31 c9                xor    %r9d,%r9d
   0x00007ffff7e9096a <+10>:    45 31 c0                xor    %r8d,%r8d
   0x00007ffff7e9096d <+13>:    6a 01                   push   $0x1
   0x00007ffff7e9096f <+15>:    31 c9                   xor    %ecx,%ecx
   0x00007ffff7e90971 <+17>:    e8 2a ad f8 ff          call   0x7ffff7e1b6a0 <__syscall_cancel>
   0x00007ffff7e90976 <+22>:    48 83 c4 18             add    $0x18,%rsp
   0x00007ffff7e9097a <+26>:    c3                      ret
End of assembler dump.
(gdb) disassemble /r __syscall_cancel
Dump of assembler code for function __syscall_cancel:
   0x00007ffff7e1b6a0 <+0>:     48 83 ec 10             sub    $0x10,%rsp
   0x00007ffff7e1b6a4 <+4>:     ff 74 24 18             push   0x18(%rsp)
   0x00007ffff7e1b6a8 <+8>:     e8 73 ff ff ff          call   0x7ffff7e1b620 <__internal_syscall_cancel>
   0x00007ffff7e1b6ad <+13>:    5a                      pop    %rdx
   0x00007ffff7e1b6ae <+14>:    59                      pop    %rcx
   0x00007ffff7e1b6af <+15>:    48 3d 00 f0 ff ff       cmp    $0xfffffffffffff000,%rax
   0x00007ffff7e1b6b5 <+21>:    77 09                   ja     0x7ffff7e1b6c0 <__syscall_cancel+32>
   0x00007ffff7e1b6b7 <+23>:    48 83 c4 08             add    $0x8,%rsp
   0x00007ffff7e1b6bb <+27>:    c3                      ret
   0x00007ffff7e1b6bc <+28>:    0f 1f 40 00             nopl   0x0(%rax)
   0x00007ffff7e1b6c0 <+32>:    48 8b 15 29 57 15 00    mov    0x155729(%rip),%rdx        # 0x7ffff7f70df0
   0x00007ffff7e1b6c7 <+39>:    f7 d8                   neg    %eax
   0x00007ffff7e1b6c9 <+41>:    64 89 02                mov    %eax,%fs:(%rdx)
   0x00007ffff7e1b6cc <+44>:    48 c7 c0 ff ff ff ff    mov    $0xffffffffffffffff,%rax
   0x00007ffff7e1b6d3 <+51>:    48 83 c4 08             add    $0x8,%rsp
   0x00007ffff7e1b6d7 <+55>:    c3                      ret
End of assembler dump.
(gdb) disassemble /r __internal_syscall_cancel
Dump of assembler code for function __internal_syscall_cancel:
   0x00007ffff7e1b620 <+0>:     53                      push   %rbx
   0x00007ffff7e1b621 <+1>:     49 89 ca                mov    %rcx,%r10
   0x00007ffff7e1b624 <+4>:     64 48 8b 1c 25 10 00 00 00      mov    %fs:0x10,%rbx
   0x00007ffff7e1b62d <+13>:    8b 83 08 03 00 00       mov    0x308(%rbx),%eax
   0x00007ffff7e1b633 <+19>:    80 3d c6 da 15 00 00    cmpb   $0x0,0x15dac6(%rip)        # 0x7ffff7f79100 <__libc_single_threaded>
   0x00007ffff7e1b63a <+26>:    75 44                   jne    0x7ffff7e1b680 <__internal_syscall_cancel+96>
   0x00007ffff7e1b63c <+28>:    a8 01                   test   $0x1,%al
   0x00007ffff7e1b63e <+30>:    75 40                   jne    0x7ffff7e1b680 <__internal_syscall_cancel+96>
   0x00007ffff7e1b640 <+32>:    a8 10                   test   $0x10,%al
   0x00007ffff7e1b642 <+34>:    75 3c                   jne    0x7ffff7e1b680 <__internal_syscall_cancel+96>
   0x00007ffff7e1b644 <+36>:    41 51                   push   %r9
   0x00007ffff7e1b646 <+38>:    4c 8d 9b 08 03 00 00    lea    0x308(%rbx),%r11
   0x00007ffff7e1b64d <+45>:    49 89 c9                mov    %rcx,%r9
   0x00007ffff7e1b650 <+48>:    48 89 f1                mov    %rsi,%rcx
   0x00007ffff7e1b653 <+51>:    41 50                   push   %r8
   0x00007ffff7e1b655 <+53>:    48 8b 74 24 20          mov    0x20(%rsp),%rsi
   0x00007ffff7e1b65a <+58>:    49 89 d0                mov    %rdx,%r8
   0x00007ffff7e1b65d <+61>:    48 89 fa                mov    %rdi,%rdx
   0x00007ffff7e1b660 <+64>:    4c 89 df                mov    %r11,%rdi
   0x00007ffff7e1b663 <+67>:    e8 58 b3 00 00          call   0x7ffff7e269c0 <__syscall_cancel_arch>
   0x00007ffff7e1b668 <+72>:    8b 93 08 03 00 00       mov    0x308(%rbx),%edx
   0x00007ffff7e1b66e <+78>:    59                      pop    %rcx
   0x00007ffff7e1b66f <+79>:    5e                      pop    %rsi
   0x00007ffff7e1b670 <+80>:    48 83 f8 fc             cmp    $0xfffffffffffffffc,%rax
   0x00007ffff7e1b674 <+84>:    74 1a                   je     0x7ffff7e1b690 <__internal_syscall_cancel+112>
   0x00007ffff7e1b676 <+86>:    5b                      pop    %rbx
   0x00007ffff7e1b677 <+87>:    c3                      ret
   0x00007ffff7e1b678 <+88>:    0f 1f 84 00 00 00 00 00 nopl   0x0(%rax,%rax,1)
   0x00007ffff7e1b680 <+96>:    48 8b 44 24 10          mov    0x10(%rsp),%rax
=> 0x00007ffff7e1b685 <+101>:   0f 05                   syscall
   0x00007ffff7e1b687 <+103>:   5b                      pop    %rbx
   0x00007ffff7e1b688 <+104>:   c3                      ret
   0x00007ffff7e1b689 <+105>:   0f 1f 80 00 00 00 00    nopl   0x0(%rax)
   0x00007ffff7e1b690 <+112>:   83 e2 39                and    $0x39,%edx
   0x00007ffff7e1b693 <+115>:   83 fa 08                cmp    $0x8,%edx
   0x00007ffff7e1b696 <+118>:   75 de                   jne    0x7ffff7e1b676 <__internal_syscall_cancel+86>
   0x00007ffff7e1b698 <+120>:   e8 23 ff ff ff          call   0x7ffff7e1b5c0 <__syscall_do_cancel>
End of assembler dump.
(gdb)
Debian 12 bookworm
(gdb) disassemble /r __GI___libc_write
Dump of assembler code for function __GI___libc_write:
   0x00007ffff7ed1330 <+0>:     80 3d a1 32 0e 00 00    cmpb   $0x0,0xe32a1(%rip)        # 0x7ffff7fb45d8 <__libc_single_threaded>
   0x00007ffff7ed1337 <+7>:     74 17                   je     0x7ffff7ed1350 <__GI___libc_write+32>
   0x00007ffff7ed1339 <+9>:     b8 01 00 00 00          mov    $0x1,%eax
   0x00007ffff7ed133e <+14>:    0f 05                   syscall
=> 0x00007ffff7ed1340 <+16>:    48 3d 00 f0 ff ff       cmp    $0xfffffffffffff000,%rax
   0x00007ffff7ed1346 <+22>:    77 58                   ja     0x7ffff7ed13a0 <__GI___libc_write+112>
   0x00007ffff7ed1348 <+24>:    c3                      ret
   0x00007ffff7ed1349 <+25>:    0f 1f 80 00 00 00 00    nopl   0x0(%rax)
   0x00007ffff7ed1350 <+32>:    48 83 ec 28             sub    $0x28,%rsp
   0x00007ffff7ed1354 <+36>:    48 89 54 24 18          mov    %rdx,0x18(%rsp)
   0x00007ffff7ed1359 <+41>:    48 89 74 24 10          mov    %rsi,0x10(%rsp)
   0x00007ffff7ed135e <+46>:    89 7c 24 08             mov    %edi,0x8(%rsp)
   0x00007ffff7ed1362 <+50>:    e8 b9 d4 f8 ff          call   0x7ffff7e5e820 <__GI___pthread_enable_asynccancel>
   0x00007ffff7ed1367 <+55>:    48 8b 54 24 18          mov    0x18(%rsp),%rdx
   0x00007ffff7ed136c <+60>:    48 8b 74 24 10          mov    0x10(%rsp),%rsi
   0x00007ffff7ed1371 <+65>:    41 89 c0                mov    %eax,%r8d
   0x00007ffff7ed1374 <+68>:    8b 7c 24 08             mov    0x8(%rsp),%edi
   0x00007ffff7ed1378 <+72>:    b8 01 00 00 00          mov    $0x1,%eax
   0x00007ffff7ed137d <+77>:    0f 05                   syscall
   0x00007ffff7ed137f <+79>:    48 3d 00 f0 ff ff       cmp    $0xfffffffffffff000,%rax
   0x00007ffff7ed1385 <+85>:    77 31                   ja     0x7ffff7ed13b8 <__GI___libc_write+136>
   0x00007ffff7ed1387 <+87>:    44 89 c7                mov    %r8d,%edi
   0x00007ffff7ed138a <+90>:    48 89 44 24 08          mov    %rax,0x8(%rsp)
   0x00007ffff7ed138f <+95>:    e8 0c d5 f8 ff          call   0x7ffff7e5e8a0 <__GI___pthread_disable_asynccancel>
   0x00007ffff7ed1394 <+100>:   48 8b 44 24 08          mov    0x8(%rsp),%rax
   0x00007ffff7ed1399 <+105>:   48 83 c4 28             add    $0x28,%rsp
   0x00007ffff7ed139d <+109>:   c3                      ret
   0x00007ffff7ed139e <+110>:   66 90                   xchg   %ax,%ax
   0x00007ffff7ed13a0 <+112>:   48 8b 15 39 aa 0d 00    mov    0xdaa39(%rip),%rdx        # 0x7ffff7fabde0
   0x00007ffff7ed13a7 <+119>:   f7 d8                   neg    %eax
   0x00007ffff7ed13a9 <+121>:   64 89 02                mov    %eax,%fs:(%rdx)
   0x00007ffff7ed13ac <+124>:   48 c7 c0 ff ff ff ff    mov    $0xffffffffffffffff,%rax
   0x00007ffff7ed13b3 <+131>:   c3                      ret
   0x00007ffff7ed13b4 <+132>:   0f 1f 40 00             nopl   0x0(%rax)
   0x00007ffff7ed13b8 <+136>:   48 8b 15 21 aa 0d 00    mov    0xdaa21(%rip),%rdx        # 0x7ffff7fabde0
   0x00007ffff7ed13bf <+143>:   f7 d8                   neg    %eax
   0x00007ffff7ed13c1 <+145>:   64 89 02                mov    %eax,%fs:(%rdx)
   0x00007ffff7ed13c4 <+148>:   48 c7 c0 ff ff ff ff    mov    $0xffffffffffffffff,%rax
   0x00007ffff7ed13cb <+155>:   eb ba                   jmp    0x7ffff7ed1387 <__GI___libc_write+87>
End of assembler dump.
(gdb)
Attempt to create a patch for rr
diff --git a/src/preload/syscall_hook.S b/src/preload/syscall_hook.S
index 15dd12b8..f4810275 100644
--- a/src/preload/syscall_hook.S
+++ b/src/preload/syscall_hook.S
@@ -567,6 +567,27 @@ SYSCALLHOOK_START(_syscall_hook_trampoline_c3_nop)
         .cfi_endproc
         .size _syscall_hook_trampoline_c3_nop, .-_syscall_hook_trampoline_c3_nop
 
+SYSCALLHOOK_START(_syscall_hook_trampoline_5b_c3_nop)
+        .cfi_offset %rip, 16
+        RSP_IS_CFA_PLUS_OFFSET(24)
+        callq __morestack
+        /* The original instructions after the syscall are
+           pop %rbx; retq; nopl 0x0(%rax,%rax,1) */
+        /* We're not returning to the dynamically generated stub, so
+           we need to fix the stack pointer ourselves. */
+        pop %rbx
+        CFA_AT_RSP_OFFSET(0)
+        pop %rsp
+        .cfi_def_cfa %rsp, 0;
+        pop %rbx
+        .cfi_adjust_cfa_offset -8
+        pop (stub_scratch_1)
+        .cfi_adjust_cfa_offset -8
+        jmp _syscallbuf_final_exit_instruction
+
+        .cfi_endproc
+        .size _syscall_hook_trampoline_5b_c3_nop, .-_syscall_hook_trampoline_5b_c3_nop
+
 SYSCALLHOOK_START(_syscall_hook_trampoline_40_80_f6_81)
        xor $0x81, %sil
        call __morestack
diff --git a/src/preload/syscallbuf.c b/src/preload/syscallbuf.c
index 2b30d9fc..ab024490 100644
--- a/src/preload/syscallbuf.c
+++ b/src/preload/syscallbuf.c
@@ -818,6 +818,7 @@ static void __attribute__((constructor)) init_process(void) {
   extern RR_HIDDEN void _syscall_hook_trampoline_ba_01_00_00_00(void);
   extern RR_HIDDEN void _syscall_hook_trampoline_89_c1_31_d2(void);
   extern RR_HIDDEN void _syscall_hook_trampoline_c3_nop(void);
+  extern RR_HIDDEN void _syscall_hook_trampoline_5b_c3_nop(void);
   extern RR_HIDDEN void _syscall_hook_trampoline_40_80_f6_81(void);
   extern RR_HIDDEN void _syscall_hook_trampoline_49_89_ca(void);
   extern RR_HIDDEN void _syscall_hook_trampoline_48_89_c1(void);
@@ -973,6 +974,12 @@ static void __attribute__((constructor)) init_process(void) {
       3,
       { 0xc3, 0xcc, 0xcc },
       (uintptr_t)_syscall_hook_trampoline_c3_nop },
+    /* __internal_syscall_cancel has 'syscall' followed by 'pop %rbx; retq; nopl 0x0(%rax,%rax,1)'
+       in debian-13-trixie libc6 2.41-12+deb13u2 */
+    { PATCH_IS_MULTIPLE_INSTRUCTIONS,
+      9,
+      { 0x5b, 0xc3, 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00 },
+      (uintptr_t)_syscall_hook_trampoline_5b_c3_nop },
     /* glibc-2.31 on Ubuntu 20.04 has 'xor $0x81, %sil' followed by 'syscall' */
     { PATCH_SYSCALL_INSTRUCTION_IS_LAST,
       4,

EDIT: slightly improved version (comment above belongs to the element; use in both pop instructions rbx)

Unclean backtrace with above patch
(rr) bt
#0  _syscall_hook_trampoline () at src/preload/syscall_hook.S:256
#1  0x00007fac6f9e834d in __morestack () at src/preload/syscall_hook.S:443
#2  0x00007fac6f9e8488 in _syscall_hook_trampoline_5b_c3_nop () at src/preload/syscall_hook.S:573
#3  0x0000000000000001 in ?? ()
#4  0x00007fac6f7ba600 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#5  0x00007fac6f9ff910 in ?? ()
#6  0x00007fac6f8b5976 in __GI___libc_write (fd=<optimized out>, buf=<optimized out>, nbytes=<optimized out>) at ../sysdeps/unix/sysv/linux/write.c:26
#7  0x000055b181eae224 in atomic_printf (fmt=0x55b181eaf008 "%s\n") at src/test/x86/../util.h:161
#8  0x000055b181eae24d in atomic_puts (str=0x55b181eaf033 "EXIT-SUCCESS") at src/test/x86/../util.h:170
#9  0x000055b181eae2d9 in main () at src/test/x86/morestack_unwind.c:21

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions