Last active
May 10, 2024 17:22
-
-
Save zhangyoufu/86910448ec92c7eca7e39186b79c98c2 to your computer and use it in GitHub Desktop.
The architecture-specific signal handling code may adjust RIP/RAX to restart interrupted syscall. Address set be tracer via PTRACE_SETREGS may be decreased by 2 bytes unexpectedly on i386/x86-64. To workaround this behavior, tracer have to check whether tracee is in system call and whether the errno indicates restartable.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(gdb) set $rip=0xdeadbeef | |
(gdb) c | |
Continuing. | |
Program received signal SIGSEGV, Segmentation fault. | |
0x00000000deadbeed in ?? () | |
=> 0x00000000deadbeed: | |
Cannot access memory at address 0xdeadbeed |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// arch/x86/kernel/signal.c, arch_do_signal_or_restart | |
/* Did we come from a system call? */ | |
if (syscall_get_nr(current, regs) != -1) { | |
/* Restart the system call - no handlers present */ | |
switch (syscall_get_error(current, regs)) { | |
case -ERESTARTNOHAND: | |
case -ERESTARTSYS: | |
case -ERESTARTNOINTR: | |
regs->ax = regs->orig_ax; | |
regs->ip -= 2; | |
break; | |
case -ERESTART_RESTARTBLOCK: | |
regs->ax = get_nr_restart_syscall(regs); | |
regs->ip -= 2; | |
break; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// from linux/errno.h, unfortunately they does not belong to uapi | |
#define ERESTARTSYS 512 | |
#define ERESTARTNOINTR 513 | |
#define ERESTARTNOHAND 514 | |
#define ERESTART_RESTARTBLOCK 516 | |
ptrace(PTRACE_ATTACH, pid, NULL, NULL); | |
waitpid(pid, NULL, 0); | |
// PTRACE_POKETEXT as you wish | |
ptrace(PTRACE_GETREGS, pid, NULL, ®s); | |
regs.rip = EXPECTED_RIP_AFTER_CONTINUE; | |
if (regs.orig_rax != -1) { | |
// tracee stopped in system call | |
switch (regs.rax) { // errno | |
case -ERESTARTNOHAND: | |
case -ERESTARTSYS: | |
case -ERESTARTNOINTR: | |
case -ERESTART_RESTARTBLOCK: | |
// balance the decrease in arch_do_signal_or_restart | |
regs.rip += 2; // either syscall (0F 05) or int 80h (CD 80) | |
default: | |
// do nothing | |
} | |
} | |
ptrace(PTRACE_SETREGS, pid, NULL, ®s); | |
ptrace(PTRACE_DETACH, pid, NULL, NULL); // suppress SIGSTOP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment