On Wed, Jan 25, 2023 at 02:17:41AM -0800, H. Peter Anvin wrote: > I guess it would depend on what they "normally" are. My #1 impulse would be to leave them both unchanged. Ah okay... I think I understand now. My confusion came from a comment in that code. The current SIGUSR1 handler has a comment: /* Set IP and CX to match so that SYSRET can happen. */ ctx->uc_mcontext.gregs[REG_RIP] = rip; ctx->uc_mcontext.gregs[REG_RCX] = rip; So I thought if we leave them both unchanged, then SYSRET can happen too, because IP and CX match. My initial confusion about that was: Where do we actually exercise IRET if the SIGUSR2 handler exercises SYSRET then? I realized my assumption was wrong. The current SIGUSR1 handler actually forces the kernel to use IRET, not SYSRET. Because the %rip is set to a non-canonical address. So that's the place where it exercises IRET. IOW, my understanding now: The current SIGUSR1 handler exercises the SYSRET-appropriate condition detector in the kernel. It doesn't actually go to the SYSRET path despite the comment saying "SYSRET can happen". That detector must take us to the IRET path or we will #GP in kernel space on Intel CPUs. In short, the SIGUSR1 handler asserts that "SYSRET must *not* happen". The expected SIGUSR2 handler addition exercises the SYSRET path by leaving REG_IP and REG_CX unchanged. Am I correct? -- Ammar Faizi