linux/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/capability.h>
  11#include <linux/module.h>
  12#include <linux/sched.h>
  13#include <linux/errno.h>
  14#include <linux/mm.h>
  15#include <linux/highmem.h>
  16#include <linux/pagemap.h>
  17#include <linux/smp_lock.h>
  18#include <linux/ptrace.h>
  19#include <linux/security.h>
  20#include <linux/signal.h>
  21
  22#include <asm/pgtable.h>
  23#include <asm/uaccess.h>
  24
  25/*
  26 * ptrace a task: make the debugger its new parent and
  27 * move it to the ptrace list.
  28 *
  29 * Must be called with the tasklist lock write-held.
  30 */
  31void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
  32{
  33        BUG_ON(!list_empty(&child->ptrace_list));
  34        if (child->parent == new_parent)
  35                return;
  36        list_add(&child->ptrace_list, &child->parent->ptrace_children);
  37        remove_parent(child);
  38        child->parent = new_parent;
  39        add_parent(child);
  40}
  41 
  42/*
  43 * Turn a tracing stop into a normal stop now, since with no tracer there
  44 * would be no way to wake it up with SIGCONT or SIGKILL.  If there was a
  45 * signal sent that would resume the child, but didn't because it was in
  46 * TASK_TRACED, resume it now.
  47 * Requires that irqs be disabled.
  48 */
  49void ptrace_untrace(struct task_struct *child)
  50{
  51        spin_lock(&child->sighand->siglock);
  52        if (child->state == TASK_TRACED) {
  53                if (child->signal->flags & SIGNAL_STOP_STOPPED) {
  54                        child->state = TASK_STOPPED;
  55                } else {
  56                        signal_wake_up(child, 1);
  57                }
  58        }
  59        spin_unlock(&child->sighand->siglock);
  60}
  61
  62/*
  63 * unptrace a task: move it back to its original parent and
  64 * remove it from the ptrace list.
  65 *
  66 * Must be called with the tasklist lock write-held.
  67 */
  68void __ptrace_unlink(struct task_struct *child)
  69{
  70        BUG_ON(!child->ptrace);
  71
  72        child->ptrace = 0;
  73        if (!list_empty(&child->ptrace_list)) {
  74                list_del_init(&child->ptrace_list);
  75                remove_parent(child);
  76                child->parent = child->real_parent;
  77                add_parent(child);
  78        }
  79
  80        if (child->state == TASK_TRACED)
  81                ptrace_untrace(child);
  82}
  83
  84/*
  85 * Check that we have indeed attached to the thing..
  86 */
  87int ptrace_check_attach(struct task_struct *child, int kill)
  88{
  89        int ret = -ESRCH;
  90
  91        /*
  92         * We take the read lock around doing both checks to close a
  93         * possible race where someone else was tracing our child and
  94         * detached between these two checks.  After this locked check,
  95         * we are sure that this is our traced child and that can only
  96         * be changed by us so it's not changing right after this.
  97         */
  98        read_lock(&tasklist_lock);
  99        if ((child->ptrace & PT_PTRACED) && child->parent == current &&
 100            (!(child->ptrace & PT_ATTACHED) || child->real_parent != current)
 101            && child->signal != NULL) {
 102                ret = 0;
 103                spin_lock_irq(&child->sighand->siglock);
 104                if (child->state == TASK_STOPPED) {
 105                        child->state = TASK_TRACED;
 106                } else if (child->state != TASK_TRACED && !kill) {
 107                        ret = -ESRCH;
 108                }
 109                spin_unlock_irq(&child->sighand->siglock);
 110        }
 111        read_unlock(&tasklist_lock);
 112
 113        if (!ret && !kill) {
 114                wait_task_inactive(child);
 115        }
 116
 117        /* All systems go.. */
 118        return ret;
 119}
 120
 121static int may_attach(struct task_struct *task)
 122{
 123        /* May we inspect the given task?
 124         * This check is used both for attaching with ptrace
 125         * and for allowing access to sensitive information in /proc.
 126         *
 127         * ptrace_attach denies several cases that /proc allows
 128         * because setting up the necessary parent/child relationship
 129         * or halting the specified task is impossible.
 130         */
 131        int dumpable = 0;
 132        /* Don't let security modules deny introspection */
 133        if (task == current)
 134                return 0;
 135        if (((current->uid != task->euid) ||
 136             (current->uid != task->suid) ||
 137             (current->uid != task->uid) ||
 138             (current->gid != task->egid) ||
 139             (current->gid != task->sgid) ||
 140             (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
 141                return -EPERM;
 142        smp_rmb();
 143        if (task->mm)
 144                dumpable = task->mm->dumpable;
 145        if (!dumpable && !capable(CAP_SYS_PTRACE))
 146                return -EPERM;
 147
 148        return security_ptrace(current, task);
 149}
 150
 151int ptrace_may_attach(struct task_struct *task)
 152{
 153        int err;
 154        task_lock(task);
 155        err = may_attach(task);
 156        task_unlock(task);
 157        return !err;
 158}
 159
 160int ptrace_attach(struct task_struct *task)
 161{
 162        int retval;
 163
 164        retval = -EPERM;
 165        if (task->pid <= 1)
 166                goto out;
 167        if (task->tgid == current->tgid)
 168                goto out;
 169
 170repeat:
 171        /*
 172         * Nasty, nasty.
 173         *
 174         * We want to hold both the task-lock and the
 175         * tasklist_lock for writing at the same time.
 176         * But that's against the rules (tasklist_lock
 177         * is taken for reading by interrupts on other
 178         * cpu's that may have task_lock).
 179         */
 180        task_lock(task);
 181        local_irq_disable();
 182        if (!write_trylock(&tasklist_lock)) {
 183                local_irq_enable();
 184                task_unlock(task);
 185                do {
 186                        cpu_relax();
 187                } while (!write_can_lock(&tasklist_lock));
 188                goto repeat;
 189        }
 190
 191        if (!task->mm)
 192                goto bad;
 193        /* the same process cannot be attached many times */
 194        if (task->ptrace & PT_PTRACED)
 195                goto bad;
 196        retval = may_attach(task);
 197        if (retval)
 198                goto bad;
 199
 200        /* Go */
 201        task->ptrace |= PT_PTRACED | ((task->real_parent != current)
 202                                      ? PT_ATTACHED : 0);
 203        if (capable(CAP_SYS_PTRACE))
 204                task->ptrace |= PT_PTRACE_CAP;
 205
 206        __ptrace_link(task, current);
 207
 208        force_sig_specific(SIGSTOP, task);
 209
 210bad:
 211        write_unlock_irq(&tasklist_lock);
 212        task_unlock(task);
 213out:
 214        return retval;
 215}
 216
 217static inline void __ptrace_detach(struct task_struct *child, unsigned int data)
 218{
 219        child->exit_code = data;
 220        /* .. re-parent .. */
 221        __ptrace_unlink(child);
 222        /* .. and wake it up. */
 223        if (child->exit_state != EXIT_ZOMBIE)
 224                wake_up_process(child);
 225}
 226
 227int ptrace_detach(struct task_struct *child, unsigned int data)
 228{
 229        if (!valid_signal(data))
 230                return -EIO;
 231
 232        /* Architecture-specific hardware disable .. */
 233        ptrace_disable(child);
 234
 235        write_lock_irq(&tasklist_lock);
 236        /* protect against de_thread()->release_task() */
 237        if (child->ptrace)
 238                __ptrace_detach(child, data);
 239        write_unlock_irq(&tasklist_lock);
 240
 241        return 0;
 242}
 243
 244int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
 245{
 246        int copied = 0;
 247
 248        while (len > 0) {
 249                char buf[128];
 250                int this_len, retval;
 251
 252                this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
 253                retval = access_process_vm(tsk, src, buf, this_len, 0);
 254                if (!retval) {
 255                        if (copied)
 256                                break;
 257                        return -EIO;
 258                }
 259                if (copy_to_user(dst, buf, retval))
 260                        return -EFAULT;
 261                copied += retval;
 262                src += retval;
 263                dst += retval;
 264                len -= retval;                  
 265        }
 266        return copied;
 267}
 268
 269int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len)
 270{
 271        int copied = 0;
 272
 273        while (len > 0) {
 274                char buf[128];
 275                int this_len, retval;
 276
 277                this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
 278                if (copy_from_user(buf, src, this_len))
 279                        return -EFAULT;
 280                retval = access_process_vm(tsk, dst, buf, this_len, 1);
 281                if (!retval) {
 282                        if (copied)
 283                                break;
 284                        return -EIO;
 285                }
 286                copied += retval;
 287                src += retval;
 288                dst += retval;
 289                len -= retval;                  
 290        }
 291        return copied;
 292}
 293
 294static int ptrace_setoptions(struct task_struct *child, long data)
 295{
 296        child->ptrace &= ~PT_TRACE_MASK;
 297
 298        if (data & PTRACE_O_TRACESYSGOOD)
 299                child->ptrace |= PT_TRACESYSGOOD;
 300
 301        if (data & PTRACE_O_TRACEFORK)
 302                child->ptrace |= PT_TRACE_FORK;
 303
 304        if (data & PTRACE_O_TRACEVFORK)
 305                child->ptrace |= PT_TRACE_VFORK;
 306
 307        if (data & PTRACE_O_TRACECLONE)
 308                child->ptrace |= PT_TRACE_CLONE;
 309
 310        if (data & PTRACE_O_TRACEEXEC)
 311                child->ptrace |= PT_TRACE_EXEC;
 312
 313        if (data & PTRACE_O_TRACEVFORKDONE)
 314                child->ptrace |= PT_TRACE_VFORK_DONE;
 315
 316        if (data & PTRACE_O_TRACEEXIT)
 317                child->ptrace |= PT_TRACE_EXIT;
 318
 319        return (data & ~PTRACE_O_MASK) ? -EINVAL : 0;
 320}
 321
 322static int ptrace_getsiginfo(struct task_struct *child, siginfo_t __user * data)
 323{
 324        siginfo_t lastinfo;
 325        int error = -ESRCH;
 326
 327        read_lock(&tasklist_lock);
 328        if (likely(child->sighand != NULL)) {
 329                error = -EINVAL;
 330                spin_lock_irq(&child->sighand->siglock);
 331                if (likely(child->last_siginfo != NULL)) {
 332                        lastinfo = *child->last_siginfo;
 333                        error = 0;
 334                }
 335                spin_unlock_irq(&child->sighand->siglock);
 336        }
 337        read_unlock(&tasklist_lock);
 338        if (!error)
 339                return copy_siginfo_to_user(data, &lastinfo);
 340        return error;
 341}
 342
 343static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data)
 344{
 345        siginfo_t newinfo;
 346        int error = -ESRCH;
 347
 348        if (copy_from_user(&newinfo, data, sizeof (siginfo_t)))
 349                return -EFAULT;
 350
 351        read_lock(&tasklist_lock);
 352        if (likely(child->sighand != NULL)) {
 353                error = -EINVAL;
 354                spin_lock_irq(&child->sighand->siglock);
 355                if (likely(child->last_siginfo != NULL)) {
 356                        *child->last_siginfo = newinfo;
 357                        error = 0;
 358                }
 359                spin_unlock_irq(&child->sighand->siglock);
 360        }
 361        read_unlock(&tasklist_lock);
 362        return error;
 363}
 364
 365int ptrace_request(struct task_struct *child, long request,
 366                   long addr, long data)
 367{
 368        int ret = -EIO;
 369
 370        switch (request) {
 371#ifdef PTRACE_OLDSETOPTIONS
 372        case PTRACE_OLDSETOPTIONS:
 373#endif
 374        case PTRACE_SETOPTIONS:
 375                ret = ptrace_setoptions(child, data);
 376                break;
 377        case PTRACE_GETEVENTMSG:
 378                ret = put_user(child->ptrace_message, (unsigned long __user *) data);
 379                break;
 380        case PTRACE_GETSIGINFO:
 381                ret = ptrace_getsiginfo(child, (siginfo_t __user *) data);
 382                break;
 383        case PTRACE_SETSIGINFO:
 384                ret = ptrace_setsiginfo(child, (siginfo_t __user *) data);
 385                break;
 386        default:
 387                break;
 388        }
 389
 390        return ret;
 391}
 392
 393/**
 394 * ptrace_traceme  --  helper for PTRACE_TRACEME
 395 *
 396 * Performs checks and sets PT_PTRACED.
 397 * Should be used by all ptrace implementations for PTRACE_TRACEME.
 398 */
 399int ptrace_traceme(void)
 400{
 401        int ret = -EPERM;
 402
 403        /*
 404         * Are we already being traced?
 405         */
 406        task_lock(current);
 407        if (!(current->ptrace & PT_PTRACED)) {
 408                ret = security_ptrace(current->parent, current);
 409                /*
 410                 * Set the ptrace bit in the process ptrace flags.
 411                 */
 412                if (!ret)
 413                        current->ptrace |= PT_PTRACED;
 414        }
 415        task_unlock(current);
 416        return ret;
 417}
 418
 419/**
 420 * ptrace_get_task_struct  --  grab a task struct reference for ptrace
 421 * @pid:       process id to grab a task_struct reference of
 422 *
 423 * This function is a helper for ptrace implementations.  It checks
 424 * permissions and then grabs a task struct for use of the actual
 425 * ptrace implementation.
 426 *
 427 * Returns the task_struct for @pid or an ERR_PTR() on failure.
 428 */
 429struct task_struct *ptrace_get_task_struct(pid_t pid)
 430{
 431        struct task_struct *child;
 432
 433        /*
 434         * Tracing init is not allowed.
 435         */
 436        if (pid == 1)
 437                return ERR_PTR(-EPERM);
 438
 439        read_lock(&tasklist_lock);
 440        child = find_task_by_pid(pid);
 441        if (child)
 442                get_task_struct(child);
 443
 444        read_unlock(&tasklist_lock);
 445        if (!child)
 446                return ERR_PTR(-ESRCH);
 447        return child;
 448}
 449
 450#ifndef __ARCH_SYS_PTRACE
 451asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
 452{
 453        struct task_struct *child;
 454        long ret;
 455
 456        /*
 457         * This lock_kernel fixes a subtle race with suid exec
 458         */
 459        lock_kernel();
 460        if (request == PTRACE_TRACEME) {
 461                ret = ptrace_traceme();
 462                goto out;
 463        }
 464
 465        child = ptrace_get_task_struct(pid);
 466        if (IS_ERR(child)) {
 467                ret = PTR_ERR(child);
 468                goto out;
 469        }
 470
 471        if (request == PTRACE_ATTACH) {
 472                ret = ptrace_attach(child);
 473                goto out_put_task_struct;
 474        }
 475
 476        ret = ptrace_check_attach(child, request == PTRACE_KILL);
 477        if (ret < 0)
 478                goto out_put_task_struct;
 479
 480        ret = arch_ptrace(child, request, addr, data);
 481        if (ret < 0)
 482                goto out_put_task_struct;
 483
 484 out_put_task_struct:
 485        put_task_struct(child);
 486 out:
 487        unlock_kernel();
 488        return ret;
 489}
 490#endif /* __ARCH_SYS_PTRACE */
 491