From 4b4633062461248be91d450d990c41a6d60ec7bc Mon Sep 17 00:00:00 2001 From: Tomoki Shirasawa Date: Wed, 8 Oct 2014 14:56:28 +0900 Subject: [PATCH] support ptrace(PTRACE_PEEKUSER, ...) --- arch/x86/kernel/syscall.c | 51 +++++++++++++++++++++++++++-- kernel/include/process.h | 67 +++++++++++++++++++++++++++++++++++++++ kernel/syscall.c | 30 ++++++++++++++++-- 3 files changed, 144 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/syscall.c b/arch/x86/kernel/syscall.c index 390e857a..6afde263 100644 --- a/arch/x86/kernel/syscall.c +++ b/arch/x86/kernel/syscall.c @@ -195,6 +195,52 @@ do_setpgid(int pid, int pgid) } } +void +peekuser(struct process *proc, void *regs0) +{ + struct x86_regs *regs = regs0; + + if(regs == NULL){ + asm("movq %%gs:132, %0" : "=r" (regs)); + --regs; + } + if(proc->userp == NULL){ + proc->userp = kmalloc(sizeof(struct user), IHK_MC_AP_NOWAIT); + memset(proc->userp, '\0', sizeof(struct user)); + } + asm("mov %%db0, %0" :"=r" (proc->userp->u_debugreg[0])); + asm("mov %%db1, %0" :"=r" (proc->userp->u_debugreg[1])); + asm("mov %%db2, %0" :"=r" (proc->userp->u_debugreg[2])); + asm("mov %%db3, %0" :"=r" (proc->userp->u_debugreg[3])); +// asm("mov %%db4, %0" :"=r" (proc->userp->u_debugreg[4])); +// asm("mov %%db5, %0" :"=r" (proc->userp->u_debugreg[5])); + asm("mov %%db6, %0" :"=r" (proc->userp->u_debugreg[6])); + asm("mov %%db7, %0" :"=r" (proc->userp->u_debugreg[7])); + proc->userp->regs.r15 = regs->r15; + proc->userp->regs.r14 = regs->r14; + proc->userp->regs.r13 = regs->r13; + proc->userp->regs.r12 = regs->r12; + proc->userp->regs.rbp = regs->rbp; + proc->userp->regs.rbx = regs->rbx; + proc->userp->regs.r11 = regs->r11; + proc->userp->regs.r10 = regs->r10; + proc->userp->regs.r9 = regs->r9; + proc->userp->regs.r8 = regs->r8; + proc->userp->regs.rax = regs->rax; + proc->userp->regs.rcx = regs->rcx; + proc->userp->regs.rdx = regs->rdx; + proc->userp->regs.rsi = regs->rsi; + proc->userp->regs.rdi = regs->rdi; + proc->userp->regs.rip = regs->rip; + proc->userp->regs.cs = regs->cs; + proc->userp->regs.eflags = regs->rflags; + proc->userp->regs.rsp = regs->rsp; + proc->userp->regs.ss = regs->ss; + asm("mov %%es, %0" :"=r" (proc->userp->regs.es)); + asm("mov %%fs, %0" :"=r" (proc->userp->regs.fs)); + asm("mov %%gs, %0" :"=r" (proc->userp->regs.gs)); +} + extern void coredump(struct process *proc, void *regs); void @@ -358,7 +404,7 @@ do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pendin } } -static int ptrace_report_signal(struct process *proc, struct sig_pending *pending) +static int ptrace_report_signal(struct process *proc, struct x86_regs *regs, struct sig_pending *pending) { int sig; __sigset_t w; @@ -395,6 +441,7 @@ static int ptrace_report_signal(struct process *proc, struct sig_pending *pendin waitq_wakeup(&proc->ftn->parent->waitpid_q); } + peekuser(proc, regs); dkprintf("ptrace_report_signal,sleeping\n"); /* Sleep */ proc->status = PS_TRACED; @@ -464,7 +511,7 @@ check_signal(unsigned long rc, void *regs0) for(sig_bv = pending->sigmask.__val[0], sig = 0; sig_bv; sig++, sig_bv >>= 1); if((proc->ftn->ptrace & PT_TRACED) && sig != SIGKILL) { - sig = ptrace_report_signal(proc, pending); + sig = ptrace_report_signal(proc, regs, pending); /* TODO: Tracing process could overwrite signal, so handle the case here. */ } diff --git a/kernel/include/process.h b/kernel/include/process.h index 2789409a..783af72d 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -143,6 +143,71 @@ #include #include +struct user_fpregs_struct +{ + unsigned short cwd; + unsigned short swd; + unsigned short ftw; + unsigned short fop; + unsigned long rip; + unsigned long rdp; + unsigned int mxcsr; + unsigned int mxcr_mask; + unsigned int st_space[32]; + unsigned int xmm_space[64]; + unsigned int padding[24]; +}; + +struct user_regs_struct +{ + unsigned long r15; + unsigned long r14; + unsigned long r13; + unsigned long r12; + unsigned long rbp; + unsigned long rbx; + unsigned long r11; + unsigned long r10; + unsigned long r9; + unsigned long r8; + unsigned long rax; + unsigned long rcx; + unsigned long rdx; + unsigned long rsi; + unsigned long rdi; + unsigned long orig_rax; + unsigned long rip; + unsigned long cs; + unsigned long eflags; + unsigned long rsp; + unsigned long ss; + unsigned long fs_base; + unsigned long gs_base; + unsigned long ds; + unsigned long es; + unsigned long fs; + unsigned long gs; +}; + +struct user +{ + struct user_regs_struct regs; + int u_fpvalid; + struct user_fpregs_struct i387; + unsigned long int u_tsize; + unsigned long int u_dsize; + unsigned long int u_ssize; + unsigned long start_code; + unsigned long start_stack; + long int signal; + int reserved; + struct user_regs_struct* u_ar0; + struct user_fpregs_struct* u_fpstate; + unsigned long int magic; + char u_comm [32]; + unsigned long int u_debugreg [8]; +}; + #define AUXV_LEN 14 struct vm_range { @@ -273,6 +338,8 @@ struct process { cpu_set_t cpu_set; unsigned long saved_auxv[AUXV_LEN]; int pgid; /* process group id */ + + struct user *userp; }; struct process_vm { diff --git a/kernel/syscall.c b/kernel/syscall.c index c2a3ca6b..d7ad798f 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -1379,6 +1379,8 @@ SYSCALL_DECLARE(arch_prctl) ihk_mc_syscall_arg1(ctx)); } +extern void peekuser(struct process *proc, void *regs); + static int ptrace_report_exec(struct process *proc) { dkprintf("ptrace_report_exec,enter\n"); @@ -1429,7 +1431,8 @@ static int ptrace_report_exec(struct process *proc) /* Wake parent (if sleeping in wait4()) */ waitq_wakeup(&proc->ftn->parent->waitpid_q); } - + + peekuser(proc, NULL); /* Sleep */ dkprintf("ptrace_report_exec,sleeping\n"); proc->status = PS_TRACED; @@ -2375,13 +2378,32 @@ out: return error; } +static long ptrace_peekuser(int pid, long addr) +{ + long rc = -EIO; + struct process *child; + ihk_spinlock_t *savelock; + unsigned long irqstate; + + if(addr > sizeof(struct user) || addr < 0) + return -EFAULT; + child = findthread_and_lock(pid, -1, &savelock, &irqstate); + if (!child) + return -ESRCH; + if(child->status == PS_TRACED) + memcpy(&rc, (char *)child->userp + addr, 8); + ihk_mc_spinlock_unlock(savelock, irqstate); + + return rc; +} + SYSCALL_DECLARE(ptrace) { const long request = (long)ihk_mc_syscall_arg0(ctx); const int pid = (int)ihk_mc_syscall_arg1(ctx); const long addr = (long)ihk_mc_syscall_arg2(ctx); const long data = (long)ihk_mc_syscall_arg3(ctx); - int error; + long error = -EOPNOTSUPP; switch(request) { case PTRACE_TRACEME: @@ -2393,6 +2415,10 @@ SYSCALL_DECLARE(ptrace) dkprintf("ptrace: PTRACE_KILL/CONT\n"); error = ptrace_wakeup_sig(pid, request, data); break; + case PTRACE_PEEKUSER: + error = ptrace_peekuser(pid, addr); + dkprintf("PTRACE_PEEKUSER: addr=%p return=%p\n", addr, error); + break; default: dkprintf("ptrace: unimplemented ptrace called.\n"); break;