📄 ptrace.c
字号:
if (addr == (addr_t) &dummy32->regs.psw.mask) { /* Fake a 31 bit psw mask. */ tmp = (__u32)(__KSTK_PTREGS(child)->psw.mask >> 32); tmp = PSW32_MASK_MERGE(PSW32_USER_BITS, tmp); } else if (addr == (addr_t) &dummy32->regs.psw.addr) { /* Fake a 31 bit psw address. */ tmp = (__u32) __KSTK_PTREGS(child)->psw.addr | PSW32_ADDR_AMODE31; } else { /* gpr 0-15 */ tmp = *(__u32 *)((addr_t) &__KSTK_PTREGS(child)->psw + addr*2 + 4); } } else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) { /* * access registers are stored in the thread structure */ offset = addr - (addr_t) &dummy32->regs.acrs; tmp = *(__u32*)((addr_t) &child->thread.acrs + offset); } else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) { /* * orig_gpr2 is stored on the kernel stack */ tmp = *(__u32*)((addr_t) &__KSTK_PTREGS(child)->orig_gpr2 + 4); } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { /* * floating point regs. are stored in the thread structure */ offset = addr - (addr_t) &dummy32->regs.fp_regs; tmp = *(__u32 *)((addr_t) &child->thread.fp_regs + offset); } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { /* * per_info is found in the thread structure */ offset = addr - (addr_t) &dummy32->regs.per_info; /* This is magic. See per_struct and per_struct32. */ if ((offset >= (addr_t) &dummy_per32->control_regs && offset < (addr_t) (&dummy_per32->control_regs + 1)) || (offset >= (addr_t) &dummy_per32->starting_addr && offset <= (addr_t) &dummy_per32->ending_addr) || offset == (addr_t) &dummy_per32->lowcore.words.address) offset = offset*2 + 4; else offset = offset*2; tmp = *(__u32 *)((addr_t) &child->thread.per_info + offset); } else tmp = 0; return put_user(tmp, (__u32 __user *) data);}/* * Same as poke_user but for a 31 bit program. */static intpoke_user_emu31(struct task_struct *child, addr_t addr, addr_t data){ struct user32 *dummy32 = NULL; per_struct32 *dummy_per32 = NULL; addr_t offset; __u32 tmp; if (!test_thread_flag(TIF_31BIT) || (addr & 3) || addr > sizeof(struct user32) - 3) return -EIO; tmp = (__u32) data; if (addr < (addr_t) &dummy32->regs.acrs) { /* * psw, gprs, acrs and orig_gpr2 are stored on the stack */ if (addr == (addr_t) &dummy32->regs.psw.mask) { /* Build a 64 bit psw mask from 31 bit mask. */ if (tmp != PSW32_MASK_MERGE(PSW32_USER_BITS, tmp)) /* Invalid psw mask. */ return -EINVAL; __KSTK_PTREGS(child)->psw.mask = PSW_MASK_MERGE(PSW_USER32_BITS, (__u64) tmp << 32); } else if (addr == (addr_t) &dummy32->regs.psw.addr) { /* Build a 64 bit psw address from 31 bit address. */ __KSTK_PTREGS(child)->psw.addr = (__u64) tmp & PSW32_ADDR_INSN; } else { /* gpr 0-15 */ *(__u32*)((addr_t) &__KSTK_PTREGS(child)->psw + addr*2 + 4) = tmp; } } else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) { /* * access registers are stored in the thread structure */ offset = addr - (addr_t) &dummy32->regs.acrs; *(__u32*)((addr_t) &child->thread.acrs + offset) = tmp; } else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) { /* * orig_gpr2 is stored on the kernel stack */ *(__u32*)((addr_t) &__KSTK_PTREGS(child)->orig_gpr2 + 4) = tmp; } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { /* * floating point regs. are stored in the thread structure */ if (addr == (addr_t) &dummy32->regs.fp_regs.fpc && (tmp & ~FPC_VALID_MASK) != 0) /* Invalid floating point control. */ return -EINVAL; offset = addr - (addr_t) &dummy32->regs.fp_regs; *(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp; } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { /* * per_info is found in the thread structure. */ offset = addr - (addr_t) &dummy32->regs.per_info; /* * This is magic. See per_struct and per_struct32. * By incident the offsets in per_struct are exactly * twice the offsets in per_struct32 for all fields. * The 8 byte fields need special handling though, * because the second half (bytes 4-7) is needed and * not the first half. */ if ((offset >= (addr_t) &dummy_per32->control_regs && offset < (addr_t) (&dummy_per32->control_regs + 1)) || (offset >= (addr_t) &dummy_per32->starting_addr && offset <= (addr_t) &dummy_per32->ending_addr) || offset == (addr_t) &dummy_per32->lowcore.words.address) offset = offset*2 + 4; else offset = offset*2; *(__u32 *)((addr_t) &child->thread.per_info + offset) = tmp; } FixPerRegisters(child); return 0;}static intdo_ptrace_emu31(struct task_struct *child, long request, long addr, long data){ unsigned int tmp; /* 4 bytes !! */ ptrace_area_emu31 parea; int copied, ret; switch (request) { case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: /* read word at location addr. */ copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); if (copied != sizeof(tmp)) return -EIO; return put_user(tmp, (unsigned int __user *) data); case PTRACE_PEEKUSR: /* read the word at location addr in the USER area. */ return peek_user_emu31(child, addr, data); case PTRACE_POKETEXT: case PTRACE_POKEDATA: /* write the word at location addr. */ tmp = data; copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1); if (copied != sizeof(tmp)) return -EIO; return 0; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ return poke_user_emu31(child, addr, data); case PTRACE_PEEKUSR_AREA: case PTRACE_POKEUSR_AREA: if (copy_from_user(&parea, (void __user *) addr, sizeof(parea))) return -EFAULT; addr = parea.kernel_addr; data = parea.process_addr; copied = 0; while (copied < parea.len) { if (request == PTRACE_PEEKUSR_AREA) ret = peek_user_emu31(child, addr, data); else { __u32 tmp; if (get_user (tmp, (__u32 __user *) data)) return -EFAULT; ret = poke_user_emu31(child, addr, tmp); } if (ret) return ret; addr += sizeof(unsigned int); data += sizeof(unsigned int); copied += sizeof(unsigned int); } return 0; case PTRACE_GETEVENTMSG: return put_user((__u32) child->ptrace_message, (unsigned int __user *) data); case PTRACE_GETSIGINFO: if (child->last_siginfo == NULL) return -EINVAL; return copy_siginfo_to_user32((compat_siginfo_t __user *) data, child->last_siginfo); case PTRACE_SETSIGINFO: if (child->last_siginfo == NULL) return -EINVAL; return copy_siginfo_from_user32(child->last_siginfo, (compat_siginfo_t __user *) data); } return ptrace_request(child, request, addr, data);}#endif#define PT32_IEEE_IP 0x13cstatic intdo_ptrace(struct task_struct *child, long request, long addr, long data){ int ret; if (request == PTRACE_ATTACH) return ptrace_attach(child); /* * Special cases to get/store the ieee instructions pointer. */ if (child == current) { if (request == PTRACE_PEEKUSR && addr == PT_IEEE_IP) return peek_user(child, addr, data); if (request == PTRACE_POKEUSR && addr == PT_IEEE_IP) return poke_user(child, addr, data);#ifdef CONFIG_S390_SUPPORT if (request == PTRACE_PEEKUSR && addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT)) return peek_user_emu31(child, addr, data); if (request == PTRACE_POKEUSR && addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT)) return poke_user_emu31(child, addr, data);#endif } ret = ptrace_check_attach(child, request == PTRACE_KILL); if (ret < 0) return ret; switch (request) { case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: /* restart after signal. */ 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); child->exit_code = data; /* make sure the single step bit is not set. */ clear_single_step(child); wake_up_process(child); return 0; case PTRACE_KILL: /* * make the child exit. Best I can do is send it a sigkill. * perhaps it should be put in the status that it wants to * exit. */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */ return 0; child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ clear_single_step(child); wake_up_process(child); return 0; case PTRACE_SINGLESTEP: /* set the trap flag. */ if (!valid_signal(data)) return -EIO; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; if (data) set_tsk_thread_flag(child, TIF_SINGLE_STEP); else set_single_step(child); /* give it a chance to run. */ wake_up_process(child); return 0; case PTRACE_DETACH: /* detach a process that was attached. */ return ptrace_detach(child, data); /* Do requests that differ for 31/64 bit */ default:#ifdef CONFIG_S390_SUPPORT if (test_thread_flag(TIF_31BIT)) return do_ptrace_emu31(child, request, addr, data);#endif return do_ptrace_normal(child, request, addr, data); } /* Not reached. */ return -EIO;}asmlinkage longsys_ptrace(long request, long pid, long addr, long data){ struct task_struct *child; int ret; lock_kernel(); if (request == PTRACE_TRACEME) { /* are we already being traced? */ ret = -EPERM; if (current->ptrace & PT_PTRACED) goto out; ret = security_ptrace(current->parent, current); if (ret) goto out; /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; goto out; } ret = -EPERM; if (pid == 1) /* you may not mess with init */ goto out; ret = -ESRCH; read_lock(&tasklist_lock); child = find_task_by_pid(pid); if (child) get_task_struct(child); read_unlock(&tasklist_lock); if (!child) goto out; ret = do_ptrace(child, request, addr, data); put_task_struct(child);out: unlock_kernel(); return ret;}asmlinkage voidsyscall_trace(struct pt_regs *regs, int entryexit){ if (unlikely(current->audit_context) && entryexit) audit_syscall_exit(current, AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]); if (!test_thread_flag(TIF_SYSCALL_TRACE)) goto out; if (!(current->ptrace & PT_PTRACED)) goto out; ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); /* * If the debuffer has set an invalid system call number, * we prepare to skip the system call restart handling. */ if (!entryexit && regs->gprs[2] >= NR_syscalls) regs->trap = -1; /* * this isn't the same as continuing with a signal, but it will do * for normal use. strace only continues with a signal if the * stopping signal is not SIGTRAP. -brl */ if (current->exit_code) { send_sig(current->exit_code, current, 1); current->exit_code = 0; } out: if (unlikely(current->audit_context) && !entryexit) audit_syscall_entry(current, test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X, regs->gprs[2], regs->orig_gpr2, regs->gprs[3], regs->gprs[4], regs->gprs[5]);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -