linux-bk/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/sched.h>
  11#include <linux/errno.h>
  12#include <linux/mm.h>
  13#include <linux/highmem.h>
  14#include <linux/pagemap.h>
  15#include <linux/smp_lock.h>
  16#include <linux/ptrace.h>
  17
  18#include <asm/pgtable.h>
  19#include <asm/uaccess.h>
  20
  21/*
  22 * ptrace a task: make the debugger its new parent and
  23 * move it to the ptrace list.
  24 *
  25 * Must be called with the tasklist lock write-held.
  26 */
  27void __ptrace_link(task_t *child, task_t *new_parent)
  28{
  29        if (!list_empty(&child->ptrace_list))
  30                BUG();
  31        if (child->parent == new_parent)
  32                return;
  33        list_add(&child->ptrace_list, &child->parent->ptrace_children);
  34        REMOVE_LINKS(child);
  35        child->parent = new_parent;
  36        SET_LINKS(child);
  37}
  38 
  39/*
  40 * unptrace a task: move it back to its original parent and
  41 * remove it from the ptrace list.
  42 *
  43 * Must be called with the tasklist lock write-held.
  44 */
  45void __ptrace_unlink(task_t *child)
  46{
  47        if (!child->ptrace)
  48                BUG();
  49        child->ptrace = 0;
  50        if (list_empty(&child->ptrace_list))
  51                return;
  52        list_del_init(&child->ptrace_list);
  53        REMOVE_LINKS(child);
  54        child->parent = child->real_parent;
  55        SET_LINKS(child);
  56}
  57
  58/*
  59 * Check that we have indeed attached to the thing..
  60 */
  61int ptrace_check_attach(struct task_struct *child, int kill)
  62{
  63        if (!(child->ptrace & PT_PTRACED))
  64                return -ESRCH;
  65
  66        if (child->parent != current)
  67                return -ESRCH;
  68
  69        if (!kill) {
  70                if (child->state != TASK_STOPPED)
  71                        return -ESRCH;
  72                wait_task_inactive(child);
  73        }
  74
  75        /* All systems go.. */
  76        return 0;
  77}
  78
  79int ptrace_attach(struct task_struct *task)
  80{
  81        int retval;
  82        task_lock(task);
  83        retval = -EPERM;
  84        if (task->pid <= 1)
  85                goto bad;
  86        if (task == current)
  87                goto bad;
  88        if (!task->mm)
  89                goto bad;
  90        if(((current->uid != task->euid) ||
  91            (current->uid != task->suid) ||
  92            (current->uid != task->uid) ||
  93            (current->gid != task->egid) ||
  94            (current->gid != task->sgid) ||
  95            (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
  96                goto bad;
  97        rmb();
  98        if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE))
  99                goto bad;
 100        /* the same process cannot be attached many times */
 101        if (task->ptrace & PT_PTRACED)
 102                goto bad;
 103        retval = security_ops->ptrace(current, task);
 104        if (retval)
 105                goto bad;
 106
 107        /* Go */
 108        task->ptrace |= PT_PTRACED;
 109        if (capable(CAP_SYS_PTRACE))
 110                task->ptrace |= PT_PTRACE_CAP;
 111        task_unlock(task);
 112
 113        write_lock_irq(&tasklist_lock);
 114        __ptrace_link(task, current);
 115        write_unlock_irq(&tasklist_lock);
 116
 117        send_sig(SIGSTOP, task, 1);
 118        return 0;
 119
 120bad:
 121        task_unlock(task);
 122        return retval;
 123}
 124
 125int ptrace_detach(struct task_struct *child, unsigned int data)
 126{
 127        if ((unsigned long) data > _NSIG)
 128                return  -EIO;
 129
 130        /* Architecture-specific hardware disable .. */
 131        ptrace_disable(child);
 132
 133        /* .. re-parent .. */
 134        child->exit_code = data;
 135
 136        write_lock_irq(&tasklist_lock);
 137        __ptrace_unlink(child);
 138        /* .. and wake it up. */
 139        if (child->state != TASK_ZOMBIE)
 140                wake_up_process(child);
 141        write_unlock_irq(&tasklist_lock);
 142
 143        return 0;
 144}
 145
 146/*
 147 * Access another process' address space.
 148 * Source/target buffer must be kernel space, 
 149 * Do not walk the page table directly, use get_user_pages
 150 */
 151
 152int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
 153{
 154        struct mm_struct *mm;
 155        struct vm_area_struct *vma;
 156        struct page *page;
 157        void *old_buf = buf;
 158
 159        mm = get_task_mm(tsk);
 160        if (!mm)
 161                return 0;
 162
 163        down_read(&mm->mmap_sem);
 164        /* ignore errors, just check how much was sucessfully transfered */
 165        while (len) {
 166                int bytes, ret, offset;
 167                void *maddr;
 168
 169                ret = get_user_pages(current, mm, addr, 1,
 170                                write, 1, &page, &vma);
 171                if (ret <= 0)
 172                        break;
 173
 174                bytes = len;
 175                offset = addr & (PAGE_SIZE-1);
 176                if (bytes > PAGE_SIZE-offset)
 177                        bytes = PAGE_SIZE-offset;
 178
 179                flush_cache_page(vma, addr);
 180
 181                maddr = kmap(page);
 182                if (write) {
 183                        memcpy(maddr + offset, buf, bytes);
 184                        flush_page_to_ram(page);
 185                        flush_icache_user_range(vma, page, addr, bytes);
 186                } else {
 187                        memcpy(buf, maddr + offset, bytes);
 188                        flush_page_to_ram(page);
 189                }
 190                kunmap(page);
 191                page_cache_release(page);
 192                len -= bytes;
 193                buf += bytes;
 194                addr += bytes;
 195        }
 196        up_read(&mm->mmap_sem);
 197        mmput(mm);
 198        
 199        return buf - old_buf;
 200}
 201
 202int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len)
 203{
 204        int copied = 0;
 205
 206        while (len > 0) {
 207                char buf[128];
 208                int this_len, retval;
 209
 210                this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
 211                retval = access_process_vm(tsk, src, buf, this_len, 0);
 212                if (!retval) {
 213                        if (copied)
 214                                break;
 215                        return -EIO;
 216                }
 217                if (copy_to_user(dst, buf, retval))
 218                        return -EFAULT;
 219                copied += retval;
 220                src += retval;
 221                dst += retval;
 222                len -= retval;                  
 223        }
 224        return copied;
 225}
 226
 227int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len)
 228{
 229        int copied = 0;
 230
 231        while (len > 0) {
 232                char buf[128];
 233                int this_len, retval;
 234
 235                this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
 236                if (copy_from_user(buf, src, this_len))
 237                        return -EFAULT;
 238                retval = access_process_vm(tsk, dst, buf, this_len, 1);
 239                if (!retval) {
 240                        if (copied)
 241                                break;
 242                        return -EIO;
 243                }
 244                copied += retval;
 245                src += retval;
 246                dst += retval;
 247                len -= retval;                  
 248        }
 249        return copied;
 250}
 251
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.