RHEL4/kernel/ptrace.c
<<
>>
Prefs
   1/*
   2 * linux/kernel/ptrace.c
   3 *
   4 * (C) Copyright 1999 Linus Torvalds
   5 *
   6 * Common interfaces for "ptrace()" which we do not want
   7 * to continually duplicate across every architecture.
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/sched.h>
  12#include <linux/errno.h>
  13#include <linux/mm.h>
  14#include <linux/highmem.h>
  15#include <linux/pagemap.h>
  16#include <linux/smp_lock.h>
  17#include <linux/ptrace.h>
  18#include <linux/security.h>
  19
  20#include <asm/pgtable.h>
  21#include <asm/uaccess.h>
  22
  23/*
  24 * ptrace a task: make the debugger its new parent and
  25 * move it to the ptrace list.
  26 *
  27 * Must be called with the tasklist lock write-held.
  28 */
  29void __ptrace_link(task_t *child, task_t *new_parent)
  30{
  31        if (!list_empty(&child->ptrace_list))
  32                BUG();
  33        if (child->parent == new_parent)
  34                return;
  35        list_add(&child->ptrace_list, &child->parent->ptrace_children);
  36        REMOVE_LINKS(child);
  37        child->parent = new_parent;
  38        SET_LINKS(child);
  39}
  40 
  41static inline int pending_resume_signal(struct sigpending *pending)
  42{
  43#define M(sig) (1UL << ((sig)-1))
  44        return sigtestsetmask(&pending->signal, M(SIGCONT) | M(SIGKILL));
  45}
  46
  47/*
  48 * Turn a tracing stop into a normal stop now, since with no tracer there
  49 * would be no way to wake it up with SIGCONT or SIGKILL.  If there was a
  50 * signal sent that would resume the child, but didn't because it was in
  51 * TASK_TRACED, resume it now.
  52 */
  53void ptrace_untrace(task_t *child)
  54{
  55        spin_lock(&child->sighand->siglock);
  56        if (child->state == TASK_TRACED) {
  57                if (pending_resume_signal(&child->pending) ||
  58                    pending_resume_signal(&child->signal->shared_pending)) {
  59                        signal_wake_up(child, 1);
  60                } else {
  61                        child->state = TASK_STOPPED;
  62                }
  63        }
  64        spin_unlock(&child->sighand->siglock);
  65}
  66
  67/*
  68 * unptrace a task: move it back to its original parent and
  69 * remove it from the ptrace list.
  70 *
  71 * Must be called with the tasklist lock write-held.
  72 */
  73void __ptrace_unlink(task_t *child)
  74{
  75        if (!child->ptrace)
  76                BUG();
  77        child->ptrace = 0;
  78        if (!list_empty(&child->ptrace_list)) {
  79                list_del_init(&child->ptrace_list);
  80                REMOVE_LINKS(child);
  81                child->parent = child->real_parent;
  82                SET_LINKS(child);
  83        }
  84
  85        if (child->state == TASK_TRACED)
  86                ptrace_untrace(child);
  87}
  88
  89/*
  90 * Check that we have indeed attached to the thing..
  91 */
  92int ptrace_check_attach(struct task_struct *child, int kill)
  93{
  94        int ret = -ESRCH;
  95
  96        /*
  97         * We take the read lock around doing both checks to close a
  98         * possible race where someone else was tracing our child and
  99         * detached between these two checks.  After this locked check,
 100         * we are sure that this is our traced child and that can only
 101         * be changed by us so it's not changing right after this.
 102         */
 103        read_lock(&tasklist_lock);
 104        if ((child->ptrace & PT_PTRACED) && child->parent == current &&
 105            (!(child->ptrace & PT_ATTACHED) || child->real_parent != current)
 106            && child->signal != NULL) {
 107                ret = 0;
 108                spin_lock_irq(&child->sighand->siglock);
 109                if (child->state == TASK_STOPPED) {
 110                        child->state = TASK_TRACED;
 111                } else if (child->state != TASK_TRACED && !kill) {
 112                        ret = -ESRCH;
 113                }
 114                spin_unlock_irq(&child->sighand->siglock);
 115        }
 116        read_unlock(&tasklist_lock);
 117
 118        if (!ret && !kill) {
 119                wait_task_inactive(child);
 120        }
 121
 122        /* All systems go.. */
 123        return ret;
 124}
 125
 126int ptrace_attach(struct task_struct *task)
 127{
 128        int retval;
 129
 130        retval = -EPERM;
 131        if (task->pid <= 1)
 132                goto out;
 133        if (task == current)
 134                goto out;
 135
 136repeat:
 137        /*
 138         * Nasty, nasty.
 139         *
 140         * We want to hold both the task-lock and the
 141         * tasklist_lock for writing at the same time.
 142         * But that's against the rules (tasklist_lock
 143         * is taken for reading by interrupts on other
 144         * cpu's that may have task_lock).
 145         */
 146        task_lock(task);
 147        local_irq_disable();
 148        if (!write_trylock(&tasklist_lock)) {
 149                local_irq_enable();
 150                task_unlock(task);
 151                do {
 152                        cpu_relax();
 153                } while (rwlock_is_locked(&tasklist_lock));
 154                goto repeat;
 155        }
 156
 157        if (!task->mm)
 158                goto bad;
 159        if(((current->uid != task->euid) ||
 160            (current->uid != task->suid) ||
 161            (current->uid != task->uid) ||
 162            (current->gid != task->egid) ||
 163            (current->gid != task->sgid) ||
 164            (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
 165                goto bad;
 166        rmb();
 167        if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE))
 168                goto bad;
 169        /* the same process cannot be attached many times */
 170        if (task->ptrace & PT_PTRACED)
 171                goto bad;
 172        retval = security_ptrace(current, task);
 173        if (retval)
 174                goto bad;
 175
 176        /* Go */
 177        task->ptrace |= PT_PTRACED | ((task->real_parent != current)
 178                                      ? PT_ATTACHED : 0);
 179        if (capable(CAP_SYS_PTRACE))
 180                task->ptrace |= PT_PTRACE_CAP;
 181
 182        __ptrace_link(task, current);
 183
 184        force_sig_specific(SIGSTOP, task);
 185
 186bad:
 187        write_unlock_irq(&tasklist_lock);
 188        task_unlock(task);
 189out:
 190        return retval;
 191}
 192
 193void __ptrace_detach(struct task_struct *child, unsigned int data)
 194{
 195        /* .. re-parent .. */
 196        child->exit_code = data;
 197        __ptrace_unlink(child);
 198        /* .. and wake it up. */
 199        if (child->exit_state != EXIT_ZOMBIE)
 200                wake_up_process(child);
 201}
 202
 203int ptrace_detach(struct task_struct *child, unsigned int data)
 204{
 205        if ((unsigned long) data > _NSIG)
 206                return  -EIO;
 207
 208        /* Architecture-specific hardware disable .. */
 209        ptrace_disable(child);
 210        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 211
 212        write_lock_irq(&tasklist_lock);
 213        /* protect against de_thread()->release_task() */
 214        if (child->ptrace)
 215                __ptrace_detach(child, data);
 216        write_unlock_irq(&tasklist_lock);
 217
 218        return 0;
 219}
 220
 221/*
 222 * Access another process' address space.
 223 * Source/target buffer must be kernel space, 
 224 * Do not walk the page table directly, use get_user_pages
 225 */
 226
 227int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
 228{
 229        struct mm_struct *mm;
 230        struct vm_area_struct *vma;
 231        struct page *page;
 232        void *old_buf = buf;
 233
 234        mm = get_task_mm(tsk);
 235        if (!mm)
 236                return 0;
 237
 238        down_read(&mm->mmap_sem);
 239        /* ignore errors, just check how much was sucessfully transfered */
 240        while (len) {
 241                int bytes, ret, offset;
 242                void *maddr;
 243
 244                ret = get_user_pages(tsk, mm, addr, 1,
 245                                write, 1, &page, &vma);
 246                if (ret <= 0)
 247                        break;
 248
 249                bytes = len;
 250                offset = addr & (PAGE_SIZE-1);
 251                if (bytes > PAGE_SIZE-offset)
 252                        bytes = PAGE_SIZE-offset;
 253
 254                maddr = kmap(page);
 255                if (write) {
 256                        copy_to_user_page(vma, page, addr,
 257                                          maddr + offset, buf, bytes);
 258                        if (!PageCompound(page))
 259                                set_page_dirty_lock(page);
 260                } else {
 261                        copy_from_user_page(vma, page, addr,
 262                                            buf, maddr + offset, bytes);
 263                }
 264                kunmap(page);
 265                page_cache_release(page);
 266                len -= bytes;
 267                buf += bytes;
 268                addr += bytes;
 269        }
 270        up_read(&mm->mmap_sem);
 271        mmput(mm);
 272        
 273        return buf - old_buf;
 274}
 275
 276int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
 277{
 278        int copied = 0;
 279
 280        while (len > 0) {
 281                char buf[128];
 282                int this_len, retval;
 283
 284                this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
 285                retval = access_process_vm(tsk, src, buf, this_len, 0);
 286                if (!retval) {
 287                        if (copied)
 288                                break;
 289                        return -EIO;
 290                }
 291                if (copy_to_user(dst, buf, retval))
 292                        return -EFAULT;
 293                copied += retval;
 294                src += retval;
 295                dst += retval;
 296                len -= retval;                  
 297        }
 298        return copied;
 299}
 300
 301int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len)
 302{
 303        int copied = 0;
 304
 305        while (len > 0) {
 306                char buf[128];
 307                int this_len, retval;
 308
 309                this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
 310                if (copy_from_user(buf, src, this_len))
 311                        return -EFAULT;
 312                retval = access_process_vm(tsk, dst, buf, this_len, 1);
 313                if (!retval) {
 314                        if (copied)
 315                                break;
 316                        return -EIO;
 317                }
 318                copied += retval;
 319                src += retval;
 320                dst += retval;
 321                len -= retval;                  
 322        }
 323        return copied;
 324}
 325
 326static int ptrace_setoptions(struct task_struct *child, long data)
 327{
 328        child->ptrace &= ~PT_TRACE_MASK;
 329
 330        if (data & PTRACE_O_TRACESYSGOOD)
 331                child->ptrace |= PT_TRACESYSGOOD;
 332
 333        if (data & PTRACE_O_TRACEFORK)
 334                child->ptrace |= PT_TRACE_FORK;
 335
 336        if (data & PTRACE_O_TRACEVFORK)
 337                child->ptrace |= PT_TRACE_VFORK;
 338
 339        if (data & PTRACE_O_TRACECLONE)
 340                child->ptrace |= PT_TRACE_CLONE;
 341
 342        if (data & PTRACE_O_TRACEEXEC)
 343                child->ptrace |= PT_TRACE_EXEC;
 344
 345        if (data & PTRACE_O_TRACEVFORKDONE)
 346                child->ptrace |= PT_TRACE_VFORK_DONE;
 347
 348        if (data & PTRACE_O_TRACEEXIT)
 349                child->ptrace |= PT_TRACE_EXIT;
 350
 351        return (data & ~PTRACE_O_MASK) ? -EINVAL : 0;
 352}
 353
 354static int ptrace_getsiginfo(struct task_struct *child, siginfo_t __user * data)
 355{
 356        siginfo_t lastinfo;
 357        int error = -ESRCH;
 358
 359        read_lock(&tasklist_lock);
 360        if (likely(child->sighand != NULL)) {
 361                error = -EINVAL;
 362                spin_lock_irq(&child->sighand->siglock);
 363                if (likely(child->last_siginfo != NULL)) {
 364                        lastinfo = *child->last_siginfo;
 365                        error = 0;
 366                }
 367                spin_unlock_irq(&child->sighand->siglock);
 368        }
 369        read_unlock(&tasklist_lock);
 370        if (!error)
 371                return copy_siginfo_to_user(data, &lastinfo);
 372        return error;
 373}
 374
 375static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data)
 376{
 377        siginfo_t newinfo;
 378        int error = -ESRCH;
 379
 380        if (copy_from_user(&newinfo, data, sizeof (siginfo_t)))
 381                return -EFAULT;
 382
 383        read_lock(&tasklist_lock);
 384        if (likely(child->sighand != NULL)) {
 385                error = -EINVAL;
 386                spin_lock_irq(&child->sighand->siglock);
 387                if (likely(child->last_siginfo != NULL)) {
 388                        *child->last_siginfo = newinfo;
 389                        error = 0;
 390                }
 391                spin_unlock_irq(&child->sighand->siglock);
 392        }
 393        read_unlock(&tasklist_lock);
 394        return error;
 395}
 396
 397int ptrace_request(struct task_struct *child, long request,
 398                   long addr, long data)
 399{
 400        int ret = -EIO;
 401
 402        switch (request) {
 403#ifdef PTRACE_OLDSETOPTIONS
 404        case PTRACE_OLDSETOPTIONS:
 405#endif
 406        case PTRACE_SETOPTIONS:
 407                ret = ptrace_setoptions(child, data);
 408                break;
 409        case PTRACE_GETEVENTMSG:
 410                ret = put_user(child->ptrace_message, (unsigned long __user *) data);
 411                break;
 412        case PTRACE_GETSIGINFO:
 413                ret = ptrace_getsiginfo(child, (siginfo_t __user *) data);
 414                break;
 415        case PTRACE_SETSIGINFO:
 416                ret = ptrace_setsiginfo(child, (siginfo_t __user *) data);
 417                break;
 418        default:
 419                break;
 420        }
 421
 422        return ret;
 423}
 424