lldb affecting rcx value upon EXC_SYSCALL

浪尽此生 提交于 2020-03-24 00:58:08

问题


I noticed that upon an invalid 64bit MacOS syscall

    xor eax,eax
    syscall
;lldb stops here after the syscall

When lldb stops the process while single stepping on:

thread #1, stop reason = EXC_SYSCALL (code=5797, subcode=0x1)

The rcx is equal to rsp. However when lldb is not attached or is not single stepping rcx is equal to expected return address after the syscall (i.e. is exactly of the same value as rip in user space). Is this some kind of a bug / side effect?

I'm observing this on MacOS 10.14.5, lldb-1000.11.38.2 also 10.14.6, lldb-1001.0.13.3

After some investigation relevant XNU code seems to be:

Entry(hndl_syscall)
    TIME_TRAP_UENTRY

    movq    %gs:CPU_ACTIVE_THREAD,%rcx  /* get current thread     */
    movl    $-1, TH_IOTIER_OVERRIDE(%rcx)   /* Reset IO tier override to -1 before handling syscall */
    movq    TH_TASK(%rcx),%rbx      /* point to current task  */

    /* Check for active vtimers in the current task */
    TASK_VTIMER_CHECK(%rbx,%rcx)

    /*
     * We can be here either for a mach, unix machdep or diag syscall,
     * as indicated by the syscall class:
     */
    movl    R64_RAX(%r15), %eax     /* syscall number/class */
    movl    %eax, %edx
    andl    $(SYSCALL_CLASS_MASK), %edx /* syscall class */
    cmpl    $(SYSCALL_CLASS_MACH<<SYSCALL_CLASS_SHIFT), %edx
    je  EXT(hndl_mach_scall64)
    cmpl    $(SYSCALL_CLASS_UNIX<<SYSCALL_CLASS_SHIFT), %edx
    je  EXT(hndl_unix_scall64)
    cmpl    $(SYSCALL_CLASS_MDEP<<SYSCALL_CLASS_SHIFT), %edx
    je  EXT(hndl_mdep_scall64)
    cmpl    $(SYSCALL_CLASS_DIAG<<SYSCALL_CLASS_SHIFT), %edx
    je  EXT(hndl_diag_scall64)

    /* Syscall class unknown */
    sti
    CCALL3(i386_exception, $(EXC_SYSCALL), %rax, $1)
    /* no return */

I do indeed get the rax value as the (code=xxxx) reported by lldb. And the subcode 1 also matches.

The parts relevant for returning to user space are:

EXT(ret64_iret):
        iretq               /* return from interrupt */
L_sysret:
    /*
     * Here to restore rcx/r11/rsp and perform the sysret back to user-space.
     *  rcx user rip
     *  r11 user rflags
     *  rsp user stack pointer
     */
    pop %rcx
    add $8, %rsp
    pop %r11
    pop %rsp
    sysretq             /* return from system call */

and also

L_fast_exit:
    pop %rdx            /* user return eip */
    pop %rcx            /* pop and toss cs */
    andl    $(~EFL_IF), (%rsp)  /* clear interrupts enable, sti below */
    popf                /* flags - carry denotes failure */
    pop %rcx            /* user return esp */
    sti             /* interrupts enabled after sysexit */
    sysexitl            /* 32-bit sysexit */

So I actually did disassemble the MacOS 10.14.6 kernel binary found at /System/Library/Kernels/kernel.

Interestingly the sysret variant is not there at all. Only the iret and sysexit.

Looking at 64bit relevant part really helps.

                     _ret64_iret:
ffffff800019985a         iretq                                                  ; CODE XREF=_idt64_debug+38, _ks_64bit_return+118, _ret64_iret+25DATA XREF=_idt64_stack_fault+32

                     loc_ffffff800019985c:
ffffff800019985c         cmp        eax, 0x1                                    ; CODE XREF=_ks_64bit_return+170
ffffff800019985f         je         loc_ffffff8000199875

ffffff8000199861         pop        rax
ffffff8000199862         pop        rcx
ffffff8000199863         add        rsp, 0x8
ffffff8000199867         pop        r11
ffffff8000199869         pop        rsp
ffffff800019986a         sysret

                     loc_ffffff800019986d:
ffffff800019986d         pop        rax                                         ; CODE XREF=_ks_64bit_return+179
ffffff800019986e         verw       word [rsp-0x30+arg_50]
ffffff8000199873         jmp        _ret64_iret

                     loc_ffffff8000199875:
ffffff8000199875         pop        rax                                         ; CODE XREF=_ret64_iret+5
ffffff8000199876         pop        rcx
ffffff8000199877         add        rsp, 0x8
ffffff800019987b         pop        r11
ffffff800019987d         verw       word [rsp-0x20+arg_20]
ffffff8000199882         pop        rsp
ffffff8000199883         sysret

来源:https://stackoverflow.com/questions/57523462/lldb-affecting-rcx-value-upon-exc-syscall

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!