make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / kernel / ptrace.c
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/smp_lock.h>
15
16 #include <asm/pgtable.h>
17 #include <asm/uaccess.h>
18
19 /*
20  * Check that we have indeed attached to the thing..
21  */
22 int ptrace_check_attach(struct task_struct *child, int kill)
23 {
24         if (!(child->ptrace & PT_PTRACED))
25                 return -ESRCH;
26
27         if (child->p_pptr != current)
28                 return -ESRCH;
29
30         if (!kill) {
31                 if (child->state != TASK_STOPPED)
32                         return -ESRCH;
33 #ifdef CONFIG_SMP
34                 /* Make sure the child gets off its CPU.. */
35                 for (;;) {
36                         task_lock(child);
37                         if (!task_has_cpu(child))
38                                 break;
39                         task_unlock(child);
40                         do {
41                                 if (child->state != TASK_STOPPED)
42                                         return -ESRCH;
43                                 barrier();
44                                 cpu_relax();
45                         } while (task_has_cpu(child));
46                 }
47                 task_unlock(child);
48 #endif          
49         }
50
51         /* All systems go.. */
52         return 0;
53 }
54
55 int ptrace_attach(struct task_struct *task)
56 {
57         task_lock(task);
58         if (task->pid <= 1)
59                 goto bad;
60         if (task == current)
61                 goto bad;
62         if (!task->mm)
63                 goto bad;
64         if(((current->uid != task->euid) ||
65             (current->uid != task->suid) ||
66             (current->uid != task->uid) ||
67             (current->gid != task->egid) ||
68             (current->gid != task->sgid) ||
69             (!cap_issubset(task->cap_permitted, current->cap_permitted)) ||
70             (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
71                 goto bad;
72         rmb();
73         if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE))
74                 goto bad;
75         /* the same process cannot be attached many times */
76         if (task->ptrace & PT_PTRACED)
77                 goto bad;
78
79         /* Go */
80         task->ptrace |= PT_PTRACED;
81         if (capable(CAP_SYS_PTRACE))
82                 task->ptrace |= PT_PTRACE_CAP;
83         task_unlock(task);
84
85         write_lock_irq(&tasklist_lock);
86         if (task->p_pptr != current) {
87                 REMOVE_LINKS(task);
88                 task->p_pptr = current;
89                 SET_LINKS(task);
90         }
91         write_unlock_irq(&tasklist_lock);
92
93         send_sig(SIGSTOP, task, 1);
94         return 0;
95
96 bad:
97         task_unlock(task);
98         return -EPERM;
99 }
100
101 int ptrace_detach(struct task_struct *child, unsigned int data)
102 {
103         if ((unsigned long) data > _NSIG)
104                 return  -EIO;
105
106         /* Architecture-specific hardware disable .. */
107         ptrace_disable(child);
108
109         /* .. re-parent .. */
110         child->ptrace = 0;
111         child->exit_code = data;
112         write_lock_irq(&tasklist_lock);
113         REMOVE_LINKS(child);
114         child->p_pptr = child->p_opptr;
115         SET_LINKS(child);
116         write_unlock_irq(&tasklist_lock);
117
118         /* .. and wake it up. */
119         wake_up_process(child);
120         return 0;
121 }
122
123 /*
124  * Access another process' address space.
125  * Source/target buffer must be kernel space, 
126  * Do not walk the page table directly, use get_user_pages
127  */
128
129 int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
130 {
131         struct mm_struct *mm;
132         struct vm_area_struct *vma;
133         struct page *page;
134         void *old_buf = buf;
135
136         /* Worry about races with exit() */
137         task_lock(tsk);
138         mm = tsk->mm;
139         if (mm)
140                 atomic_inc(&mm->mm_users);
141         task_unlock(tsk);
142         if (!mm)
143                 return 0;
144
145         down_read(&mm->mmap_sem);
146         /* ignore errors, just check how much was sucessfully transfered */
147         while (len) {
148                 int bytes, ret, offset;
149                 void *maddr;
150
151                 ret = get_user_pages(current, mm, addr, 1,
152                                 write, 1, &page, &vma);
153                 if (ret <= 0)
154                         break;
155
156                 bytes = len;
157                 offset = addr & (PAGE_SIZE-1);
158                 if (bytes > PAGE_SIZE-offset)
159                         bytes = PAGE_SIZE-offset;
160
161                 flush_cache_page(vma, addr);
162
163                 maddr = kmap(page);
164                 if (write) {
165                         memcpy(maddr + offset, buf, bytes);
166                         flush_page_to_ram(page);
167                         flush_icache_user_range(vma, page, addr, len);
168                 } else {
169                         memcpy(buf, maddr + offset, bytes);
170                         flush_page_to_ram(page);
171                 }
172                 kunmap(page);
173                 put_page(page);
174                 len -= bytes;
175                 buf += bytes;
176                 addr += bytes;
177         }
178         up_read(&mm->mmap_sem);
179         mmput(mm);
180         
181         return buf - old_buf;
182 }
183
184 int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len)
185 {
186         int copied = 0;
187
188         while (len > 0) {
189                 char buf[128];
190                 int this_len, retval;
191
192                 this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
193                 retval = access_process_vm(tsk, src, buf, this_len, 0);
194                 if (!retval) {
195                         if (copied)
196                                 break;
197                         return -EIO;
198                 }
199                 if (copy_to_user(dst, buf, retval))
200                         return -EFAULT;
201                 copied += retval;
202                 src += retval;
203                 dst += retval;
204                 len -= retval;                  
205         }
206         return copied;
207 }
208
209 int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len)
210 {
211         int copied = 0;
212
213         while (len > 0) {
214                 char buf[128];
215                 int this_len, retval;
216
217                 this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
218                 if (copy_from_user(buf, src, this_len))
219                         return -EFAULT;
220                 retval = access_process_vm(tsk, dst, buf, this_len, 1);
221                 if (!retval) {
222                         if (copied)
223                                 break;
224                         return -EIO;
225                 }
226                 copied += retval;
227                 src += retval;
228                 dst += retval;
229                 len -= retval;                  
230         }
231         return copied;
232 }