long compat_arch_ptrace(struct task_struct *child, compat_long_t request, compat_ulong_t addr, compat_ulong_t data) { compat_uint_t tmp; long ret = -EIO; switch (request) { case PTRACE_PEEKUSR: if (addr & (sizeof(compat_uint_t)-1)) break; addr = translate_usr_offset(addr); if (addr >= sizeof(struct pt_regs)) break; tmp = *(compat_uint_t *) ((char *) task_regs(child) + addr); ret = put_user(tmp, (compat_uint_t *) (unsigned long) data); break; case PTRACE_POKEUSR: /* Some register values written here may be ignored in * entry.S:syscall_restore_rfi; e.g. iaoq is written with * r31/r31+4, and not with the values in pt_regs. */ if (addr == PT_PSW) { /* Since PT_PSW==0, it is valid for 32 bit processes * under 64 bit kernels as well. */ ret = arch_ptrace(child, request, addr, data); } else { if (addr & (sizeof(compat_uint_t)-1)) break; addr = translate_usr_offset(addr); if (addr >= sizeof(struct pt_regs)) break; if (addr >= PT_FR0 && addr <= PT_FR31 + 4) { /* Special case, fp regs are 64 bits anyway */ *(__u64 *) ((char *) task_regs(child) + addr) = data; ret = 0; } else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) || addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4 || addr == PT_SAR+4) { /* Zero the top 32 bits */ *(__u32 *) ((char *) task_regs(child) + addr - 4) = 0; *(__u32 *) ((char *) task_regs(child) + addr) = data; ret = 0; } } break; default: ret = compat_ptrace_request(child, request, addr, data); break; } return ret; }
SYSCALL_DEFINE4(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; if (gr_handle_ptrace(child, request)) { ret = -EPERM; 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; }
asmlinkage 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(); 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; }
SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, unsigned long, data) { struct task_struct *child; long ret; #ifdef CONFIG_CCSECURITY if (ccs_ptrace_permission(request, pid)) return -EPERM; #endif 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); out_put_task_struct: put_task_struct(child); out: return ret; }
SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, unsigned long, data) { struct task_struct *child; long ret; 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 || request != PTRACE_DETACH) ptrace_unfreeze_traced(child); out_put_task_struct: put_task_struct(child); out: return ret; }
long compat_arch_ptrace(struct task_struct *child, compat_long_t request, compat_ulong_t addr, compat_ulong_t data) { compat_uint_t tmp; long ret = -EIO; switch (request) { case PTRACE_PEEKUSR: if (addr & (sizeof(compat_uint_t)-1)) break; addr = translate_usr_offset(addr); if (addr >= sizeof(struct pt_regs)) break; tmp = *(compat_uint_t *) ((char *) task_regs(child) + addr); ret = put_user(tmp, (compat_uint_t *) (unsigned long) data); break; /* Write the word at location addr in the USER area. This will need to change when the kernel no longer saves all regs on a syscall. FIXME. There is a problem at the moment in that r3-r18 are only saved if the process is ptraced on syscall entry, and even then those values are overwritten by actual register values on syscall exit. */ case PTRACE_POKEUSR: /* Some register values written here may be ignored in * entry.S:syscall_restore_rfi; e.g. iaoq is written with * r31/r31+4, and not with the values in pt_regs. */ if (addr == PT_PSW) { /* Since PT_PSW==0, it is valid for 32 bit processes * under 64 bit kernels as well. */ ret = arch_ptrace(child, request, addr, data); } else { if (addr & (sizeof(compat_uint_t)-1)) break; addr = translate_usr_offset(addr); if (addr >= sizeof(struct pt_regs)) break; if (addr >= PT_FR0 && addr <= PT_FR31 + 4) { /* Special case, fp regs are 64 bits anyway */ *(__u64 *) ((char *) task_regs(child) + addr) = data; ret = 0; } else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) || addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4 || addr == PT_SAR+4) { /* Zero the top 32 bits */ *(__u32 *) ((char *) task_regs(child) + addr - 4) = 0; *(__u32 *) ((char *) task_regs(child) + addr) = data; ret = 0; } } break; default: ret = compat_ptrace_request(child, request, addr, data); break; } return ret; }
long compat_arch_ptrace(struct task_struct *child, compat_long_t request, compat_ulong_t addr, compat_ulong_t data) { compat_uint_t tmp; long ret = -EIO; switch (request) { case PTRACE_PEEKUSR: if (addr & (sizeof(compat_uint_t)-1)) break; addr = translate_usr_offset(addr); if (addr >= sizeof(struct pt_regs)) break; tmp = *(compat_uint_t *) ((char *) task_regs(child) + addr); ret = put_user(tmp, (compat_uint_t *) (unsigned long) data); break; /* */ case PTRACE_POKEUSR: /* */ if (addr == PT_PSW) { /* */ ret = arch_ptrace(child, request, addr, data); } else { if (addr & (sizeof(compat_uint_t)-1)) break; addr = translate_usr_offset(addr); if (addr >= sizeof(struct pt_regs)) break; if (addr >= PT_FR0 && addr <= PT_FR31 + 4) { /* */ *(__u64 *) ((char *) task_regs(child) + addr) = data; ret = 0; } else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) || addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4 || addr == PT_SAR+4) { /* */ *(__u32 *) ((char *) task_regs(child) + addr - 4) = 0; *(__u32 *) ((char *) task_regs(child) + addr) = data; ret = 0; } } break; default: ret = compat_ptrace_request(child, request, addr, data); break; } return ret; }