X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fsparc64%2Fkernel%2Fptrace.c;h=ded40464e4d1bc557d4fe9803e3ab57d708da7b6;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=f493d031fd6b6da7bf21cd6d37ee8887e2beb708;hpb=cee37fe97739d85991964371c1f3a745c00dd236;p=linux-2.6.git diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index f493d031f..ded40464e 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include @@ -28,6 +30,8 @@ #include #include #include +#include +#include /* Returning from ptrace is a bit tricky because the syscall return * low level code assumes any value returned which is negative and @@ -120,26 +124,33 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, { BUG_ON(len > PAGE_SIZE); + if (tlb_type == hypervisor) + return; + #ifdef DCACHE_ALIASING_POSSIBLE /* If bit 13 of the kernel address we used to access the * user page is the same as the virtual address that page * is mapped to in the user's address space, we can skip the * D-cache flush. */ - if ((uaddr ^ kaddr) & (1UL << 13)) { + if ((uaddr ^ (unsigned long) kaddr) & (1UL << 13)) { unsigned long start = __pa(kaddr); unsigned long end = start + len; + unsigned long dcache_line_size; + + dcache_line_size = local_cpu_data().dcache_line_size; if (tlb_type == spitfire) { - for (; start < end; start += 32) - spitfire_put_dcache_tag(va & 0x3fe0, 0x0); + for (; start < end; start += dcache_line_size) + spitfire_put_dcache_tag(start & 0x3fe0, 0x0); } else { - for (; start < end; start += 32) + start &= ~(dcache_line_size - 1); + for (; start < end; start += dcache_line_size) __asm__ __volatile__( "stxa %%g0, [%0] %1\n\t" "membar #Sync" : /* no outputs */ - : "r" (va), + : "r" (start), "i" (ASI_DCACHE_INVALIDATE)); } } @@ -147,8 +158,11 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, if (write && tlb_type == spitfire) { unsigned long start = (unsigned long) kaddr; unsigned long end = start + len; + unsigned long icache_line_size; - for (; start < end; start += 32) + icache_line_size = local_cpu_data().icache_line_size; + + for (; start < end; start += icache_line_size) flushi(start); } } @@ -187,39 +201,15 @@ asmlinkage void do_ptrace(struct pt_regs *regs) } #endif if (request == PTRACE_TRACEME) { - int ret; - - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) { - pt_error_return(regs, EPERM); - goto out; - } - ret = security_ptrace(current->parent, current); - if (ret) { - pt_error_return(regs, -ret); - goto out; - } - - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; + ret = ptrace_traceme(); pt_succ_return(regs, 0); goto out; } -#ifndef ALLOW_INIT_TRACING - if (pid == 1) { - /* Can't dork with init. */ - pt_error_return(regs, EPERM); - goto out; - } -#endif - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) { - pt_error_return(regs, ESRCH); + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); + pt_error_return(regs, -ret); goto out; } if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) { @@ -258,6 +248,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs) } switch(request) { + case PTRACE_PEEKUSR: + if (addr != 0) + pt_error_return(regs, EIO); + else + pt_succ_return(regs, 0); + goto out_tsk; + case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp64; @@ -313,7 +310,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) case PTRACE_GETREGS: { struct pt_regs32 __user *pregs = (struct pt_regs32 __user *) addr; - struct pt_regs *cregs = child->thread_info->kregs; + struct pt_regs *cregs = task_pt_regs(child); int rval; if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) || @@ -337,11 +334,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs) case PTRACE_GETREGS64: { struct pt_regs __user *pregs = (struct pt_regs __user *) addr; - struct pt_regs *cregs = child->thread_info->kregs; + struct pt_regs *cregs = task_pt_regs(child); unsigned long tpc = cregs->tpc; int rval; - if ((child->thread_info->flags & _TIF_32BIT) != 0) + if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) tpc &= 0xffffffff; if (__put_user(cregs->tstate, (&pregs->tstate)) || __put_user(tpc, (&pregs->tpc)) || @@ -365,7 +362,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) case PTRACE_SETREGS: { struct pt_regs32 __user *pregs = (struct pt_regs32 __user *) addr; - struct pt_regs *cregs = child->thread_info->kregs; + struct pt_regs *cregs = task_pt_regs(child); unsigned int psr, pc, npc, y; int i; @@ -398,7 +395,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) case PTRACE_SETREGS64: { struct pt_regs __user *pregs = (struct pt_regs __user *) addr; - struct pt_regs *cregs = child->thread_info->kregs; + struct pt_regs *cregs = task_pt_regs(child); unsigned long tstate, tpc, tnpc, y; int i; @@ -412,7 +409,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, EFAULT); goto out_tsk; } - if ((child->thread_info->flags & _TIF_32BIT) != 0) { + if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) { tpc &= 0xffffffff; tnpc &= 0xffffffff; } @@ -447,11 +444,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs) } fpq[16]; }; struct fps __user *fps = (struct fps __user *) addr; - unsigned long *fpregs = child->thread_info->fpregs; + unsigned long *fpregs = task_thread_info(child)->fpregs; if (copy_to_user(&fps->regs[0], fpregs, (32 * sizeof(unsigned int))) || - __put_user(child->thread_info->xfsr[0], (&fps->fsr)) || + __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr)) || __put_user(0, (&fps->fpqd)) || __put_user(0, (&fps->flags)) || __put_user(0, (&fps->extra)) || @@ -469,11 +466,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned long fsr; }; struct fps __user *fps = (struct fps __user *) addr; - unsigned long *fpregs = child->thread_info->fpregs; + unsigned long *fpregs = task_thread_info(child)->fpregs; if (copy_to_user(&fps->regs[0], fpregs, (64 * sizeof(unsigned int))) || - __put_user(child->thread_info->xfsr[0], (&fps->fsr))) { + __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) { pt_error_return(regs, EFAULT); goto out_tsk; } @@ -494,7 +491,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) } fpq[16]; }; struct fps __user *fps = (struct fps __user *) addr; - unsigned long *fpregs = child->thread_info->fpregs; + unsigned long *fpregs = task_thread_info(child)->fpregs; unsigned fsr; if (copy_from_user(fpregs, &fps->regs[0], @@ -503,11 +500,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, EFAULT); goto out_tsk; } - child->thread_info->xfsr[0] &= 0xffffffff00000000UL; - child->thread_info->xfsr[0] |= fsr; - if (!(child->thread_info->fpsaved[0] & FPRS_FEF)) - child->thread_info->gsr[0] = 0; - child->thread_info->fpsaved[0] |= (FPRS_FEF | FPRS_DL); + task_thread_info(child)->xfsr[0] &= 0xffffffff00000000UL; + task_thread_info(child)->xfsr[0] |= fsr; + if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF)) + task_thread_info(child)->gsr[0] = 0; + task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL); pt_succ_return(regs, 0); goto out_tsk; } @@ -518,17 +515,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned long fsr; }; struct fps __user *fps = (struct fps __user *) addr; - unsigned long *fpregs = child->thread_info->fpregs; + unsigned long *fpregs = task_thread_info(child)->fpregs; if (copy_from_user(fpregs, &fps->regs[0], (64 * sizeof(unsigned int))) || - __get_user(child->thread_info->xfsr[0], (&fps->fsr))) { + __get_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) { pt_error_return(regs, EFAULT); goto out_tsk; } - if (!(child->thread_info->fpsaved[0] & FPRS_FEF)) - child->thread_info->gsr[0] = 0; - child->thread_info->fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU); + if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF)) + task_thread_info(child)->gsr[0] = 0; + task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU); pt_succ_return(regs, 0); goto out_tsk; } @@ -579,8 +576,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs) #ifdef DEBUG_PTRACE printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm, child->pid, child->exit_code, - child->thread_info->kregs->tpc, - child->thread_info->kregs->tnpc); + task_pt_regs(child)->tpc, + task_pt_regs(child)->tnpc); #endif wake_up_process(child); @@ -616,6 +613,22 @@ asmlinkage void do_ptrace(struct pt_regs *regs) /* PTRACE_DUMPCORE unsupported... */ + case PTRACE_GETEVENTMSG: { + int err; + + if (test_thread_flag(TIF_32BIT)) + err = put_user(child->ptrace_message, + (unsigned int __user *) data); + else + err = put_user(child->ptrace_message, + (unsigned long __user *) data); + if (err) + pt_error_return(regs, -err); + else + pt_succ_return(regs, 0); + break; + } + default: { int err = ptrace_request(child, request, addr, data); if (err) @@ -632,15 +645,27 @@ out: unlock_kernel(); } -asmlinkage void syscall_trace(void) +asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p) { -#ifdef DEBUG_PTRACE - printk("%s [%d]: syscall_trace\n", current->comm, current->pid); -#endif - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; + /* do the secure computing check first */ + secure_computing(regs->u_regs[UREG_G1]); + + if (unlikely(current->audit_context) && syscall_exit_p) { + unsigned long tstate = regs->tstate; + int result = AUDITSC_SUCCESS; + + if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) + result = AUDITSC_FAILURE; + + audit_syscall_exit(result, regs->u_regs[UREG_I0]); + } + if (!(current->ptrace & PT_PTRACED)) - return; + goto out; + + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + goto out; + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); @@ -649,12 +674,19 @@ asmlinkage void syscall_trace(void) * for normal use. strace only continues with a signal if the * stopping signal is not SIGTRAP. -brl */ -#ifdef DEBUG_PTRACE - printk("%s [%d]: syscall_trace exit= %x\n", current->comm, - current->pid, current->exit_code); -#endif if (current->exit_code) { - send_sig (current->exit_code, current, 1); + send_sig(current->exit_code, current, 1); current->exit_code = 0; } + +out: + if (unlikely(current->audit_context) && !syscall_exit_p) + audit_syscall_entry((test_thread_flag(TIF_32BIT) ? + AUDIT_ARCH_SPARC : + AUDIT_ARCH_SPARC64), + regs->u_regs[UREG_G1], + regs->u_regs[UREG_I0], + regs->u_regs[UREG_I1], + regs->u_regs[UREG_I2], + regs->u_regs[UREG_I3]); }