diff options
Diffstat (limited to 'arch/sparc64/kernel/ptrace.c')
-rw-r--r-- | arch/sparc64/kernel/ptrace.c | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 4063a1e86..4dd9651b3 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -591,6 +591,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs) if (((current->personality & PER_BSD) && (request == PTRACE_SUNATTACH)) || (!(current->personality & PER_BSD) && (request == PTRACE_ATTACH))) { + unsigned long flags; + if(child == current) { /* Try this under SunOS/Solaris, bwa haha * You'll never be able to kill the process. ;-) @@ -602,8 +604,9 @@ asmlinkage void do_ptrace(struct pt_regs *regs) (current->uid != child->euid) || (current->uid != child->uid) || (current->gid != child->egid) || - (current->gid != child->gid)) && - !capable(CAP_SYS_PTRACE)) { + (current->gid != child->sgid) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) { pt_error_return(regs, EPERM); goto out; } @@ -613,15 +616,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs) goto out; } child->flags |= PF_PTRACED; + write_lock_irqsave(&tasklist_lock, flags); if(child->p_pptr != current) { - unsigned long flags; - - write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); child->p_pptr = current; SET_LINKS(child); - write_unlock_irqrestore(&tasklist_lock, flags); } + write_unlock_irqrestore(&tasklist_lock, flags); send_sig(SIGSTOP, child, 1); pt_succ_return(regs, 0); goto out; @@ -670,14 +671,18 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, EINVAL); goto out; } + down(&child->mm->mmap_sem); res = read_int(child, addr, &x); + up(&child->mm->mmap_sem); tmp = x; } else { if(addr & (sizeof(unsigned long) - 1)) { pt_error_return(regs, EINVAL); goto out; } + down(&child->mm->mmap_sem); res = read_long(child, addr, &tmp); + up(&child->mm->mmap_sem); } if (res < 0) { pt_error_return(regs, -res); @@ -709,13 +714,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, EINVAL); goto out; } + down(&child->mm->mmap_sem); res = write_int(child, addr, data); + up(&child->mm->mmap_sem); } else { if(addr & (sizeof(unsigned long) - 1)) { pt_error_return(regs, EINVAL); goto out; } + down(&child->mm->mmap_sem); res = write_long(child, addr, data); + up(&child->mm->mmap_sem); } if(res < 0) pt_error_return(regs, -res); @@ -944,12 +953,15 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned long page; while(len) { + down(&child->mm->mmap_sem); vma = find_extend_vma(child, src); if (!vma) { + up(&child->mm->mmap_sem); pt_error_return(regs, EIO); goto flush_and_out; } pgtable = get_page (child, vma, src, 0); + up(&child->mm->mmap_sem); if (src & ~PAGE_MASK) { curlen = PAGE_SIZE - (src & ~PAGE_MASK); if (curlen > len) curlen = len; @@ -988,12 +1000,15 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned long page; while(len) { + down(&child->mm->mmap_sem); vma = find_extend_vma(child, dest); if (!vma) { + up(&child->mm->mmap_sem); pt_error_return(regs, EIO); goto flush_and_out; } pgtable = get_page (child, vma, dest, 1); + up(&child->mm->mmap_sem); if (dest & ~PAGE_MASK) { curlen = PAGE_SIZE - (dest & ~PAGE_MASK); if (curlen > len) curlen = len; |