📄 ptrace.c
字号:
#ifdef PTRACE_SINGLEBLOCK#define is_singleblock(request) ((request) == PTRACE_SINGLEBLOCK)#else#define is_singleblock(request) 0#endif#ifdef PTRACE_SYSEMU#define is_sysemu_singlestep(request) ((request) == PTRACE_SYSEMU_SINGLESTEP)#else#define is_sysemu_singlestep(request) 0#endifstatic int ptrace_resume(struct task_struct *child, long request, long data){ if (!valid_signal(data)) return -EIO; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);#ifdef TIF_SYSCALL_EMU if (request == PTRACE_SYSEMU || request == PTRACE_SYSEMU_SINGLESTEP) set_tsk_thread_flag(child, TIF_SYSCALL_EMU); else clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);#endif if (is_singleblock(request)) { if (unlikely(!arch_has_block_step())) return -EIO; user_enable_block_step(child); } else if (is_singlestep(request) || is_sysemu_singlestep(request)) { if (unlikely(!arch_has_single_step())) return -EIO; user_enable_single_step(child); } else user_disable_single_step(child); child->exit_code = data; wake_up_process(child); return 0;}int ptrace_request(struct task_struct *child, long request, long addr, long data){ int ret = -EIO; siginfo_t siginfo; switch (request) { case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: return generic_ptrace_peekdata(child, addr, data); case PTRACE_POKETEXT: case PTRACE_POKEDATA: return generic_ptrace_pokedata(child, addr, data);#ifdef PTRACE_OLDSETOPTIONS case PTRACE_OLDSETOPTIONS:#endif case PTRACE_SETOPTIONS: ret = ptrace_setoptions(child, data); break; case PTRACE_GETEVENTMSG: ret = put_user(child->ptrace_message, (unsigned long __user *) data); break; case PTRACE_GETSIGINFO: ret = ptrace_getsiginfo(child, &siginfo); if (!ret) ret = copy_siginfo_to_user((siginfo_t __user *) data, &siginfo); break; case PTRACE_SETSIGINFO: if (copy_from_user(&siginfo, (siginfo_t __user *) data, sizeof siginfo)) ret = -EFAULT; else ret = ptrace_setsiginfo(child, &siginfo); break; case PTRACE_DETACH: /* detach a process that was attached. */ ret = ptrace_detach(child, data); break;#ifdef PTRACE_SINGLESTEP case PTRACE_SINGLESTEP:#endif#ifdef PTRACE_SINGLEBLOCK case PTRACE_SINGLEBLOCK:#endif#ifdef PTRACE_SYSEMU case PTRACE_SYSEMU: case PTRACE_SYSEMU_SINGLESTEP:#endif case PTRACE_SYSCALL: case PTRACE_CONT: return ptrace_resume(child, request, data); case PTRACE_KILL: if (child->exit_state) /* already dead */ return 0; return ptrace_resume(child, request, SIGKILL); default: break; } return ret;}/** * ptrace_traceme -- helper for PTRACE_TRACEME * * Performs checks and sets PT_PTRACED. * Should be used by all ptrace implementations for PTRACE_TRACEME. */int ptrace_traceme(void){ int ret = -EPERM; /* * Are we already being traced? */repeat: task_lock(current); if (!(current->ptrace & PT_PTRACED)) { /* * See ptrace_attach() comments about the locking here. */ unsigned long flags; if (!write_trylock_irqsave(&tasklist_lock, flags)) { task_unlock(current); do { cpu_relax(); } while (!write_can_lock(&tasklist_lock)); goto repeat; } ret = security_ptrace_traceme(current->parent); /* * Set the ptrace bit in the process ptrace flags. * Then link us on our parent's ptraced list. */ if (!ret) { current->ptrace |= PT_PTRACED; __ptrace_link(current, current->real_parent); } write_unlock_irqrestore(&tasklist_lock, flags); } task_unlock(current); return ret;}/** * ptrace_get_task_struct -- grab a task struct reference for ptrace * @pid: process id to grab a task_struct reference of * * This function is a helper for ptrace implementations. It checks * permissions and then grabs a task struct for use of the actual * ptrace implementation. * * Returns the task_struct for @pid or an ERR_PTR() on failure. */struct task_struct *ptrace_get_task_struct(pid_t pid){ struct task_struct *child; read_lock(&tasklist_lock); child = find_task_by_vpid(pid); if (child) get_task_struct(child); read_unlock(&tasklist_lock); if (!child) return ERR_PTR(-ESRCH); return child;}#ifndef arch_ptrace_attach#define arch_ptrace_attach(child) do { } while (0)#endifasmlinkage long sys_ptrace(long request, long pid, long addr, long data){ struct task_struct *child; long ret; /* * This lock_kernel fixes a subtle race with suid exec */ lock_kernel(); if (request == PTRACE_TRACEME) { ret = ptrace_traceme(); if (!ret) arch_ptrace_attach(current); goto out; } child = ptrace_get_task_struct(pid); if (IS_ERR(child)) { ret = PTR_ERR(child); goto out; } if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); /* * Some architectures need to do book-keeping after * a ptrace attach. */ if (!ret) arch_ptrace_attach(child); goto out_put_task_struct; } ret = ptrace_check_attach(child, request == PTRACE_KILL); if (ret < 0) goto out_put_task_struct; ret = arch_ptrace(child, request, addr, data); if (ret < 0) goto out_put_task_struct; out_put_task_struct: put_task_struct(child); out: unlock_kernel(); return ret;}int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data){ unsigned long tmp; int copied; copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), 0); if (copied != sizeof(tmp)) return -EIO; return put_user(tmp, (unsigned long __user *)data);}int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data){ int copied; copied = access_process_vm(tsk, addr, &data, sizeof(data), 1); return (copied == sizeof(data)) ? 0 : -EIO;}#if defined CONFIG_COMPAT && defined __ARCH_WANT_COMPAT_SYS_PTRACE#include <linux/compat.h>int compat_ptrace_request(struct task_struct *child, compat_long_t request, compat_ulong_t addr, compat_ulong_t data){ compat_ulong_t __user *datap = compat_ptr(data); compat_ulong_t word; siginfo_t siginfo; int ret; switch (request) { case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: ret = access_process_vm(child, addr, &word, sizeof(word), 0); if (ret != sizeof(word)) ret = -EIO; else ret = put_user(word, datap); break; case PTRACE_POKETEXT: case PTRACE_POKEDATA: ret = access_process_vm(child, addr, &data, sizeof(data), 1); ret = (ret != sizeof(data) ? -EIO : 0); break; case PTRACE_GETEVENTMSG: ret = put_user((compat_ulong_t) child->ptrace_message, datap); break; case PTRACE_GETSIGINFO: ret = ptrace_getsiginfo(child, &siginfo); if (!ret) ret = copy_siginfo_to_user32( (struct compat_siginfo __user *) datap, &siginfo); break; case PTRACE_SETSIGINFO: memset(&siginfo, 0, sizeof siginfo); if (copy_siginfo_from_user32( &siginfo, (struct compat_siginfo __user *) datap)) ret = -EFAULT; else ret = ptrace_setsiginfo(child, &siginfo); break; default: ret = ptrace_request(child, request, addr, data); } return ret;}asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, compat_long_t addr, compat_long_t data){ struct task_struct *child; long ret; /* * This lock_kernel fixes a subtle race with suid exec */ lock_kernel(); if (request == PTRACE_TRACEME) { ret = ptrace_traceme(); goto out; } child = ptrace_get_task_struct(pid); if (IS_ERR(child)) { ret = PTR_ERR(child); goto out; } if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); /* * Some architectures need to do book-keeping after * a ptrace attach. */ if (!ret) arch_ptrace_attach(child); goto out_put_task_struct; } ret = ptrace_check_attach(child, request == PTRACE_KILL); if (!ret) ret = compat_arch_ptrace(child, request, addr, data); out_put_task_struct: put_task_struct(child); out: unlock_kernel(); return ret;}#endif /* CONFIG_COMPAT && __ARCH_WANT_COMPAT_SYS_PTRACE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -