On Thu, 4 Apr 2024 18:11:09 +0200 Oleg Nesterov <oleg@xxxxxxxxxx> wrote: > On 04/05, Masami Hiramatsu wrote: > > > > Can we make this syscall and uprobe behavior clearer? As you said, if > > the application use sigreturn or longjump, it may skip returns and > > shadow stack entries are left in the kernel. In such cases, can uretprobe > > detect it properly, or just crash the process (or process runs wrongly)? > > Please see the comment in handle_trampoline(), it tries to detect this case. > This patch should not make any difference. I think you mean this loop will skip and discard the stacked return_instance to find the valid one. ---- do { /* * We should throw out the frames invalidated by longjmp(). * If this chain is valid, then the next one should be alive * or NULL; the latter case means that nobody but ri->func * could hit this trampoline on return. TODO: sigaltstack(). */ next = find_next_ret_chain(ri); valid = !next || arch_uretprobe_is_alive(next, RP_CHECK_RET, regs); instruction_pointer_set(regs, ri->orig_ret_vaddr); do { if (valid) handle_uretprobe_chain(ri, regs); ri = free_ret_instance(ri); utask->depth--; } while (ri != next); } while (!valid); ---- I think this expects setjmp/longjmp as below foo() { <- retprobe1 setjmp() bar() { <- retprobe2 longjmp() } } <- return to trampoline In this case, we need to skip retprobe2's instance. My concern is, if we can not find appropriate return instance, what happen? e.g. foo() { <-- retprobe1 bar() { # sp is decremented sys_uretprobe() <-- ?? } } It seems sys_uretprobe() will handle retprobe1 at that point instead of SIGILL. Can we avoid this with below strict check? if (ri->stack != regs->sp + expected_offset) goto sigill; expected_offset should be 16 (push * 3 - ret) on x64 if we ri->stack is the regs->sp right after call. Thank you, -- Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx>